<commit_before>// Copyright (C) 2016 Elviss Strazdins
// This file is part of the Ouzel engine.

#include <windowsx.h>
#include "WindowWin.h"
#include "core/Engine.h"
#include "InputWin.h"
#include "graphics/Renderer.h"
#include "utils/Utils.h"

using namespace ouzel;

static void handleKeyEvent(UINT msg, WPARAM wParam, LPARAM)
{
    if (msg == WM_KEYDOWN)
    {
        sharedEngine->getInput()->keyDown(input::InputWin::convertKeyCode(wParam),
                                          input::InputWin::getKeyboardModifiers(wParam));
    }
    else if (msg == WM_KEYUP)
    {
        sharedEngine->getInput()->keyUp(input::InputWin::convertKeyCode(wParam),
                                        input::InputWin::getKeyboardModifiers(wParam));
    }
}

static void handleMouseMoveEvent(UINT, WPARAM wParam, LPARAM lParam)
{
    Vector2 pos(static_cast<float>(GET_X_LPARAM(lParam)),
                static_cast<float>(GET_Y_LPARAM(lParam)));

    sharedEngine->getInput()->mouseMove(sharedEngine->getRenderer()->viewToScreenLocation(pos),
                                        input::InputWin::getMouseModifiers(wParam));
}

static void handleMouseButtonEvent(UINT msg, WPARAM wParam, LPARAM lParam)
{
    Vector2 pos(static_cast<float>(GET_X_LPARAM(lParam)),
                static_cast<float>(GET_Y_LPARAM(lParam)));

    input::MouseButton button;

    if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP)
    {
        button = input::MouseButton::LEFT;
    }
    else if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONUP)
    {
        button = input::MouseButton::RIGHT;
    }
    else if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONUP)
    {
        button = input::MouseButton::MIDDLE;
    }
    else if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP)
    {
        if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1)
            button = input::MouseButton::X1;
        else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON2)
            button = input::MouseButton::X2;
        else
            return;
    }
    else
    {
        return;
    }

    if (msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN || msg == WM_MBUTTONDOWN || msg == WM_XBUTTONDOWN)
    {
        sharedEngine->getInput()->mouseDown(button,
                                            sharedEngine->getRenderer()->viewToScreenLocation(pos),
                                            input::InputWin::getMouseModifiers(wParam));
    }
    else if (msg == WM_LBUTTONUP || msg == WM_RBUTTONUP || msg == WM_MBUTTONUP || msg == WM_XBUTTONUP)
    {
        sharedEngine->getInput()->mouseUp(button,
                                          sharedEngine->getRenderer()->viewToScreenLocation(pos),
                                          input::InputWin::getMouseModifiers(wParam));
    }
}

static void handleMouseWheelEvent(UINT msg, WPARAM wParam, LPARAM lParam)
{
    Vector2 pos(static_cast<float>(GET_X_LPARAM(lParam)),
                static_cast<float>(GET_Y_LPARAM(lParam)));

    if (msg == WM_MOUSEWHEEL)
    {
        short param = static_cast<short>(HIWORD(wParam));
        sharedEngine->getInput()->mouseScroll(Vector2(0.0f, -static_cast<float>(param) / static_cast<float>(WHEEL_DELTA)),
                                              sharedEngine->getRenderer()->viewToScreenLocation(pos),
                                              input::InputWin::getMouseModifiers(wParam));
    }
    else if (msg == WM_MOUSEHWHEEL)
    {
        short param = static_cast<short>(HIWORD(wParam));
        sharedEngine->getInput()->mouseScroll(Vector2(static_cast<float>(param) / static_cast<float>(WHEEL_DELTA), 0.0f),
                                              sharedEngine->getRenderer()->viewToScreenLocation(pos),
                                              input::InputWin::getMouseModifiers(wParam));
    }
}

static LRESULT CALLBACK windowProc(HWND window, UINT msg, WPARAM wParam, LPARAM lParam)
{
    WindowWin* windowWin = reinterpret_cast<WindowWin*>(GetWindowLongPtr(window, GWLP_USERDATA));

    switch (msg)
    {
        case WM_ACTIVATE:
        {
            UINT state = LOWORD(wParam);

            if (state == WA_ACTIVE || state == WA_CLICKACTIVE)
            {
                ouzel::sharedEngine->resume();
            }
            else if (state == WA_INACTIVE)
            {
                ouzel::sharedEngine->pause();
            }
            break;
        }
        case WM_KEYUP:
        case WM_KEYDOWN:
        {
            handleKeyEvent(msg, wParam, lParam);
            break;
        }
        case WM_LBUTTONDOWN:
        case WM_LBUTTONUP:
        case WM_RBUTTONDOWN:
        case WM_RBUTTONUP:
        case WM_MBUTTONDOWN:
        case WM_MBUTTONUP:
        case WM_XBUTTONDOWN:
        case WM_XBUTTONUP:
        {
            handleMouseButtonEvent(msg, wParam, lParam);

            if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP)
                return TRUE;

            return 0;
        }
        case WM_MOUSEMOVE:
        {
            handleMouseMoveEvent(msg, wParam, lParam);
            return 0;
        }
        case WM_MOUSEWHEEL:
        case WM_MOUSEHWHEEL:
        {
            handleMouseWheelEvent(msg, wParam, lParam);
            return 0;
        }
        case WM_SETCURSOR:
        {
            if (LOWORD(lParam) == HTCLIENT)
            {
                if (!sharedEngine->getInput()->isCursorVisible())
                {
                    SetCursor(nullptr);
                    return TRUE;
                }
            }
            break;
        }
        case WM_SIZE:
        {
            if (wParam == SIZE_MINIMIZED)
            {
                // TODO: stop engine
            }
            else if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED)
            {
                windowWin->handleResize(LOWORD(lParam), HIWORD(lParam));
            }
            return 0;
        }
        case WM_ERASEBKGND:
        {
            return TRUE;
        }
        case WM_SYSCOMMAND:
        {
            switch (wParam)
            {
            case SC_SCREENSAVE:
            case SC_MONITORPOWER:
            {
                if (windowWin->isFullscreen())
                {
                    // Disable screensaver in fullscreen mode
                    return 0;
                }
                break;
            }
            // Disable accessing menu using alt key
            case SC_KEYMENU:
                return 0;
            }
            break;
        }
        case WM_DESTROY:
        {
            PostQuitMessage(0);
            return 0;
        }
    }

    return DefWindowProcW(window, msg, wParam, lParam);
}

const LPCWSTR WINDOW_CLASS_NAME = L"OuzelWindow";

namespace ouzel
{
    WindowWin::WindowWin(const Size2& pSize, bool pResizable, bool pFullscreen, const std::string& pTitle):
        Window(pSize, pResizable, pFullscreen, pTitle)
    {

    }

    WindowWin::~WindowWin()
    {
        if (window)
        {
            DestroyWindow(window);
        }

        if (windowClass)
        {
            UnregisterClassW(WINDOW_CLASS_NAME, GetModuleHandle(nullptr));
        }
    }

    bool WindowWin::init()
    {
        HINSTANCE hInstance = GetModuleHandleW(nullptr);

        WNDCLASSEXW wc;
        memset(&wc, 0, sizeof(wc));
        wc.cbSize = sizeof(wc);
        wc.style = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc = windowProc;
        wc.hInstance = hInstance;
        wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
        wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
        wc.lpszClassName = WINDOW_CLASS_NAME;
        // Application icon should be the first resource
        wc.hIcon = LoadIconW(hInstance, MAKEINTRESOURCE(101));

        windowClass = RegisterClassExW(&wc);
        if (!windowClass)
        {
            log("Failed to register window class");
            return false;
        }

        windowStyle = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;

        if (resizable)
        {
            windowStyle |= WS_SIZEBOX | WS_MAXIMIZEBOX;
        }

        int x = CW_USEDEFAULT;
        int y = CW_USEDEFAULT;
        if (fullscreen)
        {
            windowStyle = WS_POPUP;
            x = 0;
            y = 0;
        }
        RECT windowRect = { 0, 0, static_cast<LONG>(size.width), static_cast<LONG>(size.height) };
        AdjustWindowRect(&windowRect, windowStyle, FALSE);

        wchar_t titleBuffer[256];
        MultiByteToWideChar(CP_UTF8, 0, title.c_str(), -1, titleBuffer, 256);

        window = CreateWindowExW(
            0,
            WINDOW_CLASS_NAME,
            titleBuffer,
            windowStyle,
            x,
            y,
            windowRect.right - windowRect.left,
            windowRect.bottom - windowRect.top,
            nullptr,
            nullptr,
            hInstance,
            nullptr);

        if (!window)
        {
            log("Failed to create window");
            return false;
        }

        SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
        ShowWindow(window, SW_SHOW);

        return Window::init();
    }

    void WindowWin::close()
    {
        SendMessage(window, WM_CLOSE, 0, 0);
    }

    void WindowWin::setSize(const Size2& newSize)
    {
        UINT width = static_cast<UINT>(newSize.width);
        UINT height = static_cast<UINT>(newSize.height);

        UINT swpFlags = SWP_NOMOVE | SWP_NOZORDER;

        RECT rect = { 0, 0, static_cast<LONG>(width), static_cast<LONG>(height) };
        AdjustWindowRect(&rect, windowStyle, GetMenu(window) ? TRUE : FALSE);

        SetWindowPos(window, nullptr, 0, 0, rect.right - rect.left, rect.bottom - rect.top, swpFlags);

        Window::setSize(newSize);
    }

    void WindowWin::setTitle(const std::string& newTitle)
    {
        if (title != newTitle)
        {
            wchar_t titleBuffer[256];
            MultiByteToWideChar(CP_UTF8, 0, newTitle.c_str(), -1, titleBuffer, 256);

            SetWindowTextW(window, titleBuffer);
        }

        Window::setTitle(newTitle);
    }

    void WindowWin::handleResize(INT width, INT height)
    {
        setSize(Size2(static_cast<float>(width), static_cast<float>(height)));
    }

    void WindowWin::addAccelerator(HACCEL accelerator)
    {
        accelerators.insert(accelerator);
    }

