<commit_before>/*
 * Copyright (C) 2008-2010 The QXmpp developers
 *
 * Author:
 *  Manjeet Dahiya
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * 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.
 *
 */

#include "QXmppDiscoveryManager.h"

#include <QDomElement>
#include <QCoreApplication>

#include "QXmppClient.h"
#include "QXmppConstants.h"
#include "QXmppDiscoveryIq.h"
#include "QXmppStream.h"
#include "QXmppGlobal.h"

QXmppDiscoveryManager::QXmppDiscoveryManager() : QXmppClientExtension(),
    m_clientCategory("client"),
    m_clientType("pc"),
    m_clientName(QString("%1 %2").arg(qApp->applicationName(), qApp->applicationVersion()))
{
    if(m_clientName.isEmpty())
    {
        m_clientName = QString("%1 %2").arg("Based on QXmpp", QXmppVersion());
    }
}

bool QXmppDiscoveryManager::handleStanza(QXmppStream *stream, const QDomElement &element)
{
    if (element.tagName() == "iq" && QXmppDiscoveryIq::isDiscoveryIq(element))
    {
        QXmppDiscoveryIq receivedIq;
        receivedIq.parse(element);

        if(receivedIq.type() == QXmppIq::Get &&
           receivedIq.queryType() == QXmppDiscoveryIq::InfoQuery &&
           (receivedIq.queryNode().isEmpty() || receivedIq.queryNode().startsWith(QString(capabilities_node))))
        {
            // respond to query
            QXmppDiscoveryIq qxmppFeatures = capabilities();
            qxmppFeatures.setId(receivedIq.id());
            qxmppFeatures.setTo(receivedIq.from());
            qxmppFeatures.setQueryNode(receivedIq.queryNode());
            stream->sendPacket(qxmppFeatures);
        }
        else if(receivedIq.queryType() == QXmppDiscoveryIq::InfoQuery)
            emit infoReceived(receivedIq);
        else if(receivedIq.queryType() == QXmppDiscoveryIq::ItemsQuery)
            emit itemsReceived(receivedIq);

        return true;
    }
    return false;
}

QString QXmppDiscoveryManager::requestInfo(const QString& jid, const QString& node)
{
    QXmppDiscoveryIq request;
    request.setType(QXmppIq::Get);
    request.setQueryType(QXmppDiscoveryIq::InfoQuery);
    request.setTo(jid);
    request.setFrom(client()->configuration().jid());
    if(!node.isEmpty())
        request.setQueryNode(node);
    if(client()->sendPacket(request))
        return request.id();
    else
        return "";
}

QString QXmppDiscoveryManager::requestItems(const QString& jid, const QString& node)
{
    QXmppDiscoveryIq request;
    request.setType(QXmppIq::Get);
    request.setQueryType(QXmppDiscoveryIq::ItemsQuery);
    request.setTo(jid);
    request.setFrom(client()->configuration().jid());
    if(!node.isEmpty())
        request.setQueryNode(node);
    if(client()->sendPacket(request))
        return request.id();
    else
        return "";
}

QStringList QXmppDiscoveryManager::discoveryFeatures() const
{
    return QStringList() << ns_disco_info;
}

QXmppDiscoveryIq QXmppDiscoveryManager::capabilities()
{
    QXmppDiscoveryIq iq;
    iq.setType(QXmppIq::Result);
    iq.setQueryType(QXmppDiscoveryIq::InfoQuery);

    // features
    QStringList features;
    features
        << ns_rpc               // XEP-0009: Jabber-RPC
//        << ns_vcard             // XEP-0054: vcard-temp
        << ns_chat_states       // XEP-0085: Chat State Notifications
        << ns_capabilities      // XEP-0115 : Entity Capabilities
        << ns_ping;             // XEP-0199: XMPP Ping

    foreach(QXmppClientExtension* extension, client()->extensions())
    {
        if(extension)
            features << extension->discoveryFeatures();
    }

    iq.setFeatures(features);

    // TODO: get identities from the extensions itself like the features
    // identities
    QList<QXmppDiscoveryIq::Identity> identities;
    QXmppDiscoveryIq::Identity identity;

    identity.setCategory("automation");
    identity.setType("rpc");
    identities.append(identity);

    identity.setCategory(clientCategory());
    identity.setType(clientType());
    identity.setName(clientName());
    identities.append(identity);

    iq.setIdentities(identities);
    return iq;
}

/// http://xmpp.org/registrar/disco-categories.html#client
void QXmppDiscoveryManager::setClientCategory(const QString& category)
{
    m_clientCategory = category;
}

void QXmppDiscoveryManager::setClientType(const QString& type)
{
    m_clientType = type;
}

void QXmppDiscoveryManager::setClientName(const QString& name)
{
    m_clientName = name;
}

QString QXmppDiscoveryManager::clientCategory()
{
    return m_clientCategory;
}

QString QXmppDiscoveryManager::clientType()
{
    return m_clientType;
}

QString QXmppDiscoveryManager::clientName()
{
    return m_clientName;
}
<commit_msg>bugfix<commit_after>/*
 * Copyright (C) 2008-2010 The QXmpp developers
 *
 * Author:
 *  Manjeet Dahiya
 *
 * Source:
 *  http://code.google.com/p/qxmpp
 *
 * This file is a part of QXmpp library.
 *
 * 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.
 *
 */

#include "QXmppDiscoveryManager.h"

#include <QDomElement>
#include <QCoreApplication>

#include "QXmppClient.h"
#include "QXmppConstants.h"
#include "QXmppDiscoveryIq.h"
#include "QXmppStream.h"
#include "QXmppGlobal.h"

QXmppDiscoveryManager::QXmppDiscoveryManager() : QXmppClientExtension(),
    m_clientCategory("client"),
    m_clientType("pc"),
    m_clientName(QString("%1 %2").arg(qApp->applicationName(), qApp->applicationVersion()))
{
    if(qApp->applicationName().isEmpty() && qApp->applicationVersion().isEmpty())
    {
        m_clientName = QString("%1 %2").arg("Based on QXmpp", QXmppVersion());
    }
}

bool QXmppDiscoveryManager::handleStanza(QXmppStream *stream, const QDomElement &element)
{
    if (element.tagName() == "iq" && QXmppDiscoveryIq::isDiscoveryIq(element))
    {
        QXmppDiscoveryIq receivedIq;
        receivedIq.parse(element);

        if(receivedIq.type() == QXmppIq::Get &&
           receivedIq.queryType() == QXmppDiscoveryIq::InfoQuery &&
           (receivedIq.queryNode().isEmpty() || receivedIq.queryNode().startsWith(QString(capabilities_node))))
        {
            // respond to query
            QXmppDiscoveryIq qxmppFeatures = capabilities();
            qxmppFeatures.setId(receivedIq.id());
            qxmppFeatures.setTo(receivedIq.from());
            qxmppFeatures.setQueryNode(receivedIq.queryNode());
            stream->sendPacket(qxmppFeatures);
        }
        else if(receivedIq.queryType() == QXmppDiscoveryIq::InfoQuery)
            emit infoReceived(receivedIq);
        else if(receivedIq.queryType() == QXmppDiscoveryIq::ItemsQuery)
            emit itemsReceived(receivedIq);

        return true;
    }
    return false;
}

QString QXmppDiscoveryManager::requestInfo(const QString& jid, const QString& node)
{
    QXmppDiscoveryIq request;
    request.setType(QXmppIq::Get);
    request.setQueryType(QXmppDiscoveryIq::InfoQuery);
    request.setTo(jid);
    request.setFrom(client()->configuration().jid());
    if(!node.isEmpty())
        request.setQueryNode(node);
    if(client()->sendPacket(request))
        return request.id();
    else
        return "";
}

QString QXmppDiscoveryManager::requestItems(const QString& jid, const QString& node)
{
    QXmppDiscoveryIq request;
    request.setType(QXmppIq::Get);
    request.setQueryType(QXmppDiscoveryIq::ItemsQuery);
    request.setTo(jid);
    request.setFrom(client()->configuration().jid());
    if(!node.isEmpty())
        request.setQueryNode(node);
    if(client()->sendPacket(request))
        return request.id();
    else
        return "";
}

QStringList QXmppDiscoveryManager::discoveryFeatures() const
{
    return QStringList() << ns_disco_info;
}

QXmppDiscoveryIq QXmppDiscoveryManager::capabilities()
{
    QXmppDiscoveryIq iq;
    iq.setType(QXmppIq::Result);
    iq.setQueryType(QXmppDiscoveryIq::InfoQuery);

    // features
    QStringList features;
    features
        << ns_rpc               // XEP-0009: Jabber-RPC
//        << ns_vcard             // XEP-0054: vcard-temp
        << ns_chat_states       // XEP-0085: Chat State Notifications
        << ns_capabilities      // XEP-0115 : Entity Capabilities
        << ns_ping;             // XEP-0199: XMPP Ping

    foreach(QXmppClientExtension* extension, client()->extensions())
    {
        if(extension)
            features << extension->discoveryFeatures();
    }

    iq.setFeatures(features);

    // TODO: get identities from the extensions itself like the features
    // identities
    QList<QXmppDiscoveryIq::Identity> identities;
    QXmppDiscoveryIq::Identity identity;

    identity.setCategory("automation");
    identity.setType("rpc");
    identities.append(identity);

    identity.setCategory(clientCategory());
    identity.setType(clientType());
    identity.setName(clientName());
    identities.append(identity);

    iq.setIdentities(identities);
    return iq;
}

/// http://xmpp.org/registrar/disco-categories.html#client
void QXmppDiscoveryManager::setClientCategory(const QString& category)
{
    m_clientCategory = category;
}

void QXmppDiscoveryManager::setClientType(const QString& type)
{
    m_clientType = type;
}

void QXmppDiscoveryManager::setClientName(const QString& name)
{
    m_clientName = name;
}

QString QXmppDiscoveryManager::clientCategory()
{
    return m_clientCategory;
}

QString QXmppDiscoveryManager::clientType()
{
    return m_clientType;
}

QString QXmppDiscoveryManager::clientName()
{
    return m_clientName;
}
<|endoftext|>


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

#include "MonoRuntime.h"
#include <stdio.h>
#include <mono/jit/jit.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/mono-debug.h>
#include <mono/utils/mono-logger.h>
#include <sampgdk/sampgdk.h>
#include "Config.h"

bool MonoRuntime::isLoaded_;

