<commit_before>/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/
#include <algorithm>
#include <miopen/device_name.hpp>
#include <miopen/errors.hpp>
#include <miopen/handle.hpp>
#include <miopen/kernel_cache.hpp>
#include <miopen/binary_cache.hpp>
#include <boost/filesystem.hpp>

#ifndef _WIN32
#include <unistd.h>
#endif

#include <cassert>
#include <chrono>
#include <thread>

namespace miopen {

// Get current context
// We leak resources for now as there is no hipCtxRetain API
hipCtx_t get_ctx()
{
    hipInit(0);
    hipCtx_t ctx;
    auto status = hipCtxGetCurrent(&ctx);
    if(status != hipSuccess)
        MIOPEN_THROW("No device");
    return ctx;
}

std::size_t GetAvailableMemory()
{
    size_t free, total;
    auto status = hipMemGetInfo(&free, &total);
    if(status != hipSuccess)
        MIOPEN_THROW_HIP_STATUS(status, "Failed getting available memory");
    return free;
}

void* default_allocator(void*, size_t sz)
{
    if(sz > GetAvailableMemory())
        MIOPEN_THROW("Memory not available to allocate buffer: " + std::to_string(sz));
    void* result;
    auto status = hipMalloc(&result, sz);
    if(status != hipSuccess)
    {
        status = hipHostMalloc(&result, sz);
        if(status != hipSuccess)
            MIOPEN_THROW_HIP_STATUS(status,
                                    "Hip error creating buffer " + std::to_string(sz) + ": ");
    }
    return result;
}

void default_deallocator(void*, void* mem) { hipFree(mem); }

int get_device_id() // Get random device
{
    int device;
    auto status = hipGetDevice(&device);
    if(status != hipSuccess)
        MIOPEN_THROW("No device");
    return device;
}

void set_device(int id)
{
    auto status = hipSetDevice(id);
    if(status != hipSuccess)
        MIOPEN_THROW("Error setting device");
}

void set_ctx(hipCtx_t ctx)
{
    auto status = hipCtxSetCurrent(ctx);
    if(status != hipSuccess)
        MIOPEN_THROW("Error setting context");
}

int set_default_device()
{
    int n;
    auto status = hipGetDeviceCount(&n);
    if(status != hipSuccess)
        MIOPEN_THROW("Error getting device count");
    // Pick device based on process id
    auto pid = ::getpid();
    assert(pid > 0);
    set_device(pid % n);
    return (pid % n);
}

struct HandleImpl
{
    // typedef MIOPEN_MANAGE_PTR(hipStream_t, hipStreamDestroy) StreamPtr;
    using StreamPtr = std::shared_ptr<typename std::remove_pointer<hipStream_t>::type>;

    HandleImpl() : ctx(get_ctx()) {}

    StreamPtr create_stream()
    {
        hipStream_t result;
        auto status = hipStreamCreate(&result);
        if(status != hipSuccess)
            MIOPEN_THROW_HIP_STATUS(status, "Failed to allocate stream");
        return StreamPtr{result, &hipStreamDestroy};
    }

    static StreamPtr reference_stream(hipStream_t s) { return StreamPtr{s, null_deleter{}}; }

    void elapsed_time(hipEvent_t start, hipEvent_t stop)
    {
        hipEventElapsedTime(&this->profiling_result, start, stop);
    }

    std::function<void(hipEvent_t, hipEvent_t)> elapsed_time_handler()
    {
        return std::bind(
            &HandleImpl::elapsed_time, this, std::placeholders::_1, std::placeholders::_2);
    }

    void set_ctx()
    {
        miopen::set_ctx(this->ctx);
        // TODO: Check device matches
    }

    bool enable_profiling  = false;
    StreamPtr stream       = nullptr;
    float profiling_result = 0.0;
    int device             = -1;
    Allocator allocator{};
    KernelCache cache;
    hipCtx_t ctx;
};

Handle::Handle(miopenAcceleratorQueue_t stream) : impl(new HandleImpl())
{
    this->impl->device = get_device_id();
    this->impl->ctx    = get_ctx();

    if(stream == nullptr)
        this->impl->stream = HandleImpl::reference_stream(nullptr);
    else
        this->impl->stream = HandleImpl::reference_stream(stream);

    this->SetAllocator(nullptr, nullptr, nullptr);
}

Handle::Handle() : impl(new HandleImpl())
{
#if MIOPEN_BUILD_DEV
    this->impl->device = set_default_device();
    this->impl->ctx    = get_ctx();
    this->impl->stream = impl->create_stream();
#else
    this->impl->device = get_device_id();
    this->impl->ctx    = get_ctx();
    this->impl->stream = HandleImpl::reference_stream(nullptr);
#endif
    this->SetAllocator(nullptr, nullptr, nullptr);
}

Handle::~Handle() {}

void Handle::SetStream(miopenAcceleratorQueue_t streamID) const
{
    this->impl->stream = HandleImpl::reference_stream(streamID);
}

miopenAcceleratorQueue_t Handle::GetStream() const { return impl->stream.get(); }

void Handle::SetAllocator(miopenAllocatorFunction allocator,
                          miopenDeallocatorFunction deallocator,
                          void* allocatorContext) const
{
    this->impl->allocator.allocator   = allocator == nullptr ? default_allocator : allocator;
    this->impl->allocator.deallocator = deallocator == nullptr ? default_deallocator : deallocator;

    this->impl->allocator.context = allocatorContext;
}

void Handle::EnableProfiling(bool enable) { this->impl->enable_profiling = enable; }

float Handle::GetKernelTime() const { return this->impl->profiling_result; }

Allocator::ManageDataPtr Handle::Create(std::size_t sz)
{
    this->Finish();
    return this->impl->allocator(sz);
}
Allocator::ManageDataPtr&
Handle::WriteTo(const void* data, Allocator::ManageDataPtr& ddata, std::size_t sz)
{
    auto status = hipMemcpy(ddata.get(), data, sz, hipMemcpyHostToDevice);
    if(status != hipSuccess)
        MIOPEN_THROW_HIP_STATUS(status, "Hip error writing to buffer: ");
    return ddata;
}
void Handle::ReadTo(void* data, const Allocator::ManageDataPtr& ddata, std::size_t sz)
{
    auto status = hipMemcpy(data, ddata.get(), sz, hipMemcpyDeviceToHost);
    if(status != hipSuccess)
        MIOPEN_THROW_HIP_STATUS(status, "Hip error reading from buffer: ");
}

void Handle::Copy(ConstData_t src, Data_t dest, std::size_t size)
{
    this->impl->set_ctx();
    auto status = hipMemcpy(dest, src, size, hipMemcpyDeviceToDevice);
    if(status != hipSuccess)
        MIOPEN_THROW_HIP_STATUS(status, "Hip error copying buffer: ");
}

KernelInvoke Handle::GetKernel(const std::string& algorithm,
                               const std::string& network_config,
                               const std::string& program_name,
                               const std::string& kernel_name,
                               const std::vector<size_t>& vld,
                               const std::vector<size_t>& vgd,
                               const std::string& params)
{
    this->impl->set_ctx();
    auto k = this->impl->cache.GetKernel(
        *this, algorithm, network_config, program_name, kernel_name, vld, vgd, params);
    if(this->impl->enable_profiling)
        return k.Invoke(this->GetStream(), this->impl->elapsed_time_handler());
    else
        return k.Invoke(this->GetStream());
}

KernelInvoke Handle::GetKernel(const std::string& algorithm, const std::string& network_config)
{
    this->impl->set_ctx();
    auto k = this->impl->cache.GetKernel(algorithm, network_config);
    if(this->impl->enable_profiling)
        return k.Invoke(this->GetStream(), this->impl->elapsed_time_handler());
    else
        return k.Invoke(this->GetStream());
}

Program Handle::LoadProgram(const std::string& program_name, std::string params, bool is_kernel_str)
{
    this->impl->set_ctx();
    params += " -mcpu=" + this->GetDeviceName();
    auto cache_file =
        miopen::LoadBinary(this->GetDeviceName(), program_name, params, is_kernel_str);
    if(cache_file.empty())
    {
        auto p = HIPOCProgram{program_name, params, is_kernel_str};

        // Save to cache
        auto path = miopen::GetCachePath() / boost::filesystem::unique_path();
        boost::filesystem::copy_file(p.GetBinary(), path);
        miopen::SaveBinary(path, this->GetDeviceName(), program_name, params, is_kernel_str);

        return p;
    }
    else
    {
        return HIPOCProgram{program_name, cache_file};
    }
}

void Handle::Finish() const
{
    this->impl->set_ctx();
#if MIOPEN_BUILD_DEV
    auto start = std::chrono::system_clock::now();
    auto ev    = make_hip_event();
    hipEventRecord(ev.get(), this->GetStream());
    while(hipEventQuery(ev.get()) == hipErrorNotReady)
    {
        std::this_thread::yield();
        if((std::chrono::system_clock::now() - start) > std::chrono::seconds(60))
        {
            std::cerr << "Timeout: Handle::Finish" << std::endl;
            std::abort();
        }
    }
#else
    auto status        = hipStreamSynchronize(this->GetStream());
    if(status != hipSuccess)
        MIOPEN_THROW_HIP_STATUS(status, "Failed hip sychronization");
#endif
}
void Handle::Flush() const {}

bool Handle::IsProfilingEnabled() const { return this->impl->enable_profiling; }

void Handle::ResetKernelTime() { this->impl->profiling_result = 0.0; }
void Handle::AccumKernelTime(float curr_time) { this->impl->profiling_result += curr_time; }

std::size_t Handle::GetLocalMemorySize()
{
    int result;
    auto status = hipDeviceGetAttribute(
        &result, hipDeviceAttributeMaxSharedMemoryPerBlock, this->impl->device);
    if(status != hipSuccess)
        MIOPEN_THROW_HIP_STATUS(status);

    return result;
}

std::size_t Handle::GetMaxComputeUnits()
{
    int result;
    auto status =
        hipDeviceGetAttribute(&result, hipDeviceAttributeMultiprocessorCount, this->impl->device);
    if(status != hipSuccess)
        MIOPEN_THROW_HIP_STATUS(status);

    return result;
}

std::string Handle::GetDeviceName()
{
    hipDeviceProp_t props{};
    hipGetDeviceProperties(&props, this->impl->device);
    std::string n("gfx" + std::to_string(props.gcnArch));
    return GetDeviceNameFromMap(n);
}
} // namespace miopen
<commit_msg>Revert "Remove Finish from HIP WriteTo/ReadTo."<commit_after>/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/
#include <algorithm>
#include <miopen/device_name.hpp>
#include <miopen/errors.hpp>
#include <miopen/handle.hpp>
#include <miopen/kernel_cache.hpp>
#include <miopen/binary_cache.hpp>
#include <boost/filesystem.hpp>

#ifndef _WIN32
#include <unistd.h>
#endif

#include <cassert>
#include <chrono>
#include <thread>