    void WindowWin::removeAccelerator(HACCEL accelerator)
    {
        accelerators.erase(accelerator);
    }

    HMONITOR WindowWin::getMonitor() const
    {
        return MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
    }
}
<commit_msg>Execute Windows window functions on main thread<commit_after>// Copyright (C) 2016 Elviss Strazdins
// This file is part of the Ouzel engine.

#include <windowsx.h>
#include "WindowWin.h"
#include "core/Application.h"
#include "core/Engine.h"
#include "InputWin.h"
#include "graphics/Renderer.h"
#include "utils/Utils.h"

using namespace ouzel;

static void handleKeyEvent(UINT msg, WPARAM wParam, LPARAM)
{
    if (msg == WM_KEYDOWN)
    {
        sharedEngine->getInput()->keyDown(input::InputWin::convertKeyCode(wParam),
                                          input::InputWin::getKeyboardModifiers(wParam));
    }
    else if (msg == WM_KEYUP)
    {
        sharedEngine->getInput()->keyUp(input::InputWin::convertKeyCode(wParam),
                                        input::InputWin::getKeyboardModifiers(wParam));
    }
}

static void handleMouseMoveEvent(UINT, WPARAM wParam, LPARAM lParam)
{
    Vector2 pos(static_cast<float>(GET_X_LPARAM(lParam)),
                static_cast<float>(GET_Y_LPARAM(lParam)));

    sharedEngine->getInput()->mouseMove(sharedEngine->getRenderer()->viewToScreenLocation(pos),
                                        input::InputWin::getMouseModifiers(wParam));
}

static void handleMouseButtonEvent(UINT msg, WPARAM wParam, LPARAM lParam)
{
    Vector2 pos(static_cast<float>(GET_X_LPARAM(lParam)),
                static_cast<float>(GET_Y_LPARAM(lParam)));

    input::MouseButton button;

    if (msg == WM_LBUTTONDOWN || msg == WM_LBUTTONUP)
    {
        button = input::MouseButton::LEFT;
    }
    else if (msg == WM_RBUTTONDOWN || msg == WM_RBUTTONUP)
    {
        button = input::MouseButton::RIGHT;
    }
    else if (msg == WM_MBUTTONDOWN || msg == WM_MBUTTONUP)
    {
        button = input::MouseButton::MIDDLE;
    }
    else if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP)
    {
        if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1)
            button = input::MouseButton::X1;
        else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON2)
            button = input::MouseButton::X2;
        else
            return;
    }
    else
    {
        return;
    }

    if (msg == WM_LBUTTONDOWN || msg == WM_RBUTTONDOWN || msg == WM_MBUTTONDOWN || msg == WM_XBUTTONDOWN)
    {
        sharedEngine->getInput()->mouseDown(button,
                                            sharedEngine->getRenderer()->viewToScreenLocation(pos),
                                            input::InputWin::getMouseModifiers(wParam));
    }
    else if (msg == WM_LBUTTONUP || msg == WM_RBUTTONUP || msg == WM_MBUTTONUP || msg == WM_XBUTTONUP)
    {
        sharedEngine->getInput()->mouseUp(button,
                                          sharedEngine->getRenderer()->viewToScreenLocation(pos),
                                          input::InputWin::getMouseModifiers(wParam));
    }
}

static void handleMouseWheelEvent(UINT msg, WPARAM wParam, LPARAM lParam)
{
    Vector2 pos(static_cast<float>(GET_X_LPARAM(lParam)),
                static_cast<float>(GET_Y_LPARAM(lParam)));

    if (msg == WM_MOUSEWHEEL)
    {
        short param = static_cast<short>(HIWORD(wParam));
        sharedEngine->getInput()->mouseScroll(Vector2(0.0f, -static_cast<float>(param) / static_cast<float>(WHEEL_DELTA)),
                                              sharedEngine->getRenderer()->viewToScreenLocation(pos),
                                              input::InputWin::getMouseModifiers(wParam));
    }
    else if (msg == WM_MOUSEHWHEEL)
    {
        short param = static_cast<short>(HIWORD(wParam));
        sharedEngine->getInput()->mouseScroll(Vector2(static_cast<float>(param) / static_cast<float>(WHEEL_DELTA), 0.0f),
                                              sharedEngine->getRenderer()->viewToScreenLocation(pos),
                                              input::InputWin::getMouseModifiers(wParam));
    }
}

static LRESULT CALLBACK windowProc(HWND window, UINT msg, WPARAM wParam, LPARAM lParam)
{
    WindowWin* windowWin = reinterpret_cast<WindowWin*>(GetWindowLongPtr(window, GWLP_USERDATA));

    switch (msg)
    {
        case WM_ACTIVATE:
        {
            UINT state = LOWORD(wParam);

            if (state == WA_ACTIVE || state == WA_CLICKACTIVE)
            {
                ouzel::sharedEngine->resume();
            }
            else if (state == WA_INACTIVE)
            {
                ouzel::sharedEngine->pause();
            }
            break;
        }
        case WM_KEYUP:
        case WM_KEYDOWN:
        {
            handleKeyEvent(msg, wParam, lParam);
            break;
        }
        case WM_LBUTTONDOWN:
        case WM_LBUTTONUP:
        case WM_RBUTTONDOWN:
        case WM_RBUTTONUP:
        case WM_MBUTTONDOWN:
        case WM_MBUTTONUP:
        case WM_XBUTTONDOWN:
        case WM_XBUTTONUP:
        {
            handleMouseButtonEvent(msg, wParam, lParam);

            if (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP)
                return TRUE;

            return 0;
        }
        case WM_MOUSEMOVE:
        {
            handleMouseMoveEvent(msg, wParam, lParam);
            return 0;
        }
        case WM_MOUSEWHEEL:
        case WM_MOUSEHWHEEL:
        {
            handleMouseWheelEvent(msg, wParam, lParam);
            return 0;
        }
        case WM_SETCURSOR:
        {
            if (LOWORD(lParam) == HTCLIENT)
            {
                if (!sharedEngine->getInput()->isCursorVisible())
                {
                    SetCursor(nullptr);
                    return TRUE;
                }
            }
            break;
        }
        case WM_SIZE:
        {
            if (wParam == SIZE_MINIMIZED)
            {
                // TODO: stop engine
            }
            else if (wParam == SIZE_MAXIMIZED || wParam == SIZE_RESTORED)
            {
                windowWin->handleResize(LOWORD(lParam), HIWORD(lParam));
            }
            return 0;
        }
        case WM_ERASEBKGND:
        {
            return TRUE;
        }
        case WM_SYSCOMMAND:
        {
            switch (wParam)
            {
            case SC_SCREENSAVE:
            case SC_MONITORPOWER:
            {
                if (windowWin->isFullscreen())
                {
                    // Disable screensaver in fullscreen mode
                    return 0;
                }
                break;
            }
            // Disable accessing menu using alt key
            case SC_KEYMENU:
                return 0;
            }
            break;
        }
        case WM_DESTROY:
        {
            PostQuitMessage(0);
            return 0;
        }
    }

    return DefWindowProcW(window, msg, wParam, lParam);
}

const LPCWSTR WINDOW_CLASS_NAME = L"OuzelWindow";

namespace ouzel
{
    WindowWin::WindowWin(const Size2& pSize, bool pResizable, bool pFullscreen, const std::string& pTitle):
        Window(pSize, pResizable, pFullscreen, pTitle)
    {

    }

    WindowWin::~WindowWin()
    {
        if (window)
        {
            DestroyWindow(window);
        }

        if (windowClass)
        {
            UnregisterClassW(WINDOW_CLASS_NAME, GetModuleHandle(nullptr));
        }
    }

    bool WindowWin::init()
    {
        HINSTANCE hInstance = GetModuleHandleW(nullptr);

        WNDCLASSEXW wc;
        memset(&wc, 0, sizeof(wc));
        wc.cbSize = sizeof(wc);
        wc.style = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc = windowProc;
        wc.hInstance = hInstance;
        wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
        wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
        wc.lpszClassName = WINDOW_CLASS_NAME;
        // Application icon should be the first resource
        wc.hIcon = LoadIconW(hInstance, MAKEINTRESOURCE(101));

        windowClass = RegisterClassExW(&wc);
        if (!windowClass)
        {
            log("Failed to register window class");
            return false;
        }

        windowStyle = WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX;

        if (resizable)
        {
            windowStyle |= WS_SIZEBOX | WS_MAXIMIZEBOX;
        }

        int x = CW_USEDEFAULT;
        int y = CW_USEDEFAULT;
        if (fullscreen)
        {
            windowStyle = WS_POPUP;
            x = 0;
            y = 0;
        }
        RECT windowRect = { 0, 0, static_cast<LONG>(size.width), static_cast<LONG>(size.height) };
        AdjustWindowRect(&windowRect, windowStyle, FALSE);

        wchar_t titleBuffer[256];
        MultiByteToWideChar(CP_UTF8, 0, title.c_str(), -1, titleBuffer, 256);

        window = CreateWindowExW(
            0,
            WINDOW_CLASS_NAME,
            titleBuffer,
            windowStyle,
            x,
            y,
            windowRect.right - windowRect.left,
            windowRect.bottom - windowRect.top,
            nullptr,
            nullptr,
            hInstance,
            nullptr);

        if (!window)
        {
            log("Failed to create window");
            return false;
        }

        SetWindowLongPtr(window, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(this));
        ShowWindow(window, SW_SHOW);

        return Window::init();
    }

