<commit_before>#include <stdint.h>
#include <unistd.h>
#include <pthread.h>
#include <android/native_window.h> // requires ndk r5 or newer
#include <EGL/egl.h> // requires ndk r5 or newer
#include <GLES/gl.h>
#include <EGL/eglplatform.h>
#include <string>
#include <time.h>
#include "renderer.h"

#include <common/MapController.hpp>
#include <common/MapDisplay.hpp>
#include <common/Camera.hpp>
#include <common/Nodes.hpp>

void DetachThreadFromVM(void);

Renderer::Renderer() {
    LOG_INFO("Renderer instance created");
    pthread_mutex_init(&_mutex, 0);
    _window = NULL;
    _display = 0;
    _surface = 0;
    _context = 0;

    _currentTimeSec = double(clock()) / double(CLOCKS_PER_SEC);
    _initialTimeSec = _currentTimeSec;

    // Lock the mutex to keep the thread from doing anything until we get resumed
    pthread_mutex_lock(&_mutex);
    _paused = true;

    // Create the rendering thread
    _done = false;
    pthread_create(&_threadId, 0, threadStartCallback, this);

    return;
}

Renderer::~Renderer() {
    LOG_INFO("Renderer instance destroyed");
    _done = true;
    if (_paused) {
        pthread_mutex_unlock(&_mutex);
    }
    pthread_join(_threadId, 0);
    destroy();
    pthread_mutex_destroy(&_mutex);
    return;
}

void Renderer::resume() {
    assert(_paused);
    pthread_mutex_unlock(&_mutex);
    return;
}

void Renderer::pause() {
    assert(!_paused);
    pthread_mutex_lock(&_mutex);
    return;
}

void Renderer::setWindow(ANativeWindow *window, float displayScale) {
    _displayScale = displayScale;

    // notify render thread that window has changed
    if (!_paused) {
        pthread_mutex_lock(&_mutex);
    }
    _window = window;
    if (!_paused) {
        pthread_mutex_unlock(&_mutex);
    }

    return;
}

void Renderer::renderLoop() {
    pthread_mutex_lock(&_mutex);

    while (!_done) {
        // TODO: do we need to handle the window changing after creation, don't think so, but not sure
        if ((_display == 0) && _window) {
            initialize();
        }

        pthread_mutex_unlock(&_mutex);

        if (_display) {
            drawFrame();

            if (!eglSwapBuffers(_display, _surface)) {
                LOG_ERROR("eglSwapBuffers() returned error %d", eglGetError());
                // Hack: this fails when we rotate, delete the context to force a recreation
                // TODO: need to detect and handle this better
                destroy();
            }
        }

        pthread_mutex_lock(&_mutex);
    }

    pthread_mutex_unlock(&_mutex);

    DetachThreadFromVM();

    LOG_INFO("Render loop exits");

    return;
}

bool Renderer::initialize() {
    const EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_BLUE_SIZE, 8,
            EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_NONE };

    const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };

    EGLDisplay display;
    EGLConfig config;
    EGLint numConfigs;
    EGLint format;
    EGLSurface surface;
    EGLContext context;
    EGLint width;
    EGLint height;

    LOG_INFO("Initializing context");

    if ((display = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY) {
        LOG_ERROR("eglGetDisplay() returned error %d", eglGetError());
        return false;
    }
    if (!eglInitialize(display, 0, 0)) {
        LOG_ERROR("eglInitialize() returned error %d", eglGetError());
        return false;
    }

    if (!eglChooseConfig(display, attribs, &config, 1, &numConfigs)) {
        LOG_ERROR("eglChooseConfig() returned error %d", eglGetError());
        destroy();
        return false;
    }

    if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format)) {
        LOG_ERROR("eglGetConfigAttrib() returned error %d", eglGetError());
        destroy();
        return false;
    }

    ANativeWindow_setBuffersGeometry(_window, 0, 0, format);

    if (!(surface = eglCreateWindowSurface(display, config, _window, 0))) {
        LOG_ERROR("eglCreateWindowSurface() returned error %d", eglGetError());
        destroy();
        return false;
    }

    if (!(context = eglCreateContext(display, config, 0, contextAttribs))) {
        LOG_ERROR("eglCreateContext() returned error %d", eglGetError());
        destroy();
        return false;
    }

    if (!eglMakeCurrent(display, surface, surface, context)) {
        LOG_ERROR("eglMakeCurrent() returned error %d", eglGetError());
        destroy();
        return false;
    }

    if (!eglQuerySurface(display, surface, EGL_WIDTH, &width)
            || !eglQuerySurface(display, surface, EGL_HEIGHT, &height)) {
        LOG_ERROR("eglQuerySurface() returned error %d", eglGetError());
        destroy();
        return false;
    }

    LOG("display size: %d %d %.2f", width, height, _displayScale);
    _display = display;
    _surface = surface;
    _context = context;
    _width = width;
    _height = height;

    _mapController = new MapController;
    _mapController->display->camera->setDisplaySize(width, height);

    _mapController->display->setDisplayScale(_displayScale);

    _mapController->data->updateDisplay(_mapController->display);

    _mapController->display->camera->setAllowIdleAnimation(true);

    return true;
}

void Renderer::destroy() {
    LOG_INFO("Destroying context");

    delete _mapController;
    _mapController = NULL;

    eglMakeCurrent(_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroyContext(_display, _context);
    eglDestroySurface(_display, _surface);
    eglTerminate(_display);

    _display = EGL_NO_DISPLAY;
    _surface = EGL_NO_SURFACE;
    _context = EGL_NO_CONTEXT;
    _width = 0;
    _height = 0;

    return;
}

void Renderer::drawFrame() {
    _currentTimeSec = double(clock()) / double(CLOCKS_PER_SEC);
    _mapController->display->update(_currentTimeSec - _initialTimeSec);
    _mapController->display->draw();
}

void* Renderer::threadStartCallback(void *myself) {
    Renderer *renderer = (Renderer*) myself;

    renderer->renderLoop();
    pthread_exit(0);

    return 0;
}

void cameraMoveFinishedCallback(void) {

}
<commit_msg>fix a freeze in android (hopefully)<commit_after>#include <stdint.h>
#include <unistd.h>
#include <pthread.h>
#include <android/native_window.h> // requires ndk r5 or newer
#include <EGL/egl.h> // requires ndk r5 or newer
#include <GLES/gl.h>
#include <EGL/eglplatform.h>
#include <string>
#include <time.h>
#include "renderer.h"

#include <common/MapController.hpp>
#include <common/MapDisplay.hpp>
#include <common/Camera.hpp>
#include <common/Nodes.hpp>

void DetachThreadFromVM(void);

Renderer::Renderer() {
    LOG_INFO("Renderer instance created");
    pthread_mutex_init(&_mutex, 0);
    _window = NULL;
    _display = 0;
    _surface = 0;
    _context = 0;

    _currentTimeSec = double(clock()) / double(CLOCKS_PER_SEC);
    _initialTimeSec = _currentTimeSec;

    // Lock the mutex to keep the thread from doing anything until we get resumed
    pthread_mutex_lock(&_mutex);
    _paused = true;

    // Create the rendering thread
    _done = false;
    pthread_create(&_threadId, 0, threadStartCallback, this);

    return;
}

Renderer::~Renderer() {
    LOG_INFO("Renderer instance destroyed");
    _done = true;
    if (_paused) {
        pthread_mutex_unlock(&_mutex);
    }
    pthread_join(_threadId, 0);
    destroy();
    pthread_mutex_destroy(&_mutex);
    return;
}

void Renderer::resume() {
    assert(_paused);
    pthread_mutex_unlock(&_mutex);
    return;
}

void Renderer::pause() {
    assert(!_paused);
    pthread_mutex_lock(&_mutex);
    return;
}

void Renderer::setWindow(ANativeWindow *window, float displayScale) {
    _displayScale = displayScale;

    // notify render thread that window has changed
    if (!_paused) {
        pthread_mutex_lock(&_mutex);
    }
    _window = window;
    if (!_paused) {
        pthread_mutex_unlock(&_mutex);
    }

    return;
}

void Renderer::renderLoop() {
    pthread_mutex_lock(&_mutex);

    while (!_done) {
        // TODO: do we need to handle the window changing after creation, don't think so, but not sure
        if ((_display == 0) && _window) {
            initialize();
        }

        pthread_mutex_unlock(&_mutex);
        pthread_mutex_lock(&_mutex);

        if (_display) {
            drawFrame();

            if (!eglSwapBuffers(_display, _surface)) {
                LOG_ERROR("eglSwapBuffers() returned error %d", eglGetError());
                // Hack: this fails when we rotate, delete the context to force a recreation
                // TODO: need to detect and handle this better
                destroy();
            }
        }

    }

    pthread_mutex_unlock(&_mutex);

    DetachThreadFromVM();

    LOG_INFO("Render loop exits");

    return;
}

bool Renderer::initialize() {
    const EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_BLUE_SIZE, 8,
            EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8, EGL_NONE };

    const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };

    EGLDisplay display;
    EGLConfig config;
    EGLint numConfigs;
    EGLint format;
    EGLSurface surface;
    EGLContext context;
    EGLint width;
    EGLint height;

    LOG_INFO("Initializing context");

    if ((display = eglGetDisplay(EGL_DEFAULT_DISPLAY)) == EGL_NO_DISPLAY) {
        LOG_ERROR("eglGetDisplay() returned error %d", eglGetError());
        return false;
    }
    if (!eglInitialize(display, 0, 0)) {
        LOG_ERROR("eglInitialize() returned error %d", eglGetError());
        return false;
    }

    if (!eglChooseConfig(display, attribs, &config, 1, &numConfigs)) {
        LOG_ERROR("eglChooseConfig() returned error %d", eglGetError());
        destroy();
        return false;
    }

    if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format)) {
        LOG_ERROR("eglGetConfigAttrib() returned error %d", eglGetError());
        destroy();
        return false;
    }

    ANativeWindow_setBuffersGeometry(_window, 0, 0, format);

    if (!(surface = eglCreateWindowSurface(display, config, _window, 0))) {
        LOG_ERROR("eglCreateWindowSurface() returned error %d", eglGetError());
        destroy();
        return false;
    }

    if (!(context = eglCreateContext(display, config, 0, contextAttribs))) {
        LOG_ERROR("eglCreateContext() returned error %d", eglGetError());
        destroy();
        return false;
    }

    if (!eglMakeCurrent(display, surface, surface, context)) {
        LOG_ERROR("eglMakeCurrent() returned error %d", eglGetError());
        destroy();
        return false;
    }

    if (!eglQuerySurface(display, surface, EGL_WIDTH, &width)
            || !eglQuerySurface(display, surface, EGL_HEIGHT, &height)) {
        LOG_ERROR("eglQuerySurface() returned error %d", eglGetError());
        destroy();
        return false;
    }

    LOG("display size: %d %d %.2f", width, height, _displayScale);
    _display = display;
    _surface = surface;
    _context = context;
    _width = width;
    _height = height;

    _mapController = new MapController;
    _mapController->display->camera->setDisplaySize(width, height);

    _mapController->display->setDisplayScale(_displayScale);

    _mapController->data->updateDisplay(_mapController->display);

    _mapController->display->camera->setAllowIdleAnimation(true);

    return true;
}