namespace miopen {

// Get current context
// We leak resources for now as there is no hipCtxRetain API
hipCtx_t get_ctx()
{
    hipInit(0);
    hipCtx_t ctx;
    auto status = hipCtxGetCurrent(&ctx);
    if(status != hipSuccess)
        MIOPEN_THROW("No device");
    return ctx;
}

std::size_t GetAvailableMemory()
{
    size_t free, total;
    auto status = hipMemGetInfo(&free, &total);
    if(status != hipSuccess)
        MIOPEN_THROW_HIP_STATUS(status, "Failed getting available memory");
    return free;
}

void* default_allocator(void*, size_t sz)
{
    if(sz > GetAvailableMemory())
        MIOPEN_THROW("Memory not available to allocate buffer: " + std::to_string(sz));
    void* result;
    auto status = hipMalloc(&result, sz);
    if(status != hipSuccess)
    {
        status = hipHostMalloc(&result, sz);
        if(status != hipSuccess)
            MIOPEN_THROW_HIP_STATUS(status,
                                    "Hip error creating buffer " + std::to_string(sz) + ": ");
    }
    return result;
}

void default_deallocator(void*, void* mem) { hipFree(mem); }

int get_device_id() // Get random device
{
    int device;
    auto status = hipGetDevice(&device);
    if(status != hipSuccess)
        MIOPEN_THROW("No device");
    return device;
}

void set_device(int id)
{
    auto status = hipSetDevice(id);
    if(status != hipSuccess)
        MIOPEN_THROW("Error setting device");
}

void set_ctx(hipCtx_t ctx)
{
    auto status = hipCtxSetCurrent(ctx);
    if(status != hipSuccess)
        MIOPEN_THROW("Error setting context");
}

int set_default_device()
{
    int n;
    auto status = hipGetDeviceCount(&n);
    if(status != hipSuccess)
        MIOPEN_THROW("Error getting device count");
    // Pick device based on process id
    auto pid = ::getpid();
    assert(pid > 0);
    set_device(pid % n);
    return (pid % n);
}

struct HandleImpl
{
    // typedef MIOPEN_MANAGE_PTR(hipStream_t, hipStreamDestroy) StreamPtr;
    using StreamPtr = std::shared_ptr<typename std::remove_pointer<hipStream_t>::type>;

    HandleImpl() : ctx(get_ctx()) {}

    StreamPtr create_stream()
    {
        hipStream_t result;
        auto status = hipStreamCreate(&result);
        if(status != hipSuccess)
            MIOPEN_THROW_HIP_STATUS(status, "Failed to allocate stream");
        return StreamPtr{result, &hipStreamDestroy};
    }

    static StreamPtr reference_stream(hipStream_t s) { return StreamPtr{s, null_deleter{}}; }

    void elapsed_time(hipEvent_t start, hipEvent_t stop)
    {
        hipEventElapsedTime(&this->profiling_result, start, stop);
    }

    std::function<void(hipEvent_t, hipEvent_t)> elapsed_time_handler()
    {
        return std::bind(
            &HandleImpl::elapsed_time, this, std::placeholders::_1, std::placeholders::_2);
    }

    void set_ctx()
    {
        miopen::set_ctx(this->ctx);
        // TODO: Check device matches
    }

    bool enable_profiling  = false;
    StreamPtr stream       = nullptr;
    float profiling_result = 0.0;
    int device             = -1;
    Allocator allocator{};
    KernelCache cache;
    hipCtx_t ctx;
};

Handle::Handle(miopenAcceleratorQueue_t stream) : impl(new HandleImpl())
{
    this->impl->device = get_device_id();
    this->impl->ctx    = get_ctx();

    if(stream == nullptr)
        this->impl->stream = HandleImpl::reference_stream(nullptr);
    else
        this->impl->stream = HandleImpl::reference_stream(stream);

    this->SetAllocator(nullptr, nullptr, nullptr);
}

Handle::Handle() : impl(new HandleImpl())
{
#if MIOPEN_BUILD_DEV
    this->impl->device = set_default_device();
    this->impl->ctx    = get_ctx();
    this->impl->stream = impl->create_stream();
#else
    this->impl->device = get_device_id();
    this->impl->ctx    = get_ctx();
    this->impl->stream = HandleImpl::reference_stream(nullptr);
#endif
    this->SetAllocator(nullptr, nullptr, nullptr);
}

Handle::~Handle() {}

void Handle::SetStream(miopenAcceleratorQueue_t streamID) const
{
    this->impl->stream = HandleImpl::reference_stream(streamID);
}

miopenAcceleratorQueue_t Handle::GetStream() const { return impl->stream.get(); }

void Handle::SetAllocator(miopenAllocatorFunction allocator,
                          miopenDeallocatorFunction deallocator,
                          void* allocatorContext) const
{
    this->impl->allocator.allocator   = allocator == nullptr ? default_allocator : allocator;
    this->impl->allocator.deallocator = deallocator == nullptr ? default_deallocator : deallocator;

    this->impl->allocator.context = allocatorContext;
}

void Handle::EnableProfiling(bool enable) { this->impl->enable_profiling = enable; }

float Handle::GetKernelTime() const { return this->impl->profiling_result; }

Allocator::ManageDataPtr Handle::Create(std::size_t sz)
{
    this->Finish();
    return this->impl->allocator(sz);
}
Allocator::ManageDataPtr&
Handle::WriteTo(const void* data, Allocator::ManageDataPtr& ddata, std::size_t sz)
{
    this->Finish();
    auto status = hipMemcpy(ddata.get(), data, sz, hipMemcpyHostToDevice);
    if(status != hipSuccess)
        MIOPEN_THROW_HIP_STATUS(status, "Hip error writing to buffer: ");
    return ddata;
}
void Handle::ReadTo(void* data, const Allocator::ManageDataPtr& ddata, std::size_t sz)
{
    this->Finish();
    auto status = hipMemcpy(data, ddata.get(), sz, hipMemcpyDeviceToHost);
    if(status != hipSuccess)
        MIOPEN_THROW_HIP_STATUS(status, "Hip error reading from buffer: ");
}

void Handle::Copy(ConstData_t src, Data_t dest, std::size_t size)
{
    this->impl->set_ctx();
    auto status = hipMemcpy(dest, src, size, hipMemcpyDeviceToDevice);
    if(status != hipSuccess)
        MIOPEN_THROW_HIP_STATUS(status, "Hip error copying buffer: ");
}

KernelInvoke Handle::GetKernel(const std::string& algorithm,
                               const std::string& network_config,
                               const std::string& program_name,
                               const std::string& kernel_name,
                               const std::vector<size_t>& vld,
                               const std::vector<size_t>& vgd,
                               const std::string& params)
{
    this->impl->set_ctx();
    auto k = this->impl->cache.GetKernel(
        *this, algorithm, network_config, program_name, kernel_name, vld, vgd, params);
    if(this->impl->enable_profiling)
        return k.Invoke(this->GetStream(), this->impl->elapsed_time_handler());
    else
        return k.Invoke(this->GetStream());
}

KernelInvoke Handle::GetKernel(const std::string& algorithm, const std::string& network_config)
{
    this->impl->set_ctx();
    auto k = this->impl->cache.GetKernel(algorithm, network_config);
    if(this->impl->enable_profiling)
        return k.Invoke(this->GetStream(), this->impl->elapsed_time_handler());
    else
        return k.Invoke(this->GetStream());
}

Program Handle::LoadProgram(const std::string& program_name, std::string params, bool is_kernel_str)
{
    this->impl->set_ctx();
    params += " -mcpu=" + this->GetDeviceName();
    auto cache_file =
        miopen::LoadBinary(this->GetDeviceName(), program_name, params, is_kernel_str);
    if(cache_file.empty())
    {
        auto p = HIPOCProgram{program_name, params, is_kernel_str};

        // Save to cache
        auto path = miopen::GetCachePath() / boost::filesystem::unique_path();
        boost::filesystem::copy_file(p.GetBinary(), path);
        miopen::SaveBinary(path, this->GetDeviceName(), program_name, params, is_kernel_str);

        return p;
    }
    else
    {
        return HIPOCProgram{program_name, cache_file};
    }
}

void Handle::Finish() const
{
    this->impl->set_ctx();
#if MIOPEN_BUILD_DEV
    auto start = std::chrono::system_clock::now();
    auto ev    = make_hip_event();
    hipEventRecord(ev.get(), this->GetStream());
    while(hipEventQuery(ev.get()) == hipErrorNotReady)
    {
        std::this_thread::yield();
        if((std::chrono::system_clock::now() - start) > std::chrono::seconds(60))
        {
            std::cerr << "Timeout: Handle::Finish" << std::endl;
            std::abort();
        }
    }
#else
    auto status        = hipStreamSynchronize(this->GetStream());
    if(status != hipSuccess)
        MIOPEN_THROW_HIP_STATUS(status, "Failed hip sychronization");
#endif
}
void Handle::Flush() const {}

bool Handle::IsProfilingEnabled() const { return this->impl->enable_profiling; }

void Handle::ResetKernelTime() { this->impl->profiling_result = 0.0; }
void Handle::AccumKernelTime(float curr_time) { this->impl->profiling_result += curr_time; }

std::size_t Handle::GetLocalMemorySize()
{
    int result;
    auto status = hipDeviceGetAttribute(
        &result, hipDeviceAttributeMaxSharedMemoryPerBlock, this->impl->device);
    if(status != hipSuccess)
        MIOPEN_THROW_HIP_STATUS(status);

    return result;
}

std::size_t Handle::GetMaxComputeUnits()
{
    int result;
    auto status =
        hipDeviceGetAttribute(&result, hipDeviceAttributeMultiprocessorCount, this->impl->device);
    if(status != hipSuccess)
        MIOPEN_THROW_HIP_STATUS(status);

    return result;
}

std::string Handle::GetDeviceName()
{
    hipDeviceProp_t props{};
    hipGetDeviceProperties(&props, this->impl->device);
    std::string n("gfx" + std::to_string(props.gcnArch));
    return GetDeviceNameFromMap(n);
}
} // namespace miopen
<|endoftext|>


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

#include <limits.h>

#include <iostream>
#include <sstream>
#include <stdexcept>
#include <iomanip>

#include "HostShare.h"

using namespace std;

/* ************************************************************************ */
/* HostSharePCI                                                             */
/* ************************************************************************ */

int HostSharePCI::from_xml_node(const xmlNodePtr node)
{
    int rc = Template::from_xml_node(node);

    if (rc != 0)
    {
        return -1;
    }

    return init();
}

/* ------------------------------------------------------------------------*/

int HostSharePCI::init()
{
    vector<Attribute *> devices;

    int num_devs = get("PCI", devices);

    for (int i=0; i < num_devs; i++)
    {
        VectorAttribute * pci = dynamic_cast<VectorAttribute *>(devices[i]);

        if (pci == 0)
        {
            return -1;
        }

        PCIDevice * pcidev = new PCIDevice(pci);

        pci_devices.insert(make_pair(pcidev->address, pcidev));
    }

    return 0;
}