void MonoRuntime::Load(std::string assemblyDir, std::string configDir,
    std::string traceLevel, std::string file) {
    if (isLoaded_) {
        return;
    }

    if (!assemblyDir.empty() && !configDir.empty()) {
        mono_set_dirs(assemblyDir.c_str(), configDir.c_str());
    }
#ifdef _WIN32
    else {
        mono_set_dirs(PathUtil::GetLibDirectory().c_str(),
            PathUtil::GetConfigDirectory().c_str());
    }

#endif

#ifdef _WIN32
    char debugger_address[32];
    debugger_address[0] = '\0';
    size_t required_size;
    getenv_s(&required_size, debugger_address, sizeof(debugger_address), "debugger_address");
#else
    char* debugger_address = getenv("debugger_address");
#endif

    if (Config::GetDebuggerEnable().compare("1") == 0 || (debugger_address != NULL && strlen(debugger_address) > 0)) {

        char* agent = new char[128];

        if (debugger_address == NULL) {
            snprintf(agent, 128,
                "--debugger-agent=transport=dt_socket,address=%s,server=y",
                Config::GetDebuggerAddress().c_str());
        }
        else {
            snprintf(agent, 128,
                "--debugger-agent=transport=dt_socket,address=%s,server=y",
                debugger_address);
        }

        const char* jit_options[] = {
            "--soft-breakpoints",
            agent
        };

        sampgdk::logprintf("Mono launch options options: --soft-breakpoints %s",
            agent);
        sampgdk::logprintf("Launching with debugger at %s...",
            Config::GetDebuggerAddress().c_str());

        mono_jit_parse_options(2, (char**)jit_options);

        delete agent;

        sampgdk::logprintf("Waiting for debugger to attach...");
    }

    mono_debug_init(MONO_DEBUG_FORMAT_MONO);
    mono_trace_set_level_string(traceLevel.c_str());
    MonoDomain *dom = mono_jit_init(file.c_str());

    isLoaded_ = true;
}
<commit_msg>Improved formatting of output when starting the debugger<commit_after>// SampSharp
// Copyright 2016 Tim Potze
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "MonoRuntime.h"
#include <stdio.h>
#include <mono/jit/jit.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/mono-debug.h>
#include <mono/utils/mono-logger.h>
#include <sampgdk/sampgdk.h>
#include "Config.h"

bool MonoRuntime::isLoaded_;

void MonoRuntime::Load(std::string assemblyDir, std::string configDir,
    std::string traceLevel, std::string file) {
    if (isLoaded_) {
        return;
    }

    if (!assemblyDir.empty() && !configDir.empty()) {
        mono_set_dirs(assemblyDir.c_str(), configDir.c_str());
    }
#ifdef _WIN32
    else {
        mono_set_dirs(PathUtil::GetLibDirectory().c_str(),
            PathUtil::GetConfigDirectory().c_str());
    }

#endif

#ifdef _WIN32
    char debugger_address[32];
    debugger_address[0] = '\0';
    size_t required_size;
    getenv_s(&required_size, debugger_address, sizeof(debugger_address), "debugger_address");
#else
    char* debugger_address = getenv("debugger_address");
#endif

    bool has_debugger = false;
    if (Config::GetDebuggerEnable().compare("1") == 0 || (debugger_address != NULL && strlen(debugger_address) > 0)) {

        char* agent = new char[128];

        sampgdk::logprintf("Soft Debugger");
        sampgdk::logprintf("---------------");

        if (debugger_address == NULL) {
            snprintf(agent, 128,
                "--debugger-agent=transport=dt_socket,address=%s,server=y",
                Config::GetDebuggerAddress().c_str());

            sampgdk::logprintf("Launching debugger at %s...",
                Config::GetDebuggerAddress().c_str());
        }
        else {
            snprintf(agent, 128,
                "--debugger-agent=transport=dt_socket,address=%s,server=y",
                debugger_address);

            sampgdk::logprintf("Launching debugger at %s...", debugger_address);
        }

        const char* jit_options[] = {
            "--soft-breakpoints",
            agent
        };

        mono_jit_parse_options(2, (char**)jit_options);

        delete agent;

        sampgdk::logprintf("Waiting for debugger to attach...");
        has_debugger = true;
    }

    mono_debug_init(MONO_DEBUG_FORMAT_MONO);
    mono_trace_set_level_string(traceLevel.c_str());
    MonoDomain *dom = mono_jit_init(file.c_str());

    if (has_debugger) {
        sampgdk::logprintf("Debugger attached!");
        sampgdk::logprintf("");
    }

    isLoaded_ = true;
}
<|endoftext|>


<commit_before>/******************************************************************************/
/*
  Author  - Ming-Lun "Allen" Chou
  Web     - http://AllenChou.net
  Twitter - @TheAllenChou
 */
/******************************************************************************/

#include "sidnet/sidnet.h"
#include "sidnet/sidclient.h"

static bool s_shouldExit = false;

void StringIdToStringHandler(StringId sid, const char *str)
{
  // TODO
}

void StringToStringIdHandler(const char *str, StringId sid)
{
  // TODO
}

int main(int argc, const char** argv)
{
  // default config
  const char *cfgPath = "sidclient.cfg";
  int ip[4] = {127, 0, 0, 1};
  char ipStr[128];
  int port = 2266;

  FILE *pCfgFile = std::fopen(cfgPath, "r");
  if (pCfgFile)
  {
    std::fscanf(pCfgFile, "%d.%d.%d.%d:%d", ip, ip + 1, ip + 2, ip + 3, &port);
  }
  else if (pCfgFile = std::fopen(cfgPath, "w+"))
  {
    std::fprintf(pCfgFile, "%d.%d.%d.%d:%d", ip[0], ip[1], ip[2], ip[3], port);
  }
  if (pCfgFile)
  {
    std::fclose(pCfgFile);
  }

  std::sprintf(ipStr, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);

  int err = 0;
  err = sidnet::Init();
  if (err)
    return err;

  sidnet::SidClient client(StringIdToStringHandler, StringToStringIdHandler);
  err = client.Connect(ipStr, port);
  if (!err)
    return err;

  while (!s_shouldExit)
  {
    char input[256];
    scanf_s("%s", input, int(sizeof(input)));
    if (!std::strcmp(input, "--exit"))
      s_shouldExit = true;
  }

  sidnet::ShutDown();

  return 0;
}
<commit_msg>First working iteration of SID client.<commit_after>/******************************************************************************/
/*
  Author  - Ming-Lun "Allen" Chou
  Web     - http://AllenChou.net
  Twitter - @TheAllenChou
 */
/******************************************************************************/

#include "sidnet/sidnet.h"
#include "sidnet/sidclient.h"

void StringIdToStringHandler(StringId sid, const char *str)
{
  if (std::strlen(str) > 0)
  {
    std::printf("  0x%016llx -> %s\n", sid.GetValue(), str);
  }
  else
  {
    std::printf("  0x%016llx -> ???\n", sid.GetValue());
  }
}

void StringToStringIdHandler(const char *str, StringId sid)
{
  std::printf("  %s -> 0x%016llx\n", str, sid.GetValue());
}

int main(int argc, const char** argv)
{
  // default config
  const char *cfgPath = "sidclient.cfg";
  int ip[4] = {127, 0, 0, 1};
  char ipStr[128];
  int port = 2266;

  FILE *pCfgFile = std::fopen(cfgPath, "r");
  if (pCfgFile)
  {
    std::fscanf(pCfgFile, "%d.%d.%d.%d:%d", ip, ip + 1, ip + 2, ip + 3, &port);
  }
  else if (pCfgFile = std::fopen(cfgPath, "w+"))
  {
    std::fprintf(pCfgFile, "%d.%d.%d.%d:%d", ip[0], ip[1], ip[2], ip[3], port);
  }
  if (pCfgFile)
  {
    std::fclose(pCfgFile);
  }

  std::sprintf(ipStr, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);

  int err = 0;
  err = sidnet::Init();
  if (err)
    return err;

  sidnet::SidClient client(StringIdToStringHandler, StringToStringIdHandler);
  err = client.Connect(ipStr, port);
  if (err)
    return err;

  bool shouldExit = false;
  while (!shouldExit)
  {
    char buffer[256];
    std::printf("sidclient>");
    scanf_s("%s", buffer, (int) sizeof(buffer));

    // option
    if (std::strlen(buffer) > 2 && buffer[0] == '-' && buffer[1] == '-')
    {
      const char* pOption = buffer + 2;

      // exit
      if (!std::strcmp(pOption, "exit"))
      {
        shouldExit = true;
      }
    }
    // hex
    else if (buffer[0] == '0' && (buffer[1] == 'x' || buffer[1] == 'X'))
    {
      StringId::Storage sidVal;
      sscanf_s(buffer, "%llx", &sidVal);

      client.SendFindRequest(StringId(sidVal));
    }
    // dec
    else if (buffer[0] >= '0' && buffer[0] <= '9')
    {
      StringId::Storage sidVal;
      sscanf_s(buffer, "%lld", &sidVal);

      client.SendFindRequest(StringId(sidVal));
    }
    // string
    else
    {
      client.SendFindRequest(buffer);
    }
  }

  sidnet::ShutDown();

  return 0;
}
<|endoftext|>


<commit_before>// Copyright (c) 2012-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "compressor.h"
#include "util.h"
#include "test/test_bitcoin.h"

#include <stdint.h>

#include <boost/test/unit_test.hpp>

// amounts 0.00000001 .. 0.00100000
#define NUM_MULTIPLES_UNIT 100000

// amounts 0.01 .. 100.00
#define NUM_MULTIPLES_CENT 10000

// amounts 1 .. 10000
#define NUM_MULTIPLES_1BTC 10000

// amounts 50 .. 21000000
#define NUM_MULTIPLES_50BTC 420000

BOOST_FIXTURE_TEST_SUITE(compress_tests, BasicTestingSetup)

bool static TestEncode(uint64_t in) {
    return in == CTxOutCompressor::DecompressAmount(CTxOutCompressor::CompressAmount(in));
}

bool static TestDecode(uint64_t in) {
    return in == CTxOutCompressor::CompressAmount(CTxOutCompressor::DecompressAmount(in));
}

bool static TestPair(uint64_t dec, uint64_t enc) {
    return CTxOutCompressor::CompressAmount(dec) == enc &&
           CTxOutCompressor::DecompressAmount(enc) == dec;
}