void Renderer::destroy() {
    LOG_INFO("Destroying context");

    delete _mapController;
    _mapController = NULL;

    eglMakeCurrent(_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    eglDestroyContext(_display, _context);
    eglDestroySurface(_display, _surface);
    eglTerminate(_display);

    _display = EGL_NO_DISPLAY;
    _surface = EGL_NO_SURFACE;
    _context = EGL_NO_CONTEXT;
    _width = 0;
    _height = 0;

    return;
}

void Renderer::drawFrame() {
    _currentTimeSec = double(clock()) / double(CLOCKS_PER_SEC);
    _mapController->display->update(_currentTimeSec - _initialTimeSec);
    _mapController->display->draw();
}

void* Renderer::threadStartCallback(void *myself) {
    Renderer *renderer = (Renderer*) myself;

    renderer->renderLoop();
    pthread_exit(0);

    return 0;
}

void cameraMoveFinishedCallback(void) {

}
<|endoftext|>


<commit_before>#include "chainerx/routines/linalg.h"

#include <algorithm>
#include <cassert>
#include <cstdint>
#include <utility>
#include <vector>

#include "chainerx/array.h"
#include "chainerx/axes.h"
#include "chainerx/backprop_mode.h"
#include "chainerx/backward_builder.h"
#include "chainerx/backward_context.h"
#include "chainerx/dtype.h"
#include "chainerx/error.h"
#include "chainerx/graph.h"
#include "chainerx/routines/creation.h"
#include "chainerx/routines/type_util.h"
#include "chainerx/shape.h"

namespace chainerx {

Array Dot(const Array& a, const Array& b) {
    Dtype out_dtype = ResultType(a, b);

    if (a.ndim() == 0 || b.ndim() == 0) {
        // TODO(hvy): Avoid unnecessary cast here when multiplication supports mixed dtypes.
        const Array& a_cast = a.dtype() == out_dtype ? a : a.AsType(out_dtype);
        const Array& b_cast = b.dtype() == out_dtype ? b : b.AsType(out_dtype);
        return a_cast * b_cast;
    }

    // TODO(beam2d): dtype conversion
    CheckEqual(a.dtype(), b.dtype());

    Array modified_b{};

    Shape out_shape{};
    std::copy(a.shape().begin(), a.shape().end() - 1, std::back_inserter(out_shape));

    if (b.ndim() > 2) {
        std::vector<int> b_transpose_axes{};
        b_transpose_axes.reserve(b.ndim());
        std::vector<int> axes_index(b.ndim());
        std::iota(axes_index.begin(), axes_index.end(), 0);
        std::copy(axes_index.begin(), axes_index.end() - 2, std::back_inserter(b_transpose_axes));
        std::reverse_copy(axes_index.end() - 2, axes_index.end(), std::back_inserter(b_transpose_axes));

        Axes axes(b_transpose_axes.begin(), b_transpose_axes.end());
        modified_b = b.Transpose(axes);
        std::copy(modified_b.shape().begin(), modified_b.shape().end() - 1, std::back_inserter(out_shape));

        modified_b = modified_b.Reshape({-1, modified_b.shape().back()});
        modified_b = modified_b.Transpose();
    } else {
        std::copy(b.shape().begin() + 1, b.shape().end(), std::back_inserter(out_shape));
        modified_b = b;
    }

    int64_t k = a.shape()[a.ndim() - 1];
    if (modified_b.shape()[0] != k) {
        throw DimensionError{"Axis dimension mismatch"};
    }
    if (k == 0) {
        return Zeros(out_shape, out_dtype, a.device());
    }

    // Make each operand a matrix
    int64_t m = a.GetTotalSize() / k;
    int64_t n = b.GetTotalSize() / k;
    Array a_matrix = a.Reshape({m, k});
    Array b_matrix = modified_b.Reshape({k, n});

    // Matrix-matrix product
    Array out_matrix = Empty({m, n}, out_dtype, a.device());
    {
        NoBackpropModeScope scope{};
        a.device().Dot(a_matrix, b_matrix, out_matrix);
    }

    {
        BackwardBuilder bb{"dot", {a_matrix, b_matrix}, out_matrix};
        if (BackwardBuilder::Target bt = bb.CreateTarget(0)) {
            bt.Define([b_matrix_tok = bb.RetainInput(1), a_dtype = a.dtype()](BackwardContext& bctx) {
                const Array& b_matrix = bctx.GetRetainedInput(b_matrix_tok);
                const Array& gout = *bctx.output_grad();
                Array ga = Dot(gout, b_matrix.Transpose());
                if (ga.dtype() == a_dtype) {
                    bctx.input_grad() = std::move(ga);
                } else {
                    bctx.input_grad() = ga.AsType(a_dtype);
                }
            });
        }
        if (BackwardBuilder::Target bt = bb.CreateTarget(1)) {
            bt.Define([a_matrix_tok = bb.RetainInput(0), b_dtype = b.dtype()](BackwardContext& bctx) {
                const Array& a_matrix = bctx.GetRetainedInput(a_matrix_tok);
                const Array& gout = *bctx.output_grad();
                Array gb = Dot(a_matrix.Transpose(), gout);
                if (gb.dtype() == b_dtype) {
                    bctx.input_grad() = std::move(gb);
                } else {
                    bctx.input_grad() = gb.AsType(b_dtype);
                }
            });
        }
        bb.Finalize();
    }

return out_matrix.Reshape(out_shape);
}

}  // namespace chainerx
<commit_msg>done syncing<commit_after>#include "chainerx/routines/linalg.h"

#include <algorithm>
#include <cassert>
#include <cstdint>
#include <utility>
#include <vector>

#include "chainerx/array.h"
#include "chainerx/axes.h"
#include "chainerx/backprop_mode.h"
#include "chainerx/backward_builder.h"
#include "chainerx/backward_context.h"
#include "chainerx/dtype.h"
#include "chainerx/error.h"
#include "chainerx/graph.h"
#include "chainerx/routines/creation.h"
#include "chainerx/routines/type_util.h"
#include "chainerx/shape.h"

namespace chainerx {

Array Dot(const Array& a, const Array& b) {
    Dtype out_dtype = ResultType(a, b);

    if (a.ndim() == 0 || b.ndim() == 0) {
        // TODO(hvy): Avoid unnecessary cast here when multiplication supports mixed dtypes.
        const Array& a_cast = a.dtype() == out_dtype ? a : a.AsType(out_dtype);
        const Array& b_cast = b.dtype() == out_dtype ? b : b.AsType(out_dtype);
        return a_cast * b_cast;
    }

    Array modified_b{};

    Shape out_shape{};
    std::copy(a.shape().begin(), a.shape().end() - 1, std::back_inserter(out_shape));

    if (b.ndim() > 2) {
        std::vector<int> b_transpose_axes{};
        b_transpose_axes.reserve(b.ndim());
        std::vector<int> axes_index(b.ndim());
        std::iota(axes_index.begin(), axes_index.end(), 0);
        std::copy(axes_index.begin(), axes_index.end() - 2, std::back_inserter(b_transpose_axes));
        std::reverse_copy(axes_index.end() - 2, axes_index.end(), std::back_inserter(b_transpose_axes));

        Axes axes(b_transpose_axes.begin(), b_transpose_axes.end());
        modified_b = b.Transpose(axes);
        std::copy(modified_b.shape().begin(), modified_b.shape().end() - 1, std::back_inserter(out_shape));

        modified_b = modified_b.Reshape({-1, modified_b.shape().back()});
        modified_b = modified_b.Transpose();
    } else {
        std::copy(b.shape().begin() + 1, b.shape().end(), std::back_inserter(out_shape));
        modified_b = b;
    }

    int64_t k = a.shape()[a.ndim() - 1];
    if (modified_b.shape()[0] != k) {
        throw DimensionError{"Axis dimension mismatch"};
    }
    if (k == 0) {
        return Zeros(out_shape, out_dtype, a.device());
    }

    // Make each operand a matrix
    int64_t m = a.GetTotalSize() / k;
    int64_t n = b.GetTotalSize() / k;
    Array a_matrix = a.Reshape({m, k});
    Array b_matrix = modified_b.Reshape({k, n});

    // Matrix-matrix product
    Array out_matrix = Empty({m, n}, out_dtype, a.device());
    {
        NoBackpropModeScope scope{};
        a.device().Dot(a_matrix, b_matrix, out_matrix);
    }

    {
        BackwardBuilder bb{"dot", {a_matrix, b_matrix}, out_matrix};
        if (BackwardBuilder::Target bt = bb.CreateTarget(0)) {
            bt.Define([b_matrix_tok = bb.RetainInput(1), a_dtype = a.dtype()](BackwardContext& bctx) {
                const Array& b_matrix = bctx.GetRetainedInput(b_matrix_tok);
                const Array& gout = *bctx.output_grad();
                Array ga = Dot(gout, b_matrix.Transpose());
                if (ga.dtype() == a_dtype) {
                    bctx.input_grad() = std::move(ga);
                } else {
                    bctx.input_grad() = ga.AsType(a_dtype);
                }
            });
        }
        if (BackwardBuilder::Target bt = bb.CreateTarget(1)) {
            bt.Define([a_matrix_tok = bb.RetainInput(0), b_dtype = b.dtype()](BackwardContext& bctx) {
                const Array& a_matrix = bctx.GetRetainedInput(a_matrix_tok);
                const Array& gout = *bctx.output_grad();
                Array gb = Dot(a_matrix.Transpose(), gout);
                if (gb.dtype() == b_dtype) {
                    bctx.input_grad() = std::move(gb);
                } else {
                    bctx.input_grad() = gb.AsType(b_dtype);
                }
            });
        }
        bb.Finalize();
    }

return out_matrix.Reshape(out_shape);
}

}  // namespace chainerx
<|endoftext|>


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

#include "base/basictypes.h"
#include "base/file_path.h"
#include "build/build_config.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"

class DefaultPluginUITest : public UITest {
 public:
  DefaultPluginUITest() {
    dom_automation_enabled_ = true;
  }
};

TEST_F(DefaultPluginUITest, DefaultPluginLoadTest) {
  // Open page with default plugin.
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("default_plugin.html");
  NavigateToURL(net::FilePathToFileURL(test_file));

  // Check that the default plugin was loaded. It executes a bit of javascript
  // in the HTML file which replaces the innerHTML of div |result| with "DONE".
  scoped_refptr<TabProxy> tab(GetActiveTab());
  std::wstring out;
  ASSERT_TRUE(tab->ExecuteAndExtractString(L"",
      L"domAutomationController.send("
      L"document.getElementById('result').innerHTML)", &out));
  ASSERT_EQ(L"DONE", out);
}
<commit_msg>Disable failing test DefaultPluginUITest.DefaultPluginLoadTest.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/basictypes.h"
#include "base/file_path.h"
#include "build/build_config.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/ui/ui_test.h"
#include "net/base/net_util.h"

class DefaultPluginUITest : public UITest {
 public:
  DefaultPluginUITest() {
    dom_automation_enabled_ = true;
  }
};

// Failing consistently: crbug/46662
TEST_F(DefaultPluginUITest, DISABLED_DefaultPluginLoadTest) {
  // Open page with default plugin.
  FilePath test_file(test_data_directory_);
  test_file = test_file.AppendASCII("default_plugin.html");
  NavigateToURL(net::FilePathToFileURL(test_file));

  // Check that the default plugin was loaded. It executes a bit of javascript
  // in the HTML file which replaces the innerHTML of div |result| with "DONE".
  scoped_refptr<TabProxy> tab(GetActiveTab());
  std::wstring out;
  ASSERT_TRUE(tab->ExecuteAndExtractString(L"",
      L"domAutomationController.send("
      L"document.getElementById('result').innerHTML)", &out));
  ASSERT_EQ(L"DONE", out);
}
<|endoftext|>


<commit_before>// @(#)root/hist:$Id$
// Author: Olivier Couet 13/07/09

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TGraph.h"
#include "TArrow.h"
#include "TPolyLine.h"
#include "TGraphEdge.h"
#include "TGraphNode.h"

#include <gvc.h>

ClassImp(TGraphEdge)

////////////////////////////////////////////////////////////////////////////////

/** \class TGraphEdge
TGraphEdge is an edge object connecting two nodes which can be added in a
TGraphStruct.
End_Html
*/

////////////////////////////////////////////////////////////////////////////////
/// Graph Edge default constructor.

TGraphEdge::TGraphEdge(): TObject(), TAttLine()
{
   fNode1  = 0;
   fNode2  = 0;
   fGVEdge = 0;
   fX      = 0;
   fY      = 0;
   fN      = 0;
   fArrX   = 0;
   fArrY   = 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Graph Edge normal constructor.

TGraphEdge::TGraphEdge(TGraphNode *n1, TGraphNode *n2)
           :TObject(), TAttLine()
{
   fNode1  = n1;
   fNode2  = n2;
   fGVEdge = 0;
   fX      = 0;
   fY      = 0;
   fN      = 0;
   fArrX   = 0;
   fArrY   = 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Graph Edge default destructor.

TGraphEdge::~TGraphEdge()
{
   if (fNode1) delete fNode1;
   if (fNode2) delete fNode2;
   if (fX) delete [] fX; fX = 0;
   if (fY) delete [] fY; fY = 0;
   if (fN) delete [] fN; fN = 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Create the GraphViz edge into the GraphViz data structure gv.

void TGraphEdge::CreateGVEdge(GVizAgraph_t *gv)
{
   if (gv) {
      Agnode_t *n1 = (Agnode_t*)fNode1->GetGVNode();
      Agnode_t *n2 = (Agnode_t*)fNode2->GetGVNode();
#ifdef WITH_CGRAPH
      fGVEdge = (GVizAgedge_t*)agedge((Agraph_t *)gv, n1, n2, NULL, 1);
#else
      fGVEdge = (GVizAgedge_t*)agedge((Agraph_t *)gv, n1, n2);
#endif
   } else {
      Error("CreateGVEdge","Invalid graphviz graph");
   }
}

////////////////////////////////////////////////////////////////////////////////
/// Compute distance from point px,py to an edge.

Int_t TGraphEdge::DistancetoPrimitive(Int_t px, Int_t py)
{
   Int_t i,n,a,dist=999;

   TPolyLine *polyline;
   a = 0;

   for (i=1; i<=fN[0]; i++) {
      n = fN[i];
      polyline = new TPolyLine(n, &fX[a], &fY[a], "L");
      dist = polyline->DistancetoPrimitive(px, py);
      a = a+n;
   }

   return dist;
}

////////////////////////////////////////////////////////////////////////////////
/// Execute action corresponding to one event.

void TGraphEdge::ExecuteEvent(Int_t event, Int_t px, Int_t py)
{
   Int_t i,n,a;

   TPolyLine *polyline;
   a = 0;

   for (i=1; i<=fN[0]; i++) {
      n = fN[i];
      polyline = new TPolyLine(n, &fX[a], &fY[a], "L");
      polyline->ExecuteEvent(event, px, py);
      a = a+n;
   }
}

////////////////////////////////////////////////////////////////////////////////
/// Layout this edge in the GraphViz space. This is done after gvLayout
/// has been performed.

void TGraphEdge::Layout()
{
   bezier bz;
   Int_t i,j;

   if (fX) delete [] fX; fX = 0;
   if (fY) delete [] fY; fY = 0;
   if (fN) delete [] fN; fN = 0;

   Int_t np = ED_spl((Agedge_t*)fGVEdge)->size;
   fN       = new Int_t[np+1];
   fN[0]    = np;
   Int_t nb = 0;

   // Compute the total size of the splines arrays
   for (i=0; i<np; i++) {
      bz      = ED_spl((Agedge_t*)fGVEdge)->list[i];
      fN[i+1] = bz.size;
      nb      = nb+fN[i+1];
   }

   // Create the vectors holding all the splines' points.
   fX = new Double_t[nb];
   fY = new Double_t[nb];

   // Fill the vectors with the splines' points.
   Int_t k=0;
   for (i=0; i<np; i++) {
      bz    = ED_spl((Agedge_t*)fGVEdge)->list[i];
      fArrX =  bz.ep.x;
      fArrY =  bz.ep.y;
      for (j=0; j<fN[i+1]; j++) {
         fX[k] = bz.list[j].x;
         fY[k] = bz.list[j].y;
         k++;
      }
   }
}

////////////////////////////////////////////////////////////////////////////////
/// Paint this edge with its current attributes.

void TGraphEdge::Paint(Option_t *)
{
   Int_t i,n,a;

   TArrow arrow;
   TGraph graph;

   graph.SetLineColor(GetLineColor());
   graph.SetLineStyle(GetLineStyle());
   graph.SetLineWidth(GetLineWidth());
   arrow.SetAngle(38);
   arrow.SetFillColor(GetLineColor());
   arrow.SetLineColor(GetLineColor());

   a = 0;

   for (i=1; i<=fN[0]; i++) {

      // Draw the edge body
      n = fN[i];
      graph.PaintGraph(n, &fX[a], &fY[a], "L");

      // Draw the edge arrow
      arrow.PaintArrow(fX[a+n-1], fY[a+n-1], fArrX, fArrY, 0.03, "|>");

      a = a+n;
   }
}

////////////////////////////////////////////////////////////////////////////////
/// Save primitive as a C++ statement(s) on output stream out

void TGraphEdge::SavePrimitive(std::ostream &, Option_t *)
{
}

////////////////////////////////////////////////////////////////////////////////
/// Save attributes as a C++ statement(s) on output stream out
/// called by TGraphStruct::SavePrimitive.

void TGraphEdge::SaveAttributes(std::ostream &out, const char* name)
{
   SaveLineAttributes(out,name,1,1,1);
}

////////////////////////////////////////////////////////////////////////////////

void TGraphEdge::Streamer(TBuffer &/*b*/)
{
}
<commit_msg>Fix typo<commit_after>// @(#)root/hist:$Id$
// Author: Olivier Couet 13/07/09

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TGraph.h"
#include "TArrow.h"
#include "TPolyLine.h"
#include "TGraphEdge.h"
#include "TGraphNode.h"

#include <gvc.h>

ClassImp(TGraphEdge)

/** \class TGraphEdge
TGraphEdge is an edge object connecting two nodes which can be added in a
TGraphStruct.
*/

////////////////////////////////////////////////////////////////////////////////
/// Graph Edge default constructor.

TGraphEdge::TGraphEdge(): TObject(), TAttLine()
{
   fNode1  = 0;
   fNode2  = 0;
   fGVEdge = 0;
   fX      = 0;
   fY      = 0;
   fN      = 0;
   fArrX   = 0;
   fArrY   = 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Graph Edge normal constructor.

TGraphEdge::TGraphEdge(TGraphNode *n1, TGraphNode *n2)
           :TObject(), TAttLine()
{
   fNode1  = n1;
   fNode2  = n2;
   fGVEdge = 0;
   fX      = 0;
   fY      = 0;
   fN      = 0;
   fArrX   = 0;
   fArrY   = 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Graph Edge default destructor.

TGraphEdge::~TGraphEdge()
{
   if (fNode1) delete fNode1;
   if (fNode2) delete fNode2;
   if (fX) delete [] fX; fX = 0;
   if (fY) delete [] fY; fY = 0;
   if (fN) delete [] fN; fN = 0;
}

////////////////////////////////////////////////////////////////////////////////
/// Create the GraphViz edge into the GraphViz data structure gv.

void TGraphEdge::CreateGVEdge(GVizAgraph_t *gv)
{
   if (gv) {
      Agnode_t *n1 = (Agnode_t*)fNode1->GetGVNode();
      Agnode_t *n2 = (Agnode_t*)fNode2->GetGVNode();
#ifdef WITH_CGRAPH
      fGVEdge = (GVizAgedge_t*)agedge((Agraph_t *)gv, n1, n2, NULL, 1);
#else
      fGVEdge = (GVizAgedge_t*)agedge((Agraph_t *)gv, n1, n2);
#endif
   } else {
      Error("CreateGVEdge","Invalid graphviz graph");
   }
}

////////////////////////////////////////////////////////////////////////////////
/// Compute distance from point px,py to an edge.

Int_t TGraphEdge::DistancetoPrimitive(Int_t px, Int_t py)
{
   Int_t i,n,a,dist=999;

   TPolyLine *polyline;
   a = 0;

   for (i=1; i<=fN[0]; i++) {
      n = fN[i];
      polyline = new TPolyLine(n, &fX[a], &fY[a], "L");
      dist = polyline->DistancetoPrimitive(px, py);
      a = a+n;
   }

   return dist;
}

////////////////////////////////////////////////////////////////////////////////
/// Execute action corresponding to one event.

void TGraphEdge::ExecuteEvent(Int_t event, Int_t px, Int_t py)
{
   Int_t i,n,a;

   TPolyLine *polyline;
   a = 0;

   for (i=1; i<=fN[0]; i++) {
      n = fN[i];
      polyline = new TPolyLine(n, &fX[a], &fY[a], "L");
      polyline->ExecuteEvent(event, px, py);
      a = a+n;
   }
}

////////////////////////////////////////////////////////////////////////////////
/// Layout this edge in the GraphViz space. This is done after gvLayout
/// has been performed.

void TGraphEdge::Layout()
{
   bezier bz;
   Int_t i,j;

   if (fX) delete [] fX; fX = 0;
   if (fY) delete [] fY; fY = 0;
   if (fN) delete [] fN; fN = 0;

   Int_t np = ED_spl((Agedge_t*)fGVEdge)->size;
   fN       = new Int_t[np+1];
   fN[0]    = np;
   Int_t nb = 0;

   // Compute the total size of the splines arrays
   for (i=0; i<np; i++) {
      bz      = ED_spl((Agedge_t*)fGVEdge)->list[i];
      fN[i+1] = bz.size;
      nb      = nb+fN[i+1];
   }

   // Create the vectors holding all the splines' points.
   fX = new Double_t[nb];
   fY = new Double_t[nb];

   // Fill the vectors with the splines' points.
   Int_t k=0;
   for (i=0; i<np; i++) {
      bz    = ED_spl((Agedge_t*)fGVEdge)->list[i];
      fArrX =  bz.ep.x;
      fArrY =  bz.ep.y;
      for (j=0; j<fN[i+1]; j++) {
         fX[k] = bz.list[j].x;
         fY[k] = bz.list[j].y;
         k++;
      }
   }
}

////////////////////////////////////////////////////////////////////////////////
/// Paint this edge with its current attributes.

void TGraphEdge::Paint(Option_t *)
{
   Int_t i,n,a;

   TArrow arrow;
   TGraph graph;

   graph.SetLineColor(GetLineColor());
   graph.SetLineStyle(GetLineStyle());
   graph.SetLineWidth(GetLineWidth());
   arrow.SetAngle(38);
   arrow.SetFillColor(GetLineColor());
   arrow.SetLineColor(GetLineColor());

   a = 0;

   for (i=1; i<=fN[0]; i++) {

      // Draw the edge body
      n = fN[i];
      graph.PaintGraph(n, &fX[a], &fY[a], "L");

      // Draw the edge arrow
      arrow.PaintArrow(fX[a+n-1], fY[a+n-1], fArrX, fArrY, 0.03, "|>");

      a = a+n;
   }
}

////////////////////////////////////////////////////////////////////////////////
/// Save primitive as a C++ statement(s) on output stream out

void TGraphEdge::SavePrimitive(std::ostream &, Option_t *)
{
}

////////////////////////////////////////////////////////////////////////////////
/// Save attributes as a C++ statement(s) on output stream out
/// called by TGraphStruct::SavePrimitive.

void TGraphEdge::SaveAttributes(std::ostream &out, const char* name)
{
   SaveLineAttributes(out,name,1,1,1);
}

////////////////////////////////////////////////////////////////////////////////

void TGraphEdge::Streamer(TBuffer &/*b*/)
{
}
<|endoftext|>


<commit_before>#include "argumentlist.h"

#include "../testutil.h"

#include <cstring>
#include <iostream>

using namespace std;

void test_stringValidation()
{
    {
        cstring emptyWithNull("");
        cstring emptyWithoutNull;

        TEST(!ArgumentList::isStringValid(emptyWithoutNull));
        TEST(ArgumentList::isStringValid(emptyWithNull));

        TEST(!ArgumentList::isObjectPathValid(emptyWithoutNull));
        TEST(!ArgumentList::isObjectPathValid(emptyWithNull));

        TEST(ArgumentList::isSignatureValid(emptyWithNull));
        TEST(!ArgumentList::isSignatureValid(emptyWithoutNull));
        TEST(ArgumentList::isSignatureValid(emptyWithNull, ArgumentList::VariantSignature));
        TEST(!ArgumentList::isSignatureValid(emptyWithoutNull, ArgumentList::VariantSignature));
    }
    {
        cstring trivial("i");
        TEST(ArgumentList::isSignatureValid(trivial));
        TEST(ArgumentList::isSignatureValid(trivial, ArgumentList::VariantSignature));
    }
    {
        cstring list("iqb");
        TEST(ArgumentList::isSignatureValid(list));
        TEST(!ArgumentList::isSignatureValid(list, ArgumentList::VariantSignature));
        cstring list2("aii");
        TEST(ArgumentList::isSignatureValid(list2));
        TEST(!ArgumentList::isSignatureValid(list2, ArgumentList::VariantSignature));
    }
    {
        cstring simpleArray("ai");
        TEST(ArgumentList::isSignatureValid(simpleArray));
        TEST(ArgumentList::isSignatureValid(simpleArray, ArgumentList::VariantSignature));
    }
    {
        cstring messyArray("a(iaia{ia{iv}})");
        TEST(ArgumentList::isSignatureValid(messyArray));
        TEST(ArgumentList::isSignatureValid(messyArray, ArgumentList::VariantSignature));
    }
    {
        cstring dictFail("a{vi}");
        TEST(!ArgumentList::isSignatureValid(dictFail));
        TEST(!ArgumentList::isSignatureValid(dictFail, ArgumentList::VariantSignature));
    }
    {
        cstring emptyStruct("()");
        TEST(!ArgumentList::isSignatureValid(emptyStruct));
        TEST(!ArgumentList::isSignatureValid(emptyStruct, ArgumentList::VariantSignature));
        cstring emptyStruct2("(())");
        TEST(!ArgumentList::isSignatureValid(emptyStruct2));
        TEST(!ArgumentList::isSignatureValid(emptyStruct2, ArgumentList::VariantSignature));
        cstring miniStruct("(t)");
        TEST(ArgumentList::isSignatureValid(miniStruct));
        TEST(ArgumentList::isSignatureValid(miniStruct, ArgumentList::VariantSignature));
    }
    {
        cstring nullStr;
        cstring emptyStr("");
        TEST(!ArgumentList::isObjectPathValid(nullStr));
        TEST(!ArgumentList::isObjectPathValid(emptyStr));
        TEST(ArgumentList::isObjectPathValid(cstring("/")));
        TEST(!ArgumentList::isObjectPathValid(cstring("/abc/")));
        TEST(ArgumentList::isObjectPathValid(cstring("/abc")));
        TEST(ArgumentList::isObjectPathValid(cstring("/abc/def")));
        TEST(!ArgumentList::isObjectPathValid(cstring("/abc&def")));
        TEST(!ArgumentList::isObjectPathValid(cstring("/abc//def")));
        TEST(ArgumentList::isObjectPathValid(cstring("/aZ/0123_zAZa9_/_")));
    }

    // TODO test nesting limits in signatures (might be best to generate strings)
}

void test_roundtrip()
{
    cstring signature(""); // TODO
    array data; // TODO

    ArgumentList arg(signature, data);
    ArgumentList::ReadCursor reader = arg.beginRead();
    {
        ArgumentList::ReadCursor reader2 = arg.beginRead();
        TEST(reader2.isValid());
    }

    ArgumentList copy;
    ArgumentList::WriteCursor writer = copy.beginWrite();
    {
        ArgumentList::WriteCursor writer2 = copy.beginWrite();
        TEST(!writer2.isValid());
    }
    {
        ArgumentList::ReadCursor reader3 = copy.beginRead();
        TEST(!reader3.isValid());
    }

    bool isDone = false;
    while (!isDone) {
        TEST(writer.state() != ArgumentList::InvalidData);
        cerr << "Reader state: " << reader.state() << endl;

        switch(reader.state()) {
        case ArgumentList::Finished:
            writer.finish();
            isDone = true;
            break;
        case ArgumentList::NeedMoreData:
            TEST(false);
            break;
        case ArgumentList::BeginStruct:
            reader.beginStruct();
            writer.beginStruct();
            break;
        case ArgumentList::EndStruct:
            reader.endStruct();
            writer.endStruct();
            break;
        case ArgumentList::BeginVariant:
            reader.beginVariant();
            writer.beginVariant();
            break;
        case ArgumentList::EndVariant:
            reader.endVariant();
            writer.endVariant();
            break;
        case ArgumentList::BeginArray: {
            bool isEmpty;
            reader.beginArray(&isEmpty);
            writer.beginArray(isEmpty);
            break; }
        case ArgumentList::NextArrayEntry:
            if (reader.nextArrayEntry()) {
                writer.nextArrayEntry();
            } else {
                writer.endArray();
            }
            break;
        case ArgumentList::EndArray:
            reader.endArray();
            // writer.endArray(); // already done when reader.nextArrayEntry() returns false
            break;
        case ArgumentList::BeginDict: {
            bool isEmpty;
            reader.beginDict(&isEmpty);
            writer.beginDict(isEmpty);
            break; }
        case ArgumentList::NextDictEntry:
            if (reader.nextDictEntry()) {
                writer.nextDictEntry();
            } else {
                writer.endDict();
            }
            break;
        case ArgumentList::EndDict:
            reader.endDict();
            // writer.endDict(); // already done when reader.nextDictEntry() returns false
            break;
        case ArgumentList::Byte:
            writer.writeByte(reader.readByte());
            break;
        case ArgumentList::Boolean:
            writer.writeBoolean(reader.readBoolean());
            break;
        case ArgumentList::Int16:
            writer.writeInt16(reader.readInt16());
            break;
        case ArgumentList::Uint16:
            writer.writeUint16(reader.readUint16());
            break;
        case ArgumentList::Int32:
            writer.writeInt32(reader.readInt32());
            break;
        case ArgumentList::Uint32:
            writer.writeUint32(reader.readUint32());
            break;
        case ArgumentList::Int64:
            writer.writeInt64(reader.readInt64());
            break;
        case ArgumentList::Uint64:
            writer.writeUint64(reader.readUint64());
            break;
        case ArgumentList::Double:
            writer.writeDouble(reader.readDouble());
            break;
        case ArgumentList::String:
            writer.writeString(reader.readString());
            break;
        case ArgumentList::ObjectPath:
            writer.writeObjectPath(reader.readObjectPath());
            break;
        case ArgumentList::Signature:
            writer.writeSignature(reader.readSignature());
            break;
        case ArgumentList::UnixFd:
            writer.writeUnixFd(reader.readUnixFd());
            break;
        default:
            TEST(false);
            break;
        }
    }

    writer.finish();

    // TODO compare the binary output of writer with the binary input of reader
}

int main(int argc, char *argv[])
{
    test_stringValidation();
    test_roundtrip();
}
<commit_msg>Test unbalanced struct parentheses and nesting limits.<commit_after>#include "argumentlist.h"

#include "../testutil.h"

#include <cstring>
#include <iostream>

using namespace std;

void test_stringValidation()
{
    {
        cstring emptyWithNull("");
        cstring emptyWithoutNull;

        TEST(!ArgumentList::isStringValid(emptyWithoutNull));
        TEST(ArgumentList::isStringValid(emptyWithNull));

        TEST(!ArgumentList::isObjectPathValid(emptyWithoutNull));
        TEST(!ArgumentList::isObjectPathValid(emptyWithNull));

        TEST(ArgumentList::isSignatureValid(emptyWithNull));
        TEST(!ArgumentList::isSignatureValid(emptyWithoutNull));
        TEST(ArgumentList::isSignatureValid(emptyWithNull, ArgumentList::VariantSignature));
        TEST(!ArgumentList::isSignatureValid(emptyWithoutNull, ArgumentList::VariantSignature));
    }
    {
        cstring trivial("i");
        TEST(ArgumentList::isSignatureValid(trivial));
        TEST(ArgumentList::isSignatureValid(trivial, ArgumentList::VariantSignature));
    }
    {
        cstring list("iqb");
        TEST(ArgumentList::isSignatureValid(list));
        TEST(!ArgumentList::isSignatureValid(list, ArgumentList::VariantSignature));
        cstring list2("aii");
        TEST(ArgumentList::isSignatureValid(list2));
        TEST(!ArgumentList::isSignatureValid(list2, ArgumentList::VariantSignature));
    }
    {
        cstring simpleArray("ai");
        TEST(ArgumentList::isSignatureValid(simpleArray));
        TEST(ArgumentList::isSignatureValid(simpleArray, ArgumentList::VariantSignature));
    }
    {
        cstring messyArray("a(iaia{ia{iv}})");
        TEST(ArgumentList::isSignatureValid(messyArray));
        TEST(ArgumentList::isSignatureValid(messyArray, ArgumentList::VariantSignature));
    }
    {
        cstring dictFail("a{vi}");
        TEST(!ArgumentList::isSignatureValid(dictFail));
        TEST(!ArgumentList::isSignatureValid(dictFail, ArgumentList::VariantSignature));
    }
    {
        cstring emptyStruct("()");
        TEST(!ArgumentList::isSignatureValid(emptyStruct));
        TEST(!ArgumentList::isSignatureValid(emptyStruct, ArgumentList::VariantSignature));
        cstring emptyStruct2("(())");
        TEST(!ArgumentList::isSignatureValid(emptyStruct2));
        TEST(!ArgumentList::isSignatureValid(emptyStruct2, ArgumentList::VariantSignature));
        cstring miniStruct("(t)");
        TEST(ArgumentList::isSignatureValid(miniStruct));
        TEST(ArgumentList::isSignatureValid(miniStruct, ArgumentList::VariantSignature));
        cstring badStruct("(()");
        TEST(!ArgumentList::isSignatureValid(badStruct));
        TEST(!ArgumentList::isSignatureValid(badStruct, ArgumentList::VariantSignature));
        cstring badStruct2("())");
        TEST(!ArgumentList::isSignatureValid(badStruct2));
        TEST(!ArgumentList::isSignatureValid(badStruct2, ArgumentList::VariantSignature));
    }
    {
        cstring nullStr;
        cstring emptyStr("");
        TEST(!ArgumentList::isObjectPathValid(nullStr));
        TEST(!ArgumentList::isObjectPathValid(emptyStr));
        TEST(ArgumentList::isObjectPathValid(cstring("/")));
        TEST(!ArgumentList::isObjectPathValid(cstring("/abc/")));
        TEST(ArgumentList::isObjectPathValid(cstring("/abc")));
        TEST(ArgumentList::isObjectPathValid(cstring("/abc/def")));
        TEST(!ArgumentList::isObjectPathValid(cstring("/abc&def")));
        TEST(!ArgumentList::isObjectPathValid(cstring("/abc//def")));
        TEST(ArgumentList::isObjectPathValid(cstring("/aZ/0123_zAZa9_/_")));
    }
    {
        cstring maxStruct("((((((((((((((((((((((((((((((((i"
                          "))))))))))))))))))))))))))))))))");
        TEST(ArgumentList::isSignatureValid(maxStruct));
        TEST(ArgumentList::isSignatureValid(maxStruct, ArgumentList::VariantSignature));
        cstring struct33("(((((((((((((((((((((((((((((((((i" // too much nesting by one
                         ")))))))))))))))))))))))))))))))))");

        cstring maxArray("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaai");
        TEST(ArgumentList::isSignatureValid(maxArray));
        TEST(ArgumentList::isSignatureValid(maxArray, ArgumentList::VariantSignature));
        cstring array33("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaai");
        TEST(!ArgumentList::isSignatureValid(array33));
        TEST(!ArgumentList::isSignatureValid(array33, ArgumentList::VariantSignature));
    }
}

void test_roundtrip()
{
    cstring signature(""); // TODO
    array data; // TODO

    ArgumentList arg(signature, data);
    ArgumentList::ReadCursor reader = arg.beginRead();
    {
        ArgumentList::ReadCursor reader2 = arg.beginRead();
        TEST(reader2.isValid());
    }

    ArgumentList copy;
    ArgumentList::WriteCursor writer = copy.beginWrite();
    {
        ArgumentList::WriteCursor writer2 = copy.beginWrite();
        TEST(!writer2.isValid());
    }
    {
        ArgumentList::ReadCursor reader3 = copy.beginRead();
        TEST(!reader3.isValid());
    }

    bool isDone = false;
    while (!isDone) {
        TEST(writer.state() != ArgumentList::InvalidData);
        cerr << "Reader state: " << reader.state() << endl;

        switch(reader.state()) {
        case ArgumentList::Finished:
            writer.finish();
            isDone = true;
            break;
        case ArgumentList::NeedMoreData:
            TEST(false);
            break;
        case ArgumentList::BeginStruct:
            reader.beginStruct();
            writer.beginStruct();
            break;
        case ArgumentList::EndStruct:
            reader.endStruct();
            writer.endStruct();
            break;
        case ArgumentList::BeginVariant:
            reader.beginVariant();
            writer.beginVariant();
            break;
        case ArgumentList::EndVariant:
            reader.endVariant();
            writer.endVariant();
            break;
        case ArgumentList::BeginArray: {
            bool isEmpty;
            reader.beginArray(&isEmpty);
            writer.beginArray(isEmpty);
            break; }
        case ArgumentList::NextArrayEntry:
            if (reader.nextArrayEntry()) {
                writer.nextArrayEntry();
            } else {
                writer.endArray();
            }
            break;
        case ArgumentList::EndArray:
            reader.endArray();
            // writer.endArray(); // already done when reader.nextArrayEntry() returns false
            break;
        case ArgumentList::BeginDict: {
            bool isEmpty;
            reader.beginDict(&isEmpty);
            writer.beginDict(isEmpty);
            break; }
        case ArgumentList::NextDictEntry:
            if (reader.nextDictEntry()) {
                writer.nextDictEntry();
            } else {
                writer.endDict();
            }
            break;
        case ArgumentList::EndDict:
            reader.endDict();
            // writer.endDict(); // already done when reader.nextDictEntry() returns false
            break;
        case ArgumentList::Byte:
            writer.writeByte(reader.readByte());
            break;
        case ArgumentList::Boolean:
            writer.writeBoolean(reader.readBoolean());
            break;
        case ArgumentList::Int16:
            writer.writeInt16(reader.readInt16());
            break;
        case ArgumentList::Uint16:
            writer.writeUint16(reader.readUint16());
            break;
        case ArgumentList::Int32:
            writer.writeInt32(reader.readInt32());
            break;
        case ArgumentList::Uint32:
            writer.writeUint32(reader.readUint32());
            break;
        case ArgumentList::Int64:
            writer.writeInt64(reader.readInt64());
            break;
        case ArgumentList::Uint64:
            writer.writeUint64(reader.readUint64());
            break;
        case ArgumentList::Double:
            writer.writeDouble(reader.readDouble());
            break;
        case ArgumentList::String:
            writer.writeString(reader.readString());
            break;
        case ArgumentList::ObjectPath:
            writer.writeObjectPath(reader.readObjectPath());
            break;
        case ArgumentList::Signature:
            writer.writeSignature(reader.readSignature());
            break;
        case ArgumentList::UnixFd:
            writer.writeUnixFd(reader.readUnixFd());
            break;
        default:
            TEST(false);
            break;
        }
    }

    writer.finish();

    // TODO compare the binary output of writer with the binary input of reader
}

int main(int argc, char *argv[])
{
    test_stringValidation();
    test_roundtrip();
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2018 ArangoDB GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Simon Grätzer
////////////////////////////////////////////////////////////////////////////////

#include <fuerte/fuerte.h>
#include <fuerte/loop.h>
#include <fuerte/helper.h>
#include <thread>
#include <velocypack/velocypack-aliases.h>

#include "gtest/gtest.h"
#include "authentication_test.h"
#include "connection_test.h"

// Tesuite checks the thread-safety properties of the connection
// implementations. Try to send requests on the same connection object
// concurrently

// need a new class to use test fixture
class ConcurrentConnectionF : public ConnectionTestF {

  virtual void SetUp() override {
    ConnectionTestF::SetUp();
    dropCollection("concurrent"); // ignore response
    ASSERT_EQ(createCollection("concurrent"), fu::StatusOK);
  }

  virtual void TearDown() override {
    // drop the collection
    ASSERT_EQ(dropCollection("concurrent"), fu::StatusOK);
    ConnectionTestF::TearDown();
  }
};

TEST_P(ConcurrentConnectionF, ApiVersionParallel) {
  fu::WaitGroup wg;
  std::atomic<size_t> counter(0);
  auto cb = [&](fu::Error error, std::unique_ptr<fu::Request> req, std::unique_ptr<fu::Response> res) {
    fu::WaitGroupDone done(wg);
    if (error != fu::Error::NoError) {
      ASSERT_TRUE(false) << fu::to_string(error);
    } else {
      ASSERT_EQ(res->statusCode(), fu::StatusOK);
      auto slice = res->slices().front();
      auto version = slice.get("version").copyString();
      auto server = slice.get("server").copyString();
      ASSERT_EQ(server, "arango");
      ASSERT_EQ(version[0], _major_arango_version);
      counter.fetch_add(1, std::memory_order_relaxed);
    }
  };

  std::vector<std::thread> joins;
  for (size_t t = 0; t < threads(); t++) {
    wg.add(repeat());
    joins.emplace_back([&]{
      for (size_t i = 0; i < repeat(); i++) {
        auto request = fu::createRequest(fu::RestVerb::Get, "/_api/version");
        while (_connection->requestsLeft() >= 1000) {
          std::this_thread::yield();
        }
        _connection->sendRequest(std::move(request), cb);
      }
    });
  }
  ASSERT_TRUE(wg.wait_for(std::chrono::seconds(300))); // wait for all threads to return

  // wait for all threads to end
  for (std::thread& t : joins) {
    t.join();
  }

  ASSERT_EQ(repeat() * threads(), counter);
}

TEST_P(ConcurrentConnectionF, CreateDocumentsParallel){

  std::atomic<size_t> counter(0);
  fu::WaitGroup wg;
  auto cb = [&](fu::Error error, std::unique_ptr<fu::Request> req,
                std::unique_ptr<fu::Response> res) {
    counter.fetch_add(1, std::memory_order_relaxed);
    fu::WaitGroupDone done(wg);
    if (error != fu::Error::NoError) {
      ASSERT_TRUE(false) << fu::to_string(error);
    } else {
      ASSERT_EQ(res->statusCode(), fu::StatusAccepted);
      auto slice = res->slices().front();
      ASSERT_TRUE(slice.get("_id").isString());
      ASSERT_TRUE(slice.get("_key").isString());
      ASSERT_TRUE(slice.get("_rev").isString());
    }
  };

  VPackBuilder builder;
  builder.openObject();
  builder.add("hello", VPackValue("world"));
  builder.close();

  std::vector<std::thread> joins;
  for (size_t t = 0; t < threads(); t++) {
    wg.add(repeat());
    joins.emplace_back([&]{
      for (size_t i = 0; i < repeat(); i++) {
        auto request = fu::createRequest(fu::RestVerb::Post, "/_api/document/concurrent");
        request->addVPack(builder.slice());
        while (_connection->requestsLeft() >= 1000) {
          std::this_thread::yield();
        }
        _connection->sendRequest(std::move(request), cb);
      }
    });
  }
  ASSERT_TRUE(wg.wait_for(std::chrono::seconds(60))); // wait for all threads to return

  // wait for all threads to end
  for (std::thread& t : joins) {
    t.join();
  }

  ASSERT_EQ(repeat() * threads(), counter);
}

static const ConnectionTestParams params[] = {
  {._url= "http://127.0.0.1:8529", ._threads=2, ._repeat=1000},
  {._url= "vst://127.0.0.1:8529", ._threads=2, ._repeat=1000},
  {._url= "http://127.0.0.1:8529", ._threads=4, ._repeat=10000},
  {._url= "vst://127.0.0.1:8529", ._threads=4, ._repeat=10000},
};

INSTANTIATE_TEST_CASE_P(ConcurrentRequestsTests, ConcurrentConnectionF,
  ::testing::ValuesIn(params));

<commit_msg>increase test timeout<commit_after>////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2018 ArangoDB GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Simon Grätzer
////////////////////////////////////////////////////////////////////////////////

#include <fuerte/fuerte.h>
#include <fuerte/loop.h>
#include <fuerte/helper.h>
#include <thread>
#include <velocypack/velocypack-aliases.h>

#include "gtest/gtest.h"
#include "authentication_test.h"
#include "connection_test.h"

// Tesuite checks the thread-safety properties of the connection
// implementations. Try to send requests on the same connection object
// concurrently

// need a new class to use test fixture
class ConcurrentConnectionF : public ConnectionTestF {

  virtual void SetUp() override {
    ConnectionTestF::SetUp();
    dropCollection("concurrent"); // ignore response
    ASSERT_EQ(createCollection("concurrent"), fu::StatusOK);
  }

  virtual void TearDown() override {
    // drop the collection
    ASSERT_EQ(dropCollection("concurrent"), fu::StatusOK);
    ConnectionTestF::TearDown();
  }
};

TEST_P(ConcurrentConnectionF, ApiVersionParallel) {
  fu::WaitGroup wg;
  std::atomic<size_t> counter(0);
  auto cb = [&](fu::Error error, std::unique_ptr<fu::Request> req, std::unique_ptr<fu::Response> res) {
    fu::WaitGroupDone done(wg);
    if (error != fu::Error::NoError) {
      ASSERT_TRUE(false) << fu::to_string(error);
    } else {
      ASSERT_EQ(res->statusCode(), fu::StatusOK);
      auto slice = res->slices().front();
      auto version = slice.get("version").copyString();
      auto server = slice.get("server").copyString();
      ASSERT_EQ(server, "arango");
      ASSERT_EQ(version[0], _major_arango_version);
      counter.fetch_add(1, std::memory_order_relaxed);
    }
  };

  std::vector<std::thread> joins;
  for (size_t t = 0; t < threads(); t++) {
    wg.add(repeat());
    joins.emplace_back([&]{
      for (size_t i = 0; i < repeat(); i++) {
        auto request = fu::createRequest(fu::RestVerb::Get, "/_api/version");
        while (_connection->requestsLeft() >= 1000) {
          std::this_thread::yield();
        }
        _connection->sendRequest(std::move(request), cb);
      }
    });
  }
  ASSERT_TRUE(wg.wait_for(std::chrono::seconds(300))); // wait for all threads to return

  // wait for all threads to end
  for (std::thread& t : joins) {
    t.join();
  }

  ASSERT_EQ(repeat() * threads(), counter);
}

TEST_P(ConcurrentConnectionF, CreateDocumentsParallel){

  std::atomic<size_t> counter(0);
  fu::WaitGroup wg;
  auto cb = [&](fu::Error error, std::unique_ptr<fu::Request> req,
                std::unique_ptr<fu::Response> res) {
    counter.fetch_add(1, std::memory_order_relaxed);
    fu::WaitGroupDone done(wg);
    if (error != fu::Error::NoError) {
      ASSERT_TRUE(false) << fu::to_string(error);
    } else {
      ASSERT_EQ(res->statusCode(), fu::StatusAccepted);
      auto slice = res->slices().front();
      ASSERT_TRUE(slice.get("_id").isString());
      ASSERT_TRUE(slice.get("_key").isString());
      ASSERT_TRUE(slice.get("_rev").isString());
    }
  };

  VPackBuilder builder;
  builder.openObject();
  builder.add("hello", VPackValue("world"));
  builder.close();

  std::vector<std::thread> joins;
  for (size_t t = 0; t < threads(); t++) {
    wg.add(repeat());
    joins.emplace_back([&]{
      for (size_t i = 0; i < repeat(); i++) {
        auto request = fu::createRequest(fu::RestVerb::Post, "/_api/document/concurrent");
        request->addVPack(builder.slice());
        while (_connection->requestsLeft() >= 1000) {
          std::this_thread::yield();
        }
        _connection->sendRequest(std::move(request), cb);
      }
    });
  }
  ASSERT_TRUE(wg.wait_for(std::chrono::seconds(300))); // wait for all threads to return

  // wait for all threads to end
  for (std::thread& t : joins) {
    t.join();
  }

  ASSERT_EQ(repeat() * threads(), counter);
}

static const ConnectionTestParams params[] = {
  {._url= "http://127.0.0.1:8529", ._threads=2, ._repeat=1000},
  {._url= "vst://127.0.0.1:8529", ._threads=2, ._repeat=1000},
  {._url= "http://127.0.0.1:8529", ._threads=4, ._repeat=10000},
  {._url= "vst://127.0.0.1:8529", ._threads=4, ._repeat=10000},
};

INSTANTIATE_TEST_CASE_P(ConcurrentRequestsTests, ConcurrentConnectionF,
  ::testing::ValuesIn(params));

<|endoftext|>


<commit_before><commit_msg>In the HTTP Basic Auth login prompt, show the URL in a usable way.<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "mfem.hpp"
#include "unit_tests.hpp"

#include <iostream>

using namespace mfem;

TEST_CASE("Test order of boundary integrators",
          "[BilinearForm]")
{
   // Create a simple mesh
   int dim = 2, nx = 2, ny = 2, order = 2;
   Element::Type e_type = Element::QUADRILATERAL;
   Mesh mesh = Mesh::MakeCartesian2D(nx, ny, e_type);

   H1_FECollection fec(order, dim);
   FiniteElementSpace fes(&mesh, &fec);

   SECTION("Order of restricted boundary integrators")
   {
      ConstantCoefficient one(1.0);
      ConstantCoefficient two(2.0);
      ConstantCoefficient three(3.0);
      ConstantCoefficient four(4.0);

      Array<int> bdr1(4); bdr1 = 0; bdr1[0] = 1;
      Array<int> bdr2(4); bdr2 = 0; bdr2[1] = 1;
      Array<int> bdr3(4); bdr3 = 0; bdr3[2] = 1;
      Array<int> bdr4(4); bdr4 = 0; bdr4[3] = 1;

      BilinearForm a1234(&fes);
      a1234.AddBoundaryIntegrator(new MassIntegrator(one), bdr1);
      a1234.AddBoundaryIntegrator(new MassIntegrator(two), bdr2);
      a1234.AddBoundaryIntegrator(new MassIntegrator(three), bdr3);
      a1234.AddBoundaryIntegrator(new MassIntegrator(four), bdr4);
      a1234.Assemble(0);
      a1234.Finalize(0);

      BilinearForm a4321(&fes);
      a4321.AddBoundaryIntegrator(new MassIntegrator(four), bdr4);
      a4321.AddBoundaryIntegrator(new MassIntegrator(three), bdr3);
      a4321.AddBoundaryIntegrator(new MassIntegrator(two), bdr2);
      a4321.AddBoundaryIntegrator(new MassIntegrator(one), bdr1);
      a4321.Assemble(0);
      a4321.Finalize(0);

      const SparseMatrix &A1234 = a1234.SpMat();
      const SparseMatrix &A4321 = a4321.SpMat();

      SparseMatrix *D = Add(1.0, A1234, -1.0, A4321);

      REQUIRE(D->MaxNorm() == MFEM_Approx(0.0));

      delete D;
   }
}

TEST_CASE("FormLinearSystem/SolutionScope",
          "[BilinearForm]"
          "[CUDA]")
{
   // Create a simple mesh and FE space
   int dim = 2, nx = 2, ny = 2, order = 2;
   Element::Type e_type = Element::QUADRILATERAL;
   Mesh mesh = Mesh::MakeCartesian2D(nx, ny, e_type);

   H1_FECollection fec(order, dim);
   FiniteElementSpace fes(&mesh, &fec);
   int bdr_dof;

   // Solve a PDE on the conforming mesh and FE space defined above, storing the
   // result in 'sol'.
   auto SolvePDE = [&](AssemblyLevel al, GridFunction &sol)
   {
      // Linear form: rhs
      ConstantCoefficient f(1.0);
      LinearForm b(&fes);
      b.AddDomainIntegrator(new DomainLFIntegrator(f));
      // Bilinear form: matrix
      BilinearForm a(&fes);
      a.AddDomainIntegrator(new DiffusionIntegrator);
      a.SetAssemblyLevel(al);
      a.Assemble();
      // Setup b.c.
      Array<int> ess_tdof_list;
      REQUIRE(mesh.bdr_attributes.Max() > 0);
      Array<int> bdr_attr_is_ess(mesh.bdr_attributes.Max());
      bdr_attr_is_ess = 1;
      fes.GetEssentialTrueDofs(bdr_attr_is_ess, ess_tdof_list);
      REQUIRE(ess_tdof_list.Size() > 0);
      // Setup (on host) solution initial guess satisfying the desired b.c.
      ConstantCoefficient zero(0.0);
      sol.ProjectCoefficient(zero); // performed on host
      // Setup the linear system
      Vector B, X;
      OperatorPtr A;
      const bool copy_interior = true; // interior(sol) --> interior(X)
      a.FormLinearSystem(ess_tdof_list, sol, b, A, X, B, copy_interior);
      // Solve the system
      CGSolver cg;
      cg.SetMaxIter(2000);
      cg.SetRelTol(1e-8);
      cg.SetAbsTol(0.0);
      cg.SetPrintLevel(0);
      cg.SetOperator(*A);
      cg.Mult(B, X);
      // Recover the solution
      a.RecoverFEMSolution(X, b, sol);
      // Initialize the bdr_dof to be checked
      ess_tdof_list.HostRead();
      bdr_dof = AsConst(ess_tdof_list)[0]; // here, L-dof is the same T-dof
   };

   // Legacy full assembly
   {
      GridFunction sol(&fes);
      SolvePDE(AssemblyLevel::LEGACYFULL, sol);
      // Make sure the solution is still accessible after 'X' is destoyed
      sol.HostRead();
      REQUIRE(AsConst(sol)(bdr_dof) == 0.0);
   }

   // Partial assembly
   {
      GridFunction sol(&fes);
      SolvePDE(AssemblyLevel::PARTIAL, sol);
      // Make sure the solution is still accessible after 'X' is destoyed
      sol.HostRead();
      REQUIRE(AsConst(sol)(bdr_dof) == 0.0);
   }
}
<commit_msg>Fix yet another bug in the unit test FormLinearSystem/SolutionScope: the LinearForm was not assembled.<commit_after>// Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
// LICENSE and NOTICE for details. LLNL-CODE-806117.
//
// This file is part of the MFEM library. For more information and source code
// availability visit https://mfem.org.
//
// MFEM is free software; you can redistribute it and/or modify it under the
// terms of the BSD-3 license. We welcome feedback and contributions, see file
// CONTRIBUTING.md for details.

#include "mfem.hpp"
#include "unit_tests.hpp"

#include <iostream>

using namespace mfem;

TEST_CASE("Test order of boundary integrators",
          "[BilinearForm]")
{
   // Create a simple mesh
   int dim = 2, nx = 2, ny = 2, order = 2;
   Element::Type e_type = Element::QUADRILATERAL;
   Mesh mesh = Mesh::MakeCartesian2D(nx, ny, e_type);

   H1_FECollection fec(order, dim);
   FiniteElementSpace fes(&mesh, &fec);

   SECTION("Order of restricted boundary integrators")
   {
      ConstantCoefficient one(1.0);
      ConstantCoefficient two(2.0);
      ConstantCoefficient three(3.0);
      ConstantCoefficient four(4.0);

      Array<int> bdr1(4); bdr1 = 0; bdr1[0] = 1;
      Array<int> bdr2(4); bdr2 = 0; bdr2[1] = 1;
      Array<int> bdr3(4); bdr3 = 0; bdr3[2] = 1;
      Array<int> bdr4(4); bdr4 = 0; bdr4[3] = 1;

      BilinearForm a1234(&fes);
      a1234.AddBoundaryIntegrator(new MassIntegrator(one), bdr1);
      a1234.AddBoundaryIntegrator(new MassIntegrator(two), bdr2);
      a1234.AddBoundaryIntegrator(new MassIntegrator(three), bdr3);
      a1234.AddBoundaryIntegrator(new MassIntegrator(four), bdr4);
      a1234.Assemble(0);
      a1234.Finalize(0);

      BilinearForm a4321(&fes);
      a4321.AddBoundaryIntegrator(new MassIntegrator(four), bdr4);
      a4321.AddBoundaryIntegrator(new MassIntegrator(three), bdr3);
      a4321.AddBoundaryIntegrator(new MassIntegrator(two), bdr2);
      a4321.AddBoundaryIntegrator(new MassIntegrator(one), bdr1);
      a4321.Assemble(0);
      a4321.Finalize(0);

      const SparseMatrix &A1234 = a1234.SpMat();
      const SparseMatrix &A4321 = a4321.SpMat();

      SparseMatrix *D = Add(1.0, A1234, -1.0, A4321);

      REQUIRE(D->MaxNorm() == MFEM_Approx(0.0));

      delete D;
   }
}

TEST_CASE("FormLinearSystem/SolutionScope",
          "[BilinearForm]"
          "[CUDA]")
{
   // Create a simple mesh and FE space
   int dim = 2, nx = 2, ny = 2, order = 2;
   Element::Type e_type = Element::QUADRILATERAL;
   Mesh mesh = Mesh::MakeCartesian2D(nx, ny, e_type);

   H1_FECollection fec(order, dim);
   FiniteElementSpace fes(&mesh, &fec);
   int bdr_dof;

   // Solve a PDE on the conforming mesh and FE space defined above, storing the
   // result in 'sol'.
   auto SolvePDE = [&](AssemblyLevel al, GridFunction &sol)
   {
      // Linear form: rhs
      ConstantCoefficient f(1.0);
      LinearForm b(&fes);
      b.AddDomainIntegrator(new DomainLFIntegrator(f));
      b.Assemble();
      // Bilinear form: matrix
      BilinearForm a(&fes);
      a.AddDomainIntegrator(new DiffusionIntegrator);
      a.SetAssemblyLevel(al);
      a.Assemble();
      // Setup b.c.
      Array<int> ess_tdof_list;
      REQUIRE(mesh.bdr_attributes.Max() > 0);
      Array<int> bdr_attr_is_ess(mesh.bdr_attributes.Max());
      bdr_attr_is_ess = 1;
      fes.GetEssentialTrueDofs(bdr_attr_is_ess, ess_tdof_list);
      REQUIRE(ess_tdof_list.Size() > 0);
      // Setup (on host) solution initial guess satisfying the desired b.c.
      ConstantCoefficient zero(0.0);
      sol.ProjectCoefficient(zero); // performed on host
      // Setup the linear system
      Vector B, X;
      OperatorPtr A;
      const bool copy_interior = true; // interior(sol) --> interior(X)
      a.FormLinearSystem(ess_tdof_list, sol, b, A, X, B, copy_interior);
      // Solve the system
      CGSolver cg;
      cg.SetMaxIter(2000);
      cg.SetRelTol(1e-8);
      cg.SetAbsTol(0.0);
      cg.SetPrintLevel(0);
      cg.SetOperator(*A);
      cg.Mult(B, X);
      // Recover the solution
      a.RecoverFEMSolution(X, b, sol);
      // Initialize the bdr_dof to be checked
      ess_tdof_list.HostRead();
      bdr_dof = AsConst(ess_tdof_list)[0]; // here, L-dof is the same T-dof
   };

   // Legacy full assembly
   {
      GridFunction sol(&fes);
      SolvePDE(AssemblyLevel::LEGACYFULL, sol);
      // Make sure the solution is still accessible after 'X' is destoyed
      sol.HostRead();
      REQUIRE(AsConst(sol)(bdr_dof) == 0.0);
   }

   // Partial assembly
   {
      GridFunction sol(&fes);
      SolvePDE(AssemblyLevel::PARTIAL, sol);
      // Make sure the solution is still accessible after 'X' is destoyed
      sol.HostRead();
      REQUIRE(AsConst(sol)(bdr_dof) == 0.0);
   }
}
<|endoftext|>


<commit_before>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/base/logging.h"
#include "xenia/emulator.h"
#include "xenia/hid/input.h"
#include "xenia/hid/input_system.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/util/shim_utils.h"
#include "xenia/kernel/xam/xam_private.h"
#include "xenia/xbox.h"

namespace xe {
namespace kernel {
namespace xam {

using xe::hid::X_INPUT_CAPABILITIES;
using xe::hid::X_INPUT_KEYSTROKE;
using xe::hid::X_INPUT_STATE;
using xe::hid::X_INPUT_VIBRATION;

constexpr uint32_t XINPUT_FLAG_GAMEPAD = 0x01;
constexpr uint32_t XINPUT_FLAG_ANY_USER = 1 << 30;

dword_result_t XamResetInactivity(dword_t unk) {
  // Result ignored.
  return 0;
}
DECLARE_XAM_EXPORT(XamResetInactivity, ExportTag::kInput | ExportTag::kStub);

dword_result_t XamEnableInactivityProcessing(dword_t zero, dword_t unk) {
  // Expects 0.
  return 0;
}
DECLARE_XAM_EXPORT(XamEnableInactivityProcessing,
                   ExportTag::kInput | ExportTag::kStub);

// http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.reference.xinputgetcapabilities(v=vs.85).aspx
dword_result_t XamInputGetCapabilities(dword_t user_index, dword_t flags,
                                       pointer_t<X_INPUT_CAPABILITIES> caps) {
  if (!caps) {
    return X_ERROR_BAD_ARGUMENTS;
  }

  if ((flags & 0xFF) && (flags & XINPUT_FLAG_GAMEPAD) == 0) {
    // Ignore any query for other types of devices.
    return X_ERROR_DEVICE_NOT_CONNECTED;
  }

  uint32_t actual_user_index = user_index;
  if ((actual_user_index & 0xFF) == 0xFF || (flags & XINPUT_FLAG_ANY_USER)) {
    // Always pin user to 0.
    actual_user_index = 0;
  }

  auto input_system = kernel_state()->emulator()->input_system();
  return input_system->GetCapabilities(actual_user_index, flags, caps);
}
DECLARE_XAM_EXPORT(XamInputGetCapabilities,
                   ExportTag::kInput | ExportTag::kSketchy);

dword_result_t XamInputGetCapabilitiesEx(dword_t unk, dword_t user_index,
                                         dword_t flags,
                                         pointer_t<X_INPUT_CAPABILITIES> caps) {
  if (!caps) {
    return X_ERROR_BAD_ARGUMENTS;
  }

  if ((flags & 0xFF) && (flags & XINPUT_FLAG_GAMEPAD) == 0) {
    // Ignore any query for other types of devices.
    return X_ERROR_DEVICE_NOT_CONNECTED;
  }

  uint32_t actual_user_index = user_index;
  if ((actual_user_index & 0xFF) == 0xFF || (flags & XINPUT_FLAG_ANY_USER)) {
    // Always pin user to 0.
    actual_user_index = 0;
  }

  auto input_system = kernel_state()->emulator()->input_system();
  return input_system->GetCapabilities(actual_user_index, flags, caps);
}
DECLARE_XAM_EXPORT(XamInputGetCapabilitiesEx,
                   ExportTag::kInput | ExportTag::kSketchy);

// http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.reference.xinputgetstate(v=vs.85).aspx
dword_result_t XamInputGetState(dword_t user_index, dword_t flags,
                                pointer_t<X_INPUT_STATE> input_state) {
  // Games call this with a NULL state ptr, probably as a query.

  if ((flags & 0xFF) && (flags & XINPUT_FLAG_GAMEPAD) == 0) {
    // Ignore any query for other types of devices.
    return X_ERROR_DEVICE_NOT_CONNECTED;
  }

  uint32_t actual_user_index = user_index;
  if ((actual_user_index & 0xFF) == 0xFF || (flags & XINPUT_FLAG_ANY_USER)) {
    // Always pin user to 0.
    actual_user_index = 0;
  }

  auto input_system = kernel_state()->emulator()->input_system();
  return input_system->GetState(user_index, input_state);
}
DECLARE_XAM_EXPORT(XamInputGetState,
                   ExportTag::kInput | ExportTag::kImplemented);

// http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.reference.xinputsetstate(v=vs.85).aspx
dword_result_t XamInputSetState(dword_t user_index, dword_t unk,
                                pointer_t<X_INPUT_VIBRATION> vibration) {
  if (!vibration) {
    return X_ERROR_BAD_ARGUMENTS;
  }

  uint32_t actual_user_index = user_index;
  if ((user_index & 0xFF) == 0xFF) {
    // Always pin user to 0.
    actual_user_index = 0;
  }

  auto input_system = kernel_state()->emulator()->input_system();
  return input_system->SetState(user_index, vibration);
}
DECLARE_XAM_EXPORT(XamInputSetState,
                   ExportTag::kInput | ExportTag::kImplemented);

// http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.reference.xinputgetkeystroke(v=vs.85).aspx
dword_result_t XamInputGetKeystroke(dword_t user_index, dword_t flags,
                                    pointer_t<X_INPUT_KEYSTROKE> keystroke) {
  // http://ffplay360.googlecode.com/svn/Test/Common/AtgXime.cpp
  // user index = index or XUSER_INDEX_ANY
  // flags = XINPUT_FLAG_GAMEPAD (| _ANYUSER | _ANYDEVICE)

  if (!keystroke) {
    return X_ERROR_BAD_ARGUMENTS;
  }

  if ((flags & 0xFF) && (flags & XINPUT_FLAG_GAMEPAD) == 0) {
    // Ignore any query for other types of devices.
    return X_ERROR_DEVICE_NOT_CONNECTED;
  }

  uint32_t actual_user_index = user_index;
  if ((actual_user_index & 0xFF) == 0xFF || (flags & XINPUT_FLAG_ANY_USER)) {
    // Always pin user to 0.
    actual_user_index = 0;
  }

  auto input_system = kernel_state()->emulator()->input_system();
  return input_system->GetKeystroke(user_index, flags, keystroke);
}
DECLARE_XAM_EXPORT(XamInputGetKeystroke,
                   ExportTag::kInput | ExportTag::kImplemented);

// Same as non-ex, just takes a pointer to user index.
dword_result_t XamInputGetKeystrokeEx(lpdword_t user_index_ptr, dword_t flags,
                                      pointer_t<X_INPUT_KEYSTROKE> keystroke) {
  if (!keystroke) {
    return X_ERROR_BAD_ARGUMENTS;
  }

  if ((flags & 0xFF) && (flags & XINPUT_FLAG_GAMEPAD) == 0) {
    // Ignore any query for other types of devices.
    return X_ERROR_DEVICE_NOT_CONNECTED;
  }

  uint32_t user_index = *user_index_ptr;
  if ((user_index & 0xFF) == 0xFF || (flags & XINPUT_FLAG_ANY_USER)) {
    // Always pin user to 0.
    user_index = 0;
  }

  auto input_system = kernel_state()->emulator()->input_system();
  auto result = input_system->GetKeystroke(user_index, flags, keystroke);
  if (XSUCCEEDED(result)) {
    *user_index_ptr = keystroke->user_index;
  }
  return result;
}
DECLARE_XAM_EXPORT(XamInputGetKeystrokeEx,
                   ExportTag::kInput | ExportTag::kImplemented);

dword_result_t XamUserGetDeviceContext(dword_t user_index, dword_t unk,
                                       lpdword_t out_ptr) {
  // Games check the result - usually with some masking.
  // If this function fails they assume zero, so let's fail AND
  // set zero just to be safe.
  *out_ptr = 0;
  if (!user_index || (user_index & 0xFF) == 0xFF) {
    return 0;
  } else {
    return -1;
  }
}
DECLARE_XAM_EXPORT(XamUserGetDeviceContext,
                   ExportTag::kInput | ExportTag::kStub);

void RegisterInputExports(xe::cpu::ExportResolver* export_resolver,
                          KernelState* kernel_state) {
}

}  // namespace xam
}  // namespace kernel
}  // namespace xe
<commit_msg>[Kernel] Fix return of XamUserGetDeviceContext.<commit_after>/**
 ******************************************************************************
 * Xenia : Xbox 360 Emulator Research Project                                 *
 ******************************************************************************
 * Copyright 2013 Ben Vanik. All rights reserved.                             *
 * Released under the BSD license - see LICENSE in the root for more details. *
 ******************************************************************************
 */

#include "xenia/base/logging.h"
#include "xenia/emulator.h"
#include "xenia/hid/input.h"
#include "xenia/hid/input_system.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/kernel/util/shim_utils.h"
#include "xenia/kernel/xam/xam_private.h"
#include "xenia/xbox.h"

namespace xe {
namespace kernel {
namespace xam {

using xe::hid::X_INPUT_CAPABILITIES;
using xe::hid::X_INPUT_KEYSTROKE;
using xe::hid::X_INPUT_STATE;
using xe::hid::X_INPUT_VIBRATION;

constexpr uint32_t XINPUT_FLAG_GAMEPAD = 0x01;
constexpr uint32_t XINPUT_FLAG_ANY_USER = 1 << 30;

void XamResetInactivity() {
  // Do we need to do anything?
}
DECLARE_XAM_EXPORT(XamResetInactivity, ExportTag::kInput | ExportTag::kStub);

dword_result_t XamEnableInactivityProcessing(dword_t unk, dword_t enable) {
  return X_ERROR_SUCCESS;
}
DECLARE_XAM_EXPORT(XamEnableInactivityProcessing,
                   ExportTag::kInput | ExportTag::kStub);

// http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.reference.xinputgetcapabilities(v=vs.85).aspx
dword_result_t XamInputGetCapabilities(dword_t user_index, dword_t flags,
                                       pointer_t<X_INPUT_CAPABILITIES> caps) {
  if (!caps) {
    return X_ERROR_BAD_ARGUMENTS;
  }

  if ((flags & 0xFF) && (flags & XINPUT_FLAG_GAMEPAD) == 0) {
    // Ignore any query for other types of devices.
    return X_ERROR_DEVICE_NOT_CONNECTED;
  }

  uint32_t actual_user_index = user_index;
  if ((actual_user_index & 0xFF) == 0xFF || (flags & XINPUT_FLAG_ANY_USER)) {
    // Always pin user to 0.
    actual_user_index = 0;
  }

  auto input_system = kernel_state()->emulator()->input_system();
  return input_system->GetCapabilities(actual_user_index, flags, caps);
}
DECLARE_XAM_EXPORT(XamInputGetCapabilities,
                   ExportTag::kInput | ExportTag::kSketchy);

dword_result_t XamInputGetCapabilitiesEx(dword_t unk, dword_t user_index,
                                         dword_t flags,
                                         pointer_t<X_INPUT_CAPABILITIES> caps) {
  if (!caps) {
    return X_ERROR_BAD_ARGUMENTS;
  }

  if ((flags & 0xFF) && (flags & XINPUT_FLAG_GAMEPAD) == 0) {
    // Ignore any query for other types of devices.
    return X_ERROR_DEVICE_NOT_CONNECTED;
  }

  uint32_t actual_user_index = user_index;
  if ((actual_user_index & 0xFF) == 0xFF || (flags & XINPUT_FLAG_ANY_USER)) {
    // Always pin user to 0.
    actual_user_index = 0;
  }

  auto input_system = kernel_state()->emulator()->input_system();
  return input_system->GetCapabilities(actual_user_index, flags, caps);
}
DECLARE_XAM_EXPORT(XamInputGetCapabilitiesEx,
                   ExportTag::kInput | ExportTag::kSketchy);

// http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.reference.xinputgetstate(v=vs.85).aspx
dword_result_t XamInputGetState(dword_t user_index, dword_t flags,
                                pointer_t<X_INPUT_STATE> input_state) {
  // Games call this with a NULL state ptr, probably as a query.

  if ((flags & 0xFF) && (flags & XINPUT_FLAG_GAMEPAD) == 0) {
    // Ignore any query for other types of devices.
    return X_ERROR_DEVICE_NOT_CONNECTED;
  }

  uint32_t actual_user_index = user_index;
  if ((actual_user_index & 0xFF) == 0xFF || (flags & XINPUT_FLAG_ANY_USER)) {
    // Always pin user to 0.
    actual_user_index = 0;
  }

  auto input_system = kernel_state()->emulator()->input_system();
  return input_system->GetState(user_index, input_state);
}
DECLARE_XAM_EXPORT(XamInputGetState,
                   ExportTag::kInput | ExportTag::kImplemented);

// http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.reference.xinputsetstate(v=vs.85).aspx
dword_result_t XamInputSetState(dword_t user_index, dword_t unk,
                                pointer_t<X_INPUT_VIBRATION> vibration) {
  if (!vibration) {
    return X_ERROR_BAD_ARGUMENTS;
  }

  uint32_t actual_user_index = user_index;
  if ((user_index & 0xFF) == 0xFF) {
    // Always pin user to 0.
    actual_user_index = 0;
  }

  auto input_system = kernel_state()->emulator()->input_system();
  return input_system->SetState(user_index, vibration);
}
DECLARE_XAM_EXPORT(XamInputSetState,
                   ExportTag::kInput | ExportTag::kImplemented);

// http://msdn.microsoft.com/en-us/library/windows/desktop/microsoft.directx_sdk.reference.xinputgetkeystroke(v=vs.85).aspx
dword_result_t XamInputGetKeystroke(dword_t user_index, dword_t flags,
                                    pointer_t<X_INPUT_KEYSTROKE> keystroke) {
  // http://ffplay360.googlecode.com/svn/Test/Common/AtgXime.cpp
  // user index = index or XUSER_INDEX_ANY
  // flags = XINPUT_FLAG_GAMEPAD (| _ANYUSER | _ANYDEVICE)

  if (!keystroke) {
    return X_ERROR_BAD_ARGUMENTS;
  }

  if ((flags & 0xFF) && (flags & XINPUT_FLAG_GAMEPAD) == 0) {
    // Ignore any query for other types of devices.
    return X_ERROR_DEVICE_NOT_CONNECTED;
  }

  uint32_t actual_user_index = user_index;
  if ((actual_user_index & 0xFF) == 0xFF || (flags & XINPUT_FLAG_ANY_USER)) {
    // Always pin user to 0.
    actual_user_index = 0;
  }

  auto input_system = kernel_state()->emulator()->input_system();
  return input_system->GetKeystroke(user_index, flags, keystroke);
}
DECLARE_XAM_EXPORT(XamInputGetKeystroke,
                   ExportTag::kInput | ExportTag::kImplemented);

// Same as non-ex, just takes a pointer to user index.
dword_result_t XamInputGetKeystrokeEx(lpdword_t user_index_ptr, dword_t flags,
                                      pointer_t<X_INPUT_KEYSTROKE> keystroke) {
  if (!keystroke) {
    return X_ERROR_BAD_ARGUMENTS;
  }

  if ((flags & 0xFF) && (flags & XINPUT_FLAG_GAMEPAD) == 0) {
    // Ignore any query for other types of devices.
    return X_ERROR_DEVICE_NOT_CONNECTED;
  }

  uint32_t user_index = *user_index_ptr;
  if ((user_index & 0xFF) == 0xFF || (flags & XINPUT_FLAG_ANY_USER)) {
    // Always pin user to 0.
    user_index = 0;
  }

  auto input_system = kernel_state()->emulator()->input_system();
  auto result = input_system->GetKeystroke(user_index, flags, keystroke);
  if (XSUCCEEDED(result)) {
    *user_index_ptr = keystroke->user_index;
  }
  return result;
}
DECLARE_XAM_EXPORT(XamInputGetKeystrokeEx,
                   ExportTag::kInput | ExportTag::kImplemented);

X_HRESULT_result_t XamUserGetDeviceContext(dword_t user_index, dword_t unk,
                                           lpdword_t out_ptr) {
  // Games check the result - usually with some masking.
  // If this function fails they assume zero, so let's fail AND
  // set zero just to be safe.
  *out_ptr = 0;
  if (!user_index || (user_index & 0xFF) == 0xFF) {
    return X_E_SUCCESS;
  } else {
    return X_E_DEVICE_NOT_CONNECTED;
  }
}
DECLARE_XAM_EXPORT(XamUserGetDeviceContext,
                   ExportTag::kInput | ExportTag::kStub);

void RegisterInputExports(xe::cpu::ExportResolver* export_resolver,
                          KernelState* kernel_state) {
}

}  // namespace xam
}  // namespace kernel
}  // namespace xe
<|endoftext|>


<commit_before>//
// Amity - cross-platform game engine
// https://github.com/aduros/amity/blob/master/LICENSE.txt

#include "script/HttpHandle.h"

#include "SDL.h"

#include "script/Script.h"
#include "script/util.h"
#include "log.h"

JSPropertySpec HttpHandle::jsProperties[] = { NULL };
JSFunctionSpec HttpHandle::jsFunctions[] = {
    JS_FS("setHeader", HttpHandle::bindFunction<&HttpHandle::setHeader>, 2, 0),
    JS_FS("send", HttpHandle::bindFunction<&HttpHandle::send>, 1, 0),
    JS_FS_END
};
DEFINE_HANDLE_JSCLASS(HttpHandle, "Http");

struct HttpThreadData {
    HttpHandle* handle;
    JSContext* jsCtx;
};

static int threadSend (HttpThreadData* data)
{
    HttpHandle* handle = data->handle;
    JSContext* jsCtx = data->jsCtx;

    bool success = handle->http.send();
    AmityEvent* event = new AmityEvent();
    const char* param;

    JS_BeginRequest(jsCtx);
    if (success) {
        event->handler = getInternedId(jsCtx, "onComplete");
        param = handle->http.getData();
    } else {
        event->handler = getInternedId(jsCtx, "onError");
        param = handle->http.getErrorMessage();
    }
    event->param = STRING_TO_JSVAL(JS_NewStringCopyZ(jsCtx, param));
    event->obj = handle->getJSObject();
    postEvent(jsCtx, event);
    JS_EndRequest(jsCtx);

    delete data;
}

SCRIPT_FUNCTION (HttpHandle::setHeader, jsCtx, argc, vp)
{
    LOGI("TODO: HttpHandle.setHeader");
    return JS_TRUE;
}

SCRIPT_FUNCTION (HttpHandle::send, jsCtx, argc, vp)
{
    jsval val = JS_ARGV(jsCtx, vp)[0];
    if (JSVAL_IS_STRING(val)) {
        JSString* str = JSVAL_TO_STRING(val);
        char* postData = JS_EncodeString(jsCtx, str);
        int length = JS_GetStringEncodingLength(jsCtx, str);
        http.setPostData(postData, length);
        JS_free(jsCtx, postData);
    } else {
        http.setPostData(NULL, 0);
    }

    HttpThreadData* threadData = new HttpThreadData();
    threadData->handle = this;
    threadData->jsCtx = jsCtx;

    SDL_Thread* thread = SDL_CreateThread((SDL_ThreadFunction) threadSend, threadData);
    if (thread == NULL) {
        LOGW("Could not create HTTP thread: %s", SDL_GetError());
        // Do it on the main thread if we have to
        threadSend(threadData);
    }

    return JS_TRUE;
}

SCRIPT_FUNCTION (amity_net_createHttpRequest, jsCtx, argc, vp)
{
    JSString* url;
    if (!JS_ConvertArguments(jsCtx, 1, JS_ARGV(jsCtx, vp), "S", &url)) {
        return JS_FALSE;
    }

    HttpHandle* handle = HttpHandle::create(jsCtx);
    char* str = JS_EncodeString(jsCtx, url);
    handle->http.setUrl(str);
    JS_free(jsCtx, str);
    JS_SET_RVAL(jsCtx, vp, OBJECT_TO_JSVAL(handle->getJSObject()));

    return JS_TRUE;
}
<commit_msg>SDL_ThreadFunction doesn't exist in webOS's SDL. Take the long way.<commit_after>//
// Amity - cross-platform game engine
// https://github.com/aduros/amity/blob/master/LICENSE.txt

#include "script/HttpHandle.h"

#include "SDL.h"

#include "script/Script.h"
#include "script/util.h"
#include "log.h"

JSPropertySpec HttpHandle::jsProperties[] = { NULL };
JSFunctionSpec HttpHandle::jsFunctions[] = {
    JS_FS("setHeader", HttpHandle::bindFunction<&HttpHandle::setHeader>, 2, 0),
    JS_FS("send", HttpHandle::bindFunction<&HttpHandle::send>, 1, 0),
    JS_FS_END
};
DEFINE_HANDLE_JSCLASS(HttpHandle, "Http");

struct HttpThreadData {
    HttpHandle* handle;
    JSContext* jsCtx;
};

static int threadSend (void* ctx)
{
    HttpThreadData* threadData = static_cast<HttpThreadData*>(ctx);
    HttpHandle* handle = threadData->handle;
    JSContext* jsCtx = threadData->jsCtx;

    bool success = handle->http.send();
    AmityEvent* event = new AmityEvent();
    const char* param;

    JS_BeginRequest(jsCtx);
    if (success) {
        event->handler = getInternedId(jsCtx, "onComplete");
        param = handle->http.getData();
    } else {
        event->handler = getInternedId(jsCtx, "onError");
        param = handle->http.getErrorMessage();
    }
    event->param = STRING_TO_JSVAL(JS_NewStringCopyZ(jsCtx, param));
    event->obj = handle->getJSObject();
    postEvent(jsCtx, event);
    JS_EndRequest(jsCtx);

    delete threadData;
}

SCRIPT_FUNCTION (HttpHandle::setHeader, jsCtx, argc, vp)
{
    LOGI("TODO: HttpHandle.setHeader");
    return JS_TRUE;
}

SCRIPT_FUNCTION (HttpHandle::send, jsCtx, argc, vp)
{
    jsval val = JS_ARGV(jsCtx, vp)[0];
    if (JSVAL_IS_STRING(val)) {
        JSString* str = JSVAL_TO_STRING(val);
        char* postData = JS_EncodeString(jsCtx, str);
        int length = JS_GetStringEncodingLength(jsCtx, str);
        http.setPostData(postData, length);
        JS_free(jsCtx, postData);
    } else {
        http.setPostData(NULL, 0);
    }

    HttpThreadData* threadData = new HttpThreadData();
    threadData->handle = this;
    threadData->jsCtx = jsCtx;

    SDL_Thread* thread = SDL_CreateThread(threadSend, threadData);
    if (thread == NULL) {
        LOGW("Could not create HTTP thread: %s", SDL_GetError());
        // Do it on the main thread if we have to
        threadSend(threadData);
    }

    return JS_TRUE;
}

SCRIPT_FUNCTION (amity_net_createHttpRequest, jsCtx, argc, vp)
{
    JSString* url;
    if (!JS_ConvertArguments(jsCtx, 1, JS_ARGV(jsCtx, vp), "S", &url)) {
        return JS_FALSE;
    }

    HttpHandle* handle = HttpHandle::create(jsCtx);
    char* str = JS_EncodeString(jsCtx, url);
    handle->http.setUrl(str);
    JS_free(jsCtx, str);
    JS_SET_RVAL(jsCtx, vp, OBJECT_TO_JSVAL(handle->getJSObject()));

    return JS_TRUE;
}
<|endoftext|>