/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/

bool HostSharePCI::test(const vector<Attribute *> &devs) const
{
    vector<Attribute *>::const_iterator it;
    map<string, PCIDevice *>::const_iterator jt;

    std::set<string> assigned;

    unsigned int vendor_id, device_id, class_id;
    bool found;

    for ( it=devs.begin(); it!= devs.end(); it++)
    {
        const VectorAttribute* pci = dynamic_cast<const VectorAttribute *>(*it);

        if ( pci == 0 )
        {
            return false;
        }

        vendor_id = get_pci_value("VENDOR", pci);
        device_id = get_pci_value("DEVICE", pci);
        class_id  = get_pci_value("CLASS", pci);

        for (jt=pci_devices.begin(), found=false; jt!=pci_devices.end(); jt++)
        {
            PCIDevice * dev = jt->second;

            if ((class_id  == 0 || dev->class_id  == class_id)  &&
                (vendor_id == 0 || dev->vendor_id == vendor_id) &&
                (device_id == 0 || dev->device_id == device_id) &&
                dev->vmid  == -1 &&
                assigned.find(dev->address) == assigned.end())
            {
                assigned.insert(dev->address);
                found=true;

                break;
            }
        }

        if (!found)
        {
            return false;
        }
    }

    return true;
}

/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/

void HostSharePCI::add(vector<Attribute *> &devs, int vmid)
{
    vector<Attribute *>::iterator it;
    map<string, PCIDevice *>::const_iterator jt;

    unsigned int vendor_id, device_id, class_id;

    for ( it=devs.begin(); it!= devs.end(); it++)
    {
        VectorAttribute * pci = dynamic_cast<VectorAttribute *>(*it);

        if ( pci == 0 )
        {
            return;
        }

        vendor_id = get_pci_value("VENDOR", pci);
        device_id = get_pci_value("DEVICE", pci);
        class_id  = get_pci_value("CLASS", pci);

        for (jt=pci_devices.begin(); jt!=pci_devices.end(); jt++)
        {
            PCIDevice * dev = jt->second;

            if ((class_id  == 0 || dev->class_id  == class_id)  &&
                (vendor_id == 0 || dev->vendor_id == vendor_id) &&
                (device_id == 0 || dev->device_id == device_id) &&
                dev->vmid  == -1 )
            {
                dev->vmid = vmid;
                dev->attrs->replace("VMID", vmid);

                pci->replace("DOMAIN",dev->attrs->vector_value("DOMAIN"));
                pci->replace("BUS",dev->attrs->vector_value("BUS"));
                pci->replace("SLOT",dev->attrs->vector_value("SLOT"));
                pci->replace("FUNCTION",dev->attrs->vector_value("FUNCTION"));

                pci->replace("ADDRESS",dev->attrs->vector_value("ADDRESS"));
            }
        }
    }
}

/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/

void HostSharePCI::del(const vector<Attribute *> &devs)
{
    vector<Attribute *>::const_iterator it;
    map<string, PCIDevice *>::iterator pci_it;

    for ( it=devs.begin(); it!= devs.end(); it++)
    {
        const VectorAttribute * pci = dynamic_cast<const VectorAttribute *>(*it);

        if ( pci == 0 )
        {
            continue;
        }

        pci_it = pci_devices.find(pci->vector_value("ADDRESS"));

        if (pci_it != pci_devices.end())
        {
            pci_it->second->vmid = -1;
            pci_it->second->attrs->replace("VMID",-1);
        }
    }
};

/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/

void HostSharePCI::set_monitorization(vector<Attribute*> &pci_att)
{
    vector<Attribute*>::iterator it;
    map<string, PCIDevice*>::iterator pci_it;

    string address;

    std::set<string> missing;
    std::set<string>::iterator jt;

    for (pci_it = pci_devices.begin(); pci_it != pci_devices.end(); pci_it++)
    {
        missing.insert(pci_it->first);
    }

    for (it = pci_att.begin(); it != pci_att.end(); it++)
    {
        VectorAttribute * pci = dynamic_cast<VectorAttribute *>(*it);

        if ( pci == 0 )
        {
            continue;
        }

        address = pci->vector_value("ADDRESS");

        if (address.empty())
        {
            delete pci;
            continue;
        }

        pci_it = pci_devices.find(address);

        if (pci_it != pci_devices.end())
        {
            missing.erase(address);
            delete pci;

            continue;
        }

        PCIDevice * dev = new PCIDevice(pci);

        pci_devices.insert(make_pair(address, dev));

        set(pci);
    }

    for ( jt = missing.begin() ; jt != missing.end(); jt ++ )
    {
        pci_it = pci_devices.find(*jt);

        remove(pci_it->second->attrs);

        delete pci_it->second->attrs;

        delete pci_it->second;

        pci_devices.erase(pci_it);

    }
};

/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/

unsigned int HostSharePCI::get_pci_value(const char * name,
    const VectorAttribute * pci_device)
{
    string temp;

    temp = pci_device->vector_value(name);

    if (temp.empty())
    {
        return 0;
    }

    unsigned int  pci_value;
    istringstream iss(temp);

    iss >> hex >> pci_value;

    if (iss.fail() || !iss.eof())
    {
        return 0;
    }

    return pci_value;
}

/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/

HostSharePCI::PCIDevice::PCIDevice(VectorAttribute * _attrs)
    : vmid(-1), attrs(_attrs)
{
    vendor_id = get_pci_value("VENDOR", attrs);
    device_id = get_pci_value("DEVICE", attrs);
    class_id  = get_pci_value("CLASS", attrs);

    if (attrs->vector_value("VMID", vmid) == -1)
	{
		attrs->replace("VMID", -1);
	}

    attrs->vector_value("ADDRESS", address);
};

/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/

ostream& operator<<(ostream& os, const HostSharePCI& pci)
{
    map<string, HostSharePCI::PCIDevice *>::const_iterator it;

	os  << right << setw(15)<< "PCI ADDRESS"<< " "
		<< right << setw(8) << "CLASS"  << " "
		<< right << setw(8) << "VENDOR" << " "
		<< right << setw(8) << "DEVICE" << " "
		<< right << setw(8) << "VMID"   << " "
		<< endl << setw(55) << setfill('-') << "-" << setfill(' ') << endl;

    for (it=pci.pci_devices.begin(); it!=pci.pci_devices.end(); it++)
    {
        HostSharePCI::PCIDevice * dev = it->second;

		os << right << setw(15)<< dev->address   << " "
		   << right << setw(8) << dev->class_id  << " "
		   << right << setw(8) << dev->vendor_id << " "
		   << right << setw(8) << dev->device_id << " "
		   << right << setw(8) << dev->vmid      << " " << endl;
    }

	return os;
}
/* ************************************************************************ */
/* HostShare :: Constructor/Destructor                                      */
/* ************************************************************************ */

HostShare::HostShare(long long _max_disk,long long _max_mem,long long _max_cpu):
        ObjectXML(),
        disk_usage(0),
        mem_usage(0),
        cpu_usage(0),
        max_disk(_max_disk),
        max_mem(_max_mem),
        max_cpu(_max_cpu),
        free_disk(0),
        free_mem(0),
        free_cpu(0),
        used_disk(0),
        used_mem(0),
        used_cpu(0),
        running_vms(0){};