    void WindowWin::close()
    {
        ouzel::sharedApplication->execute([this] {
            SendMessage(window, WM_CLOSE, 0, 0);
        }
    }

    void WindowWin::setSize(const Size2& newSize)
    {
        ouzel::sharedApplication->execute([this, newSize] {
            UINT width = static_cast<UINT>(newSize.width);
            UINT height = static_cast<UINT>(newSize.height);

            UINT swpFlags = SWP_NOMOVE | SWP_NOZORDER;

            RECT rect = { 0, 0, static_cast<LONG>(width), static_cast<LONG>(height) };
            AdjustWindowRect(&rect, windowStyle, GetMenu(window) ? TRUE : FALSE);

            SetWindowPos(window, nullptr, 0, 0, rect.right - rect.left, rect.bottom - rect.top, swpFlags);
        }

        Window::setSize(newSize);
    }

    void WindowWin::setTitle(const std::string& newTitle)
    {
        if (title != newTitle)
        {
            ouzel::sharedApplication->execute([this, newTitle] {
                wchar_t titleBuffer[256];
                MultiByteToWideChar(CP_UTF8, 0, newTitle.c_str(), -1, titleBuffer, 256);

                SetWindowTextW(window, titleBuffer);
            }
        }

        Window::setTitle(newTitle);
    }

    void WindowWin::handleResize(INT width, INT height)
    {
        setSize(Size2(static_cast<float>(width), static_cast<float>(height)));
    }

    void WindowWin::addAccelerator(HACCEL accelerator)
    {
        accelerators.insert(accelerator);
    }

    void WindowWin::removeAccelerator(HACCEL accelerator)
    {
        accelerators.erase(accelerator);
    }

    HMONITOR WindowWin::getMonitor() const
    {
        return MonitorFromWindow(window, MONITOR_DEFAULTTONULL);
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 Andrew C. Morrow
//
// 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.

#ifndef included_108FBB04_F426_414D_9EDD_B4D2AF941E96
#define included_108FBB04_F426_414D_9EDD_B4D2AF941E96

#include <cassert>
#include <initializer_list>
#include <memory>
#include <system_error>
#include <type_traits>

namespace acm {

    namespace detail  {

        namespace adl_swap_ns {
            using std::swap;

            template <class T>
            struct is_nothrow_swappable_test {
                static bool constexpr value = noexcept(swap(std::declval<T&>(), std::declval<T&>()));
            };
        } // namespace adl_swap_ns

        // This really should be part of C++
        template <class T>
        struct is_nothrow_swappable
            : std::integral_constant<bool, adl_swap_ns::is_nothrow_swappable_test<T>::value>
        {};

    } // namespace detail

    template<typename E, typename T>
    class error_or final {

    public:
        using error_type = E;
        using value_type = T;

        inline error_or() noexcept(std::is_nothrow_default_constructible<value_type>::value) {
            new(&val_.value) value_type;
        }

        inline error_or(error_type error) noexcept(std::is_nothrow_move_constructible<error_type>::value)
            : ok_(false) {
            assert(error);
            new(&val_.error) error_type(std::move(error));
        }

        inline error_or(value_type value) noexcept(std::is_nothrow_move_constructible<value_type>::value) {
            new(&val_.value) value_type(std::move(value));
        }

        template<typename U = value_type>
        inline error_or(std::initializer_list<typename U::value_type> values) noexcept(std::is_nothrow_constructible<U, std::initializer_list<typename U::value_type>>::value) {
            new(&val_.value) value_type(values);
        }

        inline error_or(const error_or& other) noexcept(std::is_nothrow_copy_constructible<error_type>::value and
                                                        std::is_nothrow_copy_constructible<value_type>::value) {
            if (other.ok_)
                new(&val_.value) value_type(other.val_.value);
            else
                new(&val_.error) error_type(other.val_.error);
            ok_ = other.ok_;
        }

        inline error_or(error_or&& other) noexcept((std::is_nothrow_move_constructible<error_type>::value or
                                                    std::is_nothrow_copy_constructible<error_type>::value) and
                                                   (std::is_nothrow_move_constructible<value_type>::value or
                                                    std::is_nothrow_copy_constructible<value_type>::value)) {
            if (other.ok_)
                new(&val_.value) value_type(std::move_if_noexcept(other.val_.value));
            else
                new(&val_.error) error_type(std::move_if_noexcept(other.val_.error));
            ok_ = other.ok_;
        }

        template<typename U>
        inline error_or(const error_or<error_type, U>& other) noexcept(std::is_nothrow_copy_constructible<error_type>::value and
                                                                       std::is_nothrow_copy_constructible<value_type>::value) {
            if (other.ok_)
                new(&val_.value) value_type(other.val_.value);
            else
                new(&val_.error) error_type(other.val_.error);
            ok_ = other.ok_;
        }

        template<typename U>
        inline error_or(error_or<error_type, U>&& other) noexcept((std::is_nothrow_move_constructible<error_type>::value or
                                                                   std::is_nothrow_copy_constructible<error_type>::value) and
                                                                  (std::is_nothrow_constructible<value_type, typename std::add_rvalue_reference<U>::type>::value or
                                                                   std::is_nothrow_constructible<value_type, typename std::add_lvalue_reference<U>::type>::value)) {
            if (other.ok_)
                new(&val_.value) value_type(move_if_noexcept_from(other.val_.value));
            else
                new(&val_.error) error_type(std::move_if_noexcept(other.val_.error));
            ok_ = other.ok_;
        }

        void swap(error_or& other) noexcept {
            other.sfinae_swap(*this);
        }

        friend inline void swap(error_or& a, error_or& b) noexcept {
            a.swap(b);
        }

        inline error_or& operator=(error_type error) noexcept(std::is_nothrow_constructible<error_or, typename std::add_rvalue_reference<error_type>::type>::value) {
            error_or(std::move(error)).swap(*this);
            return *this;
        }

        inline error_or& operator=(value_type value) noexcept(std::is_nothrow_constructible<error_or, typename std::add_rvalue_reference<value_type>::type>::value) {
            error_or(std::move(value)).swap(*this);
            return *this;
        }

        inline error_or& operator=(error_or other) noexcept(std::is_nothrow_move_constructible<error_or>::value) {
            error_or(std::move(other)).swap(*this);
            return *this;
        }

        template<typename U>
        inline error_or& operator=(error_or<error_type, U> other) noexcept(std::is_nothrow_constructible<error_or, error_or<E, U>&&>::value) {
            error_or(std::move(other)).swap(*this);
            return *this;
        }

        inline ~error_or() noexcept(std::is_nothrow_destructible<error_type>::value and
                                    std::is_nothrow_destructible<value_type>::value) {
            if (ok_)
                val_.value.~value_type();
            else
                val_.error.~error_type();
        }

        inline bool ok() const noexcept {
            return ok_;
        }

        inline explicit operator bool() const noexcept {
            return ok_;
        }

        inline const error_type& error() const noexcept {
            assert(!ok_);
            return val_.error;
        }

        inline value_type& value() noexcept {
            assert(ok_);
            return val_.value;
        }

        inline const value_type& value() const noexcept {
            assert(ok_);
            return val_.value;
        }

        inline error_type&& release_error() noexcept {
            assert(!ok_);
            return std::move(val_.error);
        }

        inline value_type&& release_value() noexcept {
            assert(ok_);
            return std::move(val_.value);
        }

    private:
        union val {
            // The lifecycle of members is handled by the enclosing class.
            inline val() noexcept {}
            inline ~val() noexcept {}
            value_type value;
            error_type error;
        } val_;

        bool ok_ = true;

        static constexpr bool is_nothrow_swappable =
            detail::is_nothrow_swappable<error_type>::value and
            detail::is_nothrow_swappable<value_type>::value and
            std::is_nothrow_move_constructible<error_type>::value and
            std::is_nothrow_move_constructible<value_type>::value and
            std::is_nothrow_destructible<error_type>::value and
            std::is_nothrow_destructible<value_type>::value;

        template<typename U = value_type>
        typename std::enable_if<error_or<error_type, U>::is_nothrow_swappable>::type sfinae_swap(error_or& other) noexcept {
            using std::swap;

            if (ok_ == other.ok_) {
                if (ok_)
                    swap(val_.value, other.val_.value);
                else
                    swap(val_.error, other.val_.error);
            } else {
                if (ok_) {
                    new(&val_.error) error_type(std::move(other.val_.error));
                    new(&other.val_.value) value_type(std::move(val_.value));
                    val_.value.~value_type();
                    other.val_.error.~error_type();
                } else {
                    new(&other.val_.error) error_type(std::move(val_.error));
                    new(&val_.value) value_type(std::move(other.val_.value));
                    other.val_.value.~value_type();
                    val_.error.~error_type();
                }
                swap(ok_, other.ok_);
            }
        }

        template<typename U>
        typename std::conditional
        <
            !std::is_nothrow_constructible<value_type, typename std::add_rvalue_reference<U>::type>::value and std::is_constructible<U, typename std::add_lvalue_reference<U>::type>::value,
            const U&,
            U&&
            >::type
        move_if_noexcept_from(U& u) {
            return std::move(u);
        }

    };

    template<typename E1, typename T1, typename E2, typename T2>
    bool operator==(const error_or<E1, T1>& lhs, const error_or<E2, T2>& rhs) noexcept(noexcept(lhs.value() == rhs.value()) and
                                                                                noexcept(lhs.error() == rhs.error())) {
        if (lhs.ok() == rhs.ok()) {
            if (lhs.ok()) {
                return lhs.value() == rhs.value();
            } else {
                return lhs.error() == rhs.error();
            }
        }
        return false;
    }

    template<typename E1, typename T1, typename E2, typename T2>
    bool operator!=(const error_or<E1, T1>& lhs, const error_or<E2, T2>& rhs) noexcept(noexcept(lhs == rhs)) {
        return not lhs == rhs;
    }

    template<typename T>
    using error_code_or = error_or<std::error_code, T>;

    template<typename T>
    using error_condition_or = error_or<std::error_condition, T>;

    template<typename T>
    using error_code_or_unique = error_code_or<std::unique_ptr<T>>;

    template<typename T>
    using error_condition_or_unique = error_condition_or<std::unique_ptr<T>>;

} // namespace acm

#endif // included_108FBB04_F426_414D_9EDD_B4D2AF941E96
<commit_msg>Switch const ordering<commit_after>// Copyright 2012 Andrew C. Morrow
//
// 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.

#ifndef included_108FBB04_F426_414D_9EDD_B4D2AF941E96
#define included_108FBB04_F426_414D_9EDD_B4D2AF941E96

#include <cassert>
#include <initializer_list>
#include <memory>
#include <system_error>
#include <type_traits>

namespace acm {

    namespace detail  {

        namespace adl_swap_ns {
            using std::swap;

            template <class T>
            struct is_nothrow_swappable_test {
                static bool constexpr value = noexcept(swap(std::declval<T&>(), std::declval<T&>()));
            };
        } // namespace adl_swap_ns

        // This really should be part of C++
        template <class T>
        struct is_nothrow_swappable
            : std::integral_constant<bool, adl_swap_ns::is_nothrow_swappable_test<T>::value>
        {};

    } // namespace detail

    template<typename E, typename T>
    class error_or final {

    public:
        using error_type = E;
        using value_type = T;

        inline error_or() noexcept(std::is_nothrow_default_constructible<value_type>::value) {
            new(&val_.value) value_type;
        }

        inline error_or(error_type error) noexcept(std::is_nothrow_move_constructible<error_type>::value)
            : ok_(false) {
            assert(error);
            new(&val_.error) error_type(std::move(error));
        }

        inline error_or(value_type value) noexcept(std::is_nothrow_move_constructible<value_type>::value) {
            new(&val_.value) value_type(std::move(value));
        }

        template<typename U = value_type>
        inline error_or(std::initializer_list<typename U::value_type> values) noexcept(std::is_nothrow_constructible<U, std::initializer_list<typename U::value_type>>::value) {
            new(&val_.value) value_type(values);
        }

        inline error_or(error_or const& other) noexcept(std::is_nothrow_copy_constructible<error_type>::value and
                                                        std::is_nothrow_copy_constructible<value_type>::value) {
            if (other.ok_)
                new(&val_.value) value_type(other.val_.value);
            else
                new(&val_.error) error_type(other.val_.error);
            ok_ = other.ok_;
        }

        inline error_or(error_or&& other) noexcept((std::is_nothrow_move_constructible<error_type>::value or
                                                    std::is_nothrow_copy_constructible<error_type>::value) and
                                                   (std::is_nothrow_move_constructible<value_type>::value or
                                                    std::is_nothrow_copy_constructible<value_type>::value)) {
            if (other.ok_)
                new(&val_.value) value_type(std::move_if_noexcept(other.val_.value));
            else
                new(&val_.error) error_type(std::move_if_noexcept(other.val_.error));
            ok_ = other.ok_;
        }

        template<typename U>
        inline error_or(error_or<error_type, U> const& other) noexcept(std::is_nothrow_copy_constructible<error_type>::value and
                                                                       std::is_nothrow_copy_constructible<value_type>::value) {
            if (other.ok_)
                new(&val_.value) value_type(other.val_.value);
            else
                new(&val_.error) error_type(other.val_.error);
            ok_ = other.ok_;
        }

        template<typename U>
        inline error_or(error_or<error_type, U>&& other) noexcept((std::is_nothrow_move_constructible<error_type>::value or
                                                                   std::is_nothrow_copy_constructible<error_type>::value) and
                                                                  (std::is_nothrow_constructible<value_type, typename std::add_rvalue_reference<U>::type>::value or
                                                                   std::is_nothrow_constructible<value_type, typename std::add_lvalue_reference<U>::type>::value)) {
            if (other.ok_)
                new(&val_.value) value_type(move_if_noexcept_from(other.val_.value));
            else
                new(&val_.error) error_type(std::move_if_noexcept(other.val_.error));
            ok_ = other.ok_;
        }

        void swap(error_or& other) noexcept {
            other.sfinae_swap(*this);
        }

        friend inline void swap(error_or& a, error_or& b) noexcept {
            a.swap(b);
        }

        inline error_or& operator=(error_type error) noexcept(std::is_nothrow_constructible<error_or, typename std::add_rvalue_reference<error_type>::type>::value) {
            error_or(std::move(error)).swap(*this);
            return *this;
        }

        inline error_or& operator=(value_type value) noexcept(std::is_nothrow_constructible<error_or, typename std::add_rvalue_reference<value_type>::type>::value) {
            error_or(std::move(value)).swap(*this);
            return *this;
        }

        inline error_or& operator=(error_or other) noexcept(std::is_nothrow_move_constructible<error_or>::value) {
            error_or(std::move(other)).swap(*this);
            return *this;
        }

        template<typename U>
        inline error_or& operator=(error_or<error_type, U> other) noexcept(std::is_nothrow_constructible<error_or, error_or<E, U>&&>::value) {
            error_or(std::move(other)).swap(*this);
            return *this;
        }

        inline ~error_or() noexcept(std::is_nothrow_destructible<error_type>::value and
                                    std::is_nothrow_destructible<value_type>::value) {
            if (ok_)
                val_.value.~value_type();
            else
                val_.error.~error_type();
        }

        inline bool ok() const noexcept {
            return ok_;
        }

        inline explicit operator bool() const noexcept {
            return ok_;
        }

        inline error_type const& error() const noexcept {
            assert(!ok_);
            return val_.error;
        }

        inline value_type& value() noexcept {
            assert(ok_);
            return val_.value;
        }

        inline value_type const& value() const noexcept {
            assert(ok_);
            return val_.value;
        }

        inline error_type&& release_error() noexcept {
            assert(!ok_);
            return std::move(val_.error);
        }

        inline value_type&& release_value() noexcept {
            assert(ok_);
            return std::move(val_.value);
        }

    private:
        union val {
            // The lifecycle of members is handled by the enclosing class.
            inline val() noexcept {}
            inline ~val() noexcept {}
            value_type value;
            error_type error;
        } val_;

        bool ok_ = true;

        static bool constexpr is_nothrow_swappable =
            detail::is_nothrow_swappable<error_type>::value and
            detail::is_nothrow_swappable<value_type>::value and
            std::is_nothrow_move_constructible<error_type>::value and
            std::is_nothrow_move_constructible<value_type>::value and
            std::is_nothrow_destructible<error_type>::value and
            std::is_nothrow_destructible<value_type>::value;

        template<typename U = value_type>
        typename std::enable_if<error_or<error_type, U>::is_nothrow_swappable>::type sfinae_swap(error_or& other) noexcept {
            using std::swap;

            if (ok_ == other.ok_) {
                if (ok_)
                    swap(val_.value, other.val_.value);
                else
                    swap(val_.error, other.val_.error);
            } else {
                if (ok_) {
                    new(&val_.error) error_type(std::move(other.val_.error));
                    new(&other.val_.value) value_type(std::move(val_.value));
                    val_.value.~value_type();
                    other.val_.error.~error_type();
                } else {
                    new(&other.val_.error) error_type(std::move(val_.error));
                    new(&val_.value) value_type(std::move(other.val_.value));
                    other.val_.value.~value_type();
                    val_.error.~error_type();
                }
                swap(ok_, other.ok_);
            }
        }

        template<typename U>
        typename std::conditional
        <
            !std::is_nothrow_constructible<value_type, typename std::add_rvalue_reference<U>::type>::value and std::is_constructible<U, typename std::add_lvalue_reference<U>::type>::value,
            U const&,
            U&&
            >::type
        move_if_noexcept_from(U& u) {
            return std::move(u);
        }

    };

    template<typename E1, typename T1, typename E2, typename T2>
    bool operator==(error_or<E1, T1> const& lhs, error_or<E2, T2> const& rhs) noexcept(noexcept(lhs.value() == rhs.value()) and
                                                                                noexcept(lhs.error() == rhs.error())) {
        if (lhs.ok() == rhs.ok()) {
            if (lhs.ok()) {
                return lhs.value() == rhs.value();
            } else {
                return lhs.error() == rhs.error();
            }
        }
        return false;
    }

    template<typename E1, typename T1, typename E2, typename T2>
    bool operator!=(error_or<E1, T1> const& lhs, error_or<E2, T2> const& rhs) noexcept(noexcept(lhs == rhs)) {
        return not lhs == rhs;
    }

    template<typename T>
    using error_code_or = error_or<std::error_code, T>;

    template<typename T>
    using error_condition_or = error_or<std::error_condition, T>;

    template<typename T>
    using error_code_or_unique = error_code_or<std::unique_ptr<T>>;

    template<typename T>
    using error_condition_or_unique = error_condition_or<std::unique_ptr<T>>;

} // namespace acm

#endif // included_108FBB04_F426_414D_9EDD_B4D2AF941E96
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: olecomponent.hxx,v $
 *
 *  $Revision: 1.20 $
 *
 *  last change: $Author: obo $ $Date: 2006-10-12 11:22:26 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _INC_OLECOMPONENT_HXX_
#define _INC_OLECOMPONENT_HXX_

#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_REFERENCE_HXX_
#include <com/sun/star/uno/Reference.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif

#ifndef _COM_SUN_STAR_LANG_XCOMPONENT_HPP_
#include <com/sun/star/lang/XComponent.hpp>
#endif

#ifndef _COM_SUN_STAR_UTIL_XCLOSEABLE_HPP_
#include <com/sun/star/util/XCloseable.hpp>
#endif

#ifndef _COM_SUN_STAR_DATATRANSFER_XTRANSFERABLE_HPP_
#include <com/sun/star/datatransfer/XTransferable.hpp>
#endif

#ifndef _COM_SUN_STAR_IO_XINPUTSTREAM_HPP_
#include <com/sun/star/io/XInputStream.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XOUTPUTSTREAM_HPP_
#include <com/sun/star/io/XOutputStream.hpp>
#endif

#ifndef _COM_SUN_STAR_EMBED_XOPTIMIZEDSTORAGE_HPP_
#include <com/sun/star/embed/XOptimizedStorage.hpp>
#endif

#ifndef _COM_SUN_STAR_EMBED_VERBDESCRIPTOR_HPP_
#include <com/sun/star/embed/VerbDescriptor.hpp>
#endif

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif

#ifndef _COM_SUN_STAR_AWT_SIZE_HPP_
#include <com/sun/star/awt/Size.hpp>
#endif

#ifndef _COM_SUN_STAR_LANG_XUNOTUNNEL_HPP_
#include <com/sun/star/lang/XUnoTunnel.hpp>
#endif

#ifndef _CPPUHELPER_IMPLBASE5_HXX_
#include <cppuhelper/implbase5.hxx>
#endif

#ifndef _COM_SUN_STAR_UTIL_XMODIFIABLE_HPP_
#include <com/sun/star/util/XModifiable.hpp>
#endif

#ifndef _COM_SUN_STAR_UTIL_XMODIFYLISTENER_HPP_
#include <com/sun/star/util/XModifyListener.hpp>
#endif

#include <vector>

namespace com { namespace sun { namespace star {
}}}

namespace cppu {
    class OMultiTypeInterfaceContainerHelper;
}

class OleWrapperClientSite;
class OleWrapperAdviseSink;
class OleEmbeddedObject;
struct OleComponentNative_Impl;

class OleComponent : public ::cppu::WeakImplHelper5< ::com::sun::star::util::XCloseable, ::com::sun::star::lang::XComponent,
                                                     ::com::sun::star::lang::XUnoTunnel, ::com::sun::star::util::XModifiable,
                                                     ::com::sun::star::datatransfer::XTransferable >
{
    ::osl::Mutex m_aMutex;
    ::cppu::OMultiTypeInterfaceContainerHelper* m_pInterfaceContainer;

    sal_Bool m_bDisposed;
    sal_Bool m_bModified;
    OleComponentNative_Impl* m_pNativeImpl;

    OleEmbeddedObject* m_pUnoOleObject;
    OleWrapperClientSite* m_pOleWrapClientSite;
    OleWrapperAdviseSink* m_pImplAdviseSink;

    sal_Int32 m_nOLEMiscFlags;
    sal_Int32 m_nAdvConn;

    ::com::sun::star::uno::Sequence< ::com::sun::star::embed::VerbDescriptor > m_aVerbList;
    ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > m_aDataFlavors;

    ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > m_xFactory;

    sal_Bool m_bOleInitialized;

    sal_Bool InitializeObject_Impl();

    void CreateNewIStorage_Impl();

    void RetrieveObjectDataFlavors_Impl();

    void Dispose();

public:
    OleComponent( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& m_xFactory,
                  OleEmbeddedObject* pOleObj );

    virtual ~OleComponent();

    OleComponent* createEmbeddedCopyOfLink();

    void disconnectEmbeddedObject();

    static ::com::sun::star::awt::Size CalculateWithFactor( const ::com::sun::star::awt::Size& aSize,
                                                            const ::com::sun::star::awt::Size& aMultiplier,
                                                            const ::com::sun::star::awt::Size& aDivisor );

    ::com::sun::star::awt::Size CalculateTheRealSize( const ::com::sun::star::awt::Size& aContSize, sal_Bool bUpdate );

    // ==== Initialization ==================================================
    void LoadEmbeddedObject( const ::rtl::OUString& aTempURL );

    void CreateObjectFromClipboard();

    void CreateNewEmbeddedObject( const ::com::sun::star::uno::Sequence< sal_Int8 >& aSeqCLSID );

    void CreateObjectFromData(
                        const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& xTransfer );

    void CreateObjectFromFile( const ::rtl::OUString& aFileName );

    void CreateLinkFromFile( const ::rtl::OUString& aFileName );

    void InitEmbeddedCopyOfLink( OleComponent* pOleLinkComponent );

    // ======================================================================

    void RunObject(); // switch OLE object to running state

    void CloseObject(); // switch OLE object to loaded state

    ::com::sun::star::uno::Sequence< ::com::sun::star::embed::VerbDescriptor > GetVerbList();

    void ExecuteVerb( sal_Int32 nVerbID );

    void SetHostName( const ::rtl::OUString& aContName, const ::rtl::OUString& aEmbDocName );

    void SetExtent( const ::com::sun::star::awt::Size& aVisAreaSize, sal_Int64 nAspect );

    ::com::sun::star::awt::Size GetExtent( sal_Int64 nAspect );
    ::com::sun::star::awt::Size GetCachedExtent( sal_Int64 nAspect );
    ::com::sun::star::awt::Size GetReccomendedExtent( sal_Int64 nAspect );

    sal_Int64 GetMiscStatus( sal_Int64 nAspect );

    ::com::sun::star::uno::Sequence< sal_Int8 > GetCLSID();

    sal_Bool IsDirty();

    void StoreOwnTmpIfNecessary();

    sal_Bool SaveObject_Impl();
    sal_Bool OnShowWindow_Impl( bool bShow );
    void OnViewChange_Impl( sal_uInt32 dwAspect );

    // XCloseable
    virtual void SAL_CALL close( sal_Bool DeliverOwnership ) throw (::com::sun::star::util::CloseVetoException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL addCloseListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XCloseListener >& Listener ) throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeCloseListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XCloseListener >& Listener ) throw (::com::sun::star::uno::RuntimeException);

    // XTransferable
    virtual ::com::sun::star::uno::Any SAL_CALL getTransferData( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw (::com::sun::star::datatransfer::UnsupportedFlavorException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors(  ) throw (::com::sun::star::uno::RuntimeException);
    virtual sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw (::com::sun::star::uno::RuntimeException);

    // XComponent
    virtual void SAL_CALL dispose() throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL addEventListener(const com::sun::star::uno::Reference < com::sun::star::lang::XEventListener >& aListener) throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeEventListener(const com::sun::star::uno::Reference < com::sun::star::lang::XEventListener >& aListener) throw (::com::sun::star::uno::RuntimeException);

    // XUnoTunnel
    virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) throw(::com::sun::star::uno::RuntimeException) ;

    // XModifiable
    virtual sal_Bool SAL_CALL isModified() throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL setModified( sal_Bool bModified )
        throw (::com::sun::star::beans::PropertyVetoException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL addModifyListener( const com::sun::star::uno::Reference < com::sun::star::util::XModifyListener >& xListener ) throw(::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeModifyListener( const com::sun::star::uno::Reference < com::sun::star::util::XModifyListener >& xListener) throw(::com::sun::star::uno::RuntimeException);
};

#endif

<commit_msg>INTEGRATION: CWS fwk59 (1.20.22); FILE MERGED 2007/01/04 16:05:12 mav 1.20.22.1: #i71349# introduce a better workaround for AcrobatReader 7.0.8 object<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: olecomponent.hxx,v $
 *
 *  $Revision: 1.21 $
 *
 *  last change: $Author: obo $ $Date: 2007-01-23 07:33:29 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _INC_OLECOMPONENT_HXX_
#define _INC_OLECOMPONENT_HXX_

#ifndef _COM_SUN_STAR_UNO_SEQUENCE_HXX_
#include <com/sun/star/uno/Sequence.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_REFERENCE_HXX_
#include <com/sun/star/uno/Reference.hxx>
#endif
#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
#include <com/sun/star/uno/Any.hxx>
#endif

#ifndef _COM_SUN_STAR_LANG_XCOMPONENT_HPP_
#include <com/sun/star/lang/XComponent.hpp>
#endif

#ifndef _COM_SUN_STAR_UTIL_XCLOSEABLE_HPP_
#include <com/sun/star/util/XCloseable.hpp>
#endif

#ifndef _COM_SUN_STAR_DATATRANSFER_XTRANSFERABLE_HPP_
#include <com/sun/star/datatransfer/XTransferable.hpp>
#endif

#ifndef _COM_SUN_STAR_IO_XINPUTSTREAM_HPP_
#include <com/sun/star/io/XInputStream.hpp>
#endif
#ifndef _COM_SUN_STAR_IO_XOUTPUTSTREAM_HPP_
#include <com/sun/star/io/XOutputStream.hpp>
#endif

#ifndef _COM_SUN_STAR_EMBED_XOPTIMIZEDSTORAGE_HPP_
#include <com/sun/star/embed/XOptimizedStorage.hpp>
#endif

#ifndef _COM_SUN_STAR_EMBED_VERBDESCRIPTOR_HPP_
#include <com/sun/star/embed/VerbDescriptor.hpp>
#endif

#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif

#ifndef _COM_SUN_STAR_AWT_SIZE_HPP_
#include <com/sun/star/awt/Size.hpp>
#endif

#ifndef _COM_SUN_STAR_LANG_XUNOTUNNEL_HPP_
#include <com/sun/star/lang/XUnoTunnel.hpp>
#endif

#ifndef _CPPUHELPER_IMPLBASE5_HXX_
#include <cppuhelper/implbase5.hxx>
#endif

#ifndef _COM_SUN_STAR_UTIL_XMODIFIABLE_HPP_
#include <com/sun/star/util/XModifiable.hpp>
#endif

#ifndef _COM_SUN_STAR_UTIL_XMODIFYLISTENER_HPP_
#include <com/sun/star/util/XModifyListener.hpp>
#endif

#include <vector>

namespace com { namespace sun { namespace star {
}}}

namespace cppu {
    class OMultiTypeInterfaceContainerHelper;
}

class OleWrapperClientSite;
class OleWrapperAdviseSink;
class OleEmbeddedObject;
struct OleComponentNative_Impl;

class OleComponent : public ::cppu::WeakImplHelper5< ::com::sun::star::util::XCloseable, ::com::sun::star::lang::XComponent,
                                                     ::com::sun::star::lang::XUnoTunnel, ::com::sun::star::util::XModifiable,
                                                     ::com::sun::star::datatransfer::XTransferable >
{
    ::osl::Mutex m_aMutex;
    ::cppu::OMultiTypeInterfaceContainerHelper* m_pInterfaceContainer;

    sal_Bool m_bDisposed;
    sal_Bool m_bModified;
    OleComponentNative_Impl* m_pNativeImpl;

    OleEmbeddedObject* m_pUnoOleObject;
    OleWrapperClientSite* m_pOleWrapClientSite;
    OleWrapperAdviseSink* m_pImplAdviseSink;

    sal_Int32 m_nOLEMiscFlags;
    sal_Int32 m_nAdvConn;

    ::com::sun::star::uno::Sequence< ::com::sun::star::embed::VerbDescriptor > m_aVerbList;
    ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > m_aDataFlavors;

    ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > m_xFactory;

    sal_Bool m_bOleInitialized;

    // specifies whether the workaround for some rare embedded objects is activated ( f.e. AcrobatReader 7.0.8 object )
    // such objects report the dirty state wrongly sometimes and do not allow to store them any time
    sal_Bool m_bWorkaroundActive;

    sal_Bool InitializeObject_Impl();

    void CreateNewIStorage_Impl();

    void RetrieveObjectDataFlavors_Impl();

    void Dispose();

public:
    OleComponent( const ::com::sun::star::uno::Reference< ::com::sun::star::lang::XMultiServiceFactory >& m_xFactory,
                  OleEmbeddedObject* pOleObj );

    virtual ~OleComponent();

    OleComponent* createEmbeddedCopyOfLink();

    void disconnectEmbeddedObject();

    static ::com::sun::star::awt::Size CalculateWithFactor( const ::com::sun::star::awt::Size& aSize,
                                                            const ::com::sun::star::awt::Size& aMultiplier,
                                                            const ::com::sun::star::awt::Size& aDivisor );

    ::com::sun::star::awt::Size CalculateTheRealSize( const ::com::sun::star::awt::Size& aContSize, sal_Bool bUpdate );

    // ==== Initialization ==================================================
    void LoadEmbeddedObject( const ::rtl::OUString& aTempURL );

    void CreateObjectFromClipboard();

    void CreateNewEmbeddedObject( const ::com::sun::star::uno::Sequence< sal_Int8 >& aSeqCLSID );

    void CreateObjectFromData(
                        const ::com::sun::star::uno::Reference< ::com::sun::star::datatransfer::XTransferable >& xTransfer );

    void CreateObjectFromFile( const ::rtl::OUString& aFileName );

    void CreateLinkFromFile( const ::rtl::OUString& aFileName );

    void InitEmbeddedCopyOfLink( OleComponent* pOleLinkComponent );

    // ======================================================================

    void RunObject(); // switch OLE object to running state

    void CloseObject(); // switch OLE object to loaded state

    ::com::sun::star::uno::Sequence< ::com::sun::star::embed::VerbDescriptor > GetVerbList();

    void ExecuteVerb( sal_Int32 nVerbID );

    void SetHostName( const ::rtl::OUString& aContName, const ::rtl::OUString& aEmbDocName );

    void SetExtent( const ::com::sun::star::awt::Size& aVisAreaSize, sal_Int64 nAspect );

    ::com::sun::star::awt::Size GetExtent( sal_Int64 nAspect );
    ::com::sun::star::awt::Size GetCachedExtent( sal_Int64 nAspect );
    ::com::sun::star::awt::Size GetReccomendedExtent( sal_Int64 nAspect );

    sal_Int64 GetMiscStatus( sal_Int64 nAspect );

    ::com::sun::star::uno::Sequence< sal_Int8 > GetCLSID();

    sal_Bool IsWorkaroundActive() { return m_bWorkaroundActive; }

    sal_Bool IsDirty();

    void StoreOwnTmpIfNecessary();

    sal_Bool SaveObject_Impl();
    sal_Bool OnShowWindow_Impl( bool bShow );
    void OnViewChange_Impl( sal_uInt32 dwAspect );
    void OnClose_Impl();

    // XCloseable
    virtual void SAL_CALL close( sal_Bool DeliverOwnership ) throw (::com::sun::star::util::CloseVetoException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL addCloseListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XCloseListener >& Listener ) throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeCloseListener( const ::com::sun::star::uno::Reference< ::com::sun::star::util::XCloseListener >& Listener ) throw (::com::sun::star::uno::RuntimeException);

    // XTransferable
    virtual ::com::sun::star::uno::Any SAL_CALL getTransferData( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw (::com::sun::star::datatransfer::UnsupportedFlavorException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException);
    virtual ::com::sun::star::uno::Sequence< ::com::sun::star::datatransfer::DataFlavor > SAL_CALL getTransferDataFlavors(  ) throw (::com::sun::star::uno::RuntimeException);
    virtual sal_Bool SAL_CALL isDataFlavorSupported( const ::com::sun::star::datatransfer::DataFlavor& aFlavor ) throw (::com::sun::star::uno::RuntimeException);

    // XComponent
    virtual void SAL_CALL dispose() throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL addEventListener(const com::sun::star::uno::Reference < com::sun::star::lang::XEventListener >& aListener) throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeEventListener(const com::sun::star::uno::Reference < com::sun::star::lang::XEventListener >& aListener) throw (::com::sun::star::uno::RuntimeException);

    // XUnoTunnel
    virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) throw(::com::sun::star::uno::RuntimeException) ;

    // XModifiable
    virtual sal_Bool SAL_CALL isModified() throw (::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL setModified( sal_Bool bModified )
        throw (::com::sun::star::beans::PropertyVetoException, ::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL addModifyListener( const com::sun::star::uno::Reference < com::sun::star::util::XModifyListener >& xListener ) throw(::com::sun::star::uno::RuntimeException);
    virtual void SAL_CALL removeModifyListener( const com::sun::star::uno::Reference < com::sun::star::util::XModifyListener >& xListener) throw(::com::sun::star::uno::RuntimeException);
};

#endif

<|endoftext|>


<commit_before>#ifndef _HIDA_STAR_HPP_
#define _HIDA_STAR_HPP_

#include <cassert>
#include <vector>

#include <boost/array.hpp>
#include <boost/optional.hpp>
#include <boost/pool/pool_alloc.hpp>
#include <boost/unordered_map.hpp>
#include <boost/utility.hpp>

#include "search/Constants.hpp"
#include "util/PointerOps.hpp"

template <
  class Domain,
  class Node
  >
class HIDAStar : boost::noncopyable
{
private:
  typedef typename Node::Cost Cost;
  typedef typename Node::State State;

  typedef boost::unordered_map<
    State,
    std::pair<Cost, bool>
    // ,boost::hash<State>,
    // std::equal_to<State>,
    // boost::fast_pool_allocator< std::pair<State const, std::pair<Cost, bool> > >
    > Cache;

  typedef typename Cache::iterator CacheIterator;
  typedef typename Cache::const_iterator CacheConstIterator;

  struct BoundedResult
  {
    union Result
    {
      Cost cutoff;
      Node *goal;
    } result;

    typedef enum {Cutoff, Goal, Failure} ResultType;

    ResultType result_type;

    BoundedResult(Cost cutoff)
    {
      result.cutoff = cutoff;
      result_type = Cutoff;
    }

    BoundedResult(Node *goal)
    {
      assert(goal != NULL);
      result.goal = goal;
      result_type = Goal;
    }

    BoundedResult()
    {
      result_type = Failure;
    }

    bool is_failure() const
    {
      return result_type == Failure;
    }

    bool is_goal() const
    {
      return result_type == Goal;
    }

    bool is_cutoff() const
    {
      return result_type == Cutoff;
    }

    Node * get_goal() const
    {
      assert(is_goal());
      return result.goal;
    }

    Cost get_cutoff() const
    {
      assert(is_cutoff());
      return result.cutoff;
    }
  };

private:
  const static unsigned hierarchy_height = Domain::num_abstraction_levels + 1;

  Node goal;
  bool searched;

  Domain &domain;

  boost::array<unsigned, hierarchy_height> num_expanded;
  boost::array<unsigned, hierarchy_height> num_generated;

  boost::array<State, hierarchy_height> abstract_goals;

  Cache cache;

  boost::pool<> node_pool;

public:
  HIDAStar(Domain &domain)
    : goal(domain.get_goal_state(), 0, 0)
    , searched(false)
    , domain(domain)
    , num_expanded()
    , num_generated()
    , abstract_goals()
    , cache()
    , node_pool(sizeof(Node))
  {
    num_expanded.assign(0);
    num_generated.assign(0);
    for (unsigned level = 0; level < hierarchy_height; level += 1)
      abstract_goals[level] = domain.abstract(level, domain.get_goal_state());
  }

  const Node * get_goal() const
  {
    return &goal;
  }

  const Domain & get_domain() const
  {
    return domain;
  }

  unsigned get_num_generated() const
  {
    unsigned sum = 0;
    for (unsigned i = 0; i < hierarchy_height; i += 1)
      sum += num_generated[i];

    return sum;
  }

  unsigned get_num_generated(const unsigned level) const
  {
    return num_generated[level];
  }

  unsigned get_num_expanded() const
  {
    unsigned sum = 0;
    for (unsigned i = 0; i < hierarchy_height; i += 1)
      sum += num_expanded[i];

    return sum;
  }

  unsigned get_num_expanded(const unsigned level) const
  {
    return num_expanded[level];
  }

  void search()
  {
    if (searched)
      return;
    searched = true;

    Node *start_node = new (node_pool.malloc())
      Node(domain.get_start_state(),
           0,
           0);

    Node goal_node(domain.get_goal_state(), 0, 0);
    hidastar_search(0, start_node, &goal_node);

    goal = goal_node;
  }

private:
  // start_node should be const, but that didn't work out.
  // goal_node is modified, if a goal is found.
  // returns true if a goal was found.
  bool hidastar_search(const unsigned level, Node *start_node, Node *goal_node)
  {
    assert(start_node != NULL);
    assert(goal_node != NULL);
    assert(start_node->num_nodes_to_start() == 1);
    Cost bound = start_node->get_h();
    bool failed = false;
    bool goal_found = false;

    while ( !goal_found && !failed ) {
#ifdef OUTPUT_SEARCH_PROGRESS
      if (level == 0) {
        std::cerr << "hidastar_search at level " << level << std::endl;
        std::cerr << "doing cost-bounded search with cutoff " << bound << std::endl;
        std::cerr << get_num_expanded() << " total nodes expanded" << std::endl
                  << get_num_generated() << " total nodes generated" << std::endl;
      }
#endif
      BoundedResult res = cost_bounded_search(level, start_node, bound);

      if (res.is_failure()) {
        assert(!res.is_goal());
        assert(!res.is_cutoff());
        failed = true;
      }
      else if (res.is_goal()) {
        assert(!res.is_cutoff());
        assert(!res.is_failure());
        goal_found = true;
        *goal_node = *res.get_goal();
      }
      else if (res.is_cutoff()) {
        assert(!res.is_goal());
        assert(!res.is_failure());
        bound = res.get_cutoff();
      }
      else {
        assert(false);
      }
    }

    if (goal_found) {
      cache_optimal_path(level, goal_node);
      return true;
    }
    else {
      std::cerr << "no solution found at level " << level << "!" << std::endl;
      assert(false);
      return NULL;
    }
  }

  BoundedResult
  cost_bounded_search(const unsigned level,
                      Node *start_node,
                      const Cost bound)
  {
    if (start_node->get_state() == abstract_goals[level]) {
      BoundedResult res(start_node);
      assert(res.is_goal());
      return res;
    }

    std::vector<Node *> succs;
    domain.compute_successors(*start_node, succs, node_pool);

    num_expanded[level] += 1;
    num_generated[level] += succs.size();

#ifdef OUTPUT_SEARCH_PROGRESS
      if (get_num_expanded() % 1000000 == 0) {
        std::cerr << "progress update:" << std::endl;
        std::cerr << get_num_expanded() << " total nodes expanded" << std::endl
                  << get_num_generated() << " total nodes generated" << std::endl;
        dump_cache_size(std::cerr);
      }
#endif

    boost::optional<Cost> new_cutoff;

    for (unsigned i = 0; i < succs.size(); i += 1) {
      Node *succ = succs[i];

      assert(succ->num_nodes_to_start() == start_node->num_nodes_to_start() + 1u);

      Cost hval = heuristic(level, succ);

      // P-g caching
      const Cost p_minus_g = bound >= succ->get_g() ? bound - succ->get_g() : 0;
      hval = std::max(hval, p_minus_g);
      CacheIterator cache_it = cache.find(succ->get_state());
      if (cache_it != cache.end()) {
        hval = std::max(hval, cache_it->second.first);
        cache_it->second.first = hval;
      }
      else {
        cache[succ->get_state()] = std::make_pair(hval, false);
      }
      // end P-g caching

      succ->set_h(hval);

      // Optimal path caching
      {
        CacheConstIterator cache_it = cache.find(succ->get_state());
        bool is_exact_cost = cache_it != cache.end() && cache_it->second.second;
        if (succ->get_f() == bound && is_exact_cost) {
          // std::cerr << "optimal path cache hit at level " << level << "!" << std::endl;
          assert(level > 0);
          Node *synthesized_goal = new (node_pool.malloc())
            Node(abstract_goals[level],
                 succ->get_g() + cache_it->second.first,
                 0,
                 succ);
          BoundedResult res(synthesized_goal);
          assert(res.is_goal());

          // cleanup remaining successors
          for (unsigned j = i + 1; j < succs.size(); j += 1)
            node_pool.free(succs[j]);

          return res;
        }
      }
      // end Optimal path caching

      // Normal IDA* stuff
      if (succ->get_f() <= bound) {
        BoundedResult res = cost_bounded_search(level, succ, bound);
        if (res.is_goal()) {
          assert(!res.is_cutoff());
          assert(!res.is_failure());

          // cleanup remaining successors
          for (unsigned j = i + 1; j < succs.size(); j += 1)
            node_pool.free(succs[j]);

          return res;
        }
        else if (res.is_cutoff()) {
          assert(!res.is_goal());
          assert(!res.is_failure());

          if (new_cutoff)
            new_cutoff = std::min(*new_cutoff, res.get_cutoff());
          else
            new_cutoff = res.get_cutoff();

          node_pool.free(succ);
        }
      }
      else {
        if (new_cutoff)
          new_cutoff = std::min(*new_cutoff, succ->get_f());
        else
          new_cutoff = succ->get_f();

        node_pool.free(succ);
      }
      // end Normal IDA* stuff
    } /* end for */

    if (new_cutoff) {
      BoundedResult res(*new_cutoff);
      assert(res.is_cutoff());
      assert(!res.is_goal());
      assert(!res.is_failure());
      return res;
    }
    else {
      BoundedResult res;
      assert(res.is_failure());
      assert(!res.is_cutoff());
      assert(!res.is_failure());
      return res;
    }
  }

  void cache_optimal_path(const unsigned level, const Node *goal_node)
  {
    assert(goal_node != NULL);
    assert(goal_node->get_state() == abstract_goals[level]);

    const Node *parent = goal_node->get_parent();
    while (parent != NULL) {
      assert(goal_node->get_g() >= parent->get_g());
      const Cost distance = goal_node->get_g() - parent->get_g();

      cache[parent->get_state()].first = distance;
      cache[parent->get_state()].second = distance;

      parent = parent->get_parent();
    }
  }

  Cost heuristic(const unsigned level, Node *node)
  {
    if (node->get_state() == abstract_goals[level])
      return 0;

    if (level == Domain::num_abstraction_levels)
      return domain.get_epsilon(node->get_state());

    const unsigned next_level = level + 1;
    Node node_abstraction(domain.abstract(next_level, node->get_state()),
                          0,
                          0);

    Cost hval;
    CacheConstIterator cache_it = cache.find(node_abstraction.get_state());
    if (cache_it == cache.end() || !cache_it->second.second) {
      cache[node_abstraction.get_state()] = std::make_pair(0, true);
      Node goal_abstraction(abstract_goals[next_level], 0, 0);
      bool goal_found = hidastar_search(next_level, &node_abstraction, &goal_abstraction);
      if (!goal_found) {
        std::cerr << "infinite heuristic estimate!" << std::endl;
        assert(false);
      }
      assert(cache.find(node_abstraction.get_state())->second.second);
      assert(goal_abstraction.get_h() == 0);
      assert(goal_abstraction.get_state() == abstract_goals[next_level]);
      cache[node_abstraction.get_state()].first = goal_abstraction.get_g();
      hval = goal_abstraction.get_g();
    }
    else {
      hval = cache_it->second.first;
    }

    assert(cache.find(node_abstraction.get_state()) != cache.end());

    return hval;
  }

  void dump_cache_size(std::ostream &o) const
  {
    o << "cache size: " << cache.size() << std::endl;
  }
};

#endif /* !_HIDA_STAR_HPP_ */
<commit_msg>Comment about memory leak of nodes on solution paths.<commit_after>#ifndef _HIDA_STAR_HPP_
#define _HIDA_STAR_HPP_

#include <cassert>
#include <vector>

#include <boost/array.hpp>
#include <boost/optional.hpp>
#include <boost/pool/pool_alloc.hpp>
#include <boost/unordered_map.hpp>
#include <boost/utility.hpp>

#include "search/Constants.hpp"
#include "util/PointerOps.hpp"

template <
  class Domain,
  class Node
  >
class HIDAStar : boost::noncopyable
{
private:
  typedef typename Node::Cost Cost;
  typedef typename Node::State State;

  typedef boost::unordered_map<
    State,
    std::pair<Cost, bool>
    // ,boost::hash<State>,
    // std::equal_to<State>,
    // boost::fast_pool_allocator< std::pair<State const, std::pair<Cost, bool> > >
    > Cache;

  typedef typename Cache::iterator CacheIterator;
  typedef typename Cache::const_iterator CacheConstIterator;

  struct BoundedResult
  {
    union Result
    {
      Cost cutoff;
      Node *goal;
    } result;

    typedef enum {Cutoff, Goal, Failure} ResultType;

    ResultType result_type;

    BoundedResult(Cost cutoff)
    {
      result.cutoff = cutoff;
      result_type = Cutoff;
    }

    BoundedResult(Node *goal)
    {
      assert(goal != NULL);
      result.goal = goal;
      result_type = Goal;
    }

    BoundedResult()
    {
      result_type = Failure;
    }

    bool is_failure() const
    {
      return result_type == Failure;
    }

    bool is_goal() const
    {
      return result_type == Goal;
    }

    bool is_cutoff() const
    {
      return result_type == Cutoff;
    }

    Node * get_goal() const
    {
      assert(is_goal());
      return result.goal;
    }

    Cost get_cutoff() const
    {
      assert(is_cutoff());
      return result.cutoff;
    }
  };

private:
  const static unsigned hierarchy_height = Domain::num_abstraction_levels + 1;

  Node goal;
  bool searched;

  Domain &domain;

  boost::array<unsigned, hierarchy_height> num_expanded;
  boost::array<unsigned, hierarchy_height> num_generated;

  boost::array<State, hierarchy_height> abstract_goals;

  Cache cache;

  boost::pool<> node_pool;

public:
  HIDAStar(Domain &domain)
    : goal(domain.get_goal_state(), 0, 0)
    , searched(false)
    , domain(domain)
    , num_expanded()
    , num_generated()
    , abstract_goals()
    , cache()
    , node_pool(sizeof(Node))
  {
    num_expanded.assign(0);
    num_generated.assign(0);
    for (unsigned level = 0; level < hierarchy_height; level += 1)
      abstract_goals[level] = domain.abstract(level, domain.get_goal_state());
  }

  const Node * get_goal() const
  {
    return &goal;
  }

  const Domain & get_domain() const
  {
    return domain;
  }

  unsigned get_num_generated() const
  {
    unsigned sum = 0;
    for (unsigned i = 0; i < hierarchy_height; i += 1)
      sum += num_generated[i];

    return sum;
  }

  unsigned get_num_generated(const unsigned level) const
  {
    return num_generated[level];
  }

  unsigned get_num_expanded() const
  {
    unsigned sum = 0;
    for (unsigned i = 0; i < hierarchy_height; i += 1)
      sum += num_expanded[i];

    return sum;
  }

  unsigned get_num_expanded(const unsigned level) const
  {
    return num_expanded[level];
  }

  void search()
  {
    if (searched)
      return;
    searched = true;

    Node *start_node = new (node_pool.malloc())
      Node(domain.get_start_state(),
           0,
           0);

    Node goal_node(domain.get_goal_state(), 0, 0);
    hidastar_search(0, start_node, &goal_node);

    goal = goal_node;
  }

private:
  // start_node should be const, but that didn't work out.
  // goal_node is modified, if a goal is found.
  // returns true if a goal was found.
  bool hidastar_search(const unsigned level, Node *start_node, Node *goal_node)
  {
    assert(start_node != NULL);
    assert(goal_node != NULL);
    assert(start_node->num_nodes_to_start() == 1);
    Cost bound = start_node->get_h();
    bool failed = false;
    bool goal_found = false;

    while ( !goal_found && !failed ) {
#ifdef OUTPUT_SEARCH_PROGRESS
      if (level == 0) {
        std::cerr << "hidastar_search at level " << level << std::endl;
        std::cerr << "doing cost-bounded search with cutoff " << bound << std::endl;
        std::cerr << get_num_expanded() << " total nodes expanded" << std::endl
                  << get_num_generated() << " total nodes generated" << std::endl;
      }
#endif
      BoundedResult res = cost_bounded_search(level, start_node, bound);

      if (res.is_failure()) {
        assert(!res.is_goal());
        assert(!res.is_cutoff());
        failed = true;
      }
      else if (res.is_goal()) {
        assert(!res.is_cutoff());
        assert(!res.is_failure());
        goal_found = true;
        *goal_node = *res.get_goal();
      }
      else if (res.is_cutoff()) {
        assert(!res.is_goal());
        assert(!res.is_failure());
        bound = res.get_cutoff();
      }
      else {
        assert(false);
      }
    }

    if (goal_found) {
      cache_optimal_path(level, goal_node);
      return true;
    }
    else {
      std::cerr << "no solution found at level " << level << "!" << std::endl;
      assert(false);
      return NULL;
    }
  }

  BoundedResult
  cost_bounded_search(const unsigned level,
                      Node *start_node,
                      const Cost bound)
  {
    if (start_node->get_state() == abstract_goals[level]) {
      BoundedResult res(start_node);
      assert(res.is_goal());
      return res;
    }

    std::vector<Node *> succs;
    domain.compute_successors(*start_node, succs, node_pool);

    num_expanded[level] += 1;
    num_generated[level] += succs.size();

#ifdef OUTPUT_SEARCH_PROGRESS
      if (get_num_expanded() % 1000000 == 0) {
        std::cerr << "progress update:" << std::endl;
        std::cerr << get_num_expanded() << " total nodes expanded" << std::endl
                  << get_num_generated() << " total nodes generated" << std::endl;
        dump_cache_size(std::cerr);
      }
#endif

    boost::optional<Cost> new_cutoff;

    for (unsigned i = 0; i < succs.size(); i += 1) {
      Node *succ = succs[i];

      assert(succ->num_nodes_to_start() == start_node->num_nodes_to_start() + 1u);

      Cost hval = heuristic(level, succ);

      // P-g caching
      const Cost p_minus_g = bound >= succ->get_g() ? bound - succ->get_g() : 0;
      hval = std::max(hval, p_minus_g);
      CacheIterator cache_it = cache.find(succ->get_state());
      if (cache_it != cache.end()) {
        hval = std::max(hval, cache_it->second.first);
        cache_it->second.first = hval;
      }
      else {
        cache[succ->get_state()] = std::make_pair(hval, false);
      }
      // end P-g caching

      succ->set_h(hval);

      // Optimal path caching
      {
        CacheConstIterator cache_it = cache.find(succ->get_state());
        bool is_exact_cost = cache_it != cache.end() && cache_it->second.second;
        if (succ->get_f() == bound && is_exact_cost) {
          // std::cerr << "optimal path cache hit at level " << level << "!" << std::endl;
          assert(level > 0);
          Node *synthesized_goal = new (node_pool.malloc())
            Node(abstract_goals[level],
                 succ->get_g() + cache_it->second.first,
                 0,
                 succ);
          BoundedResult res(synthesized_goal);
          assert(res.is_goal());

          // cleanup remaining successors
          for (unsigned j = i + 1; j < succs.size(); j += 1)
            node_pool.free(succs[j]);

          return res;
        }
      }
      // end Optimal path caching

      // Normal IDA* stuff
      if (succ->get_f() <= bound) {
        BoundedResult res = cost_bounded_search(level, succ, bound);
        if (res.is_goal()) {
          assert(!res.is_cutoff());
          assert(!res.is_failure());

          // cleanup remaining successors
          for (unsigned j = i + 1; j < succs.size(); j += 1)
            node_pool.free(succs[j]);

          return res;
        }
        else if (res.is_cutoff()) {
          assert(!res.is_goal());
          assert(!res.is_failure());

          if (new_cutoff)
            new_cutoff = std::min(*new_cutoff, res.get_cutoff());
          else
            new_cutoff = res.get_cutoff();

          node_pool.free(succ);
        }
      }
      else {
        if (new_cutoff)
          new_cutoff = std::min(*new_cutoff, succ->get_f());
        else
          new_cutoff = succ->get_f();

        node_pool.free(succ);
      }
      // end Normal IDA* stuff
    } /* end for */

    if (new_cutoff) {
      BoundedResult res(*new_cutoff);
      assert(res.is_cutoff());
      assert(!res.is_goal());
      assert(!res.is_failure());
      return res;
    }
    else {
      BoundedResult res;
      assert(res.is_failure());
      assert(!res.is_cutoff());
      assert(!res.is_failure());
      return res;
    }
  }

  void cache_optimal_path(const unsigned level, const Node *goal_node)
  {
    assert(goal_node != NULL);
    assert(goal_node->get_state() == abstract_goals[level]);

    const Node *parent = goal_node->get_parent();
    while (parent != NULL) {
      assert(goal_node->get_g() >= parent->get_g());
      const Cost distance = goal_node->get_g() - parent->get_g();

      cache[parent->get_state()].first = distance;
      cache[parent->get_state()].second = distance;

      parent = parent->get_parent();
    }
  }

  Cost heuristic(const unsigned level, Node *node)
  {
    if (node->get_state() == abstract_goals[level])
      return 0;

    if (level == Domain::num_abstraction_levels)
      return domain.get_epsilon(node->get_state());

    const unsigned next_level = level + 1;
    Node node_abstraction(domain.abstract(next_level, node->get_state()),
                          0,
                          0);

    Cost hval;
    CacheConstIterator cache_it = cache.find(node_abstraction.get_state());
    if (cache_it == cache.end() || !cache_it->second.second) {
      cache[node_abstraction.get_state()] = std::make_pair(0, true);
      Node goal_abstraction(abstract_goals[next_level], 0, 0);
      bool goal_found = hidastar_search(next_level, &node_abstraction, &goal_abstraction);
      if (!goal_found) {
        std::cerr << "infinite heuristic estimate!" << std::endl;
        assert(false);
      }
      assert(cache.find(node_abstraction.get_state())->second.second);
      assert(goal_abstraction.get_h() == 0);
      assert(goal_abstraction.get_state() == abstract_goals[next_level]);
      cache[node_abstraction.get_state()].first = goal_abstraction.get_g();
      hval = goal_abstraction.get_g();

      // TODO: I think this code leaks all the nodes along the goal
      // path.  However, all attempts to put cleanup code for
      // goal_abstraction's parents here has resulted in memory
      // corruption...
    }
    else {
      hval = cache_it->second.first;
    }

    assert(cache.find(node_abstraction.get_state()) != cache.end());

    return hval;
  }

  void dump_cache_size(std::ostream &o) const
  {
    o << "cache size: " << cache.size() << std::endl;
  }
};

#endif /* !_HIDA_STAR_HPP_ */
<|endoftext|>


<commit_before>#ifndef SRC_SERIALISATION_CONFIGFILE_HPP_
#define SRC_SERIALISATION_CONFIGFILE_HPP_

#include <cereal/archives/json.hpp>

#include <memory>

namespace fc
{

class config_file
{
public:
	typedef cereal::JSONInputArchive archive_t;

	explicit config_file(std::istream& stream)
	: iarchive(stream)
	, config_elements()
	{
	}

	void load()
	{
		for (auto& config : config_elements)
			config->load(iarchive);
	}

	/**
	 * \brief creates port returning value of type data_t corresponding to name
	 *
	 * \tparam data_t type of data corresponding to this port
	 * \return a passive source, which provides state of type data_t
	 *
	 */
	template<class data_t>
	auto out_value(const std::string& name);

private:
	archive_t iarchive;

	class archive_loadable
	{
	public:
		virtual void load(archive_t&) = 0;
		virtual ~archive_loadable()
		{
		}
	};

	template<class data_t>
	class config_value: public archive_loadable
	{
	public:
		config_value(const std::string& name, const data_t intial_value) :
				stored_value(intial_value), name(name)
		{
		}

		data_t stored_value;
		std::string name;

		void load(archive_t& archive) override
		{
			archive(cereal::make_nvp(name, stored_value));
		}
	};

	std::vector<std::shared_ptr<archive_loadable>> config_elements;

};

} /* namespace fc */

template<class data_t>
inline auto fc::config_file::out_value(const std::string& name)
{
	//currently forces data_t to be default constructible. is this acceptable?
	auto config = std::make_shared<config_value<data_t>>(name, data_t());
	config_elements.push_back(config);
	return [config]()
	{
		return config->stored_value;
	};
}

#endif /* SRC_SERIALISATION_CONFIGFILE_HPP_ */
<commit_msg>increase readability of declaration in configfile.hpp. unify identation of memeber initalzation list.<commit_after>#ifndef SRC_SERIALISATION_CONFIGFILE_HPP_
#define SRC_SERIALISATION_CONFIGFILE_HPP_

#include <cereal/archives/json.hpp>

#include <memory>

namespace fc
{

class config_file
{
public:
	typedef cereal::JSONInputArchive archive_t;

	explicit config_file(std::istream& stream)
		: iarchive(stream)
		, config_elements()
	{
	}

	void load()
	{
		for (auto& config : config_elements)
			config->load(iarchive);
	}

	/**
	 * \brief creates port returning value of type data_t corresponding to name
	 *
	 * \tparam data_t type of data corresponding to this port
	 * \return a passive source, which provides state of type data_t
	 */
	template<class data_t>
	auto out_value(const std::string& name);

private:
	class archive_loadable
	{
	public:
		virtual void load(archive_t&) = 0;
		virtual ~archive_loadable() { }
	};

	template<class data_t>
	class config_value: public archive_loadable
	{
	public:
		config_value(const std::string& name, const data_t intial_value)
			: stored_value(intial_value)
			, name(name)
		{
		}

		data_t stored_value;
		std::string name;

		void load(archive_t& archive) override
		{
			archive(cereal::make_nvp(name, stored_value));
		}
	};

	archive_t iarchive;
	std::vector<std::shared_ptr<archive_loadable>> config_elements;
};

} /* namespace fc */

template<class data_t>
inline auto fc::config_file::out_value(const std::string& name)
{
	//currently forces data_t to be default constructible. is this acceptable?
	auto config = std::make_shared<config_value<data_t>>(name, data_t());
	config_elements.push_back(config);
	return [config]()
	{
		return config->stored_value;
	};
}

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