BOOST_AUTO_TEST_CASE(compress_amounts)
{
    BOOST_CHECK(TestPair(            0,       0x0));
    BOOST_CHECK(TestPair(            1,       0x1));
    BOOST_CHECK(TestPair(         CENT,       0x7));
    BOOST_CHECK(TestPair(         COIN,       0x9));
    BOOST_CHECK(TestPair(      50*COIN,      0x32));
    BOOST_CHECK(TestPair(23000000*COIN, 0x15EF3C0));

    for (uint64_t i = 1; i <= NUM_MULTIPLES_UNIT; i++)
        BOOST_CHECK(TestEncode(i));

    for (uint64_t i = 1; i <= NUM_MULTIPLES_CENT; i++)
        BOOST_CHECK(TestEncode(i * CENT));

    for (uint64_t i = 1; i <= NUM_MULTIPLES_1BTC; i++)
        BOOST_CHECK(TestEncode(i * COIN));

    for (uint64_t i = 1; i <= NUM_MULTIPLES_50BTC; i++)
        BOOST_CHECK(TestEncode(i * 50 * COIN));

    for (uint64_t i = 0; i < 100000; i++)
        BOOST_CHECK(TestDecode(i));
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>test compress NUM_MULTIPLES_50BTC<commit_after>// Copyright (c) 2012-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "compressor.h"
#include "util.h"
#include "test/test_bitcoin.h"

#include <stdint.h>

#include <boost/test/unit_test.hpp>

// amounts 0.00000001 .. 0.00100000
#define NUM_MULTIPLES_UNIT 100000

// amounts 0.01 .. 100.00
#define NUM_MULTIPLES_CENT 10000

// amounts 1 .. 10000
#define NUM_MULTIPLES_1BTC 10000

// amounts 50 .. 21000000
#define NUM_MULTIPLES_50BTC 460000

BOOST_FIXTURE_TEST_SUITE(compress_tests, BasicTestingSetup)

bool static TestEncode(uint64_t in) {
    return in == CTxOutCompressor::DecompressAmount(CTxOutCompressor::CompressAmount(in));
}

bool static TestDecode(uint64_t in) {
    return in == CTxOutCompressor::CompressAmount(CTxOutCompressor::DecompressAmount(in));
}

bool static TestPair(uint64_t dec, uint64_t enc) {
    return CTxOutCompressor::CompressAmount(dec) == enc &&
           CTxOutCompressor::DecompressAmount(enc) == dec;
}

BOOST_AUTO_TEST_CASE(compress_amounts)
{
    BOOST_CHECK(TestPair(            0,       0x0));
    BOOST_CHECK(TestPair(            1,       0x1));
    BOOST_CHECK(TestPair(         CENT,       0x7));
    BOOST_CHECK(TestPair(         COIN,       0x9));
    BOOST_CHECK(TestPair(      50*COIN,      0x32));
    BOOST_CHECK(TestPair(23000000*COIN, 0x15EF3C0));

    for (uint64_t i = 1; i <= NUM_MULTIPLES_UNIT; i++)
        BOOST_CHECK(TestEncode(i));

    for (uint64_t i = 1; i <= NUM_MULTIPLES_CENT; i++)
        BOOST_CHECK(TestEncode(i * CENT));

    for (uint64_t i = 1; i <= NUM_MULTIPLES_1BTC; i++)
        BOOST_CHECK(TestEncode(i * COIN));

    for (uint64_t i = 1; i <= NUM_MULTIPLES_50BTC; i++)
        BOOST_CHECK(TestEncode(i * 50 * COIN));

    for (uint64_t i = 0; i < 100000; i++)
        BOOST_CHECK(TestDecode(i));
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


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

#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <map>
#include <string>
#include <vector>
#ifdef _WIN32
  #include <windows.h>
#else
  #ifndef _GNU_SOURCE
    #define _GNU_SOURCE 1 // for dl_addr()
  #endif
  #include <dlfcn.h>
#endif
#include <subhook.h>
#include "version.h"
#include "jit/amxdisasm.h"
#include "jit/backend-asmjit.h"
#include "jit/compiler.h"
#include "jit/jit.h"
#include "sdk/plugin.h"

extern void *pAMXFunctions;

typedef void (*logprintf_t)(const char *format, ...);
static logprintf_t logprintf;

typedef std::map<AMX*, jit::JIT*> AmxToJitMap;
static AmxToJitMap amx_to_jit;

static SubHook amx_Exec_hook;
static cell *opcode_map = 0;

static std::string GetModulePath(void *address,
                                 std::size_t max_length = FILENAME_MAX)
{
  #ifdef _WIN32
    std::vector<char> name(max_length + 1);
    if (address != 0) {
      MEMORY_BASIC_INFORMATION mbi;
      VirtualQuery(address, &mbi, sizeof(mbi));
      GetModuleFileName((HMODULE)mbi.AllocationBase, &name[0], max_length);
    }
    return std::string(&name[0]);
  #else
    std::vector<char> name(max_length + 1);
    if (address != 0) {
      Dl_info info;
      dladdr(address, &info);
      strncpy(&name[0], info.dli_fname, max_length);
    }
    return std::string(&name[0]);
  #endif
}

static std::string GetFileName(const std::string &path) {
  std::string::size_type pos = path.find_last_of("/\\");
  if (pos != std::string::npos) {
    return path.substr(pos + 1);
  }
  return path;
}

static int AMXAPI amx_Exec_JIT(AMX *amx, cell *retval, int index) {
  #if defined __GNUC__
    if ((amx->flags & AMX_FLAG_BROWSE) == AMX_FLAG_BROWSE) {
      assert(::opcode_map != 0);
      *retval = reinterpret_cast<cell>(::opcode_map);
      return AMX_ERR_NONE;
    }
  #endif
  AmxToJitMap::iterator iterator = ::amx_to_jit.find(amx);
  if (iterator == ::amx_to_jit.end()) {
    SubHook::ScopedRemove r(&amx_Exec_hook);
    return amx_Exec(amx, retval, index);
  } else {
    jit::JIT *jit = iterator->second;
    return jit->exec(index, retval);
  }
}

class CompileErrorHandler : public jit::CompileErrorHandler {
 public:
  CompileErrorHandler(jit::JIT *jit) : jit_(jit) {}
  virtual void execute(const jit::AMXInstruction &instr) {
    logprintf("[jit] Invalid or unsupported instruction at address %p:",
              instr.address());
    logprintf("[jit]   => %s", instr.string().c_str());
  }
 private:
  jit::JIT *jit_;
};

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() {
  return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;
}

static void *AMXAPI amx_Align(void *v) { return v; }

PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData) {
  logprintf = (logprintf_t)ppData[PLUGIN_DATA_LOGPRINTF];
  pAMXFunctions = reinterpret_cast<void*>(ppData[PLUGIN_DATA_AMX_EXPORTS]);

  ((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_Align16] = (void*)amx_Align;
  ((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_Align32] = (void*)amx_Align;
  ((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_Align64] = (void*)amx_Align;

  void *ptr = SubHook::ReadDst(((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_Exec]);
  if (ptr != 0) {
    std::string module = GetFileName(GetModulePath(ptr));
    if (!module.empty()) {
      logprintf("  JIT must be loaded before '%s'", module.c_str());
      return false;
    }
  }

  #if defined __GNUC__
    // Get opcode table before we hook amx_Exec().
    AMX amx = {0};
    amx.flags |= AMX_FLAG_BROWSE;
    amx_Exec(&amx, reinterpret_cast<cell*>(&::opcode_map), 0);
    amx.flags &= ~AMX_FLAG_BROWSE;
  #endif

  amx_Exec_hook.Install(((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_Exec],
                        (void*)amx_Exec_JIT);

  logprintf("  JIT plugin v%s is OK.", PROJECT_VERSION_STRING);
  return true;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload() {
  for (AmxToJitMap::iterator it = amx_to_jit.begin();
       it != amx_to_jit.end(); ++it) {
    delete it->second;
  }
}

PLUGIN_EXPORT int PLUGIN_CALL AmxLoad(AMX *amx) {
  jit::JIT *jit = new jit::JIT(amx);

  const char *backend_string = getenv("JIT_BACKEND");
  if (backend_string == 0) {
    backend_string = "asmjit";
  }

  jit::Backend *backend = 0;
  if (std::strcmp(backend_string, "asmjit") == 0) {
    backend = new jit::AsmjitBackend;
  } else {
    logprintf("[jit] Unknown backend '%s'", backend_string);
  }

  jit::Compiler compiler(backend);

  if (backend != 0) {
    CompileErrorHandler error_handler(jit);
    if (!jit->compile(&compiler, &error_handler)) {
      delete jit;
      ::amx_to_jit.insert(std::make_pair(amx, jit));
    }
  } else {
    delete jit;
  }

  delete backend;
  return AMX_ERR_NONE;
}

PLUGIN_EXPORT int PLUGIN_CALL AmxUnload(AMX *amx) {
  AmxToJitMap::iterator it = amx_to_jit.find(amx);
  if (it != amx_to_jit.end()) {
    delete it->second;
    amx_to_jit.erase(it);
  }
  return AMX_ERR_NONE;
}
<commit_msg>Fix JIT not getting called due to silly mistake<commit_after>// Copyright (c) 2012 Zeex
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <map>
#include <string>
#include <vector>
#ifdef _WIN32
  #include <windows.h>
#else
  #ifndef _GNU_SOURCE
    #define _GNU_SOURCE 1 // for dl_addr()
  #endif
  #include <dlfcn.h>
#endif
#include <subhook.h>
#include "version.h"
#include "jit/amxdisasm.h"
#include "jit/backend-asmjit.h"
#include "jit/compiler.h"
#include "jit/jit.h"
#include "sdk/plugin.h"

extern void *pAMXFunctions;

typedef void (*logprintf_t)(const char *format, ...);
static logprintf_t logprintf;

typedef std::map<AMX*, jit::JIT*> AmxToJitMap;
static AmxToJitMap amx_to_jit;

static SubHook amx_Exec_hook;
static cell *opcode_map = 0;

static std::string GetModulePath(void *address,
                                 std::size_t max_length = FILENAME_MAX)
{
  #ifdef _WIN32
    std::vector<char> name(max_length + 1);
    if (address != 0) {
      MEMORY_BASIC_INFORMATION mbi;
      VirtualQuery(address, &mbi, sizeof(mbi));
      GetModuleFileName((HMODULE)mbi.AllocationBase, &name[0], max_length);
    }
    return std::string(&name[0]);
  #else
    std::vector<char> name(max_length + 1);
    if (address != 0) {
      Dl_info info;
      dladdr(address, &info);
      strncpy(&name[0], info.dli_fname, max_length);
    }
    return std::string(&name[0]);
  #endif
}

static std::string GetFileName(const std::string &path) {
  std::string::size_type pos = path.find_last_of("/\\");
  if (pos != std::string::npos) {
    return path.substr(pos + 1);
  }
  return path;
}

static int AMXAPI amx_Exec_JIT(AMX *amx, cell *retval, int index) {
  #if defined __GNUC__
    if ((amx->flags & AMX_FLAG_BROWSE) == AMX_FLAG_BROWSE) {
      assert(::opcode_map != 0);
      *retval = reinterpret_cast<cell>(::opcode_map);
      return AMX_ERR_NONE;
    }
  #endif
  AmxToJitMap::iterator iterator = ::amx_to_jit.find(amx);
  if (iterator == ::amx_to_jit.end()) {
    SubHook::ScopedRemove r(&amx_Exec_hook);
    return amx_Exec(amx, retval, index);
  } else {
    jit::JIT *jit = iterator->second;
    return jit->exec(index, retval);
  }
}

class CompileErrorHandler : public jit::CompileErrorHandler {
 public:
  CompileErrorHandler(jit::JIT *jit) : jit_(jit) {}
  virtual void execute(const jit::AMXInstruction &instr) {
    logprintf("[jit] Invalid or unsupported instruction at address %p:",
              instr.address());
    logprintf("[jit]   => %s", instr.string().c_str());
  }
 private:
  jit::JIT *jit_;
};

PLUGIN_EXPORT unsigned int PLUGIN_CALL Supports() {
  return SUPPORTS_VERSION | SUPPORTS_AMX_NATIVES;
}

static void *AMXAPI amx_Align(void *v) { return v; }

PLUGIN_EXPORT bool PLUGIN_CALL Load(void **ppData) {
  logprintf = (logprintf_t)ppData[PLUGIN_DATA_LOGPRINTF];
  pAMXFunctions = reinterpret_cast<void*>(ppData[PLUGIN_DATA_AMX_EXPORTS]);

  ((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_Align16] = (void*)amx_Align;
  ((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_Align32] = (void*)amx_Align;
  ((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_Align64] = (void*)amx_Align;

  void *ptr = SubHook::ReadDst(((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_Exec]);
  if (ptr != 0) {
    std::string module = GetFileName(GetModulePath(ptr));
    if (!module.empty()) {
      logprintf("  JIT must be loaded before '%s'", module.c_str());
      return false;
    }
  }

  #if defined __GNUC__
    // Get opcode table before we hook amx_Exec().
    AMX amx = {0};
    amx.flags |= AMX_FLAG_BROWSE;
    amx_Exec(&amx, reinterpret_cast<cell*>(&::opcode_map), 0);
    amx.flags &= ~AMX_FLAG_BROWSE;
  #endif

  amx_Exec_hook.Install(((void**)pAMXFunctions)[PLUGIN_AMX_EXPORT_Exec],
                        (void*)amx_Exec_JIT);

  logprintf("  JIT plugin v%s is OK.", PROJECT_VERSION_STRING);
  return true;
}

PLUGIN_EXPORT void PLUGIN_CALL Unload() {
  for (AmxToJitMap::iterator it = amx_to_jit.begin();
       it != amx_to_jit.end(); ++it) {
    delete it->second;
  }
}

PLUGIN_EXPORT int PLUGIN_CALL AmxLoad(AMX *amx) {
  jit::JIT *jit = new jit::JIT(amx);

  const char *backend_string = getenv("JIT_BACKEND");
  if (backend_string == 0) {
    backend_string = "asmjit";
  }

  jit::Backend *backend = 0;
  if (std::strcmp(backend_string, "asmjit") == 0) {
    backend = new jit::AsmjitBackend;
  } else {
    logprintf("[jit] Unknown backend '%s'", backend_string);
  }

  jit::Compiler compiler(backend);

  if (backend != 0) {
    CompileErrorHandler error_handler(jit);
    if (!jit->compile(&compiler, &error_handler)) {
      delete jit;
    } else {
      ::amx_to_jit.insert(std::make_pair(amx, jit));
    }
  } else {
    delete jit;
  }

  delete backend;
  return AMX_ERR_NONE;
}

PLUGIN_EXPORT int PLUGIN_CALL AmxUnload(AMX *amx) {
  AmxToJitMap::iterator it = amx_to_jit.find(amx);
  if (it != amx_to_jit.end()) {
    delete it->second;
    amx_to_jit.erase(it);
  }
  return AMX_ERR_NONE;
}
<|endoftext|>


<commit_before>// Copyright 2014 BitPay, Inc.
// Copyright (c) 2014-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <stdint.h>
#include <vector>
#include <string>
#include <map>
#include <univalue.h>
#include "test/test_bitcoin.h"

#include <boost/test/unit_test.hpp>

using namespace std;

BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(univalue_constructor)
{
    UniValue v1;
    BOOST_CHECK(v1.isNull());

    UniValue v2(UniValue::VSTR);
    BOOST_CHECK(v2.isStr());

    UniValue v3(UniValue::VSTR, "foo");
    BOOST_CHECK(v3.isStr());
    BOOST_CHECK_EQUAL(v3.getValStr(), "foo");

    UniValue numTest;
    BOOST_CHECK(numTest.setNumStr("82"));
    BOOST_CHECK(numTest.isNum());
    BOOST_CHECK_EQUAL(numTest.getValStr(), "82");

    uint64_t vu64 = 82;
    UniValue v4(vu64);
    BOOST_CHECK(v4.isNum());
    BOOST_CHECK_EQUAL(v4.getValStr(), "82");

    int64_t vi64 = -82;
    UniValue v5(vi64);
    BOOST_CHECK(v5.isNum());
    BOOST_CHECK_EQUAL(v5.getValStr(), "-82");

    int vi = -688;
    UniValue v6(vi);
    BOOST_CHECK(v6.isNum());
    BOOST_CHECK_EQUAL(v6.getValStr(), "-688");

    double vd = -7.21;
    UniValue v7(vd);
    BOOST_CHECK(v7.isNum());
    BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21");

    string vs("yawn");
    UniValue v8(vs);
    BOOST_CHECK(v8.isStr());
    BOOST_CHECK_EQUAL(v8.getValStr(), "yawn");

    const char *vcs = "zappa";
    UniValue v9(vcs);
    BOOST_CHECK(v9.isStr());
    BOOST_CHECK_EQUAL(v9.getValStr(), "zappa");
}

BOOST_AUTO_TEST_CASE(univalue_typecheck)
{
    UniValue v1;
    BOOST_CHECK(v1.setNumStr("1"));
    BOOST_CHECK(v1.isNum());
    BOOST_CHECK_THROW(v1.get_bool(), runtime_error);

    UniValue v2;
    BOOST_CHECK(v2.setBool(true));
    BOOST_CHECK_EQUAL(v2.get_bool(), true);
    BOOST_CHECK_THROW(v2.get_int(), runtime_error);

    UniValue v3;
    BOOST_CHECK(v3.setNumStr("32482348723847471234"));
    BOOST_CHECK_THROW(v3.get_int64(), runtime_error);
    BOOST_CHECK(v3.setNumStr("1000"));
    BOOST_CHECK_EQUAL(v3.get_int64(), 1000);

    UniValue v4;
    BOOST_CHECK(v4.setNumStr("2147483648"));
    BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648);
    BOOST_CHECK_THROW(v4.get_int(), runtime_error);
    BOOST_CHECK(v4.setNumStr("1000"));
    BOOST_CHECK_EQUAL(v4.get_int(), 1000);
    BOOST_CHECK_THROW(v4.get_str(), runtime_error);
    BOOST_CHECK_EQUAL(v4.get_real(), 1000);
    BOOST_CHECK_THROW(v4.get_array(), runtime_error);
    BOOST_CHECK_THROW(v4.getKeys(), runtime_error);
    BOOST_CHECK_THROW(v4.getValues(), runtime_error);
    BOOST_CHECK_THROW(v4.get_obj(), runtime_error);

    UniValue v5;
    BOOST_CHECK(v5.read("[true, 10]"));
    BOOST_CHECK_NO_THROW(v5.get_array());
    std::vector<UniValue> vals = v5.getValues();
    BOOST_CHECK_THROW(vals[0].get_int(), runtime_error);
    BOOST_CHECK_EQUAL(vals[0].get_bool(), true);

    BOOST_CHECK_EQUAL(vals[1].get_int(), 10);
    BOOST_CHECK_THROW(vals[1].get_bool(), runtime_error);
}

BOOST_AUTO_TEST_CASE(univalue_set)
{
    UniValue v(UniValue::VSTR, "foo");
    v.clear();
    BOOST_CHECK(v.isNull());
    BOOST_CHECK_EQUAL(v.getValStr(), "");

    BOOST_CHECK(v.setObject());
    BOOST_CHECK(v.isObject());
    BOOST_CHECK_EQUAL(v.size(), 0);
    BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ);
    BOOST_CHECK(v.empty());

    BOOST_CHECK(v.setArray());
    BOOST_CHECK(v.isArray());
    BOOST_CHECK_EQUAL(v.size(), 0);

    BOOST_CHECK(v.setStr("zum"));
    BOOST_CHECK(v.isStr());
    BOOST_CHECK_EQUAL(v.getValStr(), "zum");

    BOOST_CHECK(v.setFloat(-1.01));
    BOOST_CHECK(v.isNum());
    BOOST_CHECK_EQUAL(v.getValStr(), "-1.01");

    BOOST_CHECK(v.setInt((int)1023));
    BOOST_CHECK(v.isNum());
    BOOST_CHECK_EQUAL(v.getValStr(), "1023");

    BOOST_CHECK(v.setInt((int64_t)-1023LL));
    BOOST_CHECK(v.isNum());
    BOOST_CHECK_EQUAL(v.getValStr(), "-1023");

    BOOST_CHECK(v.setInt((uint64_t)1023ULL));
    BOOST_CHECK(v.isNum());
    BOOST_CHECK_EQUAL(v.getValStr(), "1023");

    BOOST_CHECK(v.setNumStr("-688"));
    BOOST_CHECK(v.isNum());
    BOOST_CHECK_EQUAL(v.getValStr(), "-688");

    BOOST_CHECK(v.setBool(false));
    BOOST_CHECK_EQUAL(v.isBool(), true);
    BOOST_CHECK_EQUAL(v.isTrue(), false);
    BOOST_CHECK_EQUAL(v.isFalse(), true);
    BOOST_CHECK_EQUAL(v.getBool(), false);

    BOOST_CHECK(v.setBool(true));
    BOOST_CHECK_EQUAL(v.isBool(), true);
    BOOST_CHECK_EQUAL(v.isTrue(), true);
    BOOST_CHECK_EQUAL(v.isFalse(), false);
    BOOST_CHECK_EQUAL(v.getBool(), true);

    BOOST_CHECK(!v.setNumStr("zombocom"));

    BOOST_CHECK(v.setNull());
    BOOST_CHECK(v.isNull());
}

BOOST_AUTO_TEST_CASE(univalue_array)
{
    UniValue arr(UniValue::VARR);

    UniValue v((int64_t)1023LL);
    BOOST_CHECK(arr.push_back(v));

    string vStr("zippy");
    BOOST_CHECK(arr.push_back(vStr));

    const char *s = "pippy";
    BOOST_CHECK(arr.push_back(s));

    vector<UniValue> vec;
    v.setStr("boing");
    vec.push_back(v);

    v.setStr("going");
    vec.push_back(v);

    BOOST_CHECK(arr.push_backV(vec));

    BOOST_CHECK_EQUAL(arr.empty(), false);
    BOOST_CHECK_EQUAL(arr.size(), 5);

    BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023");
    BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy");
    BOOST_CHECK_EQUAL(arr[2].getValStr(), "pippy");
    BOOST_CHECK_EQUAL(arr[3].getValStr(), "boing");
    BOOST_CHECK_EQUAL(arr[4].getValStr(), "going");

    BOOST_CHECK_EQUAL(arr[999].getValStr(), "");

    arr.clear();
    BOOST_CHECK(arr.empty());
    BOOST_CHECK_EQUAL(arr.size(), 0);
}

BOOST_AUTO_TEST_CASE(univalue_object)
{
    UniValue obj(UniValue::VOBJ);
    string strKey, strVal;
    UniValue v;

    strKey = "age";
    v.setInt(100);
    BOOST_CHECK(obj.pushKV(strKey, v));

    strKey = "first";
    strVal = "John";
    BOOST_CHECK(obj.pushKV(strKey, strVal));

    strKey = "last";
    const char *cVal = "Smith";
    BOOST_CHECK(obj.pushKV(strKey, cVal));

    strKey = "distance";
    BOOST_CHECK(obj.pushKV(strKey, (int64_t) 25));

    strKey = "time";
    BOOST_CHECK(obj.pushKV(strKey, (uint64_t) 3600));

    strKey = "calories";
    BOOST_CHECK(obj.pushKV(strKey, (int) 12));

    strKey = "temperature";
    BOOST_CHECK(obj.pushKV(strKey, (double) 90.012));

    UniValue obj2(UniValue::VOBJ);
    BOOST_CHECK(obj2.pushKV("cat1", 9000));
    BOOST_CHECK(obj2.pushKV("cat2", 12345));

    BOOST_CHECK(obj.pushKVs(obj2));

    BOOST_CHECK_EQUAL(obj.empty(), false);
    BOOST_CHECK_EQUAL(obj.size(), 9);

    BOOST_CHECK_EQUAL(obj["age"].getValStr(), "100");
    BOOST_CHECK_EQUAL(obj["first"].getValStr(), "John");
    BOOST_CHECK_EQUAL(obj["last"].getValStr(), "Smith");
    BOOST_CHECK_EQUAL(obj["distance"].getValStr(), "25");
    BOOST_CHECK_EQUAL(obj["time"].getValStr(), "3600");
    BOOST_CHECK_EQUAL(obj["calories"].getValStr(), "12");
    BOOST_CHECK_EQUAL(obj["temperature"].getValStr(), "90.012");
    BOOST_CHECK_EQUAL(obj["cat1"].getValStr(), "9000");
    BOOST_CHECK_EQUAL(obj["cat2"].getValStr(), "12345");

    BOOST_CHECK_EQUAL(obj["nyuknyuknyuk"].getValStr(), "");

    BOOST_CHECK(obj.exists("age"));
    BOOST_CHECK(obj.exists("first"));
    BOOST_CHECK(obj.exists("last"));
    BOOST_CHECK(obj.exists("distance"));
    BOOST_CHECK(obj.exists("time"));
    BOOST_CHECK(obj.exists("calories"));
    BOOST_CHECK(obj.exists("temperature"));
    BOOST_CHECK(obj.exists("cat1"));
    BOOST_CHECK(obj.exists("cat2"));

    BOOST_CHECK(!obj.exists("nyuknyuknyuk"));

    map<string, UniValue::VType> objTypes;
    objTypes["age"] = UniValue::VNUM;
    objTypes["first"] = UniValue::VSTR;
    objTypes["last"] = UniValue::VSTR;
    objTypes["distance"] = UniValue::VNUM;
    objTypes["time"] = UniValue::VNUM;
    objTypes["calories"] = UniValue::VNUM;
    objTypes["temperature"] = UniValue::VNUM;
    objTypes["cat1"] = UniValue::VNUM;
    objTypes["cat2"] = UniValue::VNUM;
    BOOST_CHECK(obj.checkObject(objTypes));

    objTypes["cat2"] = UniValue::VSTR;
    BOOST_CHECK(!obj.checkObject(objTypes));

    obj.clear();
    BOOST_CHECK(obj.empty());
    BOOST_CHECK_EQUAL(obj.size(), 0);
}

static const char *json1 =
"[1.10000000,{\"key1\":\"str\\u0000\",\"key2\":800,\"key3\":{\"name\":\"martian http://test.com\"}}]";

BOOST_AUTO_TEST_CASE(univalue_readwrite)
{
    UniValue v;
    BOOST_CHECK(v.read(json1));

    string strJson1(json1);
    BOOST_CHECK(v.read(strJson1));

    BOOST_CHECK(v.isArray());
    BOOST_CHECK_EQUAL(v.size(), 2);

    BOOST_CHECK_EQUAL(v[0].getValStr(), "1.10000000");

    UniValue obj = v[1];
    BOOST_CHECK(obj.isObject());
    BOOST_CHECK_EQUAL(obj.size(), 3);

    BOOST_CHECK(obj["key1"].isStr());
    std::string correctValue("str");
    correctValue.push_back('\0');
    BOOST_CHECK_EQUAL(obj["key1"].getValStr(), correctValue);
    BOOST_CHECK(obj["key2"].isNum());
    BOOST_CHECK_EQUAL(obj["key2"].getValStr(), "800");
    BOOST_CHECK(obj["key3"].isObject());

    BOOST_CHECK_EQUAL(strJson1, v.write());

    /* Check for (correctly reporting) a parsing error if the initial
       JSON construct is followed by more stuff.  Note that whitespace
       is, of course, exempt.  */

    BOOST_CHECK(v.read("  {}\n  "));
    BOOST_CHECK(v.isObject());
    BOOST_CHECK(v.read("  []\n  "));
    BOOST_CHECK(v.isArray());

    BOOST_CHECK(!v.read("@{}"));
    BOOST_CHECK(!v.read("{} garbage"));
    BOOST_CHECK(!v.read("[]{}"));
    BOOST_CHECK(!v.read("{}[]"));
    BOOST_CHECK(!v.read("{} 42"));
}

BOOST_AUTO_TEST_SUITE_END()

<commit_msg>[issue-210] removed 'using namespace std' from univalue_tests.cpp<commit_after>// Copyright 2014 BitPay, Inc.
// Copyright (c) 2014-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <univalue.h>
#include "test/test_bitcoin.h"

#include <boost/test/unit_test.hpp>

BOOST_FIXTURE_TEST_SUITE(univalue_tests, BasicTestingSetup)

BOOST_AUTO_TEST_CASE(univalue_constructor)
{
    UniValue v1;
    BOOST_CHECK(v1.isNull());

    UniValue v2(UniValue::VSTR);
    BOOST_CHECK(v2.isStr());

    UniValue v3(UniValue::VSTR, "foo");
    BOOST_CHECK(v3.isStr());
    BOOST_CHECK_EQUAL(v3.getValStr(), "foo");

    UniValue numTest;
    BOOST_CHECK(numTest.setNumStr("82"));
    BOOST_CHECK(numTest.isNum());
    BOOST_CHECK_EQUAL(numTest.getValStr(), "82");

    uint64_t vu64 = 82;
    UniValue v4(vu64);
    BOOST_CHECK(v4.isNum());
    BOOST_CHECK_EQUAL(v4.getValStr(), "82");

    int64_t vi64 = -82;
    UniValue v5(vi64);
    BOOST_CHECK(v5.isNum());
    BOOST_CHECK_EQUAL(v5.getValStr(), "-82");

    int vi = -688;
    UniValue v6(vi);
    BOOST_CHECK(v6.isNum());
    BOOST_CHECK_EQUAL(v6.getValStr(), "-688");

    double vd = -7.21;
    UniValue v7(vd);
    BOOST_CHECK(v7.isNum());
    BOOST_CHECK_EQUAL(v7.getValStr(), "-7.21");

    std::string vs("yawn");
    UniValue v8(vs);
    BOOST_CHECK(v8.isStr());
    BOOST_CHECK_EQUAL(v8.getValStr(), "yawn");

    const char *vcs = "zappa";
    UniValue v9(vcs);
    BOOST_CHECK(v9.isStr());
    BOOST_CHECK_EQUAL(v9.getValStr(), "zappa");
}

BOOST_AUTO_TEST_CASE(univalue_typecheck)
{
    UniValue v1;
    BOOST_CHECK(v1.setNumStr("1"));
    BOOST_CHECK(v1.isNum());
    BOOST_CHECK_THROW(v1.get_bool(), std::runtime_error);

    UniValue v2;
    BOOST_CHECK(v2.setBool(true));
    BOOST_CHECK_EQUAL(v2.get_bool(), true);
    BOOST_CHECK_THROW(v2.get_int(), std::runtime_error);

    UniValue v3;
    BOOST_CHECK(v3.setNumStr("32482348723847471234"));
    BOOST_CHECK_THROW(v3.get_int64(), std::runtime_error);
    BOOST_CHECK(v3.setNumStr("1000"));
    BOOST_CHECK_EQUAL(v3.get_int64(), 1000);

    UniValue v4;
    BOOST_CHECK(v4.setNumStr("2147483648"));
    BOOST_CHECK_EQUAL(v4.get_int64(), 2147483648);
    BOOST_CHECK_THROW(v4.get_int(), std::runtime_error);
    BOOST_CHECK(v4.setNumStr("1000"));
    BOOST_CHECK_EQUAL(v4.get_int(), 1000);
    BOOST_CHECK_THROW(v4.get_str(), std::runtime_error);
    BOOST_CHECK_EQUAL(v4.get_real(), 1000);
    BOOST_CHECK_THROW(v4.get_array(), std::runtime_error);
    BOOST_CHECK_THROW(v4.getKeys(), std::runtime_error);
    BOOST_CHECK_THROW(v4.getValues(), std::runtime_error);
    BOOST_CHECK_THROW(v4.get_obj(), std::runtime_error);

    UniValue v5;
    BOOST_CHECK(v5.read("[true, 10]"));
    BOOST_CHECK_NO_THROW(v5.get_array());
    std::vector<UniValue> vals = v5.getValues();
    BOOST_CHECK_THROW(vals[0].get_int(), std::runtime_error);
    BOOST_CHECK_EQUAL(vals[0].get_bool(), true);

    BOOST_CHECK_EQUAL(vals[1].get_int(), 10);
    BOOST_CHECK_THROW(vals[1].get_bool(), std::runtime_error);
}

BOOST_AUTO_TEST_CASE(univalue_set)
{
    UniValue v(UniValue::VSTR, "foo");
    v.clear();
    BOOST_CHECK(v.isNull());
    BOOST_CHECK_EQUAL(v.getValStr(), "");

    BOOST_CHECK(v.setObject());
    BOOST_CHECK(v.isObject());
    BOOST_CHECK_EQUAL(v.size(), 0);
    BOOST_CHECK_EQUAL(v.getType(), UniValue::VOBJ);
    BOOST_CHECK(v.empty());

    BOOST_CHECK(v.setArray());
    BOOST_CHECK(v.isArray());
    BOOST_CHECK_EQUAL(v.size(), 0);

    BOOST_CHECK(v.setStr("zum"));
    BOOST_CHECK(v.isStr());
    BOOST_CHECK_EQUAL(v.getValStr(), "zum");

    BOOST_CHECK(v.setFloat(-1.01));
    BOOST_CHECK(v.isNum());
    BOOST_CHECK_EQUAL(v.getValStr(), "-1.01");

    BOOST_CHECK(v.setInt((int)1023));
    BOOST_CHECK(v.isNum());
    BOOST_CHECK_EQUAL(v.getValStr(), "1023");

    BOOST_CHECK(v.setInt((int64_t)-1023LL));
    BOOST_CHECK(v.isNum());
    BOOST_CHECK_EQUAL(v.getValStr(), "-1023");

    BOOST_CHECK(v.setInt((uint64_t)1023ULL));
    BOOST_CHECK(v.isNum());
    BOOST_CHECK_EQUAL(v.getValStr(), "1023");

    BOOST_CHECK(v.setNumStr("-688"));
    BOOST_CHECK(v.isNum());
    BOOST_CHECK_EQUAL(v.getValStr(), "-688");

    BOOST_CHECK(v.setBool(false));
    BOOST_CHECK_EQUAL(v.isBool(), true);
    BOOST_CHECK_EQUAL(v.isTrue(), false);
    BOOST_CHECK_EQUAL(v.isFalse(), true);
    BOOST_CHECK_EQUAL(v.getBool(), false);

    BOOST_CHECK(v.setBool(true));
    BOOST_CHECK_EQUAL(v.isBool(), true);
    BOOST_CHECK_EQUAL(v.isTrue(), true);
    BOOST_CHECK_EQUAL(v.isFalse(), false);
    BOOST_CHECK_EQUAL(v.getBool(), true);

    BOOST_CHECK(!v.setNumStr("zombocom"));

    BOOST_CHECK(v.setNull());
    BOOST_CHECK(v.isNull());
}

BOOST_AUTO_TEST_CASE(univalue_array)
{
    UniValue arr(UniValue::VARR);

    UniValue v((int64_t)1023LL);
    BOOST_CHECK(arr.push_back(v));

    std::string vStr("zippy");
    BOOST_CHECK(arr.push_back(vStr));

    const char *s = "pippy";
    BOOST_CHECK(arr.push_back(s));

    std::vector<UniValue> vec;
    v.setStr("boing");
    vec.push_back(v);

    v.setStr("going");
    vec.push_back(v);

    BOOST_CHECK(arr.push_backV(vec));

    BOOST_CHECK_EQUAL(arr.empty(), false);
    BOOST_CHECK_EQUAL(arr.size(), 5);

    BOOST_CHECK_EQUAL(arr[0].getValStr(), "1023");
    BOOST_CHECK_EQUAL(arr[1].getValStr(), "zippy");
    BOOST_CHECK_EQUAL(arr[2].getValStr(), "pippy");
    BOOST_CHECK_EQUAL(arr[3].getValStr(), "boing");
    BOOST_CHECK_EQUAL(arr[4].getValStr(), "going");

    BOOST_CHECK_EQUAL(arr[999].getValStr(), "");

    arr.clear();
    BOOST_CHECK(arr.empty());
    BOOST_CHECK_EQUAL(arr.size(), 0);
}

BOOST_AUTO_TEST_CASE(univalue_object)
{
    UniValue obj(UniValue::VOBJ);
    std::string strKey, strVal;
    UniValue v;

    strKey = "age";
    v.setInt(100);
    BOOST_CHECK(obj.pushKV(strKey, v));

    strKey = "first";
    strVal = "John";
    BOOST_CHECK(obj.pushKV(strKey, strVal));

    strKey = "last";
    const char *cVal = "Smith";
    BOOST_CHECK(obj.pushKV(strKey, cVal));

    strKey = "distance";
    BOOST_CHECK(obj.pushKV(strKey, (int64_t) 25));

    strKey = "time";
    BOOST_CHECK(obj.pushKV(strKey, (uint64_t) 3600));

    strKey = "calories";
    BOOST_CHECK(obj.pushKV(strKey, (int) 12));

    strKey = "temperature";
    BOOST_CHECK(obj.pushKV(strKey, (double) 90.012));

    UniValue obj2(UniValue::VOBJ);
    BOOST_CHECK(obj2.pushKV("cat1", 9000));
    BOOST_CHECK(obj2.pushKV("cat2", 12345));

    BOOST_CHECK(obj.pushKVs(obj2));

    BOOST_CHECK_EQUAL(obj.empty(), false);
    BOOST_CHECK_EQUAL(obj.size(), 9);

    BOOST_CHECK_EQUAL(obj["age"].getValStr(), "100");
    BOOST_CHECK_EQUAL(obj["first"].getValStr(), "John");
    BOOST_CHECK_EQUAL(obj["last"].getValStr(), "Smith");
    BOOST_CHECK_EQUAL(obj["distance"].getValStr(), "25");
    BOOST_CHECK_EQUAL(obj["time"].getValStr(), "3600");
    BOOST_CHECK_EQUAL(obj["calories"].getValStr(), "12");
    BOOST_CHECK_EQUAL(obj["temperature"].getValStr(), "90.012");
    BOOST_CHECK_EQUAL(obj["cat1"].getValStr(), "9000");
    BOOST_CHECK_EQUAL(obj["cat2"].getValStr(), "12345");

    BOOST_CHECK_EQUAL(obj["nyuknyuknyuk"].getValStr(), "");

    BOOST_CHECK(obj.exists("age"));
    BOOST_CHECK(obj.exists("first"));
    BOOST_CHECK(obj.exists("last"));
    BOOST_CHECK(obj.exists("distance"));
    BOOST_CHECK(obj.exists("time"));
    BOOST_CHECK(obj.exists("calories"));
    BOOST_CHECK(obj.exists("temperature"));
    BOOST_CHECK(obj.exists("cat1"));
    BOOST_CHECK(obj.exists("cat2"));

    BOOST_CHECK(!obj.exists("nyuknyuknyuk"));

    std::map<std::string, UniValue::VType> objTypes;
    objTypes["age"] = UniValue::VNUM;
    objTypes["first"] = UniValue::VSTR;
    objTypes["last"] = UniValue::VSTR;
    objTypes["distance"] = UniValue::VNUM;
    objTypes["time"] = UniValue::VNUM;
    objTypes["calories"] = UniValue::VNUM;
    objTypes["temperature"] = UniValue::VNUM;
    objTypes["cat1"] = UniValue::VNUM;
    objTypes["cat2"] = UniValue::VNUM;
    BOOST_CHECK(obj.checkObject(objTypes));

    objTypes["cat2"] = UniValue::VSTR;
    BOOST_CHECK(!obj.checkObject(objTypes));

    obj.clear();
    BOOST_CHECK(obj.empty());
    BOOST_CHECK_EQUAL(obj.size(), 0);
}

static const char *json1 =
"[1.10000000,{\"key1\":\"str\\u0000\",\"key2\":800,\"key3\":{\"name\":\"martian http://test.com\"}}]";

BOOST_AUTO_TEST_CASE(univalue_readwrite)
{
    UniValue v;
    BOOST_CHECK(v.read(json1));

    std::string strJson1(json1);
    BOOST_CHECK(v.read(strJson1));

    BOOST_CHECK(v.isArray());
    BOOST_CHECK_EQUAL(v.size(), 2);

    BOOST_CHECK_EQUAL(v[0].getValStr(), "1.10000000");

    UniValue obj = v[1];
    BOOST_CHECK(obj.isObject());
    BOOST_CHECK_EQUAL(obj.size(), 3);

    BOOST_CHECK(obj["key1"].isStr());
    std::string correctValue("str");
    correctValue.push_back('\0');
    BOOST_CHECK_EQUAL(obj["key1"].getValStr(), correctValue);
    BOOST_CHECK(obj["key2"].isNum());
    BOOST_CHECK_EQUAL(obj["key2"].getValStr(), "800");
    BOOST_CHECK(obj["key3"].isObject());

    BOOST_CHECK_EQUAL(strJson1, v.write());

    /* Check for (correctly reporting) a parsing error if the initial
       JSON construct is followed by more stuff.  Note that whitespace
       is, of course, exempt.  */

    BOOST_CHECK(v.read("  {}\n  "));
    BOOST_CHECK(v.isObject());
    BOOST_CHECK(v.read("  []\n  "));
    BOOST_CHECK(v.isArray());

    BOOST_CHECK(!v.read("@{}"));
    BOOST_CHECK(!v.read("{} garbage"));
    BOOST_CHECK(!v.read("[]{}"));
    BOOST_CHECK(!v.read("{}[]"));
    BOOST_CHECK(!v.read("{} 42"));
}

BOOST_AUTO_TEST_SUITE_END()

<|endoftext|>


<commit_before>/// \file FunctionCompiler.cpp

#include "chi/FunctionCompiler.hpp"
#include "chi/Context.hpp"
#include "chi/DataType.hpp"
#include "chi/FunctionValidator.hpp"
#include "chi/GraphFunction.hpp"
#include "chi/GraphModule.hpp"
#include "chi/LLVMVersion.hpp"
#include "chi/LangModule.hpp"
#include "chi/NameMangler.hpp"
#include "chi/NodeInstance.hpp"
#include "chi/NodeType.hpp"
#include "chi/Support/Result.hpp"

#include <boost/bimap.hpp>
#include <boost/dynamic_bitset.hpp>
#include <boost/range/join.hpp>
#include <boost/uuid/uuid_io.hpp>

#include <unordered_map>

#include <llvm/IR/DIBuilder.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Module.h>

namespace fs = boost::filesystem;

namespace chi {

FunctionCompiler::FunctionCompiler(const chi::GraphFunction& func, llvm::Module& moduleToGenInto,
                                   llvm::DICompileUnit& debugCU, llvm::DIBuilder& debugBuilder)
    : mModule{&moduleToGenInto}, mDIBuilder{&debugBuilder}, mDebugCU{&debugCU}, mFunction{&func} {}

Result FunctionCompiler::initialize(bool validate) {
	assert(initialized() == false && "Cannot initialize a FunctionCompiler more than once");

	mInitialized = true;

	Result res;
	auto   compilerCtx = res.addScopedContext(
	    {{"Function", function().name()}, {"Module", function().module().fullName()}});

	if (validate) {
		res += validateFunction(function());
		if (!res) { return res; }
	}

	// get the entry node
	auto entry = function().entryNode();
	if (entry == nullptr) {
		res.addEntry("EUKN", "No entry node", {});
		return res;
	}

	// create function
	auto mangledName = mangleFunctionName(module().fullName(), function().name());
	mLLFunction      = llvm::cast<llvm::Function>(
	    llvmModule().getOrInsertFunction(mangledName, function().functionType()));

	// create the debug file
	auto debugFile = diBuilder().createFile(debugCompileUnit()->getFilename(),
	                                        debugCompileUnit()->getDirectory());

	auto subroutineType = createSubroutineType();

	mNodeLocations = module().createLineNumberAssoc();
	auto entryLN   = nodeLineNumber(*entry);

	// TODO(#65): line numbers?
	mDebugFunc =
	    diBuilder().createFunction(debugFile, module().fullName() + ":" + function().name(),
	                               mangledName, debugFile, entryLN, subroutineType, false, true, 0,
#if LLVM_VERSION_LESS_EQUAL(3, 6)
	                               0,
#else
	                               llvm::DINode::DIFlags{},
#endif
	                               false);

#if LLVM_VERSION_LESS_EQUAL(3, 7)
	mDebugFunc->replaceFunction(mLLFunction);
#else
	mLLFunction->setSubprogram(mDebugFunc);
#endif

	mAllocBlock = llvm::BasicBlock::Create(context().llvmContext(), "alloc", mLLFunction);

	// set argument names
	auto idx = 0ull;
	for (auto& arg : mLLFunction->
#if LLVM_VERSION_AT_LEAST(5, 0)
	                 args()
#else
	                 getArgumentList()
#endif
	         ) {
		// the first one is the input exec ID
		if (idx == 0) {
			arg.setName("inputexec_id");

			// create debug info
			DataType intDataType;
			res += context().typeFromModule("lang", "i32", &intDataType);
			assert(intDataType.valid());
			auto debugParam = diBuilder().
#if LLVM_VERSION_LESS_EQUAL(3, 7)
			                  createLocalVariable(llvm::dwarf::DW_TAG_arg_variable, mDebugFunc,
			                                      "inputexec_id", debugFile, entryLN,
#if LLVM_VERSION_LESS_EQUAL(3, 6)
			                                      *
#endif
			                                      intDataType.debugType());
#else

			                  createParameterVariable(mDebugFunc, "inputexec_id", 1, debugFile,
			                                          entryLN, intDataType.debugType());
#endif
			diBuilder()
			    .insertDeclare(&arg, debugParam,
#if LLVM_VERSION_AT_LEAST(3, 6)
			                   diBuilder().createExpression(),
#if LLVM_VERSION_AT_LEAST(3, 7)
			                   llvm::DebugLoc::get(entryLN, 1, mDebugFunc),
#endif
#endif
			                   &allocBlock())
#if LLVM_VERSION_LESS_EQUAL(3, 6)
			    ->setDebugLoc(llvm::DebugLoc::get(entryLN, 1, mDebugFunc))
#endif
			    ;  // TODO(#65): "line" numbers

			++idx;
			continue;
		}

		NamedDataType tyAndName;
		// all the - 1's is becaues the first is the inputexec_id
		if (idx - 1 < function().dataInputs().size()) {
			tyAndName = function().dataInputs()[idx - 1];
		} else {
			tyAndName = function().dataOutputs()[idx - 1 - entry->type().dataOutputs().size()];
		}
		arg.setName(tyAndName.name);

		// create debug info

		// create DIType*
		llvm::DIType* dType      = tyAndName.type.debugType();
		auto          debugParam = diBuilder().
#if LLVM_VERSION_LESS_EQUAL(3, 7)
		                  createLocalVariable(llvm::dwarf::DW_TAG_arg_variable, mDebugFunc,
		                                      tyAndName.name, debugFile, entryLN,
#if LLVM_VERSION_LESS_EQUAL(3, 6)
		                                      *
#endif
		                                      dType);
#else
		                  createParameterVariable(mDebugFunc, tyAndName.name,
		                                          idx + 1,  // + 1 because it starts at 1
		                                          debugFile, entryLN, dType);
#endif
		diBuilder()
		    .insertDeclare(&arg, debugParam,
#if LLVM_VERSION_AT_LEAST(3, 6)
		                   diBuilder().createExpression(),
#if LLVM_VERSION_AT_LEAST(3, 7)
		                   llvm::DebugLoc::get(entryLN, 1, mDebugFunc),
#endif
#endif
		                   &allocBlock())
#if LLVM_VERSION_LESS_EQUAL(3, 6)
		    ->setDebugLoc(llvm::DebugLoc::get(entryLN, 1, mDebugFunc))
#endif
		    ;  // TODO(#65): line numbers

		++idx;
	}

	// create mPostPureBreak
	llvm::IRBuilder<> allocBuilder{&allocBlock()};
	mPostPureBreak = allocBuilder.CreateAlloca(
	    llvm::IntegerType::getInt8PtrTy(context().llvmContext()), nullptr, "pure_jumpback");

	// alloc local variables and zero them
	for (const auto& localVar : function().localVariables()) {
		mLocalVariables[localVar.name] =
		    allocBuilder.CreateAlloca(localVar.type.llvmType(), nullptr, "var_" + localVar.name);
		allocBuilder.CreateStore(llvm::Constant::getNullValue(localVar.type.llvmType()),
		                         mLocalVariables[localVar.name]);
	}

	return res;
}

Result FunctionCompiler::compile() {
	assert(initialized() && "You must initialize a FunctionCompiler before you compile it");
	assert(compiled() == false && "You cannot compile a FunctionCompiler twice");

	// compile the entry
	auto entry = function().entryNode();
	assert(entry != nullptr);

	std::deque<std::pair<NodeInstance*, size_t>> nodesToCompile;
	nodesToCompile.emplace_back(entry, 0);

	Result res;

	auto compilePureDependencies = [this](NodeInstance& node) {
		Result res;

		auto depPures = dependentPuresRecursive(node);
		for (auto pure : depPures) {
			auto compiler = getOrCreateNodeCompiler(*pure);
			res += compiler->compile_stage2({}, 0);

			if (!res) { return res; }
		}
		return res;
	};

	while (!nodesToCompile.empty()) {
		auto& node        = *nodesToCompile[0].first;
		auto  inputExecID = nodesToCompile[0].second;

		assert(!node.type().pure());

		auto compiler = getOrCreateNodeCompiler(node);
		if (compiler->compiled(inputExecID)) {
			nodesToCompile.pop_front();

			continue;
		}

		// compile dependent pures
		res += compilePureDependencies(node);
		if (!res) { return res; }

		std::vector<llvm::BasicBlock*> outputBlocks;
		// make sure the output nodes have done stage 1 and collect output blocks
		for (const auto& conn : node.outputExecConnections) {
			res += compilePureDependencies(*conn.first);
			if (!res) { return res; }

			auto depCompiler = getOrCreateNodeCompiler(*conn.first);
			depCompiler->compile_stage1(conn.second);

			outputBlocks.push_back(&depCompiler->firstBlock(conn.second));
		}

		// compile this one
		res += compiler->compile_stage2(outputBlocks, inputExecID);
		if (!res) { return res; }

		// recurse
		for (const auto& conn : node.outputExecConnections) {
			// add them to the end
			nodesToCompile.emplace_back(conn.first, conn.second);
		}

		// pop it off
		nodesToCompile.pop_front();
	}

	if (!res) { return res; }

	llvm::IRBuilder<> allocBuilder{&allocBlock()};
	allocBuilder.CreateBr(&nodeCompiler(*entry)->firstBlock(0));

	return res;
}

FunctionCompiler::DebugFunctionType FunctionCompiler::createSubroutineType() {
	// create param list
	std::vector<
#if LLVM_VERSION_LESS_EQUAL(3, 5)
	    llvm::Value*
#else
	    llvm::Metadata*
#endif
	    >
	    params;
	{
		// ret first
		DataType intType = function().context().langModule()->typeFromName("i32");
		assert(intType.valid());

		params.push_back(
#if LLVM_VERSION_LESS_EQUAL(3, 6)
		    *
#endif
		    intType.debugType());

		// then first in inputexec id
		params.push_back(
#if LLVM_VERSION_LESS_EQUAL(3, 6)
		    *
#endif
		    intType.debugType());

		// add paramters
		for (const auto& dType :
		     boost::range::join(function().dataInputs(), function().dataOutputs())) {
			params.push_back(
#if LLVM_VERSION_LESS_EQUAL(3, 6)
			    *
#endif
			    dType.type.debugType());
		}
	}

	// create type
	auto subroutineType = diBuilder().createSubroutineType(
#if LLVM_VERSION_LESS_EQUAL(3, 7)
	    diFunction()->getFile(),
#endif
	    diBuilder().
#if LLVM_VERSION_LESS_EQUAL(3, 5)
	    getOrCreateArray
#else
	    getOrCreateTypeArray
#endif
	    (params));

	return subroutineType;
}

llvm::Value* FunctionCompiler::localVariable(boost::string_view name) {
	assert(initialized() &&
	       "Please initialize the function compiler before getting a local variable");

	auto iter = mLocalVariables.find(name.to_string());
	if (iter != mLocalVariables.end()) { return iter->second; }
	return nullptr;
}

GraphModule& FunctionCompiler::module() const { return function().module(); }
Context&     FunctionCompiler::context() const { return function().context(); }

int FunctionCompiler::nodeLineNumber(NodeInstance& node) {
	assert(&node.function() == &function() &&
	       "Cannot get node line number for a node not in the function");

	auto iter = mNodeLocations.right.find(&node);
	if (iter == mNodeLocations.right.end()) {
		return -1;  // ?
	}
	return iter->second;
}

NodeCompiler* FunctionCompiler::nodeCompiler(NodeInstance& node) {
	assert(&node.function() == &function() &&
	       "Cannot get a NodeCompiler for a node instance not in this function");

	auto iter = mNodeCompilers.find(&node);
	if (iter != mNodeCompilers.end()) { return &iter->second; }
	return nullptr;
}

NodeCompiler* FunctionCompiler::getOrCreateNodeCompiler(NodeInstance& node) {
	assert(&node.function() == &function() &&
	       "Cannot get a NodeCompiler for a node instance not in this function");

	auto iter = mNodeCompilers.find(&node);
	if (iter != mNodeCompilers.end()) { return &iter->second; }
	return &mNodeCompilers.emplace(&node, NodeCompiler{*this, node}).first->second;
}

Result compileFunction(const GraphFunction& func, llvm::Module* mod, llvm::DICompileUnit* debugCU,
                       llvm::DIBuilder& debugBuilder) {
	FunctionCompiler compiler{func, *mod, *debugCU, debugBuilder};

	auto res = compiler.initialize();
	if (!res) { return res; }

	res += compiler.compile();

	return res;
}

}  // namespace chi
<commit_msg>Fix relaceFunction call<commit_after>/// \file FunctionCompiler.cpp

#include "chi/FunctionCompiler.hpp"
#include "chi/Context.hpp"
#include "chi/DataType.hpp"
#include "chi/FunctionValidator.hpp"
#include "chi/GraphFunction.hpp"
#include "chi/GraphModule.hpp"
#include "chi/LLVMVersion.hpp"
#include "chi/LangModule.hpp"
#include "chi/NameMangler.hpp"
#include "chi/NodeInstance.hpp"
#include "chi/NodeType.hpp"
#include "chi/Support/Result.hpp"

#include <boost/bimap.hpp>
#include <boost/dynamic_bitset.hpp>
#include <boost/range/join.hpp>
#include <boost/uuid/uuid_io.hpp>

#include <unordered_map>

#include <llvm/IR/DIBuilder.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/Module.h>

namespace fs = boost::filesystem;

namespace chi {

FunctionCompiler::FunctionCompiler(const chi::GraphFunction& func, llvm::Module& moduleToGenInto,
                                   llvm::DICompileUnit& debugCU, llvm::DIBuilder& debugBuilder)
    : mModule{&moduleToGenInto}, mDIBuilder{&debugBuilder}, mDebugCU{&debugCU}, mFunction{&func} {}

Result FunctionCompiler::initialize(bool validate) {
	assert(initialized() == false && "Cannot initialize a FunctionCompiler more than once");

	mInitialized = true;

	Result res;
	auto   compilerCtx = res.addScopedContext(
	    {{"Function", function().name()}, {"Module", function().module().fullName()}});

	if (validate) {
		res += validateFunction(function());
		if (!res) { return res; }
	}

	// get the entry node
	auto entry = function().entryNode();
	if (entry == nullptr) {
		res.addEntry("EUKN", "No entry node", {});
		return res;
	}

	// create function
	auto mangledName = mangleFunctionName(module().fullName(), function().name());
	mLLFunction      = llvm::cast<llvm::Function>(
	    llvmModule().getOrInsertFunction(mangledName, function().functionType()));

	// create the debug file
	auto debugFile = diBuilder().createFile(debugCompileUnit()->getFilename(),
	                                        debugCompileUnit()->getDirectory());

	auto subroutineType = createSubroutineType();

	mNodeLocations = module().createLineNumberAssoc();
	auto entryLN   = nodeLineNumber(*entry);

	// TODO(#65): line numbers?
	mDebugFunc =
	    diBuilder().createFunction(debugFile, module().fullName() + ":" + function().name(),
	                               mangledName, debugFile, entryLN, subroutineType, false, true, 0,
#if LLVM_VERSION_LESS_EQUAL(3, 6)
	                               0,
#else
	                               llvm::DINode::DIFlags{},
#endif
	                               false);

#if LLVM_VERSION_LESS_EQUAL(3, 7)
	mDebugFunc.replaceFunction(mLLFunction);
#else
	mLLFunction->setSubprogram(mDebugFunc);
#endif

	mAllocBlock = llvm::BasicBlock::Create(context().llvmContext(), "alloc", mLLFunction);

	// set argument names
	auto idx = 0ull;
	for (auto& arg : mLLFunction->
#if LLVM_VERSION_AT_LEAST(5, 0)
	                 args()
#else
	                 getArgumentList()
#endif
	         ) {
		// the first one is the input exec ID
		if (idx == 0) {
			arg.setName("inputexec_id");

			// create debug info
			DataType intDataType;
			res += context().typeFromModule("lang", "i32", &intDataType);
			assert(intDataType.valid());
			auto debugParam = diBuilder().
#if LLVM_VERSION_LESS_EQUAL(3, 7)
			                  createLocalVariable(llvm::dwarf::DW_TAG_arg_variable, mDebugFunc,
			                                      "inputexec_id", debugFile, entryLN,
#if LLVM_VERSION_LESS_EQUAL(3, 6)
			                                      *
#endif
			                                      intDataType.debugType());
#else

			                  createParameterVariable(mDebugFunc, "inputexec_id", 1, debugFile,
			                                          entryLN, intDataType.debugType());
#endif
			diBuilder()
			    .insertDeclare(&arg, debugParam,
#if LLVM_VERSION_AT_LEAST(3, 6)
			                   diBuilder().createExpression(),
#if LLVM_VERSION_AT_LEAST(3, 7)
			                   llvm::DebugLoc::get(entryLN, 1, mDebugFunc),
#endif
#endif
			                   &allocBlock())
#if LLVM_VERSION_LESS_EQUAL(3, 6)
			    ->setDebugLoc(llvm::DebugLoc::get(entryLN, 1, mDebugFunc))
#endif
			    ;  // TODO(#65): "line" numbers

			++idx;
			continue;
		}

		NamedDataType tyAndName;
		// all the - 1's is becaues the first is the inputexec_id
		if (idx - 1 < function().dataInputs().size()) {
			tyAndName = function().dataInputs()[idx - 1];
		} else {
			tyAndName = function().dataOutputs()[idx - 1 - entry->type().dataOutputs().size()];
		}
		arg.setName(tyAndName.name);

		// create debug info

		// create DIType*
		llvm::DIType* dType      = tyAndName.type.debugType();
		auto          debugParam = diBuilder().
#if LLVM_VERSION_LESS_EQUAL(3, 7)
		                  createLocalVariable(llvm::dwarf::DW_TAG_arg_variable, mDebugFunc,
		                                      tyAndName.name, debugFile, entryLN,
#if LLVM_VERSION_LESS_EQUAL(3, 6)
		                                      *
#endif
		                                      dType);
#else
		                  createParameterVariable(mDebugFunc, tyAndName.name,
		                                          idx + 1,  // + 1 because it starts at 1
		                                          debugFile, entryLN, dType);
#endif
		diBuilder()
		    .insertDeclare(&arg, debugParam,
#if LLVM_VERSION_AT_LEAST(3, 6)
		                   diBuilder().createExpression(),
#if LLVM_VERSION_AT_LEAST(3, 7)
		                   llvm::DebugLoc::get(entryLN, 1, mDebugFunc),
#endif
#endif
		                   &allocBlock())
#if LLVM_VERSION_LESS_EQUAL(3, 6)
		    ->setDebugLoc(llvm::DebugLoc::get(entryLN, 1, mDebugFunc))
#endif
		    ;  // TODO(#65): line numbers

		++idx;
	}

	// create mPostPureBreak
	llvm::IRBuilder<> allocBuilder{&allocBlock()};
	mPostPureBreak = allocBuilder.CreateAlloca(
	    llvm::IntegerType::getInt8PtrTy(context().llvmContext()), nullptr, "pure_jumpback");

	// alloc local variables and zero them
	for (const auto& localVar : function().localVariables()) {
		mLocalVariables[localVar.name] =
		    allocBuilder.CreateAlloca(localVar.type.llvmType(), nullptr, "var_" + localVar.name);
		allocBuilder.CreateStore(llvm::Constant::getNullValue(localVar.type.llvmType()),
		                         mLocalVariables[localVar.name]);
	}

	return res;
}

Result FunctionCompiler::compile() {
	assert(initialized() && "You must initialize a FunctionCompiler before you compile it");
	assert(compiled() == false && "You cannot compile a FunctionCompiler twice");

	// compile the entry
	auto entry = function().entryNode();
	assert(entry != nullptr);

	std::deque<std::pair<NodeInstance*, size_t>> nodesToCompile;
	nodesToCompile.emplace_back(entry, 0);

	Result res;

	auto compilePureDependencies = [this](NodeInstance& node) {
		Result res;

		auto depPures = dependentPuresRecursive(node);
		for (auto pure : depPures) {
			auto compiler = getOrCreateNodeCompiler(*pure);
			res += compiler->compile_stage2({}, 0);

			if (!res) { return res; }
		}
		return res;
	};

	while (!nodesToCompile.empty()) {
		auto& node        = *nodesToCompile[0].first;
		auto  inputExecID = nodesToCompile[0].second;

		assert(!node.type().pure());

		auto compiler = getOrCreateNodeCompiler(node);
		if (compiler->compiled(inputExecID)) {
			nodesToCompile.pop_front();

			continue;
		}

		// compile dependent pures
		res += compilePureDependencies(node);
		if (!res) { return res; }

		std::vector<llvm::BasicBlock*> outputBlocks;
		// make sure the output nodes have done stage 1 and collect output blocks
		for (const auto& conn : node.outputExecConnections) {
			res += compilePureDependencies(*conn.first);
			if (!res) { return res; }

			auto depCompiler = getOrCreateNodeCompiler(*conn.first);
			depCompiler->compile_stage1(conn.second);

			outputBlocks.push_back(&depCompiler->firstBlock(conn.second));
		}

		// compile this one
		res += compiler->compile_stage2(outputBlocks, inputExecID);
		if (!res) { return res; }

		// recurse
		for (const auto& conn : node.outputExecConnections) {
			// add them to the end
			nodesToCompile.emplace_back(conn.first, conn.second);
		}

		// pop it off
		nodesToCompile.pop_front();
	}

	if (!res) { return res; }

	llvm::IRBuilder<> allocBuilder{&allocBlock()};
	allocBuilder.CreateBr(&nodeCompiler(*entry)->firstBlock(0));

	return res;
}

FunctionCompiler::DebugFunctionType FunctionCompiler::createSubroutineType() {
	// create param list
	std::vector<
#if LLVM_VERSION_LESS_EQUAL(3, 5)
	    llvm::Value*
#else
	    llvm::Metadata*
#endif
	    >
	    params;
	{
		// ret first
		DataType intType = function().context().langModule()->typeFromName("i32");
		assert(intType.valid());

		params.push_back(
#if LLVM_VERSION_LESS_EQUAL(3, 6)
		    *
#endif
		    intType.debugType());

		// then first in inputexec id
		params.push_back(
#if LLVM_VERSION_LESS_EQUAL(3, 6)
		    *
#endif
		    intType.debugType());

		// add paramters
		for (const auto& dType :
		     boost::range::join(function().dataInputs(), function().dataOutputs())) {
			params.push_back(
#if LLVM_VERSION_LESS_EQUAL(3, 6)
			    *
#endif
			    dType.type.debugType());
		}
	}

	// create type
	auto subroutineType = diBuilder().createSubroutineType(
#if LLVM_VERSION_LESS_EQUAL(3, 7)
	    diFunction()->getFile(),
#endif
	    diBuilder().
#if LLVM_VERSION_LESS_EQUAL(3, 5)
	    getOrCreateArray
#else
	    getOrCreateTypeArray
#endif
	    (params));

	return subroutineType;
}

llvm::Value* FunctionCompiler::localVariable(boost::string_view name) {
	assert(initialized() &&
	       "Please initialize the function compiler before getting a local variable");

	auto iter = mLocalVariables.find(name.to_string());
	if (iter != mLocalVariables.end()) { return iter->second; }
	return nullptr;
}

GraphModule& FunctionCompiler::module() const { return function().module(); }
Context&     FunctionCompiler::context() const { return function().context(); }

int FunctionCompiler::nodeLineNumber(NodeInstance& node) {
	assert(&node.function() == &function() &&
	       "Cannot get node line number for a node not in the function");

	auto iter = mNodeLocations.right.find(&node);
	if (iter == mNodeLocations.right.end()) {
		return -1;  // ?
	}
	return iter->second;
}

NodeCompiler* FunctionCompiler::nodeCompiler(NodeInstance& node) {
	assert(&node.function() == &function() &&
	       "Cannot get a NodeCompiler for a node instance not in this function");

	auto iter = mNodeCompilers.find(&node);
	if (iter != mNodeCompilers.end()) { return &iter->second; }
	return nullptr;
}

NodeCompiler* FunctionCompiler::getOrCreateNodeCompiler(NodeInstance& node) {
	assert(&node.function() == &function() &&
	       "Cannot get a NodeCompiler for a node instance not in this function");

	auto iter = mNodeCompilers.find(&node);
	if (iter != mNodeCompilers.end()) { return &iter->second; }
	return &mNodeCompilers.emplace(&node, NodeCompiler{*this, node}).first->second;
}

Result compileFunction(const GraphFunction& func, llvm::Module* mod, llvm::DICompileUnit* debugCU,
                       llvm::DIBuilder& debugBuilder) {
	FunctionCompiler compiler{func, *mod, *debugCU, debugBuilder};

	auto res = compiler.initialize();
	if (!res) { return res; }

	res += compiler.compile();

	return res;
}

}  // namespace chi
<|endoftext|>