ostream& operator<<(ostream& os, HostShare& hs)
{
    string str;

    os << hs.to_xml(str);

    return os;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

string& HostShare::to_xml(string& xml) const
{
    string ds_xml, pci_xml;
    ostringstream   oss;

    oss << "<HOST_SHARE>"
          << "<DISK_USAGE>" << disk_usage << "</DISK_USAGE>"
          << "<MEM_USAGE>"  << mem_usage  << "</MEM_USAGE>"
          << "<CPU_USAGE>"  << cpu_usage  << "</CPU_USAGE>"
          << "<MAX_DISK>"   << max_disk   << "</MAX_DISK>"
          << "<MAX_MEM>"    << max_mem    << "</MAX_MEM>"
          << "<MAX_CPU>"    << max_cpu    << "</MAX_CPU>"
          << "<FREE_DISK>"  << free_disk  << "</FREE_DISK>"
          << "<FREE_MEM>"   << free_mem   << "</FREE_MEM>"
          << "<FREE_CPU>"   << free_cpu   << "</FREE_CPU>"
          << "<USED_DISK>"  << used_disk  << "</USED_DISK>"
          << "<USED_MEM>"   << used_mem   << "</USED_MEM>"
          << "<USED_CPU>"   << used_cpu   << "</USED_CPU>"
          << "<RUNNING_VMS>"<<running_vms <<"</RUNNING_VMS>"
          << ds.to_xml(ds_xml)
          << pci.to_xml(pci_xml)
        << "</HOST_SHARE>";

    xml = oss.str();

    return xml;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int HostShare::from_xml_node(const xmlNodePtr node)
{
    vector<xmlNodePtr> content;
    int rc = 0;

    // Initialize the internal XML object
    ObjectXML::update_from_node(node);

    rc += xpath(disk_usage, "/HOST_SHARE/DISK_USAGE", -1);
    rc += xpath(mem_usage,  "/HOST_SHARE/MEM_USAGE",  -1);
    rc += xpath(cpu_usage,  "/HOST_SHARE/CPU_USAGE",  -1);

    rc += xpath(max_disk,   "/HOST_SHARE/MAX_DISK",   -1);
    rc += xpath(max_mem ,   "/HOST_SHARE/MAX_MEM",    -1);
    rc += xpath(max_cpu ,   "/HOST_SHARE/MAX_CPU",    -1);

    rc += xpath(free_disk,  "/HOST_SHARE/FREE_DISK",  -1);
    rc += xpath(free_mem ,  "/HOST_SHARE/FREE_MEM",   -1);
    rc += xpath(free_cpu ,  "/HOST_SHARE/FREE_CPU",   -1);

    rc += xpath(used_disk,  "/HOST_SHARE/USED_DISK",  -1);
    rc += xpath(used_mem ,  "/HOST_SHARE/USED_MEM",   -1);
    rc += xpath(used_cpu ,  "/HOST_SHARE/USED_CPU",   -1);

    rc += xpath(running_vms,"/HOST_SHARE/RUNNING_VMS",-1);

    // ------------ Datastores ---------------

    ObjectXML::get_nodes("/HOST_SHARE/DATASTORES", content);

    if( content.empty())
    {
        return -1;
    }

    rc += ds.from_xml_node( content[0] );

    ObjectXML::free_nodes(content);

    content.clear();

    if (rc != 0)
    {
        return -1;
    }

    // ------------ PCI Devices ---------------

    ObjectXML::get_nodes("/HOST_SHARE/PCI_DEVICES", content);

    if( content.empty())
    {
        return -1;
    }

    rc += pci.from_xml_node( content[0] );

    ObjectXML::free_nodes(content);

    content.clear();

    if (rc != 0)
    {
        return -1;
    }

    return 0;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

void HostShare::set_ds_monitorization(const vector<Attribute*> &ds_att)
{
    vector<Attribute*>::const_iterator it;

    ds.erase("DS");

    for (it = ds_att.begin(); it != ds_att.end(); it++)
    {
        ds.set(*it);
    }
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

<commit_msg>feature #3028: Keep used PCI devices when updating monitoring<commit_after>/* ------------------------------------------------------------------------*/
/* Copyright 2002-2015, OpenNebula Project (OpenNebula.org), C12G Labs     */
/*                                                                         */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at                                                */
/*                                                                         */
/* http://www.apache.org/licenses/LICENSE-2.0                              */
/*                                                                         */
/* Unless required by applicable law or agreed to in writing, software     */
/* distributed under the License is distributed on an "AS IS" BASIS,       */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.*/
/* See the License for the specific language governing permissions and     */
/* limitations under the License.                                          */
/* ------------------------------------------------------------------------*/

#include <limits.h>

#include <iostream>
#include <sstream>
#include <stdexcept>
#include <iomanip>

#include "HostShare.h"

using namespace std;

/* ************************************************************************ */
/* HostSharePCI                                                             */
/* ************************************************************************ */

int HostSharePCI::from_xml_node(const xmlNodePtr node)
{
    int rc = Template::from_xml_node(node);

    if (rc != 0)
    {
        return -1;
    }

    return init();
}

/* ------------------------------------------------------------------------*/

int HostSharePCI::init()
{
    vector<Attribute *> devices;

    int num_devs = get("PCI", devices);

    for (int i=0; i < num_devs; i++)
    {
        VectorAttribute * pci = dynamic_cast<VectorAttribute *>(devices[i]);

        if (pci == 0)
        {
            return -1;
        }

        PCIDevice * pcidev = new PCIDevice(pci);

        pci_devices.insert(make_pair(pcidev->address, pcidev));
    }

    return 0;
}

/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/

bool HostSharePCI::test(const vector<Attribute *> &devs) const
{
    vector<Attribute *>::const_iterator it;
    map<string, PCIDevice *>::const_iterator jt;

    std::set<string> assigned;

    unsigned int vendor_id, device_id, class_id;
    bool found;

    for ( it=devs.begin(); it!= devs.end(); it++)
    {
        const VectorAttribute* pci = dynamic_cast<const VectorAttribute *>(*it);

        if ( pci == 0 )
        {
            return false;
        }

        vendor_id = get_pci_value("VENDOR", pci);
        device_id = get_pci_value("DEVICE", pci);
        class_id  = get_pci_value("CLASS", pci);

        for (jt=pci_devices.begin(), found=false; jt!=pci_devices.end(); jt++)
        {
            PCIDevice * dev = jt->second;

            if ((class_id  == 0 || dev->class_id  == class_id)  &&
                (vendor_id == 0 || dev->vendor_id == vendor_id) &&
                (device_id == 0 || dev->device_id == device_id) &&
                dev->vmid  == -1 &&
                assigned.find(dev->address) == assigned.end())
            {
                assigned.insert(dev->address);
                found=true;

                break;
            }
        }

        if (!found)
        {
            return false;
        }
    }

    return true;
}

/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/

void HostSharePCI::add(vector<Attribute *> &devs, int vmid)
{
    vector<Attribute *>::iterator it;
    map<string, PCIDevice *>::const_iterator jt;

    unsigned int vendor_id, device_id, class_id;

    for ( it=devs.begin(); it!= devs.end(); it++)
    {
        VectorAttribute * pci = dynamic_cast<VectorAttribute *>(*it);

        if ( pci == 0 )
        {
            return;
        }

        vendor_id = get_pci_value("VENDOR", pci);
        device_id = get_pci_value("DEVICE", pci);
        class_id  = get_pci_value("CLASS", pci);

        for (jt=pci_devices.begin(); jt!=pci_devices.end(); jt++)
        {
            PCIDevice * dev = jt->second;

            if ((class_id  == 0 || dev->class_id  == class_id)  &&
                (vendor_id == 0 || dev->vendor_id == vendor_id) &&
                (device_id == 0 || dev->device_id == device_id) &&
                dev->vmid  == -1 )
            {
                dev->vmid = vmid;
                dev->attrs->replace("VMID", vmid);

                pci->replace("DOMAIN",dev->attrs->vector_value("DOMAIN"));
                pci->replace("BUS",dev->attrs->vector_value("BUS"));
                pci->replace("SLOT",dev->attrs->vector_value("SLOT"));
                pci->replace("FUNCTION",dev->attrs->vector_value("FUNCTION"));

                pci->replace("ADDRESS",dev->attrs->vector_value("ADDRESS"));
            }
        }
    }
}

/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/

void HostSharePCI::del(const vector<Attribute *> &devs)
{
    vector<Attribute *>::const_iterator it;
    map<string, PCIDevice *>::iterator pci_it;

    for ( it=devs.begin(); it!= devs.end(); it++)
    {
        const VectorAttribute * pci = dynamic_cast<const VectorAttribute *>(*it);

        if ( pci == 0 )
        {
            continue;
        }

        pci_it = pci_devices.find(pci->vector_value("ADDRESS"));

        if (pci_it != pci_devices.end())
        {
            pci_it->second->vmid = -1;
            pci_it->second->attrs->replace("VMID",-1);
        }
    }
};

/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/

void HostSharePCI::set_monitorization(vector<Attribute*> &pci_att)
{
    vector<Attribute*>::iterator it;
    map<string, PCIDevice*>::iterator pci_it;

    string address;

    std::set<string> missing;
    std::set<string>::iterator jt;

    for (pci_it = pci_devices.begin(); pci_it != pci_devices.end(); pci_it++)
    {
        missing.insert(pci_it->first);
    }

    for (it = pci_att.begin(); it != pci_att.end(); it++)
    {
        VectorAttribute * pci = dynamic_cast<VectorAttribute *>(*it);

        if ( pci == 0 )
        {
            continue;
        }

        address = pci->vector_value("ADDRESS");

        if (address.empty())
        {
            delete pci;
            continue;
        }

        pci_it = pci_devices.find(address);

        if (pci_it != pci_devices.end())
        {
            missing.erase(address);
            delete pci;

            continue;
        }

        PCIDevice * dev = new PCIDevice(pci);

        pci_devices.insert(make_pair(address, dev));

        set(pci);
    }

    for ( jt = missing.begin() ; jt != missing.end(); jt ++ )
    {
        pci_it = pci_devices.find(*jt);

		if ( pci_it->second->vmid != -1 )
		{
			continue;
		}

        remove(pci_it->second->attrs);

        delete pci_it->second->attrs;

        delete pci_it->second;

        pci_devices.erase(pci_it);

    }
};

/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/

unsigned int HostSharePCI::get_pci_value(const char * name,
    const VectorAttribute * pci_device)
{
    string temp;

    temp = pci_device->vector_value(name);

    if (temp.empty())
    {
        return 0;
    }

    unsigned int  pci_value;
    istringstream iss(temp);

    iss >> hex >> pci_value;

    if (iss.fail() || !iss.eof())
    {
        return 0;
    }

    return pci_value;
}

/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/

HostSharePCI::PCIDevice::PCIDevice(VectorAttribute * _attrs)
    : vmid(-1), attrs(_attrs)
{
    vendor_id = get_pci_value("VENDOR", attrs);
    device_id = get_pci_value("DEVICE", attrs);
    class_id  = get_pci_value("CLASS", attrs);

    if (attrs->vector_value("VMID", vmid) == -1)
	{
		attrs->replace("VMID", -1);
	}

    attrs->vector_value("ADDRESS", address);
};

/* ------------------------------------------------------------------------*/
/* ------------------------------------------------------------------------*/

ostream& operator<<(ostream& os, const HostSharePCI& pci)
{
    map<string, HostSharePCI::PCIDevice *>::const_iterator it;

	os  << right << setw(15)<< "PCI ADDRESS"<< " "
		<< right << setw(8) << "CLASS"  << " "
		<< right << setw(8) << "VENDOR" << " "
		<< right << setw(8) << "DEVICE" << " "
		<< right << setw(8) << "VMID"   << " "
		<< endl << setw(55) << setfill('-') << "-" << setfill(' ') << endl;

    for (it=pci.pci_devices.begin(); it!=pci.pci_devices.end(); it++)
    {
        HostSharePCI::PCIDevice * dev = it->second;

		os << right << setw(15)<< dev->address   << " "
		   << right << setw(8) << dev->class_id  << " "
		   << right << setw(8) << dev->vendor_id << " "
		   << right << setw(8) << dev->device_id << " "
		   << right << setw(8) << dev->vmid      << " " << endl;
    }

	return os;
}
/* ************************************************************************ */
/* HostShare :: Constructor/Destructor                                      */
/* ************************************************************************ */

HostShare::HostShare(long long _max_disk,long long _max_mem,long long _max_cpu):
        ObjectXML(),
        disk_usage(0),
        mem_usage(0),
        cpu_usage(0),
        max_disk(_max_disk),
        max_mem(_max_mem),
        max_cpu(_max_cpu),
        free_disk(0),
        free_mem(0),
        free_cpu(0),
        used_disk(0),
        used_mem(0),
        used_cpu(0),
        running_vms(0){};

ostream& operator<<(ostream& os, HostShare& hs)
{
    string str;

    os << hs.to_xml(str);

    return os;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

string& HostShare::to_xml(string& xml) const
{
    string ds_xml, pci_xml;
    ostringstream   oss;

    oss << "<HOST_SHARE>"
          << "<DISK_USAGE>" << disk_usage << "</DISK_USAGE>"
          << "<MEM_USAGE>"  << mem_usage  << "</MEM_USAGE>"
          << "<CPU_USAGE>"  << cpu_usage  << "</CPU_USAGE>"
          << "<MAX_DISK>"   << max_disk   << "</MAX_DISK>"
          << "<MAX_MEM>"    << max_mem    << "</MAX_MEM>"
          << "<MAX_CPU>"    << max_cpu    << "</MAX_CPU>"
          << "<FREE_DISK>"  << free_disk  << "</FREE_DISK>"
          << "<FREE_MEM>"   << free_mem   << "</FREE_MEM>"
          << "<FREE_CPU>"   << free_cpu   << "</FREE_CPU>"
          << "<USED_DISK>"  << used_disk  << "</USED_DISK>"
          << "<USED_MEM>"   << used_mem   << "</USED_MEM>"
          << "<USED_CPU>"   << used_cpu   << "</USED_CPU>"
          << "<RUNNING_VMS>"<<running_vms <<"</RUNNING_VMS>"
          << ds.to_xml(ds_xml)
          << pci.to_xml(pci_xml)
        << "</HOST_SHARE>";

    xml = oss.str();

    return xml;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

int HostShare::from_xml_node(const xmlNodePtr node)
{
    vector<xmlNodePtr> content;
    int rc = 0;

    // Initialize the internal XML object
    ObjectXML::update_from_node(node);

    rc += xpath(disk_usage, "/HOST_SHARE/DISK_USAGE", -1);
    rc += xpath(mem_usage,  "/HOST_SHARE/MEM_USAGE",  -1);
    rc += xpath(cpu_usage,  "/HOST_SHARE/CPU_USAGE",  -1);

    rc += xpath(max_disk,   "/HOST_SHARE/MAX_DISK",   -1);
    rc += xpath(max_mem ,   "/HOST_SHARE/MAX_MEM",    -1);
    rc += xpath(max_cpu ,   "/HOST_SHARE/MAX_CPU",    -1);

    rc += xpath(free_disk,  "/HOST_SHARE/FREE_DISK",  -1);
    rc += xpath(free_mem ,  "/HOST_SHARE/FREE_MEM",   -1);
    rc += xpath(free_cpu ,  "/HOST_SHARE/FREE_CPU",   -1);

    rc += xpath(used_disk,  "/HOST_SHARE/USED_DISK",  -1);
    rc += xpath(used_mem ,  "/HOST_SHARE/USED_MEM",   -1);
    rc += xpath(used_cpu ,  "/HOST_SHARE/USED_CPU",   -1);

    rc += xpath(running_vms,"/HOST_SHARE/RUNNING_VMS",-1);

    // ------------ Datastores ---------------

    ObjectXML::get_nodes("/HOST_SHARE/DATASTORES", content);

    if( content.empty())
    {
        return -1;
    }

    rc += ds.from_xml_node( content[0] );

    ObjectXML::free_nodes(content);

    content.clear();

    if (rc != 0)
    {
        return -1;
    }

    // ------------ PCI Devices ---------------

    ObjectXML::get_nodes("/HOST_SHARE/PCI_DEVICES", content);

    if( content.empty())
    {
        return -1;
    }

    rc += pci.from_xml_node( content[0] );

    ObjectXML::free_nodes(content);

    content.clear();

    if (rc != 0)
    {
        return -1;
    }

    return 0;
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

void HostShare::set_ds_monitorization(const vector<Attribute*> &ds_att)
{
    vector<Attribute*>::const_iterator it;

    ds.erase("DS");

    for (it = ds_att.begin(); it != ds_att.end(); it++)
    {
        ds.set(*it);
    }
}

/* ------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------ */

<|endoftext|>


<commit_before>/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004, 2005, 2006, 2007 Olof Naessn and Per Larsson
 *
 *                                                         Js_./
 * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
 * Olof Naessn a.k.a jansem/yakslem                _asww7!uY`>  )\a//
 *                                                 _Qhm`] _f "'c  1!5m
 * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
 *                                               .)j(] .d_/ '-(  P .   S
 * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
 * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
 * binary forms, with or without                 )4d[#7r, .   '     )d`)[
 * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
 * that the following conditions are met:       j<<WP+k/);.        _W=j f
 * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
 *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
 *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
 *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
 * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
 *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
 *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
 *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
 *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
 *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
 * 3. Neither the name of Guichan nor the      :$we` _! + _/ .        j?
 *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
 *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
 *    from this software without specific        (js, \[QQW$QWW#?!V"".
 *    prior written permission.                    ]y:.<\..          .
 *                                                 -]n w/ '         [.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION)                     ^
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * For comments regarding functions please see the header file.
 */

#include "guichan/graphics.hpp"

#include "guichan/exception.hpp"
#include "guichan/font.hpp"
#include "guichan/image.hpp"

namespace gcn
{

    Graphics::Graphics()
    {
        mFont = NULL;
    }

    bool Graphics::pushClipArea(Rectangle area)
    {
        if (mClipStack.empty())
        {
            ClipRectangle carea;
            carea.x = area.x;
            carea.y = area.y;
            carea.width = area.width;
            carea.height = area.height;
            mClipStack.push(carea);
            return true;
        }

        ClipRectangle top = mClipStack.top();
        ClipRectangle carea;
        carea = area;
        carea.xOffset = top.xOffset + carea.x;
        carea.yOffset = top.yOffset + carea.y;
        carea.x += top.xOffset;
        carea.y += top.yOffset;

        bool result = carea.intersect(top);

        mClipStack.push(carea);

        return result;
    }

    void Graphics::popClipArea()
    {

        if (mClipStack.empty())
        {
            throw GCN_EXCEPTION("Tried to pop clip area from empty stack.");
        }

        mClipStack.pop();
    }

    const ClipRectangle& Graphics::getCurrentClipArea()
    {
        if (mClipStack.empty())
        {
            throw GCN_EXCEPTION("The clip area stack is empty.");
        }

        return mClipStack.top();
    }

    void Graphics::drawImage(const Image* image, int dstX, int dstY)
    {
        drawImage(image, 0, 0, dstX, dstY, image->getWidth(), image->getHeight());
    }

    void Graphics::setFont(Font* font)
    {
        mFont = font;
    }

    void Graphics::drawText(const std::string& text, int x, int y,
                            unsigned int alignment)
    {
        if (mFont == NULL)
        {
            throw GCN_EXCEPTION("No font set.");
        }

        switch (alignment)
        {
          case LEFT:
              mFont->drawString(this, text, x, y);
              break;
          case CENTER:
              mFont->drawString(this, text, x - mFont->getWidth(text) / 2, y);
              break;
          case RIGHT:
              mFont->drawString(this, text, x - mFont->getWidth(text), y);
              break;
          default:
              throw GCN_EXCEPTION("Unknown alignment.");
        }
    }
}
<commit_msg>Issue 4 has been fixed.<commit_after>/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004, 2005, 2006, 2007 Olof Naessn and Per Larsson
 *
 *                                                         Js_./
 * Per Larsson a.k.a finalman                          _RqZ{a<^_aa
 * Olof Naessn a.k.a jansem/yakslem                _asww7!uY`>  )\a//
 *                                                 _Qhm`] _f "'c  1!5m
 * Visit: http://guichan.darkbits.org             )Qk<P ` _: :+' .'  "{[
 *                                               .)j(] .d_/ '-(  P .   S
 * License: (BSD)                                <Td/Z <fP"5(\"??"\a.  .L
 * Redistribution and use in source and          _dV>ws?a-?'      ._/L  #'
 * binary forms, with or without                 )4d[#7r, .   '     )d`)[
 * modification, are permitted provided         _Q-5'5W..j/?'   -?!\)cam'
 * that the following conditions are met:       j<<WP+k/);.        _W=j f
 * 1. Redistributions of source code must       .$%w\/]Q  . ."'  .  mj$
 *    retain the above copyright notice,        ]E.pYY(Q]>.   a     J@\
 *    this list of conditions and the           j(]1u<sE"L,. .   ./^ ]{a
 *    following disclaimer.                     4'_uomm\.  )L);-4     (3=
 * 2. Redistributions in binary form must        )_]X{Z('a_"a7'<a"a,  ]"[
 *    reproduce the above copyright notice,       #}<]m7`Za??4,P-"'7. ).m
 *    this list of conditions and the            ]d2e)Q(<Q(  ?94   b-  LQ/
 *    following disclaimer in the                <B!</]C)d_, '(<' .f. =C+m
 *    documentation and/or other materials      .Z!=J ]e []('-4f _ ) -.)m]'
 *    provided with the distribution.          .w[5]' _[ /.)_-"+?   _/ <W"
 * 3. Neither the name of Guichan nor the      :$we` _! + _/ .        j?
 *    names of its contributors may be used     =3)= _f  (_yQmWW$#(    "
 *    to endorse or promote products derived     -   W,  sQQQQmZQ#Wwa]..
 *    from this software without specific        (js, \[QQW$QWW#?!V"".
 *    prior written permission.                    ]y:.<\..          .
 *                                                 -]n w/ '         [.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT       )/ )/           !
 * HOLDERS AND CONTRIBUTORS "AS IS" AND ANY         <  (; sac    ,    '
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING,               ]^ .-  %
 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF            c <   r
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR            aga<  <La
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE          5%  )P'-3L
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR        _bQf` y`..)a
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,          ,J?4P'.P"_(\?d'.,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES               _Pa,)!f/<[]/  ?"
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT      _2-..:. .r+_,.. .
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,     ?a.<%"'  " -'.a_ _,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION)                     ^
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * For comments regarding functions please see the header file.
 */

#include "guichan/graphics.hpp"

#include "guichan/exception.hpp"
#include "guichan/font.hpp"
#include "guichan/image.hpp"

namespace gcn
{

    Graphics::Graphics()
    {
        mFont = NULL;
    }

    bool Graphics::pushClipArea(Rectangle area)
    {
        if (mClipStack.empty())
        {
            ClipRectangle carea;
            carea.x = area.x;
            carea.y = area.y;
            carea.width = area.width;
            carea.height = area.height;
            mClipStack.push(carea);
            return true;
        }

        ClipRectangle top = mClipStack.top();
        ClipRectangle carea;
        carea = area;
        carea.xOffset = top.xOffset + carea.x;
        carea.yOffset = top.yOffset + carea.y;
        carea.x += top.xOffset;
        carea.y += top.yOffset;

        // Clamp the pushed clip rectangle.
        if (carea.x < top.x)
        {
            carea.x = top.x;
        }

        if (carea.y < top.y)
        {
            carea.y = top.y;
        }

        if (carea.width > top.width)
        {
            carea.width = top.width;
        }

        if (carea.height > top.height)
        {
            carea.height = top.height;
        }

        bool result = carea.intersect(top);

        mClipStack.push(carea);

        return result;
    }

    void Graphics::popClipArea()
    {

        if (mClipStack.empty())
        {
            throw GCN_EXCEPTION("Tried to pop clip area from empty stack.");
        }

        mClipStack.pop();
    }

    const ClipRectangle& Graphics::getCurrentClipArea()
    {
        if (mClipStack.empty())
        {
            throw GCN_EXCEPTION("The clip area stack is empty.");
        }

        return mClipStack.top();
    }

    void Graphics::drawImage(const Image* image, int dstX, int dstY)
    {
        drawImage(image, 0, 0, dstX, dstY, image->getWidth(), image->getHeight());
    }

    void Graphics::setFont(Font* font)
    {
        mFont = font;
    }

    void Graphics::drawText(const std::string& text, int x, int y,
                            unsigned int alignment)
    {
        if (mFont == NULL)
        {
            throw GCN_EXCEPTION("No font set.");
        }

        switch (alignment)
        {
          case LEFT:
              mFont->drawString(this, text, x, y);
              break;
          case CENTER:
              mFont->drawString(this, text, x - mFont->getWidth(text) / 2, y);
              break;
          case RIGHT:
              mFont->drawString(this, text, x - mFont->getWidth(text), y);
              break;
          default:
              throw GCN_EXCEPTION("Unknown alignment.");
        }
    }
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2011, Willow Garage, Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of the Willow Garage, Inc. nor the names of its
//       contributors may be used to endorse or promote products derived from
//       this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//

<commit_msg>cruft.<commit_after><|endoftext|>


<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2012 Scientific Computing and Imaging Institute,
   University of Utah.

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

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

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

#ifdef BUILD_WITH_PYTHON

#include <Dataflow/Engine/Controller/NetworkEditorController.h>
#include <Dataflow/Network/ModuleInterface.h>
#include <Dataflow/Network/NetworkInterface.h>
#include <Dataflow/Network/ModuleDescription.h>
#include <Dataflow/Engine/Controller/PythonImpl.h>

using namespace SCIRun::Dataflow::Engine;
using namespace SCIRun::Dataflow::Networks;

PythonImpl::PythonImpl(NetworkEditorController& nec) : nec_(nec) {}

std::string PythonImpl::addModule(const std::string& name)
{
  auto m = nec_.addModule(name);
  if (m)
    return "Module added: " + m->get_id().id_;
  else
    return "Module add failed, no such module type";
}

std::string PythonImpl::removeModule(const std::string& id)
{
  try
  {
    nec_.removeModule(ModuleId(id));
    return "Module removed";
  }
  catch (...)
  {
    return "No module by that id";
  }
}

std::string PythonImpl::executeAll(const ExecutableLookup& lookup)
{
  nec_.executeAll(lookup);
  return "Execution finished.";
}

std::string PythonImpl::connect(const std::string& moduleId1, int port1, const std::string& moduleId2, int port2)
{
  auto network = nec_.getNetwork();
  auto mod1 = network->lookupModule(ModuleId(moduleId1));
  auto mod2 = network->lookupModule(ModuleId(moduleId2));
  return "PythonImpl::connect does nothing";
}

std::string PythonImpl::disconnect(const std::string& moduleId1, int port1, const std::string& moduleId2, int port2)
{
  return "PythonImpl::disconnect does nothing";
}

std::string PythonImpl::saveNetwork(const std::string& filename)
{
  return "PythonImpl::saveNetwork does nothing";
}

std::string PythonImpl::loadNetwork(const std::string& filename)
{
  return "PythonImpl::loadNetwork does nothing";
}

std::string PythonImpl::quit(bool force)
{
  return "PythonImpl::quit does nothing";
}

#endif<commit_msg>Implement python saveNetwork (needs GUI listener though)<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2012 Scientific Computing and Imaging Institute,
   University of Utah.

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

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

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

#ifdef BUILD_WITH_PYTHON

#include <Dataflow/Engine/Controller/NetworkEditorController.h>
#include <Dataflow/Network/ModuleInterface.h>
#include <Dataflow/Network/NetworkInterface.h>
#include <Dataflow/Network/ModuleDescription.h>
#include <Dataflow/Serialization/Network/NetworkDescriptionSerialization.h>
#include <Dataflow/Serialization/Network/XMLSerializer.h>
#include <Dataflow/Engine/Controller/PythonImpl.h>

using namespace SCIRun::Dataflow::Engine;
using namespace SCIRun::Dataflow::Networks;

PythonImpl::PythonImpl(NetworkEditorController& nec) : nec_(nec) {}

std::string PythonImpl::addModule(const std::string& name)
{
  auto m = nec_.addModule(name);
  if (m)
    return "Module added: " + m->get_id().id_;
  else
    return "Module add failed, no such module type";
}

std::string PythonImpl::removeModule(const std::string& id)
{
  try
  {
    nec_.removeModule(ModuleId(id));
    return "Module removed";
  }
  catch (...)
  {
    return "No module by that id";
  }
}

std::string PythonImpl::executeAll(const ExecutableLookup& lookup)
{
  nec_.executeAll(lookup);
  return "Execution finished.";
}

std::string PythonImpl::connect(const std::string& moduleId1, int port1, const std::string& moduleId2, int port2)
{
  auto network = nec_.getNetwork();
  auto mod1 = network->lookupModule(ModuleId(moduleId1));
  auto mod2 = network->lookupModule(ModuleId(moduleId2));
  return "PythonImpl::connect does nothing";
}

std::string PythonImpl::disconnect(const std::string& moduleId1, int port1, const std::string& moduleId2, int port2)
{
  return "PythonImpl::disconnect does nothing";
}

std::string PythonImpl::saveNetwork(const std::string& filename)
{
  try
  {
    //TODO: duplicated code from SCIRunMainWindow. Obviously belongs in a separate class.
    NetworkFileHandle file = nec_.saveNetwork();
    XMLSerializer::save_xml(*file, filename, "networkFile");
    return filename + " saved.";
  }
  catch (...)
  {
    return "Save failed.";
  }
}

std::string PythonImpl::loadNetwork(const std::string& filename)
{
  return "PythonImpl::loadNetwork does nothing";
}

std::string PythonImpl::quit(bool force)
{
  return "PythonImpl::quit does nothing";
}

#endif<|endoftext|>


<commit_before>#include "alfe/main.h"

class Symbol
{
public:
    Symbol() : _cookie(_nextCookie) { ++_nextCookie; }
    bool operator==(Symbol other) { return _cookie == other._cookie; }
    bool operator!=(Symbol other) { return _cookie != other._cookie; }
    UInt32 hash(int t) { return Hash(typeid(Symbol)).mixin(_cookie); }
private:
    static int _nextCookie;
    int _cookie;
};

int Symbol::_nextCookie = 0;

Symbol zero;
Symbol unknown;

class Register
{
public:
    Register(String name, int binaryEncoding, int width)
      : _name(name), _binaryEncoding(binaryEncoding), _width(width) { }
    Word value() { return _value; }
    bool isConstant() { return _symbol == zero; }
    virtual void assign(T value, Symbol symbol)
    {
        _value = value;
        _symbol = symbol;
        for (auto& i : _partOf)
            i->partAssigned(value, symbol, this);
    }
    bool hasValue(Word v) { return isConstant() && value() == v; }
    void clear() { assign(0, unknown); }
    void makePartOf(Register* larger)
    {
        _partOf.append(larger);
    }
    virtual void partAssigned(Word value, Symbol symbol, Register* part) { }
protected:
    String _name;
    int _width;
    int _binaryEncoding;
    Word _value;
    Symbol _symbol;
    AppendableArray<Register*> _partOf;
};

class CompoundRegister : public Register
{
public:
    CompoundRegister(String name, int binaryEncoding, Register* lowPart,
        Register* highPart)
      : Register(name, binaryEncoding, lowPart->_width + highPart->_width),
        _lowPart(lowPart), _highPart(highPart)
    {
        lowPart->makePartOf(this);
        highPart->makePartOf(this);
    }
    void assign(Word value, Symbol symbol)
    {
        Register::assign(value, symbol);
        int shift = 8 * lowPart->_width;
        // Assign direcly instead of going through assign to avoid sprious
        // partAssigned() calls.
        _lowPart->_value = value & ((1 << shift) - 1);
        _lowPart->_symbol = symbol;
        _highPart->_value = value >> shift;
        _highPart->_symbol = (symbol == zero ? zero : unknown);
    }
    void partAssigned(Word value, Symbol symbol, Register* part)
    {
        int shift = 8 * lowPart->_width;
        if (part == _lowPart) {
            _value = (_highPart->_value << shift) | value;
            if (symbol != _symbol) {
                if (_highPart->_symbol == zero && symbol == zero)
                    _symbol = zero;
                else
                    _symbol = unknown;
            }
        }
        else {
            _value = _lowPart->_value | (value << shift);
            if (_lowPart->_symbol == zero && symbol == zero)
                _symbol = zero;
            else
                _symbol = unknown;
        }
    }
private:
    Register<T2>* _lowPart;
    Register<T2>* _highPart;
    int _binaryEncoding;
};

RegisterFile registerFile;
Register al("al", 0, 1);
Register cl("cl", 1, 1);
Register dl("dl", 2, 1);
Register bl("bl", 3, 1);
Register ah("ah", 4, 1);
Register ch("ch", 5, 1);
Register dh("dh", 6, 1);
Register bh("bh", 7, 1);
CompoundRegister ax("ax", 0, &al, &ah);
CompoundRegister cx("cx", 1, &cl, &dh);
CompoundRegister dx("dx", 2, &dl, &dh);
CompoundRegister bx("bx", 3, &bl, &bh);
Register sp("sp", 4, 2);
Register bp("bp", 5, 2);
Register si("si", 6, 2);
Register di("di", 7, 2);
Register es("es", 0, 2);
Register cs("cs", 1, 2);
Register ss("ss", 2, 2);
Register ds("ds", 3, 2);
Register ip("ip", 0, 2);
Register flags("flags", 0, 2);

class Instruction : public LinkedListMember<Instruction>
{
};

class MovInstruction : public Instruction
{
public:
    MovInstruction(Operand destination, Operand source)
      : _destination(destination), _source(source)
    { }
private:
    Operand _destination;
    Operand _source;

};

class LabelInstruction : public Instruction
{
};

class InstructionChain
{
public:
    void add(Instruction* instruction) { _instructions.add(instruction); }
private:
    OwningLinkedList<Instruction> _instructions;
};

class Operand
{
};

void emit_mov(InstructionChain chain, Operand destination, Operand source)
{
    chain.add(MovInstruction(destination, source));
}

void out(Operand port, Operand value)
{
    if (port >= 0x100)
        mov(dx, port);
    if (value.size() == 1) {
        mov(al, value);
        if (dx.value() == port
    }
    else
        mov(ax, value);

}

class SetInstruction
{
public:
    SetInstruction(Register* destination, Word value, Symbol symbol = zero)
      : _destination(destination), _value(value), _symbol(symbol) { }
    Instruction* expand()
    {
        if (dynamic_cast<CPURegister*>(_destination) != 0)
            return this;

        if (_symbol == zero) {
            if (_destination->symbol() == zero) {
                auto pr = dynamic_cast<PortRegister*>(_destionation);
                if (pr != 0) {
                    auto ipr = dynamic_cast<IndexedPortRegister*>(pr);
                    if (ipr != 0) {
                        insertBefore(new SetInstruction(ipr->indexRegister(),
                            ipr->indexValue());
                    }
                    insertBefore(new PortWriteByteInstruction(
                        pr->registerPort(), value);
                    insertBefore(new SetNote(_destination, _value, _symbol));
                    Instruction* r = previous();
                    remove();
                    return r;
                }
                else {
                    if (!_destination->hasValue(_value)) {

                    }
                }
            }
            else {

            }
        }
        else {

        }

    }
private:
    Register* _destination;
    Word _value;
    Symbol _symbol;
};

static const Word port_CGA_status = 0x3da;
static const Byte mask_CGA_notDisplayEnable = 1;
static const Byte mask_CGA_verticalSync = 8;

class CGAWaitForDisplayEnableInstruction : public Instruction
{
public:
    Instruction* expand()
    {
        insertBefore(new SetInstruction(&dx, port_CGA_status));
        LabelInstruction wait = new LabelInstruction();
        insertBefore(wait);
        insertBefore(new INInstruction(&al, &dx));
        insertBefore(new TESTInstruction(&al, mask_CGA_notDisplayEnable));
        insertBefore(new JNZInstruction(wait));
        Instruction* r = previous();
        remove();
        return r;
    }
};

class CGAWaitForDisplayDisableInstruction : public Instruction
{
public:
    Instruction* expand()
    {
        insertBefore(new SetInstruction(&dx, port_CGA_status));
        LabelInstruction wait = new LabelInstruction();
        insertBefore(wait);
        insertBefore(new INInstruction(&al, &dx));
        insertBefore(new TESTInstruction(&al, mask_CGA_notDisplayEnable));
        insertBefore(new JZInstruction(wait));
        Instruction* r = previous();
        remove();
        return r;
    }
};

class CGAWaitForVerticalSyncInstruction : public Instruction
{
public:
    Instruction* expand()
    {
        insertBefore(new SetInstruction(&dx, port_CGA_status));
        LabelInstruction wait = new LabelInstruction();
        insertBefore(wait);
        insertBefore(new INInstruction(&al, &dx));
        insertBefore(new TESTInstruction(&al, mask_CGA_verticalSync));
        insertBefore(new JZInstruction(wait));
        Instruction* r = previous();
        remove();
        return r;
    }
};

class CGAWaitForNoVerticalSyncInstruction : public Instruction
{
public:
    Instruction* expand()
    {
        insertBefore(new SetInstruction(&dx, port_CGA_status));
        LabelInstruction wait = new LabelInstruction();
        insertBefore(wait);
        insertBefore(new INInstruction(&al, &dx));
        insertBefore(new TESTInstruction(&al, mask_CGA_verticalSync));
        insertBefore(new JNZInstruction(wait));
        Instruction* r = previous();
        remove();
        return r;
    }
};

class Program : public ProgramBase
{
public:
    void run()
    {

    }
};
<commit_msg>More assembler work<commit_after>#include "alfe/main.h"

class Register;

class RegisterFile
{
public:
    void addRegister(Register* r)
    {
        _registers.append(r);
    }
private:
    AppendableArray<Register*> _registers;
};

class Symbol
{
public:
    Symbol() : _cookie(_nextCookie) { ++_nextCookie; }
    bool operator==(Symbol other) { return _cookie == other._cookie; }
    bool operator!=(Symbol other) { return _cookie != other._cookie; }
    UInt32 hash(int t) { return Hash(typeid(Symbol)).mixin(_cookie); }
private:
    static int _nextCookie;
    int _cookie;
};

int Symbol::_nextCookie = 0;

Symbol zero;
Symbol unknown;

class Register
{
public:
    Register(RegisterFile* file, String name, int binaryEncoding, int width)
      : _file(file), _name(name), _binaryEncoding(binaryEncoding),
        _width(width)
    {
        file->addRegister(this);
    }
    Word value() { return _value; }
    bool isConstant() { return _symbol == zero; }
    virtual void assign(T value, Symbol symbol)
    {
        _value = value;
        _symbol = symbol;
        for (auto& i : _partOf)
            i->partAssigned(value, symbol, this);
    }
    bool hasValue(Word v) { return isConstant() && value() == v; }
    void clear() { assign(0, unknown); }
    void makePartOf(Register* larger)
    {
        _partOf.append(larger);
    }
    virtual void partAssigned(Word value, Symbol symbol, Register* part) { }
protected:
    RegisterFile* _file;
    String _name;
    int _width;
    int _binaryEncoding;
    Word _value;
    Symbol _symbol;
    AppendableArray<Register*> _partOf;
};

class CompoundRegister : public Register
{
public:
    CompoundRegister(RegisterFile* file, String name, int binaryEncoding,
        Register* lowPart, Register* highPart)
      : Register(file, name, binaryEncoding,
            lowPart->_width + highPart->_width),
        _lowPart(lowPart), _highPart(highPart)
    {
        lowPart->makePartOf(this);
        highPart->makePartOf(this);
    }
    void assign(Word value, Symbol symbol)
    {
        Register::assign(value, symbol);
        int shift = 8 * lowPart->_width;
        // Assign direcly instead of going through assign to avoid sprious
        // partAssigned() calls.
        _lowPart->_value = value & ((1 << shift) - 1);
        _lowPart->_symbol = symbol;
        _highPart->_value = value >> shift;
        _highPart->_symbol = (symbol == zero ? zero : unknown);
    }
    void partAssigned(Word value, Symbol symbol, Register* part)
    {
        int shift = 8 * lowPart->_width;
        if (part == _lowPart) {
            _value = (_highPart->_value << shift) | value;
            if (symbol != _symbol) {
                if (_highPart->_symbol == zero && symbol == zero)
                    _symbol = zero;
                else
                    _symbol = unknown;
            }
        }
        else {
            _value = _lowPart->_value | (value << shift);
            if (_lowPart->_symbol == zero && symbol == zero)
                _symbol = zero;
            else
                _symbol = unknown;
        }
    }
private:
    Register<T2>* _lowPart;
    Register<T2>* _highPart;
    int _binaryEncoding;
};

RegisterFile registerFile;
Register al(&registerFile, "al", 0, 1);
Register cl(&registerFile, "cl", 1, 1);
Register dl(&registerFile, "dl", 2, 1);
Register bl(&registerFile, "bl", 3, 1);
Register ah(&registerFile, "ah", 4, 1);
Register ch(&registerFile, "ch", 5, 1);
Register dh(&registerFile, "dh", 6, 1);
Register bh(&registerFile, "bh", 7, 1);
CompoundRegister ax(&registerFile, "ax", 0, &al, &ah);
CompoundRegister cx(&registerFile, "cx", 1, &cl, &dh);
CompoundRegister dx(&registerFile, "dx", 2, &dl, &dh);
CompoundRegister bx(&registerFile, "bx", 3, &bl, &bh);
Register sp(&registerFile, "sp", 4, 2);
Register bp(&registerFile, "bp", 5, 2);
Register si(&registerFile, "si", 6, 2);
Register di(&registerFile, "di", 7, 2);
Register es(&registerFile, "es", 0, 2);
Register cs(&registerFile, "cs", 1, 2);
Register ss(&registerFile, "ss", 2, 2);
Register ds(&registerFile, "ds", 3, 2);
Register ip(&registerFile, "ip", 0, 2);
Register flags(&registerFile, "flags", 0, 2);

class Instruction : public LinkedListMember<Instruction>
{
};

class MovInstruction : public Instruction
{
public:
    MovInstruction(Operand destination, Operand source)
      : _destination(destination), _source(source)
    { }
private:
    Operand _destination;
    Operand _source;

};

class LabelInstruction : public Instruction
{
};

class InstructionChain
{
public:
    void add(Instruction* instruction) { _instructions.add(instruction); }
private:
    OwningLinkedList<Instruction> _instructions;
};

class Operand
{
};

void emit_mov(InstructionChain chain, Operand destination, Operand source)
{
    chain.add(MovInstruction(destination, source));
}

void out(Operand port, Operand value)
{
    if (port >= 0x100)
        mov(dx, port);
    if (value.size() == 1) {
        mov(al, value);
        if (dx.value() == port
    }
    else
        mov(ax, value);

}

class SetInstruction
{
public:
    SetInstruction(Register* destination, Word value, Symbol symbol = zero)
      : _destination(destination), _value(value), _symbol(symbol) { }
    Instruction* expand()
    {
        if (dynamic_cast<CPURegister*>(_destination) != 0)
            return this;

        if (_symbol == zero) {
            if (_destination->symbol() == zero) {
                auto pr = dynamic_cast<PortRegister*>(_destionation);
                if (pr != 0) {
                    auto ipr = dynamic_cast<IndexedPortRegister*>(pr);
                    if (ipr != 0) {
                        insertBefore(new SetInstruction(ipr->indexRegister(),
                            ipr->indexValue());
                    }
                    insertBefore(new PortWriteByteInstruction(
                        pr->registerPort(), value);
                    insertBefore(new SetNote(_destination, _value, _symbol));
                    Instruction* r = previous();
                    remove();
                    return r;
                }
                else {
                    if (!_destination->hasValue(_value)) {

                    }
                }
            }
            else {

            }
        }
        else {

        }

    }
private:
    Register* _destination;
    Word _value;
    Symbol _symbol;
};

static const Word port_CGA_status = 0x3da;
static const Byte mask_CGA_notDisplayEnable = 1;
static const Byte mask_CGA_verticalSync = 8;

class CGAWaitForDisplayEnableInstruction : public Instruction
{
public:
    Instruction* expand()
    {
        insertBefore(new SetInstruction(&dx, port_CGA_status));
        LabelInstruction wait = new LabelInstruction();
        insertBefore(wait);
        insertBefore(new INInstruction(&al, &dx));
        insertBefore(new TESTInstruction(&al, mask_CGA_notDisplayEnable));
        insertBefore(new JNZInstruction(wait));
        Instruction* r = previous();
        remove();
        return r;
    }
};

class CGAWaitForDisplayDisableInstruction : public Instruction
{
public:
    Instruction* expand()
    {
        insertBefore(new SetInstruction(&dx, port_CGA_status));
        LabelInstruction wait = new LabelInstruction();
        insertBefore(wait);
        insertBefore(new INInstruction(&al, &dx));
        insertBefore(new TESTInstruction(&al, mask_CGA_notDisplayEnable));
        insertBefore(new JZInstruction(wait));
        Instruction* r = previous();
        remove();
        return r;
    }
};

class CGAWaitForVerticalSyncInstruction : public Instruction
{
public:
    Instruction* expand()
    {
        insertBefore(new SetInstruction(&dx, port_CGA_status));
        LabelInstruction wait = new LabelInstruction();
        insertBefore(wait);
        insertBefore(new INInstruction(&al, &dx));
        insertBefore(new TESTInstruction(&al, mask_CGA_verticalSync));
        insertBefore(new JZInstruction(wait));
        Instruction* r = previous();
        remove();
        return r;
    }
};

class CGAWaitForNoVerticalSyncInstruction : public Instruction
{
public:
    Instruction* expand()
    {
        insertBefore(new SetInstruction(&dx, port_CGA_status));
        LabelInstruction wait = new LabelInstruction();
        insertBefore(wait);
        insertBefore(new INInstruction(&al, &dx));
        insertBefore(new TESTInstruction(&al, mask_CGA_verticalSync));
        insertBefore(new JNZInstruction(wait));
        Instruction* r = previous();
        remove();
        return r;
    }
};

class Program : public ProgramBase
{
public:
    void run()
    {

    }
};
<|endoftext|>


<commit_before>#include <algorithm>
#include <cassert>
#include <cmath>

#include "hlstrafe.hpp"
#include "util.hpp"

namespace HLStrafe
{
	double MaxAccelTheta(const PlayerData& player, const MovementVars& vars, PositionType postype, double wishspeed)
	{
		assert(postype != PositionType::WATER);

		bool onground = (postype == PositionType::GROUND);
		double accel = onground ? vars.Accelerate : vars.Airaccelerate;
		double accelspeed = accel * wishspeed * vars.EntFriction * vars.Frametime;
		if (accelspeed <= 0.0)
			return M_PI;

		double wishspeed_capped = onground ? wishspeed : 30;
		double tmp = wishspeed_capped - accelspeed;
		if (tmp <= 0.0)
			return M_PI / 2;

		double speed = Length<float, 2>(player.Velocity);
		if (tmp < speed)
			return std::acos(tmp / speed);

		return 0.0;
	}

	double MaxAngleTheta(const PlayerData& player, const MovementVars& vars, PositionType postype, double wishspeed)
	{
		assert(postype != PositionType::WATER);

		bool onground = (postype == PositionType::GROUND);
		double speed = Length<float, 2>(player.Velocity);
		double accel = onground ? vars.Accelerate : vars.Airaccelerate;
		double accelspeed = accel * wishspeed * vars.EntFriction * vars.Frametime;
		if (accelspeed <= 0.0) {
			double wishspeed_capped = onground ? wishspeed : 30;
			accelspeed *= -1;
			if (accelspeed >= speed) {
				if (wishspeed_capped >= speed)
					return 0.0;
				else
					return std::acos(wishspeed_capped / speed); // The actual angle needs to be _less_ than this.
			} else {
				if (wishspeed_capped >= speed)
					return std::acos(accelspeed / speed);
				else
					return std::acos(std::min(accelspeed, wishspeed_capped) / speed); // The actual angle needs to be _less_ than this if wishspeed_capped <= accelspeed.
			}
		} else {
			if (accelspeed >= speed)
				return M_PI;
			else
				return std::acos(-1 * accelspeed / speed);
		}
	}

	void VectorFME(PlayerData& player, const MovementVars& vars, PositionType postype, double wishspeed, const double a[2])
	{
		assert(postype != PositionType::WATER);

		bool onground = (postype == PositionType::GROUND);
		double wishspeed_capped = onground ? wishspeed : 30;
		double tmp = wishspeed_capped - DotProduct<float, double, 2>(player.Velocity, a);
		if (tmp <= 0.0)
			return;

		double accel = onground ? vars.Accelerate : vars.Airaccelerate;
		double accelspeed = accel * wishspeed * vars.EntFriction * vars.Frametime;
		if (accelspeed <= tmp)
			tmp = accelspeed;

		player.Velocity[0] += a[0] * tmp;
		player.Velocity[1] += a[1] * tmp;
	}

	inline double ButtonsPhi(HLTAS::Button button)
	{
		switch (button) {
		case HLTAS::Button::      FORWARD: return 0;
		case HLTAS::Button:: FORWARD_LEFT: return -M_PI / 4;
		case HLTAS::Button::         LEFT: return -M_PI / 2;
		case HLTAS::Button::    BACK_LEFT: return -3 * M_PI / 2;
		case HLTAS::Button::         BACK: return M_PI;
		case HLTAS::Button::   BACK_RIGHT: return 3 * M_PI / 2;
		case HLTAS::Button::        RIGHT: return M_PI / 2;
		case HLTAS::Button::FORWARD_RIGHT: return M_PI / 4;
		default: return 0;
		}
	}

	static void SideStrafeGeneral(PlayerData& player, float trial_vel[2], const MovementVars& vars, PositionType postype, double wishspeed,
		HLTAS::Button buttons, double &yaw, double &trial_yaw, double theta, bool right)
	{
		assert(postype != PositionType::WATER);

		double phi = ButtonsPhi(buttons);
		phi = right ? phi : -phi;
		theta = right ? theta : -theta;

		if (!IsZero<float, 2>(player.Velocity))
			yaw = std::atan2(player.Velocity[1], player.Velocity[0]);
		yaw += phi - theta;

		trial_yaw = AngleModRad(yaw + std::copysign(yaw, M_U_RAD));
		yaw = AngleModRad(yaw);

		double avec[2] = { std::cos(trial_yaw - phi), std::sin(trial_yaw - phi) };
		float orig_vel[2] = { player.Velocity[0], player.Velocity[1] };
		VectorFME(player, vars, postype, wishspeed, avec);
		trial_vel[0] = player.Velocity[0];
		trial_vel[1] = player.Velocity[1];
		player.Velocity[0] = orig_vel[0];
		player.Velocity[1] = orig_vel[1];

		avec[0] = std::cos(yaw - phi);
		avec[1] = std::sin(yaw - phi);
		VectorFME(player, vars, postype, wishspeed, avec);
	}

	void SideStrafeMaxAccel(PlayerData& player, const MovementVars& vars, PositionType postype, double wishspeed, HLTAS::Button buttons,
		double& yaw, bool right)
	{
		assert(postype != PositionType::WATER);
		float trial_vel[2];
		double trial_yaw = yaw;
		double theta = MaxAccelTheta(player, vars, postype, wishspeed);
		SideStrafeGeneral(player, trial_vel, vars, postype, wishspeed, buttons, yaw, trial_yaw, theta, right);

		double trial_speedsqrs[2] = {
			DotProduct<float, float, 2>(player.Velocity, player.Velocity),
			DotProduct<float, float, 2>(trial_vel, trial_vel)
		};

		if (trial_speedsqrs[1] > trial_speedsqrs[0]) {
			player.Velocity[0] = trial_vel[0];
			player.Velocity[1] = trial_vel[1];
			yaw = trial_yaw;
		}
	}
}
<commit_msg>Style a little.<commit_after>#include <algorithm>
#include <cassert>
#include <cmath>

#include "hlstrafe.hpp"
#include "util.hpp"

namespace HLStrafe
{
	double MaxAccelTheta(const PlayerData& player, const MovementVars& vars, PositionType postype, double wishspeed)
	{
		assert(postype != PositionType::WATER);

		bool onground = (postype == PositionType::GROUND);
		double accel = onground ? vars.Accelerate : vars.Airaccelerate;
		double accelspeed = accel * wishspeed * vars.EntFriction * vars.Frametime;
		if (accelspeed <= 0.0)
			return M_PI;

		double wishspeed_capped = onground ? wishspeed : 30;
		double tmp = wishspeed_capped - accelspeed;
		if (tmp <= 0.0)
			return M_PI / 2;

		double speed = Length<float, 2>(player.Velocity);
		if (tmp < speed)
			return std::acos(tmp / speed);

		return 0.0;
	}

	double MaxAngleTheta(const PlayerData& player, const MovementVars& vars, PositionType postype, double wishspeed)
	{
		assert(postype != PositionType::WATER);

		bool onground = (postype == PositionType::GROUND);
		double speed = Length<float, 2>(player.Velocity);
		double accel = onground ? vars.Accelerate : vars.Airaccelerate;
		double accelspeed = accel * wishspeed * vars.EntFriction * vars.Frametime;
		if (accelspeed <= 0.0) {
			double wishspeed_capped = onground ? wishspeed : 30;
			accelspeed *= -1;
			if (accelspeed >= speed) {
				if (wishspeed_capped >= speed)
					return 0.0;
				else
					return std::acos(wishspeed_capped / speed); // The actual angle needs to be _less_ than this.
			} else {
				if (wishspeed_capped >= speed)
					return std::acos(accelspeed / speed);
				else
					return std::acos(std::min(accelspeed, wishspeed_capped) / speed); // The actual angle needs to be _less_ than this if wishspeed_capped <= accelspeed.
			}
		} else {
			if (accelspeed >= speed)
				return M_PI;
			else
				return std::acos(-1 * accelspeed / speed);
		}
	}

	void VectorFME(PlayerData& player, const MovementVars& vars, PositionType postype, double wishspeed, const double a[2])
	{
		assert(postype != PositionType::WATER);

		bool onground = (postype == PositionType::GROUND);
		double wishspeed_capped = onground ? wishspeed : 30;
		double tmp = wishspeed_capped - DotProduct<float, double, 2>(player.Velocity, a);
		if (tmp <= 0.0)
			return;

		double accel = onground ? vars.Accelerate : vars.Airaccelerate;
		double accelspeed = accel * wishspeed * vars.EntFriction * vars.Frametime;
		if (accelspeed <= tmp)
			tmp = accelspeed;

		player.Velocity[0] += a[0] * tmp;
		player.Velocity[1] += a[1] * tmp;
	}

	inline double ButtonsPhi(HLTAS::Button button)
	{
		switch (button) {
		case HLTAS::Button::      FORWARD: return 0;
		case HLTAS::Button:: FORWARD_LEFT: return -M_PI / 4;
		case HLTAS::Button::         LEFT: return -M_PI / 2;
		case HLTAS::Button::    BACK_LEFT: return -3 * M_PI / 2;
		case HLTAS::Button::         BACK: return M_PI;
		case HLTAS::Button::   BACK_RIGHT: return 3 * M_PI / 2;
		case HLTAS::Button::        RIGHT: return M_PI / 2;
		case HLTAS::Button::FORWARD_RIGHT: return M_PI / 4;
		default: return 0;
		}
	}

	static void SideStrafeGeneral(PlayerData& player, float trial_vel[2], const MovementVars& vars, PositionType postype, double wishspeed,
		HLTAS::Button buttons, double& yaw, double& trial_yaw, double theta, bool right)
	{
		assert(postype != PositionType::WATER);

		double phi = ButtonsPhi(buttons);
		phi = right ? phi : -phi;
		theta = right ? theta : -theta;

		if (!IsZero<float, 2>(player.Velocity))
			yaw = std::atan2(player.Velocity[1], player.Velocity[0]);
		yaw += phi - theta;

		trial_yaw = AngleModRad(yaw + std::copysign(yaw, M_U_RAD));
		yaw = AngleModRad(yaw);

		double avec[2] = { std::cos(trial_yaw - phi), std::sin(trial_yaw - phi) };
		float orig_vel[2] = { player.Velocity[0], player.Velocity[1] };
		VectorFME(player, vars, postype, wishspeed, avec);
		trial_vel[0] = player.Velocity[0];
		trial_vel[1] = player.Velocity[1];
		player.Velocity[0] = orig_vel[0];
		player.Velocity[1] = orig_vel[1];

		avec[0] = std::cos(yaw - phi);
		avec[1] = std::sin(yaw - phi);
		VectorFME(player, vars, postype, wishspeed, avec);
	}

	void SideStrafeMaxAccel(PlayerData& player, const MovementVars& vars, PositionType postype, double wishspeed, HLTAS::Button buttons,
		double& yaw, bool right)
	{
		assert(postype != PositionType::WATER);

		float trial_vel[2];
		double trial_yaw = yaw;
		double theta = MaxAccelTheta(player, vars, postype, wishspeed);
		SideStrafeGeneral(player, trial_vel, vars, postype, wishspeed, buttons, yaw, trial_yaw, theta, right);

		double trial_speedsqrs[2] = {
			DotProduct<float, float, 2>(player.Velocity, player.Velocity),
			DotProduct<float, float, 2>(trial_vel, trial_vel)
		};

		if (trial_speedsqrs[1] > trial_speedsqrs[0]) {
			player.Velocity[0] = trial_vel[0];
			player.Velocity[1] = trial_vel[1];
			yaw = trial_yaw;
		}
	}
}
<|endoftext|>