<commit_before>#include <cucumber-cpp/internal/connectors/wire/WireProtocol.hpp>
#include <cucumber-cpp/internal/connectors/wire/WireProtocolCommands.hpp>

#include <gmock/gmock.h>
#include <boost/assign/list_of.hpp>
#include <boost/shared_ptr.hpp>

#include <typeinfo>

using namespace cucumber::internal;
using namespace std;
using namespace testing;

using boost::assign::list_of;

class MockCukeEngine : public CukeEngine {
public:
    MOCK_CONST_METHOD1(stepMatches, std::vector<StepMatch>(const std::string & name));
    MOCK_METHOD1(endScenario, void(const tags_type & tags));
    MOCK_METHOD3(invokeStep, void(const std::string & id, const invoke_args_type & args, const invoke_table_type & tableArg));
    MOCK_METHOD1(beginScenario, void(const tags_type & tags));
    MOCK_CONST_METHOD3(snippetText, std::string(const std::string & keyword, const std::string & name, const std::string & multilineArgClass));
};

#define EXPECT_TYPE(classname, expression) \
    EXPECT_THAT(typeid(classname).name(), StrEq(typeid(expression).name()))

#define EXPECT_PTRTYPE(classname, expression) \
    EXPECT_TYPE(classname, *expression)

class WireMessageCodecTest : public Test {
public:
    WireMessageCodecTest() {};

protected:
    boost::shared_ptr<WireCommand> commandAutoPtr;

    WireCommand& decode(const char *jsonStr) {
        commandAutoPtr = codec.decode(jsonStr);
        return *commandAutoPtr;
    }

    std::string encode(const WireResponse& response) const {
        return codec.encode(response);
    }

protected:
    const JsonSpiritWireMessageCodec codec;
};

/*
 * Request decoding
 */

TEST_F(WireMessageCodecTest, decodesUnknownOrMalformedMessage) {
    MockCukeEngine engine;

    EXPECT_EQ(encode(*decode("[\"unknown_command\"]").run(engine)), "[\"fail\"]");
    EXPECT_EQ(encode(*decode("").run(engine)), "[\"fail\"]");
    EXPECT_EQ(encode(*decode("rubbish").run(engine)), "[\"fail\"]");
    EXPECT_EQ(encode(*decode("{\"malformed_command\"}").run(engine)), "[\"fail\"]");
    EXPECT_EQ(encode(*decode("[42]").run(engine)), "[\"fail\"]");
}

TEST_F(WireMessageCodecTest, handlesStepMatchesMessage) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, stepMatches("name to match"))
            .Times(1)
            .WillRepeatedly(Return(std::vector<StepMatch>(0)));

    decode("[\"step_matches\","
           "{\"name_to_match\":\"name to match\"}]")
            .run(engine);
}

TEST_F(WireMessageCodecTest, handlesBeginScenarioMessageWithoutArgument) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, beginScenario(ElementsAre())).Times(1);

    decode("[\"begin_scenario\"]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesBeginScenarioMessageWithTagsArgument) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, beginScenario(ElementsAre("bar","baz","foo"))).Times(1);

    decode("[\"begin_scenario\","
           "{\"tags\":["
                "\"bar\","
                "\"baz\","
                "\"foo\""
           "]}]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesBeginScenarioMessageWithNullArgument) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, beginScenario(ElementsAre())).Times(1);

    decode("[\"begin_scenario\",null]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesInvokeMessageWithNoArgs) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, invokeStep("42", ElementsAre(), ElementsAre())).Times(1);

    decode("[\"invoke\",{\"id\":\"42\",\"args\":[]}]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesInvokeMessageWithoutTableArgs) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, invokeStep("42", ElementsAre("p1","p2","p3"), ElementsAre())).Times(1);

    decode("[\"invoke\",{"
           "\"id\":\"42\","
           "\"args\":["
                "\"p1\","
                "\"p2\","
                "\"p3\""
           "}]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesInvokeMessageWithTableArgs) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, invokeStep(
            "42",
            ElementsAre("p1"),
            ElementsAre(
                ElementsAre("col1","col2"),
                ElementsAre("r1c1","r1c2"),
                ElementsAre("r2c1","r2c2"),
                ElementsAre("r3c1","r3c2")
            )
        )).Times(1);

    decode("[\"invoke\",{"
           "\"id\":\"42\","
           "\"args\":["
                "\"p1\","
                "["
                    "[\"col1\",\"col2\"],"
                    "[\"r1c1\",\"r1c2\"],"
                    "[\"r2c1\",\"r2c2\"],"
                    "[\"r3c1\",\"r3c2\"]"
                "]"
           "}]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesInvokeMessageWithNullArg) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, invokeStep("42", ElementsAre(), ElementsAre())).Times(1);

    decode("[\"invoke\",{\"id\":\"42\",\"args\":[null]}]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesEndScenarioMessageWithoutArgument) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, endScenario(ElementsAre())).Times(1);

    decode("[\"end_scenario\"]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesEndScenarioMessageWithNullArgument) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, endScenario(ElementsAre())).Times(1);

    decode("[\"end_scenario\",null]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesEndScenarioMessageWithTagsArgument) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, endScenario(ElementsAre("cu","cum","ber"))).Times(1);

    decode("[\"end_scenario\","
           "{\"tags\":["
                "\"cu\","
                "\"cum\","
                "\"ber\""
           "]}]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesSnippetTextMessage) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, snippetText("Keyword", "step description","Some::Class")).Times(1);

    decode("[\"snippet_text\","
           "{\"step_keyword\":\"Keyword\","
             "\"multiline_arg_class\":\"Some::Class\","
             "\"step_name\":\"step description\"}]")
            .run(engine);
}

/*
 * Response encoding
 */

TEST_F(WireMessageCodecTest, handlesSuccessResponse) {
    SuccessResponse response;
    EXPECT_THAT(codec.encode(response), StrEq("[\"success\"]"));
}

TEST_F(WireMessageCodecTest, handlesSimpleFailureResponse) {
    FailureResponse response;
    EXPECT_THAT(codec.encode(response), StrEq("[\"fail\"]"));
}

TEST_F(WireMessageCodecTest, handlesDetailedFailureResponse) {
    FailureResponse response("My message","ExceptionClassName");
    EXPECT_THAT(codec.encode(response), StrEq(
            "[\"fail\",{"
                "\"exception\":\"ExceptionClassName\","
                "\"message\":\"My message\""
            "}]"));
}

TEST_F(WireMessageCodecTest, handlesPendingResponse) {
    PendingResponse response("I'm lazy!");
    EXPECT_THAT(codec.encode(response), StrEq("[\"pending\",\"I'm lazy!\"]"));
}

TEST_F(WireMessageCodecTest, handlesEmptyStepMatchesResponse) {
    StepMatchesResponse response(std::vector<StepMatch>(0));
    EXPECT_THAT(codec.encode(response), StrEq("[\"success\",[]]"));
}

TEST_F(WireMessageCodecTest, handlesStepMatchesResponse) {
    std::vector<StepMatch> matches;
    StepMatch sm1;
    sm1.id = "1234";
    sm1.source = "MyClass.cpp:56";
    sm1.regexp = "Some (.*) regexp";
    matches.push_back(sm1);
    StepMatch sm2;
    sm2.id = "9876";
    StepMatchArg sm2arg1;
    sm2arg1.value = "odd";
    sm2arg1.position = 5;
    sm2.args.push_back(sm2arg1);
    matches.push_back(sm2);
    StepMatchesResponse response(matches);

    EXPECT_THAT(codec.encode(response), StrEq(
            "[\"success\",[{"
                "\"args\":[],"
                "\"id\":\"1234\","
                "\"regexp\":\"Some (.*) regexp\","
                "\"source\":\"MyClass.cpp:56\""
            "},{"
                "\"args\":[{"
                    "\"pos\":5,"
                    "\"val\":\"odd\""
                "}],"
                "\"id\":\"9876\""
            "}]]"));
}

TEST_F(WireMessageCodecTest, handlesSnippetTextResponse) {
    SnippetTextResponse response("GIVEN(...)");
    EXPECT_THAT(codec.encode(response), StrEq("[\"success\",\"GIVEN(...)\"]"));
}

/*
 * Command response
 */

TEST(WireCommandsTest, succesfulInvokeReturnsSuccess) {
    MockCukeEngine engine;
    InvokeCommand invokeCommand("x", CukeEngine::invoke_args_type(), CukeEngine::invoke_table_type());
    EXPECT_CALL(engine, invokeStep(_, _, _))
            .Times(1);

    boost::shared_ptr<const WireResponse> response(invokeCommand.run(engine));
    EXPECT_PTRTYPE(SuccessResponse, response.get());
}

TEST(WireCommandsTest, throwingFailureInvokeReturnsFailure) {
    MockCukeEngine engine;
    InvokeCommand invokeCommand("x", CukeEngine::invoke_args_type(), CukeEngine::invoke_table_type());
    EXPECT_CALL(engine, invokeStep(_, _, _))
            .Times(1)
            .WillOnce(Throw(InvokeFailureException("A", "B")));

    boost::shared_ptr<const WireResponse> response(invokeCommand.run(engine));
    EXPECT_PTRTYPE(FailureResponse, response.get());
    // TODO Test A and B
}

TEST(WireCommandsTest, throwingPendingStepReturnsPending) {
    MockCukeEngine engine;
    InvokeCommand invokeCommand("x", CukeEngine::invoke_args_type(), CukeEngine::invoke_table_type());
    EXPECT_CALL(engine, invokeStep(_, _, _))
            .Times(1)
            .WillOnce(Throw(PendingStepException("S")));

    boost::shared_ptr<const WireResponse> response(invokeCommand.run(engine));
    EXPECT_PTRTYPE(PendingResponse, response.get());
    // TODO Test S
}

TEST(WireCommandsTest, throwingAnythingInvokeReturnsFailure) {
    MockCukeEngine engine;
    InvokeCommand invokeCommand("x", CukeEngine::invoke_args_type(), CukeEngine::invoke_table_type());
    EXPECT_CALL(engine, invokeStep(_, _, _))
            .Times(1)
            .WillOnce(Throw(string("something")));

    boost::shared_ptr<const WireResponse> response(invokeCommand.run(engine));
    EXPECT_PTRTYPE(FailureResponse, response.get());
    // TODO Test empty
}

<commit_msg>get rid of clang warning<commit_after>#include <cucumber-cpp/internal/connectors/wire/WireProtocol.hpp>
#include <cucumber-cpp/internal/connectors/wire/WireProtocolCommands.hpp>

#include <gmock/gmock.h>
#include <boost/assign/list_of.hpp>
#include <boost/shared_ptr.hpp>

#include <typeinfo>

using namespace cucumber::internal;
using namespace std;
using namespace testing;

using boost::assign::list_of;

class MockCukeEngine : public CukeEngine {
public:
    MOCK_CONST_METHOD1(stepMatches, std::vector<StepMatch>(const std::string & name));
    MOCK_METHOD1(endScenario, void(const tags_type & tags));
    MOCK_METHOD3(invokeStep, void(const std::string & id, const invoke_args_type & args, const invoke_table_type & tableArg));
    MOCK_METHOD1(beginScenario, void(const tags_type & tags));
    MOCK_CONST_METHOD3(snippetText, std::string(const std::string & keyword, const std::string & name, const std::string & multilineArgClass));
};

#define EXPECT_PTRTYPE(classname, expression) \
    EXPECT_NE(dynamic_cast<const classname*>(expression), (void*)NULL)

class WireMessageCodecTest : public Test {
public:
    WireMessageCodecTest() {};

protected:
    boost::shared_ptr<WireCommand> commandAutoPtr;

    WireCommand& decode(const char *jsonStr) {
        commandAutoPtr = codec.decode(jsonStr);
        return *commandAutoPtr;
    }

    std::string encode(const WireResponse& response) const {
        return codec.encode(response);
    }

protected:
    const JsonSpiritWireMessageCodec codec;
};

/*
 * Request decoding
 */

TEST_F(WireMessageCodecTest, decodesUnknownOrMalformedMessage) {
    MockCukeEngine engine;

    EXPECT_EQ(encode(*decode("[\"unknown_command\"]").run(engine)), "[\"fail\"]");
    EXPECT_EQ(encode(*decode("").run(engine)), "[\"fail\"]");
    EXPECT_EQ(encode(*decode("rubbish").run(engine)), "[\"fail\"]");
    EXPECT_EQ(encode(*decode("{\"malformed_command\"}").run(engine)), "[\"fail\"]");
    EXPECT_EQ(encode(*decode("[42]").run(engine)), "[\"fail\"]");
}

TEST_F(WireMessageCodecTest, handlesStepMatchesMessage) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, stepMatches("name to match"))
            .Times(1)
            .WillRepeatedly(Return(std::vector<StepMatch>(0)));

    decode("[\"step_matches\","
           "{\"name_to_match\":\"name to match\"}]")
            .run(engine);
}

TEST_F(WireMessageCodecTest, handlesBeginScenarioMessageWithoutArgument) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, beginScenario(ElementsAre())).Times(1);

    decode("[\"begin_scenario\"]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesBeginScenarioMessageWithTagsArgument) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, beginScenario(ElementsAre("bar","baz","foo"))).Times(1);

    decode("[\"begin_scenario\","
           "{\"tags\":["
                "\"bar\","
                "\"baz\","
                "\"foo\""
           "]}]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesBeginScenarioMessageWithNullArgument) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, beginScenario(ElementsAre())).Times(1);

    decode("[\"begin_scenario\",null]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesInvokeMessageWithNoArgs) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, invokeStep("42", ElementsAre(), ElementsAre())).Times(1);

    decode("[\"invoke\",{\"id\":\"42\",\"args\":[]}]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesInvokeMessageWithoutTableArgs) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, invokeStep("42", ElementsAre("p1","p2","p3"), ElementsAre())).Times(1);

    decode("[\"invoke\",{"
           "\"id\":\"42\","
           "\"args\":["
                "\"p1\","
                "\"p2\","
                "\"p3\""
           "}]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesInvokeMessageWithTableArgs) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, invokeStep(
            "42",
            ElementsAre("p1"),
            ElementsAre(
                ElementsAre("col1","col2"),
                ElementsAre("r1c1","r1c2"),
                ElementsAre("r2c1","r2c2"),
                ElementsAre("r3c1","r3c2")
            )
        )).Times(1);

    decode("[\"invoke\",{"
           "\"id\":\"42\","
           "\"args\":["
                "\"p1\","
                "["
                    "[\"col1\",\"col2\"],"
                    "[\"r1c1\",\"r1c2\"],"
                    "[\"r2c1\",\"r2c2\"],"
                    "[\"r3c1\",\"r3c2\"]"
                "]"
           "}]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesInvokeMessageWithNullArg) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, invokeStep("42", ElementsAre(), ElementsAre())).Times(1);

    decode("[\"invoke\",{\"id\":\"42\",\"args\":[null]}]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesEndScenarioMessageWithoutArgument) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, endScenario(ElementsAre())).Times(1);

    decode("[\"end_scenario\"]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesEndScenarioMessageWithNullArgument) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, endScenario(ElementsAre())).Times(1);

    decode("[\"end_scenario\",null]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesEndScenarioMessageWithTagsArgument) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, endScenario(ElementsAre("cu","cum","ber"))).Times(1);

    decode("[\"end_scenario\","
           "{\"tags\":["
                "\"cu\","
                "\"cum\","
                "\"ber\""
           "]}]").run(engine);
}

TEST_F(WireMessageCodecTest, handlesSnippetTextMessage) {
    MockCukeEngine engine;
    EXPECT_CALL(engine, snippetText("Keyword", "step description","Some::Class")).Times(1);

    decode("[\"snippet_text\","
           "{\"step_keyword\":\"Keyword\","
             "\"multiline_arg_class\":\"Some::Class\","
             "\"step_name\":\"step description\"}]")
            .run(engine);
}

/*
 * Response encoding
 */

TEST_F(WireMessageCodecTest, handlesSuccessResponse) {
    SuccessResponse response;
    EXPECT_THAT(codec.encode(response), StrEq("[\"success\"]"));
}

TEST_F(WireMessageCodecTest, handlesSimpleFailureResponse) {
    FailureResponse response;
    EXPECT_THAT(codec.encode(response), StrEq("[\"fail\"]"));
}

TEST_F(WireMessageCodecTest, handlesDetailedFailureResponse) {
    FailureResponse response("My message","ExceptionClassName");
    EXPECT_THAT(codec.encode(response), StrEq(
            "[\"fail\",{"
                "\"exception\":\"ExceptionClassName\","
                "\"message\":\"My message\""
            "}]"));
}

TEST_F(WireMessageCodecTest, handlesPendingResponse) {
    PendingResponse response("I'm lazy!");
    EXPECT_THAT(codec.encode(response), StrEq("[\"pending\",\"I'm lazy!\"]"));
}

TEST_F(WireMessageCodecTest, handlesEmptyStepMatchesResponse) {
    StepMatchesResponse response(std::vector<StepMatch>(0));
    EXPECT_THAT(codec.encode(response), StrEq("[\"success\",[]]"));
}

TEST_F(WireMessageCodecTest, handlesStepMatchesResponse) {
    std::vector<StepMatch> matches;
    StepMatch sm1;
    sm1.id = "1234";
    sm1.source = "MyClass.cpp:56";
    sm1.regexp = "Some (.*) regexp";
    matches.push_back(sm1);
    StepMatch sm2;
    sm2.id = "9876";
    StepMatchArg sm2arg1;
    sm2arg1.value = "odd";
    sm2arg1.position = 5;
    sm2.args.push_back(sm2arg1);
    matches.push_back(sm2);
    StepMatchesResponse response(matches);

    EXPECT_THAT(codec.encode(response), StrEq(
            "[\"success\",[{"
                "\"args\":[],"
                "\"id\":\"1234\","
                "\"regexp\":\"Some (.*) regexp\","
                "\"source\":\"MyClass.cpp:56\""
            "},{"
                "\"args\":[{"
                    "\"pos\":5,"
                    "\"val\":\"odd\""
                "}],"
                "\"id\":\"9876\""
            "}]]"));
}

TEST_F(WireMessageCodecTest, handlesSnippetTextResponse) {
    SnippetTextResponse response("GIVEN(...)");
    EXPECT_THAT(codec.encode(response), StrEq("[\"success\",\"GIVEN(...)\"]"));
}

/*
 * Command response
 */

TEST(WireCommandsTest, succesfulInvokeReturnsSuccess) {
    MockCukeEngine engine;
    InvokeCommand invokeCommand("x", CukeEngine::invoke_args_type(), CukeEngine::invoke_table_type());
    EXPECT_CALL(engine, invokeStep(_, _, _))
            .Times(1);

    boost::shared_ptr<const WireResponse> response(invokeCommand.run(engine));
    EXPECT_PTRTYPE(SuccessResponse, response.get());
}

TEST(WireCommandsTest, throwingFailureInvokeReturnsFailure) {
    MockCukeEngine engine;
    InvokeCommand invokeCommand("x", CukeEngine::invoke_args_type(), CukeEngine::invoke_table_type());
    EXPECT_CALL(engine, invokeStep(_, _, _))
            .Times(1)
            .WillOnce(Throw(InvokeFailureException("A", "B")));

    boost::shared_ptr<const WireResponse> response(invokeCommand.run(engine));
    EXPECT_PTRTYPE(FailureResponse, response.get());
    // TODO Test A and B
}

TEST(WireCommandsTest, throwingPendingStepReturnsPending) {
    MockCukeEngine engine;
    InvokeCommand invokeCommand("x", CukeEngine::invoke_args_type(), CukeEngine::invoke_table_type());
    EXPECT_CALL(engine, invokeStep(_, _, _))
            .Times(1)
            .WillOnce(Throw(PendingStepException("S")));

    boost::shared_ptr<const WireResponse> response(invokeCommand.run(engine));
    EXPECT_PTRTYPE(PendingResponse, response.get());
    // TODO Test S
}

TEST(WireCommandsTest, throwingAnythingInvokeReturnsFailure) {
    MockCukeEngine engine;
    InvokeCommand invokeCommand("x", CukeEngine::invoke_args_type(), CukeEngine::invoke_table_type());
    EXPECT_CALL(engine, invokeStep(_, _, _))
            .Times(1)
            .WillOnce(Throw(string("something")));

    boost::shared_ptr<const WireResponse> response(invokeCommand.run(engine));
    EXPECT_PTRTYPE(FailureResponse, response.get());
    // TODO Test empty
}

<|endoftext|>


<commit_before>/*
* Copyright (c) 2003-2016 Rony Shapiro <ronys@pwsafe.org>.
* All rights reserved. Use of the code is allowed under the
* Artistic License 2.0 terms, as specified in the LICENSE file
* distributed with this code, or available from
* http://www.opensource.org/licenses/artistic-license-2.0.php
*/

/*
 * macsendstring - sends keyboard events to the app in focus
 *
 */
#include "./macsendstring.h"

#include <ApplicationServices/ApplicationServices.h> // OSX-only header
#include <Carbon/Carbon.h>
#include "../sleep.h"
#include "../../core/PwsPlatform.h"
#include "../debug.h"

void SendString(CFStringRef str, unsigned delayMS)
{
  //virtual keycodes copied from 10.6 SDK.  Could not find them in 10.4 SDK
  enum { VK_RETURN = 0x24 /*KVK_Return*/, VK_TAB = 0x30 /*kVK_Tab*/, VK_SPACE = 0x31/*kVK_Space*/};

  //A list of chars for which we must specify the virtual keycode
  static const CFStringRef specialChars = CFSTR("\n\t ");

  static const UniChar verticalTab = CFStringGetCharacterAtIndex(CFSTR("\v"), 0);

  //each keycode must correspond to the correct char in 'specialChars'
  CGKeyCode specialKeyCodes[] = {VK_RETURN, VK_TAB, VK_SPACE };

  assert(CFStringGetLength(specialChars) == NumberOf(specialKeyCodes));

  for (unsigned i = 0, len = CFStringGetLength(str); i < len; ++i) {
    //The next char to send
    UniChar c = CFStringGetCharacterAtIndex(str, i);

    //throw away 'vertical tab' chars which are only used on Windows to send a shift+tab
    //as a workaround for some issues with IE
    if (verticalTab == c)
      continue;

    //see if we need to specify the virtual ekycode for this char
    CGKeyCode vKey = 0; //0 = kVK_ANSI_A, but I don't know of a more appropriate default value
    for (size_t j = 0; j < NumberOf(specialKeyCodes); ++j) {
      if ( CFStringGetCharacterAtIndex(specialChars, j) == c) {
        vKey = specialKeyCodes[j];
        break;
      }
    }

    CGEventRef keyDown = CGEventCreateKeyboardEvent(NULL, vKey, true);
    CGEventRef keyUp   = CGEventCreateKeyboardEvent(NULL, vKey, false);

    if (keyDown && keyUp) {
      //may be we should not do this if we found the virtual keycode?
      CGEventKeyboardSetUnicodeString(keyDown, 1, &c);
      CGEventKeyboardSetUnicodeString(keyUp, 1, &c);

      CGEventPost(kCGSessionEventTap, keyDown);
      CGEventPost(kCGSessionEventTap, keyUp);

      pws_os::sleep_ms(delayMS);

      CFRelease(keyDown);
      CFRelease(keyUp);
    }
    else {
      if (keyDown) CFRelease(keyDown);
      if (keyUp) CFRelease(keyUp);
      pws_os::IssueError(_T("Out of memory trying to allocate CGEventRef"));
      return;
    }
  }
}

void pws_os::SendString(const char* str, unsigned delayMS)
{
  //GetApplicationTextEncoding call here certainly seems wrong.  We should store the keyboard layout
  //and string encoding in password db.  But this works for now.
  CFStringRef cfstr = CFStringCreateWithCString(kCFAllocatorDefault, str, GetApplicationTextEncoding());
  SendString(cfstr, delayMS);
  CFRelease(cfstr);
}

struct KeyStroke {
  CGKeyCode virtualKey;
  bool down;
  bool mask;
};

bool EmulateKeyStrokes(const KeyStroke *KeySequence, size_t num, unsigned delayMS)
{
  for (size_t idx = 0; idx < num; ++idx) {
    CGEventRef keystroke = CGEventCreateKeyboardEvent(NULL, KeySequence[idx].virtualKey, KeySequence[idx].down);
    if (keystroke) {
      if (KeySequence[idx].mask) {
        CGEventSetFlags(keystroke, kCGEventFlagMaskCommand);
      }
      CGEventPost(kCGSessionEventTap, keystroke);
      CFRelease(keystroke);
      if (delayMS)
        pws_os::sleep_ms(delayMS);
    }
    else {
      return false;
    }
  }
  return true;
}

bool pws_os::MacSimulateApplicationSwitch(unsigned delayMS)
{
  enum { VK_CMD = 55, VK_TAB = 48 };

  KeyStroke KeySequence[] = { {VK_CMD, true, true},
                              {VK_TAB, true, true},
                              {VK_TAB, false, true},
                              {VK_CMD, false, false}
                            };

  return EmulateKeyStrokes(KeySequence, NumberOf(KeySequence), delayMS);
}

bool pws_os::SelectAll()
{
  enum { VK_A = kVK_ANSI_A, VK_CMD = kVK_Command };

  KeyStroke KeySequence[]={ {VK_CMD, true,  true},
                            {VK_A,   true,  true},
                            {VK_A,   false, true},
                            {VK_CMD, false, false}
                          };

  return EmulateKeyStrokes(KeySequence, NumberOf(KeySequence), 0);
}

#if 0
int main (int argc, const char * argv[])
{
    for (int i = 1; i < argc; ++i)
  {
    printf("Sending \"%s\", switch to another application in 5 seconds...\n", argv[i]);
    sleep(5);
    SendString(argv[i], 5000);
  }
    return 0;
}

#endif
<commit_msg>spelling: keycode<commit_after>/*
* Copyright (c) 2003-2016 Rony Shapiro <ronys@pwsafe.org>.
* All rights reserved. Use of the code is allowed under the
* Artistic License 2.0 terms, as specified in the LICENSE file
* distributed with this code, or available from
* http://www.opensource.org/licenses/artistic-license-2.0.php
*/

/*
 * macsendstring - sends keyboard events to the app in focus
 *
 */
#include "./macsendstring.h"

#include <ApplicationServices/ApplicationServices.h> // OSX-only header
#include <Carbon/Carbon.h>
#include "../sleep.h"
#include "../../core/PwsPlatform.h"
#include "../debug.h"

void SendString(CFStringRef str, unsigned delayMS)
{
  //virtual keycodes copied from 10.6 SDK.  Could not find them in 10.4 SDK
  enum { VK_RETURN = 0x24 /*KVK_Return*/, VK_TAB = 0x30 /*kVK_Tab*/, VK_SPACE = 0x31/*kVK_Space*/};

  //A list of chars for which we must specify the virtual keycode
  static const CFStringRef specialChars = CFSTR("\n\t ");

  static const UniChar verticalTab = CFStringGetCharacterAtIndex(CFSTR("\v"), 0);

  //each keycode must correspond to the correct char in 'specialChars'
  CGKeyCode specialKeyCodes[] = {VK_RETURN, VK_TAB, VK_SPACE };

  assert(CFStringGetLength(specialChars) == NumberOf(specialKeyCodes));

  for (unsigned i = 0, len = CFStringGetLength(str); i < len; ++i) {
    //The next char to send
    UniChar c = CFStringGetCharacterAtIndex(str, i);

    //throw away 'vertical tab' chars which are only used on Windows to send a shift+tab
    //as a workaround for some issues with IE
    if (verticalTab == c)
      continue;

    //see if we need to specify the virtual keycode for this char
    CGKeyCode vKey = 0; //0 = kVK_ANSI_A, but I don't know of a more appropriate default value
    for (size_t j = 0; j < NumberOf(specialKeyCodes); ++j) {
      if ( CFStringGetCharacterAtIndex(specialChars, j) == c) {
        vKey = specialKeyCodes[j];
        break;
      }
    }

    CGEventRef keyDown = CGEventCreateKeyboardEvent(NULL, vKey, true);
    CGEventRef keyUp   = CGEventCreateKeyboardEvent(NULL, vKey, false);

    if (keyDown && keyUp) {
      //may be we should not do this if we found the virtual keycode?
      CGEventKeyboardSetUnicodeString(keyDown, 1, &c);
      CGEventKeyboardSetUnicodeString(keyUp, 1, &c);

      CGEventPost(kCGSessionEventTap, keyDown);
      CGEventPost(kCGSessionEventTap, keyUp);

      pws_os::sleep_ms(delayMS);

      CFRelease(keyDown);
      CFRelease(keyUp);
    }
    else {
      if (keyDown) CFRelease(keyDown);
      if (keyUp) CFRelease(keyUp);
      pws_os::IssueError(_T("Out of memory trying to allocate CGEventRef"));
      return;
    }
  }
}

void pws_os::SendString(const char* str, unsigned delayMS)
{
  //GetApplicationTextEncoding call here certainly seems wrong.  We should store the keyboard layout
  //and string encoding in password db.  But this works for now.
  CFStringRef cfstr = CFStringCreateWithCString(kCFAllocatorDefault, str, GetApplicationTextEncoding());
  SendString(cfstr, delayMS);
  CFRelease(cfstr);
}

struct KeyStroke {
  CGKeyCode virtualKey;
  bool down;
  bool mask;
};

bool EmulateKeyStrokes(const KeyStroke *KeySequence, size_t num, unsigned delayMS)
{
  for (size_t idx = 0; idx < num; ++idx) {
    CGEventRef keystroke = CGEventCreateKeyboardEvent(NULL, KeySequence[idx].virtualKey, KeySequence[idx].down);
    if (keystroke) {
      if (KeySequence[idx].mask) {
        CGEventSetFlags(keystroke, kCGEventFlagMaskCommand);
      }
      CGEventPost(kCGSessionEventTap, keystroke);
      CFRelease(keystroke);
      if (delayMS)
        pws_os::sleep_ms(delayMS);
    }
    else {
      return false;
    }
  }
  return true;
}

bool pws_os::MacSimulateApplicationSwitch(unsigned delayMS)
{
  enum { VK_CMD = 55, VK_TAB = 48 };

  KeyStroke KeySequence[] = { {VK_CMD, true, true},
                              {VK_TAB, true, true},
                              {VK_TAB, false, true},
                              {VK_CMD, false, false}
                            };

  return EmulateKeyStrokes(KeySequence, NumberOf(KeySequence), delayMS);
}

bool pws_os::SelectAll()
{
  enum { VK_A = kVK_ANSI_A, VK_CMD = kVK_Command };

  KeyStroke KeySequence[]={ {VK_CMD, true,  true},
                            {VK_A,   true,  true},
                            {VK_A,   false, true},
                            {VK_CMD, false, false}
                          };

  return EmulateKeyStrokes(KeySequence, NumberOf(KeySequence), 0);
}

#if 0
int main (int argc, const char * argv[])
{
    for (int i = 1; i < argc; ++i)
  {
    printf("Sending \"%s\", switch to another application in 5 seconds...\n", argv[i]);
    sleep(5);
    SendString(argv[i], 5000);
  }
    return 0;
}

#endif
<|endoftext|>


<commit_before>#include "osg/Depth"

#include "osgDB/Registry"
#include "osgDB/Input"
#include "osgDB/Output"

using namespace osg;
using namespace osgDB;

// forward declare functions to use later.
bool Depth_readLocalData(Object& obj, Input& fr);
bool Depth_writeLocalData(const Object& obj, Output& fw);

bool Depth_matchFuncStr(const char* str,Depth::Function& func);
const char* Depth_getFuncStr(Depth::Function func);

// register the read and write functions with the osgDB::Registry.
RegisterDotOsgWrapperProxy g_DepthProxy
(
    new osg::Depth,
    "Depth",
    "Object StateAttribute Depth",
    &Depth_readLocalData,
    &Depth_writeLocalData
);

bool Depth_readLocalData(Object& obj, Input& fr)
{
    bool iteratorAdvanced = false;

    Depth& depth = static_cast<Depth&>(obj);

    Depth::Function func;
    if (fr[0].matchWord("function") && Depth_matchFuncStr(fr[1].getStr(),func))
    {
        depth.setFunction(func);
        fr+=2;
        iteratorAdvanced = true;
    }

    if (fr[0].matchWord("writeMask"))
    {
        if (fr[1].matchWord("TRUE") || fr[1].matchWord("ON"))
        {
            depth.setWriteMask(true);
            fr+=2;
            iteratorAdvanced = true;
        }
        else if (fr[1].matchWord("FALSE") || fr[1].matchWord("OFF"))
        {
            depth.setWriteMask(false);
            fr+=2;
            iteratorAdvanced = true;
        }
    }

    double znear,zfar;
    if (fr[0].matchWord("range") && fr[1].getDouble(znear) && fr[2].getDouble(zfar))
    {
        depth.setRange(znear,zfar);
        fr+=2;
        iteratorAdvanced = true;
    }

    return iteratorAdvanced;
}

bool Depth_writeLocalData(const Object& obj,Output& fw)
{
    const Depth& depth = static_cast<const Depth&>(obj);

    fw.indent() << "function " << Depth_getFuncStr(depth.getFunction()) << std::endl;

    fw.indent() << "writeMask ";
    if (depth.getWriteMask()) fw << "TRUE" << std::endl;
    else fw << "TRUE" << std::endl;

    fw.indent() << "range " << depth.getZNear() << " " << depth.getZFar() << std::endl;

    return true;
}

bool Depth_matchFuncStr(const char* str,Depth::Function& func)
{
    if (strcmp(str,"NEVER")==0) func = Depth::NEVER;
    else if (strcmp(str,"LESS")==0) func = Depth::LESS;
    else if (strcmp(str,"EQUAL")==0) func = Depth::EQUAL;
    else if (strcmp(str,"LEQUAL")==0) func = Depth::LEQUAL;
    else if (strcmp(str,"GREATER")==0) func = Depth::GREATER;
    else if (strcmp(str,"NOTEQUAL")==0) func = Depth::NOTEQUAL;
    else if (strcmp(str,"GEQUAL")==0) func = Depth::GEQUAL;
    else if (strcmp(str,"ALWAYS")==0) func = Depth::ALWAYS;
    else return false;
    return true;
}

const char* Depth_getFuncStr(Depth::Function func)
{
    switch(func)
    {
        case(Depth::NEVER): return "NEVER";
        case(Depth::LESS): return "LESS";
        case(Depth::EQUAL): return "EQUAL";
        case(Depth::LEQUAL): return "LEQUAL";
        case(Depth::GREATER): return "GREATER";
        case(Depth::NOTEQUAL): return "NOTEQUAL";
        case(Depth::GEQUAL): return "GEQUAL";
        case(Depth::ALWAYS): return "ALWAYS";
    }
    return "";
}
<commit_msg>Changed incorrect instance "TRUE" to "FALSE" to match DepthMask state.<commit_after>#include "osg/Depth"

#include "osgDB/Registry"
#include "osgDB/Input"
#include "osgDB/Output"

using namespace osg;
using namespace osgDB;

// forward declare functions to use later.
bool Depth_readLocalData(Object& obj, Input& fr);
bool Depth_writeLocalData(const Object& obj, Output& fw);

bool Depth_matchFuncStr(const char* str,Depth::Function& func);
const char* Depth_getFuncStr(Depth::Function func);

// register the read and write functions with the osgDB::Registry.
RegisterDotOsgWrapperProxy g_DepthProxy
(
    new osg::Depth,
    "Depth",
    "Object StateAttribute Depth",
    &Depth_readLocalData,
    &Depth_writeLocalData
);

bool Depth_readLocalData(Object& obj, Input& fr)
{
    bool iteratorAdvanced = false;

    Depth& depth = static_cast<Depth&>(obj);

    Depth::Function func;
    if (fr[0].matchWord("function") && Depth_matchFuncStr(fr[1].getStr(),func))
    {
        depth.setFunction(func);
        fr+=2;
        iteratorAdvanced = true;
    }

    if (fr[0].matchWord("writeMask"))
    {
        if (fr[1].matchWord("TRUE") || fr[1].matchWord("ON"))
        {
            depth.setWriteMask(true);
            fr+=2;
            iteratorAdvanced = true;
        }
        else if (fr[1].matchWord("FALSE") || fr[1].matchWord("OFF"))
        {
            depth.setWriteMask(false);
            fr+=2;
            iteratorAdvanced = true;
        }
    }

    double znear,zfar;
    if (fr[0].matchWord("range") && fr[1].getDouble(znear) && fr[2].getDouble(zfar))
    {
        depth.setRange(znear,zfar);
        fr+=2;
        iteratorAdvanced = true;
    }

    return iteratorAdvanced;
}

bool Depth_writeLocalData(const Object& obj,Output& fw)
{
    const Depth& depth = static_cast<const Depth&>(obj);

    fw.indent() << "function " << Depth_getFuncStr(depth.getFunction()) << std::endl;

    fw.indent() << "writeMask ";
    if (depth.getWriteMask()) fw << "TRUE" << std::endl;
    else fw << "FALSE" << std::endl;

    fw.indent() << "range " << depth.getZNear() << " " << depth.getZFar() << std::endl;

    return true;
}

bool Depth_matchFuncStr(const char* str,Depth::Function& func)
{
    if (strcmp(str,"NEVER")==0) func = Depth::NEVER;
    else if (strcmp(str,"LESS")==0) func = Depth::LESS;
    else if (strcmp(str,"EQUAL")==0) func = Depth::EQUAL;
    else if (strcmp(str,"LEQUAL")==0) func = Depth::LEQUAL;
    else if (strcmp(str,"GREATER")==0) func = Depth::GREATER;
    else if (strcmp(str,"NOTEQUAL")==0) func = Depth::NOTEQUAL;
    else if (strcmp(str,"GEQUAL")==0) func = Depth::GEQUAL;
    else if (strcmp(str,"ALWAYS")==0) func = Depth::ALWAYS;
    else return false;
    return true;
}

const char* Depth_getFuncStr(Depth::Function func)
{
    switch(func)
    {
        case(Depth::NEVER): return "NEVER";
        case(Depth::LESS): return "LESS";
        case(Depth::EQUAL): return "EQUAL";
        case(Depth::LEQUAL): return "LEQUAL";
        case(Depth::GREATER): return "GREATER";
        case(Depth::NOTEQUAL): return "NOTEQUAL";
        case(Depth::GEQUAL): return "GEQUAL";
        case(Depth::ALWAYS): return "ALWAYS";
    }
    return "";
}
<|endoftext|>


<commit_before><?hh //strict

/**
 * This file is part of hhpack\color.
 *
 * (c) Noritaka Horio <holy.shared.design@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace hhpack\color;

final class Color
{

    private Set<StyleType> $styles;

    public function __construct(
        private ForegroundColor $color = ForegroundColor::DefaultColor,
        private BackgroundColor $backgroundColor = BackgroundColor::DefaultColor
    )
    {
        $this->styles = Set {};
    }

    public function color(ForegroundColor $color) : this
    {
        $this->color = $color;
        return $this;
    }

    public function background(BackgroundColor $color) : this
    {
        $this->backgroundColor = $color;
        return $this;
    }

    public function addStyle(StyleType $style) : this
    {
        $this->styles->add($style);
        return $this;
    }

    public function removeStyle(StyleType $style) : this
    {
        $this->styles->remove($style);
        return $this;
    }

    public function println(string $format, ...) : void
    {
        $text = call_user_func_array([ $this, 'format' ], func_get_args());
        fwrite(STDOUT, $text . PHP_EOL);
    }

    public function display(string $format, ...) : void
    {
        $text = call_user_func_array([ $this, 'format' ], func_get_args());
        fwrite(STDOUT, $text);
    }

    public static function fromColor(ForegroundColor $color) : this
    {
        return new Color($color);
    }

    public static function fromBackground(BackgroundColor $color) : this
    {
        return new Color(ForegroundColor::DefaultColor, $color);
    }

    public static function fromDefault() : this
    {
        return new Color();
    }

    public function format(string $format, ...) : string
    {
        $parts = Set { $format };
        $parts->addAll( func_get_args() );

        $text = call_user_func_array('sprintf', $parts->toArray());

        return $this->applyTo($text);
    }

    public function applyTo(string $text) : string
    {
        $parts = Set {};
        $parts->add("\e[%s;%s;%sm%s\e[0m");

        if ($this->styles->isEmpty()) {
            $this->addStyle(StyleType::DefaultStyle);
        }

        $styles = $this->styles->toValuesArray();
        $styleText = implode(';', $styles);
        $parts->add($styleText);

        $parts->add((string) $this->color);
        $parts->add((string) $this->backgroundColor);
        $parts->add($text);

        return call_user_func_array('sprintf', $parts->toArray());
    }

}
<commit_msg>refactoring<commit_after><?hh //strict

/**
 * This file is part of hhpack\color.
 *
 * (c) Noritaka Horio <holy.shared.design@gmail.com>
 *
 * This source file is subject to the MIT license that is bundled
 * with this source code in the file LICENSE.
 */

namespace hhpack\color;

final class Color
{

    private Set<StyleType> $styles;

    public function __construct(
        private ForegroundColor $color = ForegroundColor::DefaultColor,
        private BackgroundColor $backgroundColor = BackgroundColor::DefaultColor
    )
    {
        $this->styles = Set {};
    }

    public function color(ForegroundColor $color) : this
    {
        $this->color = $color;
        return $this;
    }

    public function background(BackgroundColor $color) : this
    {
        $this->backgroundColor = $color;
        return $this;
    }

    public function addStyle(StyleType $style) : this
    {
        $this->styles->add($style);
        return $this;
    }

    public function removeStyle(StyleType $style) : this
    {
        $this->styles->remove($style);
        return $this;
    }

    public function println(string $format, ...) : void
    {
        $text = call_user_func_array([ $this, 'format' ], func_get_args());
        fwrite(STDOUT, $text . PHP_EOL);
    }

    public function display(string $format, ...) : void
    {
        $text = call_user_func_array([ $this, 'format' ], func_get_args());
        fwrite(STDOUT, $text);
    }

    public static function fromColor(ForegroundColor $color) : this
    {
        return new Color($color);
    }

    public static function fromBackground(BackgroundColor $color) : this
    {
        return new Color(ForegroundColor::DefaultColor, $color);
    }

    public static function fromDefault() : this
    {
        return new Color();
    }

    public function format(string $format, ...) : string
    {
        $parts = Set { $format };
        $parts->addAll( func_get_args() );

        $text = call_user_func_array('sprintf', $parts->toArray());

        return $this->applyTo($text);
    }

    public function applyTo(string $text) : string
    {
        $styles = Set {};

        if ($this->styles->isEmpty()) {
            $this->addStyle(StyleType::DefaultStyle);
        }

        $styles->addAll($this->styles);

        $styles->add((string) $this->color);
        $styles->add((string) $this->backgroundColor);

        $styleText = implode(';', $styles->toValuesArray());

        return sprintf("\e[%sm%s\e[0m", $styleText, $text);
    }

}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2013
 * Alessio Sclocco <a.sclocco@vu.nl>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <iostream>
#include <iomanip>
#include <fstream>
#include <cmath>
#include <cstring>
using std::cout;
using std::cerr;
using std::endl;
using std::fixed;
using std::setprecision;
using std::ofstream;
using std::ceil;
using std::pow;

#include <ArgumentList.hpp>
#include <InitializeOpenCL.hpp>
#include <CLData.hpp>
#include <Exceptions.hpp>
#include <Copy.hpp>
#include <utils.hpp>
using isa::utils::ArgumentList;
using isa::OpenCL::initializeOpenCL;
using isa::OpenCL::CLData;
using isa::Exceptions::OpenCLError;
using isa::Benchmarks::Copy;
using isa::utils::same;

const unsigned int nrIterations = 10;

int main(int argc, char * argv[]) {
	unsigned int oclPlatform = 0;
	unsigned int oclDevice = 0;
	unsigned int arrayDim = 0;
	unsigned int nrThreadsPerBlock = 0;
	unsigned int nrRows = 0;

	// Parse command line
	if ( argc != 11 ) {
		cerr << "Usage: " << argv[0] << " -opencl_platform <opencl_platform> -opencl_device <opencl_device> -n <dim> -t <threads_per_block> -r <rows>" << endl;
		return 1;
	}

	ArgumentList commandLine(argc, argv);
	try {
		oclPlatform = commandLine.getSwitchArgument< unsigned int >("-opencl_platform");
		oclDevice = commandLine.getSwitchArgument< unsigned int >("-opencl_device");
		arrayDim = commandLine.getSwitchArgument< unsigned int >("-n");
		nrThreadsPerBlock = commandLine.getSwitchArgument< unsigned int >("-t");
		nrRows = commandLine.getSwitchArgument< unsigned int >("-r");
	} catch ( exception & err ) {
		cerr << err.what() << endl;
		return 1;
	}

	// Initialize OpenCL
	vector< cl::Platform > * oclPlatforms = new vector< cl::Platform >();
	cl::Context * oclContext = new cl::Context();
	vector< cl::Device > * oclDevices = new vector< cl::Device >();
	vector< vector< cl::CommandQueue > > * oclQueues = new vector< vector< cl::CommandQueue > >();
	try {
		initializeOpenCL(oclPlatform, 1, oclPlatforms, oclContext, oclDevices, oclQueues);
	} catch ( OpenCLError err ) {
		cerr << err.what() << endl;
		return 1;
	}

	CLData< float > * A = new CLData< float >("A", true);
	CLData< float > * B = new CLData< float >("B", true);

	A->setCLContext(oclContext);
	A->setCLQueue(&(oclQueues->at(oclDevice)[0]));
	A->allocateHostData(arrayDim);
	B->setCLContext(oclContext);
	B->setCLQueue(&(oclQueues->at(oclDevice)[0]));
	B->allocateHostData(arrayDim);
	try {
		A->setDeviceWriteOnly();
		A->allocateDeviceData();
		B->setDeviceReadOnly();
		B->allocateDeviceData();
	} catch ( OpenCLError err ) {
		cerr << err.what() << endl;
		return 1;
	}

	Copy< float > copy = Copy< float >("float");
	try {
		copy.bindOpenCL(oclContext, &(oclDevices->at(oclDevice)), &(oclQueues->at(oclDevice)[0]));
		copy.setNrThreadsPerBlock(nrThreadsPerBlock);
		copy.setNrThreads(arrayDim);
		copy.setNrRows(nrRows);
		copy.generateCode();

		B->copyHostToDevice(true);
		copy(A,B);
		(copy.getTimer()).reset();
		for ( unsigned int iter = 0; iter < nrIterations; iter++ ) {
			copy(A, B);
		}
	} catch ( OpenCLError err ) {
		cerr << err.what() << endl;
		return 1;
	}

	cout << endl;
	cout << fixed << setprecision(3) << copy.getGB() / (copy.getTimer()).getAverageTime() << endl;
	cout << endl;

	return 0;
}
<commit_msg>Tuning the OpenCL copy benchmark.<commit_after>/*
 * Copyright (C) 2013
 * Alessio Sclocco <a.sclocco@vu.nl>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <iostream>
#include <iomanip>
#include <fstream>
#include <cmath>
#include <cstring>
using std::cout;
using std::cerr;
using std::endl;
using std::fixed;
using std::setprecision;
using std::ofstream;
using std::ceil;
using std::pow;

#include <ArgumentList.hpp>
#include <InitializeOpenCL.hpp>
#include <CLData.hpp>
#include <Exceptions.hpp>
#include <Copy.hpp>
#include <utils.hpp>
using isa::utils::ArgumentList;
using isa::OpenCL::initializeOpenCL;
using isa::OpenCL::CLData;
using isa::Exceptions::OpenCLError;
using isa::Benchmarks::Copy;
using isa::utils::same;

const unsigned int nrIterations = 10;

int main(int argc, char * argv[]) {
	unsigned int oclPlatform = 0;
	unsigned int oclDevice = 0;
	unsigned int arrayDim = 0;
	unsigned int maxThreads = 0;

	// Parse command line
	if ( argc != 7 ) {
		cerr << "Usage: " << argv[0] << " -opencl_platform <opencl_platform> -opencl_device <opencl_device> -m <max_threads>" << endl;
		return 1;
	}

	ArgumentList commandLine(argc, argv);
	try {
		oclPlatform = commandLine.getSwitchArgument< unsigned int >("-opencl_platform");
		oclDevice = commandLine.getSwitchArgument< unsigned int >("-opencl_device");
		maxThreads = commandLine.getSwitchArgument< unsigned int >("-max_threads");
	} catch ( exception & err ) {
		cerr << err.what() << endl;
		return 1;
	}

	// Initialize OpenCL
	vector< cl::Platform > * oclPlatforms = new vector< cl::Platform >();
	cl::Context * oclContext = new cl::Context();
	vector< cl::Device > * oclDevices = new vector< cl::Device >();
	vector< vector< cl::CommandQueue > > * oclQueues = new vector< vector< cl::CommandQueue > >();
	try {
		initializeOpenCL(oclPlatform, 1, oclPlatforms, oclContext, oclDevices, oclQueues);
	} catch ( OpenCLError err ) {
		cerr << err.what() << endl;
		return 1;
	}
	(oclDevices->at(oclDevices)).getInfo< unsigned int >(CL_DEVICE_MAX_MEM_ALLOC_SIZE, &arrayDim);
	arrayDim /= 4;

	CLData< float > * A = new CLData< float >("A", true);
	CLData< float > * B = new CLData< float >("B", true);

	A->setCLContext(oclContext);
	A->setCLQueue(&(oclQueues->at(oclDevice)[0]));
	A->allocateHostData(arrayDim);
	B->setCLContext(oclContext);
	B->setCLQueue(&(oclQueues->at(oclDevice)[0]));
	B->allocateHostData(arrayDim);
	try {
		A->setDeviceWriteOnly();
		A->allocateDeviceData();
		B->setDeviceWriteOnly();
		B->allocateDeviceData();
	} catch ( OpenCLError err ) {
		cerr << err.what() << endl;
		return 1;
	}

	cout << fixed << setprecision(3) << endl;
	for (unsigned int threads0 = 2; threads0 <= maxThreads; threads0 *= 2 ) {
		for (unsigned int threads1 = 1; threads1 <= 32; threads1++ ) {
			if ( (threads0 * threads1) > maxThreads ) {
				continue;
			}
			Copy< float > copy = Copy< float >("float");
			try {
				copy.bindOpenCL(oclContext, &(oclDevices->at(oclDevice)), &(oclQueues->at(oclDevice)[0]));
				copy.setNrThreads(arrayDim);
				copy.setNrThreadsPerBlock(threads0);
				copy.setNrRows(threads1);
				copy.generateCode();

				B->copyHostToDevice(true);
				copy(A,B);
				(copy.getTimer()).reset();
				for ( unsigned int iter = 0; iter < nrIterations; iter++ ) {
					copy(A, B);
				}
			} catch ( OpenCLError err ) {
				cerr << err.what() << endl;
				return 1;
			}

			cout << threads0 << " " << threads1 << " " << copy.getGB() / (copy.getTimer()).getAverageTime() << endl;

		}
	}
	cout << endl;

	return 0;
}
<|endoftext|>


<commit_before>// The libMesh Finite Element Library.
// Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// 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

// System Includes
#include <algorithm>
#include <iostream>

// Local Includes
#include "libmesh/libmesh_common.h"
#include "libmesh/parallel.h"
#include "libmesh/parallel_hilbert.h"
#include "libmesh/parallel_sort.h"
#include "libmesh/parallel_bin_sorter.h"
#ifdef LIBMESH_HAVE_LIBHILBERT
#  include "hilbert.h"
#endif

namespace libMesh
{

namespace Parallel {

// The Constructor sorts the local data using
// std::sort().  Therefore, the construction of
// a Parallel::Sort object takes O(nlogn) time,
// where n is the length of _data.
template <typename KeyType, typename IdxType>
Sort<KeyType,IdxType>::Sort(const Parallel::Communicator &comm_in,
                            std::vector<KeyType>& d) :
  ParallelObject(comm_in),
  _n_procs(cast_int<processor_id_type>(comm_in.size())),
  _proc_id(cast_int<processor_id_type>(comm_in.rank())),
  _bin_is_sorted(false),
  _data(d)
{
  std::sort(_data.begin(), _data.end());

  // Allocate storage
  _local_bin_sizes.resize(_n_procs);
}

template <typename KeyType, typename IdxType>
void Sort<KeyType,IdxType>::sort()
{
  // Find the global data size.  The sorting
  // algorithms assume they have a range to
  // work with, so catch the degenerate cases here
  IdxType global_data_size = cast_int<IdxType>(_data.size());

  this->comm().sum (global_data_size);

  if (global_data_size < 2)
    {
      // the entire global range is either empty
      // or contains only one element
      _my_bin = _data;

      this->comm().allgather (static_cast<IdxType>(_my_bin.size()),
                              _local_bin_sizes);
    }
  else
    {
      if (this->n_processors() > 1)
        {
          this->binsort();
          this->communicate_bins();
        }
      else
        _my_bin = _data;

      this->sort_local_bin();
    }

  // Set sorted flag to true
  _bin_is_sorted = true;
}

template <typename KeyType, typename IdxType>
void Sort<KeyType,IdxType>::binsort()
{
  // Find the global min and max from all the
  // processors.
  std::vector<KeyType> global_min_max(2);

  // Insert the local min and max for this processor
  global_min_max[0] = -_data.front();
  global_min_max[1] =  _data.back();

  // Communicate to determine the global
  // min and max for all processors.
  this->comm().max(global_min_max);

  // Multiply the min by -1 to obtain the true min
  global_min_max[0] *= -1;

  // Bin-Sort based on the global min and max
  Parallel::BinSorter<KeyType> bs(this->comm(), _data);
  bs.binsort(_n_procs, global_min_max[1], global_min_max[0]);

  // Now save the local bin sizes in a vector so
  // we don't have to keep around the BinSorter.
  for (processor_id_type i=0; i<_n_procs; ++i)
    _local_bin_sizes[i] = bs.sizeof_bin(i);
}

#if defined(LIBMESH_HAVE_LIBHILBERT) && defined(LIBMESH_HAVE_MPI)
// Full specialization for HilbertIndices, there is a fair amount of
// code duplication here that could potentially be consolidated with the
// above method
template <>
void Sort<Hilbert::HilbertIndices,unsigned int>::binsort()
{
  // Find the global min and max from all the
  // processors.  Do this using MPI_Allreduce.
  Hilbert::HilbertIndices
    local_min,  local_max,
    global_min, global_max;

  if (_data.empty())
    {
      local_min.rack0 = local_min.rack1 = local_min.rack2 = static_cast<Hilbert::inttype>(-1);
      local_max.rack0 = local_max.rack1 = local_max.rack2 = 0;
    }
  else
    {
      local_min = _data.front();
      local_max = _data.back();
    }

  MPI_Op hilbert_max, hilbert_min;

  MPI_Op_create       ((MPI_User_function*)__hilbert_max_op, true, &hilbert_max);
  MPI_Op_create       ((MPI_User_function*)__hilbert_min_op, true, &hilbert_min);

  // Communicate to determine the global
  // min and max for all processors.
  MPI_Allreduce(&local_min,
                &global_min,
                1,
                Parallel::StandardType<Hilbert::HilbertIndices>(),
                hilbert_min,
                this->comm().get());

  MPI_Allreduce(&local_max,
                &global_max,
                1,
                Parallel::StandardType<Hilbert::HilbertIndices>(),
                hilbert_max,
                this->comm().get());

  MPI_Op_free   (&hilbert_max);
  MPI_Op_free   (&hilbert_min);

  // Bin-Sort based on the global min and max
  Parallel::BinSorter<Hilbert::HilbertIndices> bs(this->comm(),_data);
  bs.binsort(_n_procs, global_max, global_min);

  // Now save the local bin sizes in a vector so
  // we don't have to keep around the BinSorter.
  for (processor_id_type i=0; i<_n_procs; ++i)
    _local_bin_sizes[i] = bs.sizeof_bin(i);
}

#endif // #ifdef LIBMESH_HAVE_LIBHILBERT

template <typename KeyType, typename IdxType>
void Sort<KeyType,IdxType>::communicate_bins()
{
#ifdef LIBMESH_HAVE_MPI
  // Create storage for the global bin sizes.  This
  // is the number of keys which will be held in
  // each bin over all processors.
  std::vector<IdxType> global_bin_sizes = _local_bin_sizes;

  // Sum to find the total number of entries in each bin.
  this->comm().sum(global_bin_sizes);

  // Create a vector to temporarily hold the results of MPI_Gatherv
  // calls.  The vector dest  may be saved away to _my_bin depending on which
  // processor is being MPI_Gatherv'd.
  std::vector<KeyType> dest;

  IdxType local_offset = 0;

  for (processor_id_type i=0; i<_n_procs; ++i)
    {
      // Vector to receive the total bin size for each
      // processor.  Processor i's bin size will be
      // held in proc_bin_size[i]
      std::vector<IdxType> proc_bin_size;

      // Find the number of contributions coming from each
      // processor for this bin.  Note: allgather combines
      // the MPI_Gather and MPI_Bcast operations into one.
      this->comm().allgather(_local_bin_sizes[i], proc_bin_size);

      // Compute the offsets into my_bin for each processor's
      // portion of the bin.  These are basically partial sums
      // of the proc_bin_size vector.
      std::vector<IdxType> displacements(_n_procs);
      for (processor_id_type j=1; j<_n_procs; ++j)
        displacements[j] = proc_bin_size[j-1] + displacements[j-1];

      // Resize the destination buffer
      dest.resize (global_bin_sizes[i]);

      MPI_Gatherv((_data.size() > local_offset) ?
                  &_data[local_offset] :
                  NULL,                            // Points to the beginning of the bin to be sent
                  _local_bin_sizes[i],               // How much data is in the bin being sent.
                  Parallel::StandardType<KeyType>(), // The data type we are sorting
                  (dest.empty()) ?
                  NULL :
                  &dest[0],                        // Enough storage to hold all bin contributions
                  (int*) &proc_bin_size[0],          // How much is to be received from each processor
                  (int*) &displacements[0],          // Offsets into the receive buffer
                  Parallel::StandardType<KeyType>(), // The data type we are sorting
                  i,                                 // The root process (we do this once for each proc)
                  this->comm().get());

      // Copy the destination buffer if it
      // corresponds to the bin for this processor
      if (i == _proc_id)
        _my_bin = dest;

      // Increment the local offset counter
      local_offset += _local_bin_sizes[i];
    }
#endif // LIBMESH_HAVE_MPI
}

#if defined(LIBMESH_HAVE_LIBHILBERT) && defined(LIBMESH_HAVE_MPI)
// Full specialization for HilbertIndices, there is a fair amount of
// code duplication here that could potentially be consolidated with the
// above method
template <>
void Sort<Hilbert::HilbertIndices,unsigned int>::communicate_bins()
{
  // Create storage for the global bin sizes.  This
  // is the number of keys which will be held in
  // each bin over all processors.
  std::vector<unsigned int> global_bin_sizes(_n_procs);

  libmesh_assert_equal_to (_local_bin_sizes.size(), global_bin_sizes.size());

  // Sum to find the total number of entries in each bin.
  // This is stored in global_bin_sizes.  Note, we
  // explicitly know that we are communicating MPI_UNSIGNED's here.
  MPI_Allreduce(&_local_bin_sizes[0],
                &global_bin_sizes[0],
                _n_procs,
                MPI_UNSIGNED,
                MPI_SUM,
                this->comm().get());

  // Create a vector to temporarily hold the results of MPI_Gatherv
  // calls.  The vector dest  may be saved away to _my_bin depending on which
  // processor is being MPI_Gatherv'd.
  std::vector<Hilbert::HilbertIndices> dest;

  unsigned int local_offset = 0;

  for (unsigned int i=0; i<_n_procs; ++i)
    {
      // Vector to receive the total bin size for each
      // processor.  Processor i's bin size will be
      // held in proc_bin_size[i]
      std::vector<unsigned int> proc_bin_size(_n_procs);

      // Find the number of contributions coming from each
      // processor for this bin.  Note: Allgather combines
      // the MPI_Gather and MPI_Bcast operations into one.
      // Note: Here again we know that we are communicating
      // MPI_UNSIGNED's so there is no need to check the MPI_traits.
      MPI_Allgather(&_local_bin_sizes[i], // Source: # of entries on this proc in bin i
                    1,                    // Number of items to gather
                    MPI_UNSIGNED,
                    &proc_bin_size[0],    // Destination: Total # of entries in bin i
                    1,
                    MPI_UNSIGNED,
                    this->comm().get());

      // Compute the offsets into my_bin for each processor's
      // portion of the bin.  These are basically partial sums
      // of the proc_bin_size vector.
      std::vector<unsigned int> displacements(_n_procs);
      for (unsigned int j=1; j<_n_procs; ++j)
        displacements[j] = proc_bin_size[j-1] + displacements[j-1];

      // Resize the destination buffer
      dest.resize (global_bin_sizes[i]);

      MPI_Gatherv((_data.size() > local_offset) ?
                  &_data[local_offset] :
                  NULL,                   // Points to the beginning of the bin to be sent
                  _local_bin_sizes[i],      // How much data is in the bin being sent.
                  Parallel::StandardType<Hilbert::HilbertIndices>(), // The data type we are sorting
                  (dest.empty()) ?
                  NULL :
                  &dest[0],               // Enough storage to hold all bin contributions
                  (int*) &proc_bin_size[0], // How much is to be received from each processor
                  (int*) &displacements[0], // Offsets into the receive buffer
                  Parallel::StandardType<Hilbert::HilbertIndices>(), // The data type we are sorting
                  i,                        // The root process (we do this once for each proc)
                  this->comm().get());

      // Copy the destination buffer if it
      // corresponds to the bin for this processor
      if (i == _proc_id)
        _my_bin = dest;

      // Increment the local offset counter
      local_offset += _local_bin_sizes[i];
    }
}

#endif // #if defined(LIBMESH_HAVE_LIBHILBERT) && defined(LIBMESH_HAVE_MPI)

template <typename KeyType, typename IdxType>
void Sort<KeyType,IdxType>::sort_local_bin()
{
  std::sort(_my_bin.begin(), _my_bin.end());
}

template <typename KeyType, typename IdxType>
const std::vector<KeyType>& Sort<KeyType,IdxType>::bin()
{
  if (!_bin_is_sorted)
    {
      libMesh::out << "Warning! Bin is not yet sorted!" << std::endl;
    }

  return _my_bin;
}

}

// Explicitly instantiate for int, double
template class Parallel::Sort<int, unsigned int>;
template class Parallel::Sort<double, unsigned int>;
#if defined(LIBMESH_HAVE_LIBHILBERT) && defined(LIBMESH_HAVE_MPI)
template class Parallel::Sort<Hilbert::HilbertIndices, unsigned int>;
#endif

} // namespace libMesh
<commit_msg>MPI expects a vector of ints, let's give it one instead of casting.<commit_after>// The libMesh Finite Element Library.
// Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner

// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.

// 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

// System Includes
#include <algorithm>
#include <iostream>

// Local Includes
#include "libmesh/libmesh_common.h"
#include "libmesh/parallel.h"
#include "libmesh/parallel_hilbert.h"
#include "libmesh/parallel_sort.h"
#include "libmesh/parallel_bin_sorter.h"
#ifdef LIBMESH_HAVE_LIBHILBERT
#  include "hilbert.h"
#endif

namespace libMesh
{

namespace Parallel {

// The Constructor sorts the local data using
// std::sort().  Therefore, the construction of
// a Parallel::Sort object takes O(nlogn) time,
// where n is the length of _data.
template <typename KeyType, typename IdxType>
Sort<KeyType,IdxType>::Sort(const Parallel::Communicator &comm_in,
                            std::vector<KeyType>& d) :
  ParallelObject(comm_in),
  _n_procs(cast_int<processor_id_type>(comm_in.size())),
  _proc_id(cast_int<processor_id_type>(comm_in.rank())),
  _bin_is_sorted(false),
  _data(d)
{
  std::sort(_data.begin(), _data.end());

  // Allocate storage
  _local_bin_sizes.resize(_n_procs);
}

template <typename KeyType, typename IdxType>
void Sort<KeyType,IdxType>::sort()
{
  // Find the global data size.  The sorting
  // algorithms assume they have a range to
  // work with, so catch the degenerate cases here
  IdxType global_data_size = cast_int<IdxType>(_data.size());

  this->comm().sum (global_data_size);

  if (global_data_size < 2)
    {
      // the entire global range is either empty
      // or contains only one element
      _my_bin = _data;

      this->comm().allgather (static_cast<IdxType>(_my_bin.size()),
                              _local_bin_sizes);
    }
  else
    {
      if (this->n_processors() > 1)
        {
          this->binsort();
          this->communicate_bins();
        }
      else
        _my_bin = _data;

      this->sort_local_bin();
    }

  // Set sorted flag to true
  _bin_is_sorted = true;
}

template <typename KeyType, typename IdxType>
void Sort<KeyType,IdxType>::binsort()
{
  // Find the global min and max from all the
  // processors.
  std::vector<KeyType> global_min_max(2);

  // Insert the local min and max for this processor
  global_min_max[0] = -_data.front();
  global_min_max[1] =  _data.back();

  // Communicate to determine the global
  // min and max for all processors.
  this->comm().max(global_min_max);

  // Multiply the min by -1 to obtain the true min
  global_min_max[0] *= -1;

  // Bin-Sort based on the global min and max
  Parallel::BinSorter<KeyType> bs(this->comm(), _data);
  bs.binsort(_n_procs, global_min_max[1], global_min_max[0]);

  // Now save the local bin sizes in a vector so
  // we don't have to keep around the BinSorter.
  for (processor_id_type i=0; i<_n_procs; ++i)
    _local_bin_sizes[i] = bs.sizeof_bin(i);
}

#if defined(LIBMESH_HAVE_LIBHILBERT) && defined(LIBMESH_HAVE_MPI)
// Full specialization for HilbertIndices, there is a fair amount of
// code duplication here that could potentially be consolidated with the
// above method
template <>
void Sort<Hilbert::HilbertIndices,unsigned int>::binsort()
{
  // Find the global min and max from all the
  // processors.  Do this using MPI_Allreduce.
  Hilbert::HilbertIndices
    local_min,  local_max,
    global_min, global_max;

  if (_data.empty())
    {
      local_min.rack0 = local_min.rack1 = local_min.rack2 = static_cast<Hilbert::inttype>(-1);
      local_max.rack0 = local_max.rack1 = local_max.rack2 = 0;
    }
  else
    {
      local_min = _data.front();
      local_max = _data.back();
    }

  MPI_Op hilbert_max, hilbert_min;

  MPI_Op_create       ((MPI_User_function*)__hilbert_max_op, true, &hilbert_max);
  MPI_Op_create       ((MPI_User_function*)__hilbert_min_op, true, &hilbert_min);

  // Communicate to determine the global
  // min and max for all processors.
  MPI_Allreduce(&local_min,
                &global_min,
                1,
                Parallel::StandardType<Hilbert::HilbertIndices>(),
                hilbert_min,
                this->comm().get());

  MPI_Allreduce(&local_max,
                &global_max,
                1,
                Parallel::StandardType<Hilbert::HilbertIndices>(),
                hilbert_max,
                this->comm().get());

  MPI_Op_free   (&hilbert_max);
  MPI_Op_free   (&hilbert_min);

  // Bin-Sort based on the global min and max
  Parallel::BinSorter<Hilbert::HilbertIndices> bs(this->comm(),_data);
  bs.binsort(_n_procs, global_max, global_min);

  // Now save the local bin sizes in a vector so
  // we don't have to keep around the BinSorter.
  for (processor_id_type i=0; i<_n_procs; ++i)
    _local_bin_sizes[i] = bs.sizeof_bin(i);
}

#endif // #ifdef LIBMESH_HAVE_LIBHILBERT

template <typename KeyType, typename IdxType>
void Sort<KeyType,IdxType>::communicate_bins()
{
#ifdef LIBMESH_HAVE_MPI
  // Create storage for the global bin sizes.  This
  // is the number of keys which will be held in
  // each bin over all processors.
  std::vector<IdxType> global_bin_sizes = _local_bin_sizes;

  // Sum to find the total number of entries in each bin.
  this->comm().sum(global_bin_sizes);

  // Create a vector to temporarily hold the results of MPI_Gatherv
  // calls.  The vector dest  may be saved away to _my_bin depending on which
  // processor is being MPI_Gatherv'd.
  std::vector<KeyType> dest;

  IdxType local_offset = 0;

  for (processor_id_type i=0; i<_n_procs; ++i)
    {
      // Vector to receive the total bin size for each
      // processor.  Processor i's bin size will be
      // held in proc_bin_size[i]
      std::vector<IdxType> proc_bin_size;

      // Find the number of contributions coming from each
      // processor for this bin.  Note: allgather combines
      // the MPI_Gather and MPI_Bcast operations into one.
      this->comm().allgather(_local_bin_sizes[i], proc_bin_size);

      // Compute the offsets into my_bin for each processor's
      // portion of the bin.  These are basically partial sums
      // of the proc_bin_size vector.
      std::vector<int> displacements(_n_procs);
      for (processor_id_type j=1; j<_n_procs; ++j)
        displacements[j] = proc_bin_size[j-1] + displacements[j-1];

      // Resize the destination buffer
      dest.resize (global_bin_sizes[i]);

      MPI_Gatherv((_data.size() > local_offset) ?
                  &_data[local_offset] :
                  NULL,                            // Points to the beginning of the bin to be sent
                  _local_bin_sizes[i],               // How much data is in the bin being sent.
                  Parallel::StandardType<KeyType>(), // The data type we are sorting
                  (dest.empty()) ?
                  NULL :
                  &dest[0],                        // Enough storage to hold all bin contributions
                  (int*) &proc_bin_size[0],          // How much is to be received from each processor
                  &displacements[0],          // Offsets into the receive buffer
                  Parallel::StandardType<KeyType>(), // The data type we are sorting
                  i,                                 // The root process (we do this once for each proc)
                  this->comm().get());

      // Copy the destination buffer if it
      // corresponds to the bin for this processor
      if (i == _proc_id)
        _my_bin = dest;

      // Increment the local offset counter
      local_offset += _local_bin_sizes[i];
    }
#endif // LIBMESH_HAVE_MPI
}

#if defined(LIBMESH_HAVE_LIBHILBERT) && defined(LIBMESH_HAVE_MPI)
// Full specialization for HilbertIndices, there is a fair amount of
// code duplication here that could potentially be consolidated with the
// above method
template <>
void Sort<Hilbert::HilbertIndices,unsigned int>::communicate_bins()
{
  // Create storage for the global bin sizes.  This
  // is the number of keys which will be held in
  // each bin over all processors.
  std::vector<unsigned int> global_bin_sizes(_n_procs);

  libmesh_assert_equal_to (_local_bin_sizes.size(), global_bin_sizes.size());

  // Sum to find the total number of entries in each bin.
  // This is stored in global_bin_sizes.  Note, we
  // explicitly know that we are communicating MPI_UNSIGNED's here.
  MPI_Allreduce(&_local_bin_sizes[0],
                &global_bin_sizes[0],
                _n_procs,
                MPI_UNSIGNED,
                MPI_SUM,
                this->comm().get());

  // Create a vector to temporarily hold the results of MPI_Gatherv
  // calls.  The vector dest  may be saved away to _my_bin depending on which
  // processor is being MPI_Gatherv'd.
  std::vector<Hilbert::HilbertIndices> dest;

  unsigned int local_offset = 0;

  for (unsigned int i=0; i<_n_procs; ++i)
    {
      // Vector to receive the total bin size for each
      // processor.  Processor i's bin size will be
      // held in proc_bin_size[i]
      std::vector<unsigned int> proc_bin_size(_n_procs);

      // Find the number of contributions coming from each
      // processor for this bin.  Note: Allgather combines
      // the MPI_Gather and MPI_Bcast operations into one.
      // Note: Here again we know that we are communicating
      // MPI_UNSIGNED's so there is no need to check the MPI_traits.
      MPI_Allgather(&_local_bin_sizes[i], // Source: # of entries on this proc in bin i
                    1,                    // Number of items to gather
                    MPI_UNSIGNED,
                    &proc_bin_size[0],    // Destination: Total # of entries in bin i
                    1,
                    MPI_UNSIGNED,
                    this->comm().get());

      // Compute the offsets into my_bin for each processor's
      // portion of the bin.  These are basically partial sums
      // of the proc_bin_size vector.
      std::vector<int> displacements(_n_procs);
      for (unsigned int j=1; j<_n_procs; ++j)
        displacements[j] = proc_bin_size[j-1] + displacements[j-1];

      // Resize the destination buffer
      dest.resize (global_bin_sizes[i]);

      MPI_Gatherv((_data.size() > local_offset) ?
                  &_data[local_offset] :
                  NULL,                   // Points to the beginning of the bin to be sent
                  _local_bin_sizes[i],      // How much data is in the bin being sent.
                  Parallel::StandardType<Hilbert::HilbertIndices>(), // The data type we are sorting
                  (dest.empty()) ?
                  NULL :
                  &dest[0],               // Enough storage to hold all bin contributions
                  (int*) &proc_bin_size[0], // How much is to be received from each processor
                  &displacements[0], // Offsets into the receive buffer
                  Parallel::StandardType<Hilbert::HilbertIndices>(), // The data type we are sorting
                  i,                        // The root process (we do this once for each proc)
                  this->comm().get());

      // Copy the destination buffer if it
      // corresponds to the bin for this processor
      if (i == _proc_id)
        _my_bin = dest;

      // Increment the local offset counter
      local_offset += _local_bin_sizes[i];
    }
}

#endif // #if defined(LIBMESH_HAVE_LIBHILBERT) && defined(LIBMESH_HAVE_MPI)

template <typename KeyType, typename IdxType>
void Sort<KeyType,IdxType>::sort_local_bin()
{
  std::sort(_my_bin.begin(), _my_bin.end());
}

template <typename KeyType, typename IdxType>
const std::vector<KeyType>& Sort<KeyType,IdxType>::bin()
{
  if (!_bin_is_sorted)
    {
      libMesh::out << "Warning! Bin is not yet sorted!" << std::endl;
    }

  return _my_bin;
}

}

// Explicitly instantiate for int, double
template class Parallel::Sort<int, unsigned int>;
template class Parallel::Sort<double, unsigned int>;
#if defined(LIBMESH_HAVE_LIBHILBERT) && defined(LIBMESH_HAVE_MPI)
template class Parallel::Sort<Hilbert::HilbertIndices, unsigned int>;
#endif

} // namespace libMesh
<|endoftext|>


<commit_before>#include "detail/Threadpool.hh"

namespace Task {
namespace Detail {

Threadpool::Threadpool(size_t threadCount) {
  _workers.reserve(threadCount);
  for (size_t i = 0; i < threadCount; ++i) {
    _workers.emplace_back([this] { this->processTasks(); });
  }
}

Threadpool::~Threadpool() {
  _stopRequested = true;
  _cv.notify_all();
  for (auto& worker : _workers) {
    worker.join();
  }
}

void Threadpool::schedule(TimedTask task) {
  {
    std::lock_guard<std::mutex> guard(_mutex);

    _tasks.push(std::move(task));
  }
  _cv.notify_one();
}

void Threadpool::processTasks() {
  while (!_stopRequested) {
    std::unique_lock<std::mutex> lock(_mutex);
    auto timeout = Clock::now() + std::chrono::hours(1);
    bool taskReady = false;

    while (!taskReady) {
      // The condvar can be unblocked by calling notify_xxx to signal that a new task has been added.
      // We should update the timeout if the new task has a higher priority.
      if (!_tasks.empty()) {
        timeout = _tasks.top().timepoint();
      }
      taskReady = _cv.wait_until(lock, timeout, [this] { //
        return !_tasks.empty() || _stopRequested;
      });
      if (_stopRequested) {
        return;
      }
      // This is done to avoid executing the most recent task when another one gets added.
      // Still, it is necessary to wake up the thread in order to update the timeout.
      // The container's size needs to be checked as the condvar is not garanted to obtain the lock first.
      if (_tasks.empty() || _tasks.top().timepoint() > Clock::now()) {
        taskReady = false;
      }
    }

    auto task = _tasks.top();
    _tasks.pop();

    lock.unlock();
    task();
  }
}

} /* namespace Detail */
} /* namespace Task */
<commit_msg>develop #comment Check that threads are joinable before joning them.<commit_after>#include "detail/Threadpool.hh"

namespace Task {
namespace Detail {

Threadpool::Threadpool(size_t threadCount) {
  _workers.reserve(threadCount);
  for (size_t i = 0; i < threadCount; ++i) {
    _workers.emplace_back(&Threadpool::processTasks, this);
  }
}

Threadpool::~Threadpool() {
  _stopRequested = true;
  _cv.notify_all();
  for (auto& worker : _workers) {
    if (worker.joinable()) {
      worker.join();
    }
  }
}

void Threadpool::schedule(TimedTask task) {
  {
    std::lock_guard<std::mutex> guard(_mutex);

    _tasks.push(std::move(task));
  }
  _cv.notify_one();
}

void Threadpool::processTasks() {
  while (!_stopRequested) {
    std::unique_lock<std::mutex> lock(_mutex);
    auto timeout = Clock::now() + std::chrono::hours(1);
    bool taskReady = false;

    while (!taskReady) {
      // The condvar can be unblocked by calling notify_xxx to signal that a new task has been added.
      // We should update the timeout if the new task has a higher priority.
      if (!_tasks.empty()) {
        timeout = _tasks.top().timepoint();
      }
      taskReady = _cv.wait_until(lock, timeout, [this] { //
        return !_tasks.empty() || _stopRequested;
      });
      if (_stopRequested) {
        return;
      }
      // This is done to avoid executing the most recent task when another one gets added.
      // Still, it is necessary to wake up the thread in order to update the timeout.
      // The container's size needs to be checked as the condvar is not garanted to obtain the lock first.
      if (_tasks.empty() || _tasks.top().timepoint() > Clock::now()) {
        taskReady = false;
      }
    }

    auto task = _tasks.top();
    _tasks.pop();

    lock.unlock();
    task();
  }
}

} /* namespace Detail */
} /* namespace Task */
<|endoftext|>


<commit_before>// This file is part of UDPipe <http://github.com/ufal/udpipe/>.
//
// Copyright 2015 Institute of Formal and Applied Linguistics, Faculty of
// Mathematics and Physics, Charles University in Prague, Czech Republic.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "pipeline.h"
#include "sentence/input_format.h"

namespace ufal {
namespace udpipe {

pipeline::pipeline(const model* m, const string& tokenizer, const string& tagger, const string& parser)
    : m(m), tokenizer(tokenizer), tagger(tagger), parser(parser), conllu_output(output_format::new_conllu_output_format()) {}

void pipeline::set_model(const model* m) {
  this->m = m;
}

void pipeline::set_tokenizer(const string& tokenizer) {
  this->tokenizer = tokenizer;
}

void pipeline::set_tagger(const string& tagger) {
  this->tagger = tagger;
}

void pipeline::set_parser(const string& parser) {
  this->parser = parser;
}

bool pipeline::process(const string& input, ostream& os, string& error) const {
  error.clear();

  sentence s;

  unique_ptr<ufal::udpipe::tokenizer> t;
  unique_ptr<input_format> conllu_input;
  if (tokenizer != "none") {
    t.reset(m->new_tokenizer(tokenizer));
    if (!t) return error.assign("Cannot allocate new tokenizer!"), false;
    t->set_text(input);
  } else {
    conllu_input.reset(input_format::new_conllu_input_format());
    if (!conllu_input) return error.assign("Cannot allocate CoNLL-U input format instance!"), false;
    conllu_input->set_text(input);
  }

  while (t ? t->next_sentence(s, error) : conllu_input->next_sentence(s, error)) {
    if (tagger != "none")
      if (!m->tag(s, tagger, error))
        return false;

    if (parser != "none")
      if (!m->parse(s, parser, error))
        return false;

    conllu_output->write_sentence(s, os);
  }
  if (!error.empty()) return false;

  return true;
}

bool pipeline::evaluate(const string& input, ostream& os, string& error) const {
  error.clear();

  sentence system, gold;

  unique_ptr<ufal::udpipe::tokenizer> t;
  unique_ptr<input_format> conllu_input;
  if (tokenizer != "none") {
    t.reset(m->new_tokenizer(tokenizer));
    if (!t) return error.assign("Cannot allocate new tokenizer!"), false;
    t->set_text(input);
  } else {
    conllu_input.reset(input_format::new_conllu_input_format());
    if (!conllu_input) return error.assign("Cannot allocate CoNLL-U input format instance!"), false;
    conllu_input->set_text(input);
  }

  int words = 0, upostag = 0, xpostag = 0, feats = 0, all_tags = 0, lemma = 0;
  int punct = 0, punct_uas = 0, punct_las = 0, nopunct = 0, nopunct_uas = 0, nopunct_las = 0;
  while (t ? t->next_sentence(gold, error) : conllu_input->next_sentence(gold, error)) {
    // Create empty copy
    system.clear();
    for (size_t i = 1; i < gold.words.size(); i++)
      system.add_word(gold.words[i].form);

    if (tagger != "none") {
      if (!m->tag(system, tagger, error))
        return false;
      for (size_t i = 1; i < gold.words.size(); i++) {
        words++;
        upostag += gold.words[i].upostag == system.words[i].upostag;
        xpostag += gold.words[i].xpostag == system.words[i].xpostag;
        feats += gold.words[i].feats == system.words[i].feats;
        all_tags += gold.words[i].upostag == system.words[i].upostag && gold.words[i].xpostag == system.words[i].xpostag && gold.words[i].feats == system.words[i].feats;
        lemma += gold.words[i].lemma == system.words[i].lemma;
      }
    } else {
      for (size_t i = 1; i < gold.words.size(); i++) {
        system.words[i].upostag = gold.words[i].upostag;
        system.words[i].xpostag = gold.words[i].xpostag;
        system.words[i].feats = gold.words[i].feats;
        system.words[i].lemma = gold.words[i].lemma;
      }
    }

    if (parser != "none") {
      if (!m->parse(system, parser, error))
        return false;
      for (size_t i = 1; i < gold.words.size(); i++) {
        punct++;
        punct_uas += gold.words[i].head == system.words[i].head;
        punct_las += gold.words[i].head == system.words[i].head && gold.words[i].deprel == system.words[i].deprel;
        if (gold.words[i].upostag != "PUNCT") {
          nopunct++;
          nopunct_uas += gold.words[i].head == system.words[i].head;
          nopunct_las += gold.words[i].head == system.words[i].head && gold.words[i].deprel == system.words[i].deprel;
        }
      }
    }
  }
  if (!error.empty()) return false;

  if (tagger != "none")
    os << "Tagging - forms: " << words << ", upostag: " << fixed << setprecision(2) << 100. * upostag / words << "%, xpostag: " << 100. * xpostag / words
       << "%, feats: " << 100. * feats / words << "%, all tags: " << 100. * all_tags / words << "%, lemma: " << 100. * lemma / words << '%' << endl;
  if (parser != "none")
    os << "Parsing - UAS: " << 100. * punct_uas / punct << "%, LAS: " << 100. * punct_las / punct << "%, "
       << "without punctuation - UAS: " << 100. * nopunct_uas / nopunct << "%, LAS: " << 100. * nopunct_las / nopunct << '%' << endl;

  return true;
}

} // namespace udpipe
} // namespace ufal
<commit_msg>Set number format when printing parsing accuracy too.<commit_after>// This file is part of UDPipe <http://github.com/ufal/udpipe/>.
//
// Copyright 2015 Institute of Formal and Applied Linguistics, Faculty of
// Mathematics and Physics, Charles University in Prague, Czech Republic.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

#include "pipeline.h"
#include "sentence/input_format.h"

namespace ufal {
namespace udpipe {

pipeline::pipeline(const model* m, const string& tokenizer, const string& tagger, const string& parser)
    : m(m), tokenizer(tokenizer), tagger(tagger), parser(parser), conllu_output(output_format::new_conllu_output_format()) {}

void pipeline::set_model(const model* m) {
  this->m = m;
}

void pipeline::set_tokenizer(const string& tokenizer) {
  this->tokenizer = tokenizer;
}

void pipeline::set_tagger(const string& tagger) {
  this->tagger = tagger;
}

void pipeline::set_parser(const string& parser) {
  this->parser = parser;
}

bool pipeline::process(const string& input, ostream& os, string& error) const {
  error.clear();

  sentence s;

  unique_ptr<ufal::udpipe::tokenizer> t;
  unique_ptr<input_format> conllu_input;
  if (tokenizer != "none") {
    t.reset(m->new_tokenizer(tokenizer));
    if (!t) return error.assign("Cannot allocate new tokenizer!"), false;
    t->set_text(input);
  } else {
    conllu_input.reset(input_format::new_conllu_input_format());
    if (!conllu_input) return error.assign("Cannot allocate CoNLL-U input format instance!"), false;
    conllu_input->set_text(input);
  }

  while (t ? t->next_sentence(s, error) : conllu_input->next_sentence(s, error)) {
    if (tagger != "none")
      if (!m->tag(s, tagger, error))
        return false;

    if (parser != "none")
      if (!m->parse(s, parser, error))
        return false;

    conllu_output->write_sentence(s, os);
  }
  if (!error.empty()) return false;

  return true;
}

bool pipeline::evaluate(const string& input, ostream& os, string& error) const {
  error.clear();

  sentence system, gold;

  unique_ptr<ufal::udpipe::tokenizer> t;
  unique_ptr<input_format> conllu_input;
  if (tokenizer != "none") {
    t.reset(m->new_tokenizer(tokenizer));
    if (!t) return error.assign("Cannot allocate new tokenizer!"), false;
    t->set_text(input);
  } else {
    conllu_input.reset(input_format::new_conllu_input_format());
    if (!conllu_input) return error.assign("Cannot allocate CoNLL-U input format instance!"), false;
    conllu_input->set_text(input);
  }

  int words = 0, upostag = 0, xpostag = 0, feats = 0, all_tags = 0, lemma = 0;
  int punct = 0, punct_uas = 0, punct_las = 0, nopunct = 0, nopunct_uas = 0, nopunct_las = 0;
  while (t ? t->next_sentence(gold, error) : conllu_input->next_sentence(gold, error)) {
    // Create empty copy
    system.clear();
    for (size_t i = 1; i < gold.words.size(); i++)
      system.add_word(gold.words[i].form);

    if (tagger != "none") {
      if (!m->tag(system, tagger, error))
        return false;
      for (size_t i = 1; i < gold.words.size(); i++) {
        words++;
        upostag += gold.words[i].upostag == system.words[i].upostag;
        xpostag += gold.words[i].xpostag == system.words[i].xpostag;
        feats += gold.words[i].feats == system.words[i].feats;
        all_tags += gold.words[i].upostag == system.words[i].upostag && gold.words[i].xpostag == system.words[i].xpostag && gold.words[i].feats == system.words[i].feats;
        lemma += gold.words[i].lemma == system.words[i].lemma;
      }
    } else {
      for (size_t i = 1; i < gold.words.size(); i++) {
        system.words[i].upostag = gold.words[i].upostag;
        system.words[i].xpostag = gold.words[i].xpostag;
        system.words[i].feats = gold.words[i].feats;
        system.words[i].lemma = gold.words[i].lemma;
      }
    }

    if (parser != "none") {
      if (!m->parse(system, parser, error))
        return false;
      for (size_t i = 1; i < gold.words.size(); i++) {
        punct++;
        punct_uas += gold.words[i].head == system.words[i].head;
        punct_las += gold.words[i].head == system.words[i].head && gold.words[i].deprel == system.words[i].deprel;
        if (gold.words[i].upostag != "PUNCT") {
          nopunct++;
          nopunct_uas += gold.words[i].head == system.words[i].head;
          nopunct_las += gold.words[i].head == system.words[i].head && gold.words[i].deprel == system.words[i].deprel;
        }
      }
    }
  }
  if (!error.empty()) return false;

  if (tagger != "none")
    os << "Tagging - forms: " << words << ", upostag: " << fixed << setprecision(2) << 100. * upostag / words << "%, xpostag: " << 100. * xpostag / words
       << "%, feats: " << 100. * feats / words << "%, all tags: " << 100. * all_tags / words << "%, lemma: " << 100. * lemma / words << '%' << endl;
  if (parser != "none")
    os << "Parsing - UAS: " << fixed << setprecision(2) << 100. * punct_uas / punct << "%, LAS: " << 100. * punct_las / punct << "%, "
       << "without punctuation - UAS: " << 100. * nopunct_uas / nopunct << "%, LAS: " << 100. * nopunct_las / nopunct << '%' << endl;

  return true;
}

} // namespace udpipe
} // namespace ufal
<|endoftext|>