<commit_before>/*
-----------------------------------------------------------------------------
Copyright (c) 2011 Joachim Dorner

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

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

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

#include "Common.h"
#include "Connection.h"
#include "Function.h"

Connection::Connection() :
  loginParamsSize(0),
  loginParams(nullptr),
  connectionHandle(nullptr)
{
  uv_mutex_init(&this->invocationMutex);
}

Connection::~Connection()
{
  this->CloseConnection();

  uv_mutex_destroy(&this->invocationMutex);

  for (unsigned int i = 0; i < this->loginParamsSize; i++) {
     free(const_cast<SAP_UC*>(loginParams[i].name));
     free(const_cast<SAP_UC*>(loginParams[i].value));
  }
  free(loginParams);

  delete this->cbOpen;
  this->cbOpen = nullptr;
}

NAN_METHOD(Connection::New)
{
  if (!info.IsConstructCall()) {
    Nan::ThrowError("Invalid call format. Please use the 'new' operator.");
    return;
  }

  Connection *self = new Connection();
  self->Wrap(info.This());

  info.GetReturnValue().Set(info.This());
}

NAN_MODULE_INIT(Connection::Init)
{
  Nan::HandleScope scope;

  v8::Local<v8::FunctionTemplate> ctorTemplate = Nan::New<v8::FunctionTemplate>(New);
  ctorTemplate->InstanceTemplate()->SetInternalFieldCount(1);
  ctorTemplate->SetClassName(Nan::New("Connection").ToLocalChecked());

  Nan::SetPrototypeMethod(ctorTemplate, "GetVersion", Connection::GetVersion);
  Nan::SetPrototypeMethod(ctorTemplate, "Open", Connection::Open);
  Nan::SetPrototypeMethod(ctorTemplate, "Close", Connection::Close);
  Nan::SetPrototypeMethod(ctorTemplate, "Ping", Connection::Ping);
  Nan::SetPrototypeMethod(ctorTemplate, "IsOpen", Connection::IsOpen);
  Nan::SetPrototypeMethod(ctorTemplate, "Lookup", Connection::Lookup);
  Nan::SetPrototypeMethod(ctorTemplate, "SetIniPath", Connection::SetIniPath);

  Nan::Set(target, Nan::New("Connection").ToLocalChecked(), ctorTemplate->GetFunction());
}

/**
 * @return Array
 */
NAN_METHOD(Connection::GetVersion)
{
  unsigned majorVersion, minorVersion, patchLevel;

  RfcGetVersion(&majorVersion, &minorVersion, &patchLevel);
  v8::Local<v8::Array> versionInfo = Nan::New<v8::Array>(3);

  versionInfo->Set(0, Nan::New<v8::Integer>(majorVersion));
  versionInfo->Set(1, Nan::New<v8::Integer>(minorVersion));
  versionInfo->Set(2, Nan::New<v8::Integer>(patchLevel));

  info.GetReturnValue().Set(versionInfo);
}

NAN_METHOD(Connection::Open)
{
  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());

  if (info.Length() < 2) {
    Nan::ThrowError("Function expects 2 arguments");
    return;
  }
  if (!info[0]->IsObject()) {
    Nan::ThrowError("Argument 1 must be an object");
    return;
  }
  if (!info[1]->IsFunction()) {
    Nan::ThrowError("Argument 2 must be a function");
    return;
  }

  v8::Local<v8::Object> optionsObj = info[0]->ToObject();
  v8::Local<v8::Array> props = optionsObj->GetPropertyNames();

  self->loginParamsSize = props->Length();
  self->loginParams = static_cast<RFC_CONNECTION_PARAMETER*>(malloc(self->loginParamsSize * sizeof(RFC_CONNECTION_PARAMETER)));
  memset(self->loginParams, 0, self->loginParamsSize * sizeof(RFC_CONNECTION_PARAMETER));
  memset(&self->errorInfo, 0, sizeof(RFC_ERROR_INFO));

  for (unsigned int i = 0; i < self->loginParamsSize; i++) {
    v8::Local<v8::Value> name = props->Get(i);
    v8::Local<v8::Value> value = optionsObj->Get(name->ToString());

    self->loginParams[i].name = convertToSAPUC(name);
    self->loginParams[i].value = convertToSAPUC(value);

#ifndef NDEBUG
    std::cout << convertToString(name) << "--> " << convertToString(value) << std::endl;
#endif
  }

  // Store callback
  self->cbOpen = new Nan::Callback(v8::Local<v8::Function>::Cast(info[1]));
  self->Ref();

  uv_work_t* req = new uv_work_t();
  req->data = self;
  uv_queue_work(uv_default_loop(), req, EIO_Open, (uv_after_work_cb)EIO_AfterOpen);
#if !NODE_VERSION_AT_LEAST(0, 7, 9)
    uv_ref(uv_default_loop());
#endif
}

void Connection::EIO_Open(uv_work_t *req)
{
  Connection *self = static_cast<Connection*>(req->data);

  self->connectionHandle = RfcOpenConnection(self->loginParams, self->loginParamsSize, &self->errorInfo);
}

void Connection::EIO_AfterOpen(uv_work_t *req)
{
  Nan::HandleScope scope;
  RFC_ERROR_INFO errorInfo;
  int isValid;
  Connection *self = static_cast<Connection*>(req->data);

  v8::Local<v8::Value> argv[1];
  argv[0] = Nan::Null();

  if (self->connectionHandle == nullptr) {
    argv[0] = RfcError(self->errorInfo);
  } else {
    RfcIsConnectionHandleValid(self->connectionHandle, &isValid, &errorInfo);
    if (!isValid) {
      argv[0] = RfcError(errorInfo);
    }
  }

  Nan::TryCatch try_catch;

  assert(!self->cbOpen->IsEmpty());
  self->cbOpen->Call(1, argv);
  delete self->cbOpen;
  self->cbOpen = nullptr;
  self->Unref();

  if (try_catch.HasCaught()) {
    Nan::FatalException(try_catch);
  }
}

NAN_METHOD(Connection::Close)
{
  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());
  info.GetReturnValue().Set(self->CloseConnection());
}

v8::Local<v8::Value> Connection::CloseConnection(void)
{
  Nan::EscapableHandleScope scope;
  RFC_RC rc = RFC_OK;
  RFC_ERROR_INFO errorInfo;

  if (this->connectionHandle != nullptr) {
    rc = RfcCloseConnection(this->connectionHandle, &errorInfo);
    if (rc != RFC_OK) {
      scope.Escape(RfcError(errorInfo));
    }
  }

  return scope.Escape(Nan::True());
}

RFC_CONNECTION_HANDLE Connection::GetConnectionHandle(void)
{
  return this->connectionHandle;
}

void Connection::LockMutex(void)
{
  uv_mutex_lock(&this->invocationMutex);
}

void Connection::UnlockMutex(void)
{
  uv_mutex_unlock(&this->invocationMutex);
}

NAN_METHOD(Connection::IsOpen)
{
  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());
  RFC_RC rc = RFC_OK;
  RFC_ERROR_INFO errorInfo;
  int isValid;

  rc = RfcIsConnectionHandleValid(self->connectionHandle, &isValid, &errorInfo);
  info.GetReturnValue().Set(isValid ? Nan::True() : Nan::False());
}

/**
 *
 * @return true if successful, else: RfcException
 */
NAN_METHOD(Connection::Ping)
{
  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());
  RFC_RC rc = RFC_OK;
  RFC_ERROR_INFO errorInfo;

  if (info.Length() > 0) {
    Nan::ThrowError("No arguments expected");
    return;
  }

  rc = RfcPing(self->connectionHandle, &errorInfo);
  if (rc != RFC_OK) {
    RETURN_RFC_ERROR(errorInfo);
  }

  info.GetReturnValue().Set(Nan::True());
}

/**
 *
 * @return Function
 */
NAN_METHOD(Connection::Lookup)
{
  RFC_RC rc = RFC_OK;
  RFC_ERROR_INFO errorInfo;
  int isValid;

  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());

  if (info.Length() != 1) {
    Nan::ThrowError("Function expects 1 argument");
    return;
  }
  if (!info[0]->IsString()) {
    Nan::ThrowError("Argument 1 must be function module name");
    return;
  }

  rc = RfcIsConnectionHandleValid(self->connectionHandle, &isValid, &errorInfo);
  if (!isValid) {
    Nan::ThrowError(RfcError(errorInfo));
    return;
  }

  v8::Local<v8::Value> f = Function::NewInstance(*self, info);
  info.GetReturnValue().Set(f);
}

/**
 *
 * @return true if successful, else: RfcException
 */
NAN_METHOD(Connection::SetIniPath)
{
  RFC_RC rc = RFC_OK;
  RFC_ERROR_INFO errorInfo;
  int isValid;

  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());

  if (info.Length() != 1) {
    THROW_V8_EXCEPTION("Function expects 1 argument");
    return;
  }
  if (!info[0]->IsString()) {
    THROW_V8_EXCEPTION("Argument 1 must be a path name");
    return;
  }

  v8::Local<v8::Value> iniPath = info[0]->ToString();

  rc = RfcSetIniPath(convertToSAPUC(iniPath), &errorInfo);
  if (rc) {
    THROW_V8_EXCEPTION(RfcError(errorInfo));
    return;
  }

  info.GetReturnValue().Set(Nan::True());
}
<commit_msg>fix deletion of THROW_V8_EXCEPTION macro<commit_after>/*
-----------------------------------------------------------------------------
Copyright (c) 2011 Joachim Dorner

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

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

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

#include "Common.h"
#include "Connection.h"
#include "Function.h"

Connection::Connection() :
  loginParamsSize(0),
  loginParams(nullptr),
  connectionHandle(nullptr)
{
  uv_mutex_init(&this->invocationMutex);
}

Connection::~Connection()
{
  this->CloseConnection();

  uv_mutex_destroy(&this->invocationMutex);

  for (unsigned int i = 0; i < this->loginParamsSize; i++) {
     free(const_cast<SAP_UC*>(loginParams[i].name));
     free(const_cast<SAP_UC*>(loginParams[i].value));
  }
  free(loginParams);

  delete this->cbOpen;
  this->cbOpen = nullptr;
}

NAN_METHOD(Connection::New)
{
  if (!info.IsConstructCall()) {
    Nan::ThrowError("Invalid call format. Please use the 'new' operator.");
    return;
  }

  Connection *self = new Connection();
  self->Wrap(info.This());

  info.GetReturnValue().Set(info.This());
}

NAN_MODULE_INIT(Connection::Init)
{
  Nan::HandleScope scope;

  v8::Local<v8::FunctionTemplate> ctorTemplate = Nan::New<v8::FunctionTemplate>(New);
  ctorTemplate->InstanceTemplate()->SetInternalFieldCount(1);
  ctorTemplate->SetClassName(Nan::New("Connection").ToLocalChecked());

  Nan::SetPrototypeMethod(ctorTemplate, "GetVersion", Connection::GetVersion);
  Nan::SetPrototypeMethod(ctorTemplate, "Open", Connection::Open);
  Nan::SetPrototypeMethod(ctorTemplate, "Close", Connection::Close);
  Nan::SetPrototypeMethod(ctorTemplate, "Ping", Connection::Ping);
  Nan::SetPrototypeMethod(ctorTemplate, "IsOpen", Connection::IsOpen);
  Nan::SetPrototypeMethod(ctorTemplate, "Lookup", Connection::Lookup);
  Nan::SetPrototypeMethod(ctorTemplate, "SetIniPath", Connection::SetIniPath);

  Nan::Set(target, Nan::New("Connection").ToLocalChecked(), ctorTemplate->GetFunction());
}

/**
 * @return Array
 */
NAN_METHOD(Connection::GetVersion)
{
  unsigned majorVersion, minorVersion, patchLevel;

  RfcGetVersion(&majorVersion, &minorVersion, &patchLevel);
  v8::Local<v8::Array> versionInfo = Nan::New<v8::Array>(3);

  versionInfo->Set(0, Nan::New<v8::Integer>(majorVersion));
  versionInfo->Set(1, Nan::New<v8::Integer>(minorVersion));
  versionInfo->Set(2, Nan::New<v8::Integer>(patchLevel));

  info.GetReturnValue().Set(versionInfo);
}

NAN_METHOD(Connection::Open)
{
  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());

  if (info.Length() < 2) {
    Nan::ThrowError("Function expects 2 arguments");
    return;
  }
  if (!info[0]->IsObject()) {
    Nan::ThrowError("Argument 1 must be an object");
    return;
  }
  if (!info[1]->IsFunction()) {
    Nan::ThrowError("Argument 2 must be a function");
    return;
  }

  v8::Local<v8::Object> optionsObj = info[0]->ToObject();
  v8::Local<v8::Array> props = optionsObj->GetPropertyNames();

  self->loginParamsSize = props->Length();
  self->loginParams = static_cast<RFC_CONNECTION_PARAMETER*>(malloc(self->loginParamsSize * sizeof(RFC_CONNECTION_PARAMETER)));
  memset(self->loginParams, 0, self->loginParamsSize * sizeof(RFC_CONNECTION_PARAMETER));
  memset(&self->errorInfo, 0, sizeof(RFC_ERROR_INFO));

  for (unsigned int i = 0; i < self->loginParamsSize; i++) {
    v8::Local<v8::Value> name = props->Get(i);
    v8::Local<v8::Value> value = optionsObj->Get(name->ToString());

    self->loginParams[i].name = convertToSAPUC(name);
    self->loginParams[i].value = convertToSAPUC(value);

#ifndef NDEBUG
    std::cout << convertToString(name) << "--> " << convertToString(value) << std::endl;
#endif
  }

  // Store callback
  self->cbOpen = new Nan::Callback(v8::Local<v8::Function>::Cast(info[1]));
  self->Ref();

  uv_work_t* req = new uv_work_t();
  req->data = self;
  uv_queue_work(uv_default_loop(), req, EIO_Open, (uv_after_work_cb)EIO_AfterOpen);
#if !NODE_VERSION_AT_LEAST(0, 7, 9)
    uv_ref(uv_default_loop());
#endif
}

void Connection::EIO_Open(uv_work_t *req)
{
  Connection *self = static_cast<Connection*>(req->data);

  self->connectionHandle = RfcOpenConnection(self->loginParams, self->loginParamsSize, &self->errorInfo);
}

void Connection::EIO_AfterOpen(uv_work_t *req)
{
  Nan::HandleScope scope;
  RFC_ERROR_INFO errorInfo;
  int isValid;
  Connection *self = static_cast<Connection*>(req->data);

  v8::Local<v8::Value> argv[1];
  argv[0] = Nan::Null();

  if (self->connectionHandle == nullptr) {
    argv[0] = RfcError(self->errorInfo);
  } else {
    RfcIsConnectionHandleValid(self->connectionHandle, &isValid, &errorInfo);
    if (!isValid) {
      argv[0] = RfcError(errorInfo);
    }
  }

  Nan::TryCatch try_catch;

  assert(!self->cbOpen->IsEmpty());
  self->cbOpen->Call(1, argv);
  delete self->cbOpen;
  self->cbOpen = nullptr;
  self->Unref();

  if (try_catch.HasCaught()) {
    Nan::FatalException(try_catch);
  }
}

NAN_METHOD(Connection::Close)
{
  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());
  info.GetReturnValue().Set(self->CloseConnection());
}

v8::Local<v8::Value> Connection::CloseConnection(void)
{
  Nan::EscapableHandleScope scope;
  RFC_RC rc = RFC_OK;
  RFC_ERROR_INFO errorInfo;

  if (this->connectionHandle != nullptr) {
    rc = RfcCloseConnection(this->connectionHandle, &errorInfo);
    if (rc != RFC_OK) {
      scope.Escape(RfcError(errorInfo));
    }
  }

  return scope.Escape(Nan::True());
}

RFC_CONNECTION_HANDLE Connection::GetConnectionHandle(void)
{
  return this->connectionHandle;
}

void Connection::LockMutex(void)
{
  uv_mutex_lock(&this->invocationMutex);
}

void Connection::UnlockMutex(void)
{
  uv_mutex_unlock(&this->invocationMutex);
}

NAN_METHOD(Connection::IsOpen)
{
  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());
  RFC_RC rc = RFC_OK;
  RFC_ERROR_INFO errorInfo;
  int isValid;

  rc = RfcIsConnectionHandleValid(self->connectionHandle, &isValid, &errorInfo);
  info.GetReturnValue().Set(isValid ? Nan::True() : Nan::False());
}

/**
 *
 * @return true if successful, else: RfcException
 */
NAN_METHOD(Connection::Ping)
{
  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());
  RFC_RC rc = RFC_OK;
  RFC_ERROR_INFO errorInfo;

  if (info.Length() > 0) {
    Nan::ThrowError("No arguments expected");
    return;
  }

  rc = RfcPing(self->connectionHandle, &errorInfo);
  if (rc != RFC_OK) {
    RETURN_RFC_ERROR(errorInfo);
  }

  info.GetReturnValue().Set(Nan::True());
}

/**
 *
 * @return Function
 */
NAN_METHOD(Connection::Lookup)
{
  RFC_RC rc = RFC_OK;
  RFC_ERROR_INFO errorInfo;
  int isValid;

  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());

  if (info.Length() != 1) {
    Nan::ThrowError("Function expects 1 argument");
    return;
  }
  if (!info[0]->IsString()) {
    Nan::ThrowError("Argument 1 must be function module name");
    return;
  }

  rc = RfcIsConnectionHandleValid(self->connectionHandle, &isValid, &errorInfo);
  if (!isValid) {
    Nan::ThrowError(RfcError(errorInfo));
    return;
  }

  v8::Local<v8::Value> f = Function::NewInstance(*self, info);
  info.GetReturnValue().Set(f);
}

/**
 *
 * @return true if successful, else: RfcException
 */
NAN_METHOD(Connection::SetIniPath)
{
  RFC_RC rc = RFC_OK;
  RFC_ERROR_INFO errorInfo;
  int isValid;

  Connection *self = node::ObjectWrap::Unwrap<Connection>(info.This());

  if (info.Length() != 1) {
    Nan::ThrowError("Function expects 1 argument");
    return;
  }
  if (!info[0]->IsString()) {
    Nan::ThrowError("Argument 1 must be a path name");
    return;
  }

  v8::Local<v8::Value> iniPath = info[0]->ToString();

  rc = RfcSetIniPath(convertToSAPUC(iniPath), &errorInfo);
  if (rc) {
    Nan::ThrowError(RfcError(errorInfo));
    return;
  }

  info.GetReturnValue().Set(Nan::True());
}
<|endoftext|>


<commit_before>//  illarionserver - server for the game Illarion
//  Copyright 2011 Illarion e.V.
//
//  This file is part of illarionserver.
//
//  illarionserver is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Affero General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  illarionserver 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 Affero General Public License for more details.
//
//  You should have received a copy of the GNU Affero General Public License
//  along with illarionserver.  If not, see <http://www.gnu.org/licenses/>.

#include "World.hpp"
#include "data/TilesTable.hpp"
#include "TableStructs.hpp"
#include "Player.hpp"
#include "NPC.hpp"
#include "Monster.hpp"
#include "Field.hpp"
#include "netinterface/protocol/ServerCommands.hpp"
#include "Logger.hpp"
#include "data/Data.hpp"

void World::sendMessageToAdmin(const std::string &message) {
    Players.for_each([&message](Player *player) {
        if (player->hasGMRight(gmr_getgmcalls)) {
            ServerCommandPointer cmd = std::make_shared<SayTC>(player->getPosition(), message);
            player->Connection->addCommand(cmd);
        }
    });
}

std::string World::languagePrefix(int Language) {
    if (Language==0) {
        return "";
    } else if (Language==1) {
        return "[hum] ";
    } else if (Language==2) {
        return "[dwa] ";
    } else if (Language==3) {
        return "[elf] ";
    } else if (Language==4) {
        return "[liz] ";
    } else if (Language==5) {
        return "[orc] ";
    } else if (Language==6) {
        return "[hal] ";
    } else if (Language==7) {
        return "[fai] ";
    } else if (Language==8) {
        return "[gno] ";
    } else if (Language==9) {
        return "[gob] ";
    } else if (Language==10) {
        return "[anc] ";
    } else {
        return "";
    }
}

std::string World::languageNumberToSkillName(int languageNumber) {
    switch (languageNumber) {
    case 0:
        return "common language";

    case 1:
        return "human language";

    case 2:
        return "dwarf language";

    case 3:
        return "elf language";

    case 4:
        return "lizard language";

    case 5:
        return "orc language";

    case 6:
        return "halfling language";

    case 7:
        return "fairy language";

    case 8:
        return "gnome language";

    case 9:
        return "goblin language";

    case 10:
        return "ancient language";

    default:
        return "";

    }
}

Range World::getTalkRange(Character::talk_type tt) const {
    Range range;

    switch (tt) {
    case Character::tt_say:
        range.radius = 14;
        break;

    case Character::tt_whisper:
        range.radius = 2;
        range.zRadius = 0;
        break;

    case Character::tt_yell:
        range.radius = 30;
        break;
    }

    return range;
}

void World::sendMessageToAllPlayers(const std::string &message) {
    Players.for_each([&message](Player *player) {
        player->inform(message, Player::informBroadcast);
    });
}

void World::broadcast(const std::string &german, const std::string &english) {
    Players.for_each([&german, &english](Player *player) {
        player->inform(german, english, Player::informBroadcast);
    });
}

void World::sendMessageToAllCharsInRange(const std::string &german, const std::string &english, Character::talk_type tt, Character *cc) {
    auto range = getTalkRange(tt);
    std::string spokenMessage_german, spokenMessage_english, tempMessage;
    bool is_action = german.substr(0, 3) == "#me";

    if (!is_action) {
        // alter message because of the speakers inability to speak...
        spokenMessage_german = cc->alterSpokenMessage(german, cc->getLanguageSkill(cc->getActiveLanguage()));
        spokenMessage_english = cc->alterSpokenMessage(english, cc->getLanguageSkill(cc->getActiveLanguage()));
    }

    // tell all OTHER players... (but tell them what they understand due to their inability to do so)
    // tell the player himself what he wanted to say
    std::string prefix = languagePrefix(cc->getActiveLanguage());

    for (const auto &player : Players.findAllCharactersInRangeOf(cc->getPosition(), range)) {
        if (!is_action && player->getId() != cc->getId()) {
            tempMessage = prefix + player->alterSpokenMessage(player->nls(spokenMessage_german, spokenMessage_english), player->getLanguageSkill(cc->getActiveLanguage()));
            player->receiveText(tt, tempMessage, cc);
        } else {
            if (is_action) {
                player->receiveText(tt, player->nls(german, english), cc);
            } else {
                player->receiveText(tt, prefix + player->nls(german, english), cc);
            }
        }
    }

    if (cc->getType() == Character::player) {
        // tell all npcs
        for (const auto &npc : Npc.findAllCharactersInRangeOf(cc->getPosition(), range)) {
            tempMessage=prefix + npc->alterSpokenMessage(english, npc->getLanguageSkill(cc->getActiveLanguage()));
            npc->receiveText(tt, tempMessage, cc);
        }

        // tell all monsters
        for (const auto &monster : Monsters.findAllCharactersInRangeOf(cc->getPosition(), range)) {
            monster->receiveText(tt, english, cc);
        }
    }
}

void World::sendLanguageMessageToAllCharsInRange(const std::string &message, Character::talk_type tt, Language lang, Character *cc) {
    auto range = getTalkRange(tt);

    // get all Players
    std::vector<Player *> players = Players.findAllCharactersInRangeOf(cc->getPosition(), range);
    // get all NPCs
    std::vector<NPC *> npcs = Npc.findAllCharactersInRangeOf(cc->getPosition(), range);
    // get all Monsters
    std::vector<Monster *> monsters = Monsters.findAllCharactersInRangeOf(cc->getPosition(), range);

    // alter message because of the speakers inability to speak...
    std::string spokenMessage,tempMessage;
    spokenMessage=cc->alterSpokenMessage(message,cc->getLanguageSkill(cc->getActiveLanguage()));

    // tell all OTHER players... (but tell them what they understand due to their inability to do so)
    // tell the player himself what he wanted to say
    if (message.substr(0, 3) == "#me") {
        for (const auto &player : players) {
            if (player->getPlayerLanguage() == lang) {
                player->receiveText(tt, message, cc);
            }
        }
    } else {
        for (const auto &player : players) {
            if (player->getPlayerLanguage() == lang) {
                if (player->getId() != cc->getId()) {
                    tempMessage=languagePrefix(cc->getActiveLanguage()) + player->alterSpokenMessage(spokenMessage, player->getLanguageSkill(cc->getActiveLanguage()));
                    player->receiveText(tt, tempMessage, cc);
                } else {
                    player->receiveText(tt, languagePrefix(cc->getActiveLanguage())+message, cc);
                }
            }
        }
    }

    if (cc->getType() == Character::player) {
        // tell all npcs
        for (const auto &npc : npcs) {
            tempMessage=languagePrefix(cc->getActiveLanguage()) + npc->alterSpokenMessage(spokenMessage, npc->getLanguageSkill(cc->getActiveLanguage()));
            npc->receiveText(tt, tempMessage, cc);
        }

        // tell all monsters
        for (const auto &monster : monsters) {
            monster->receiveText(tt, message, cc);
        }
    }
}

void World::sendMessageToAllCharsInRange(const std::string &message, Character::talk_type tt, Character *cc) {
    sendMessageToAllCharsInRange(message, message, tt, cc);
}

void World::makeGFXForAllPlayersInRange(const position &pos, int radius ,unsigned short int gfx) {
    Range range;
    range.radius = radius;

    for (const auto &player : Players.findAllCharactersInRangeOf(pos, range)) {
        ServerCommandPointer cmd = std::make_shared<GraphicEffectTC>(pos, gfx);
        player->Connection->addCommand(cmd);
    }
}

void World::makeSoundForAllPlayersInRange(const position &pos, int radius, unsigned short int sound) {
    Range range;
    range.radius = radius;

    for (const auto &player : Players.findAllCharactersInRangeOf(pos, range)) {
        ServerCommandPointer cmd = std::make_shared<SoundTC>(pos, sound);
        player->Connection->addCommand(cmd);
    }
}

void World::lookAtMapItem(Player *player, const position &pos,
                          uint8_t stackPos) {
    try {
        Field &field = fieldAt(pos);
        ScriptItem item = field.getStackItem(stackPos);

        if (item.getId()) {
            item.type = ScriptItem::it_field;
            item.pos = pos;
            item.itempos = stackPos;
            item.owner = player;

            ItemLookAt lookAt = item.getLookAt(player);

            if (lookAt.isValid()) {
                itemInform(player, item, lookAt);
            } else {
                lookAtTile(player, field.getTileId(), pos);
            }
        } else {
            lookAtTile(player, field.getTileId(), pos);
        }
    } catch (FieldNotFound &) {
    }
}

void World::lookAtTile(Player *cp, unsigned short int tile, const position &pos) {
    const TilesStruct &tileStruct = Data::Tiles[tile];
    ServerCommandPointer cmd = std::make_shared<LookAtTileTC>(pos, cp->nls(tileStruct.German, tileStruct.English));
    cp->Connection->addCommand(cmd);
}

void World::lookAtShowcaseItem(Player *cp, uint8_t showcase, unsigned char position) {

    ScriptItem titem;

    if (cp->isShowcaseOpen(showcase)) {
        Container *ps = cp->getShowcaseContainer(showcase);

        if (ps != nullptr) {
            Container *tc;

            if (ps->viewItemNr(position, titem, tc)) {
                ScriptItem n_item = titem;

                n_item.type = ScriptItem::it_container;
                n_item.pos = cp->getPosition();
                n_item.owner = cp;
                n_item.itempos = position;
                n_item.inside = ps;

                ItemLookAt lookAt = n_item.getLookAt(cp);

                if (lookAt.isValid()) {
                    itemInform(cp, n_item, lookAt);
                }
            }
        }
    }
}

void World::lookAtInventoryItem(Player *cp, unsigned char position) {
    if (cp->items[ position ].getId() != 0) {

        Item titem = cp->items[ position ];
        ScriptItem n_item(cp->items[ position ]);

        if (position < MAX_BODY_ITEMS) {
            n_item.type = ScriptItem::it_inventory;
        } else {
            n_item.type = ScriptItem::it_belt;
        }

        n_item.itempos = position;
        n_item.pos = cp->getPosition();
        n_item.owner = cp;

        ItemLookAt lookAt = n_item.getLookAt(cp);

        if (lookAt.isValid()) {
            itemInform(cp, n_item, lookAt);
        }
    }
}

void World::forceIntroducePlayer(Player *cp, Player *Admin) {
    Admin->introducePlayer(cp);
}

void World::introduceMyself(Player *cp) {
    Range range;
    range.radius = 2;
    range.zRadius = 0;

    for (const auto &player : Players.findAllCharactersInRangeOf(cp->getPosition(), range)) {
        player->introducePlayer(cp);
    }
}

void World::sendWeather(Player *cp) {
    cp->sendWeather(weather);
}

void World::sendIGTime(Player *cp) {
    ServerCommandPointer cmd = std::make_shared<UpdateTimeTC>(static_cast<unsigned char>(getTime("hour")),static_cast<unsigned char>(getTime("minute")),static_cast<unsigned char>(getTime("day")),static_cast<unsigned char>(getTime("month")), static_cast<short int>(getTime("year")));
    cp->Connection->addCommand(cmd);
}

void World::sendIGTimeToAllPlayers() {
    Players.for_each([this](Player *player) {
        sendIGTime(player);
    });
}

void World::sendWeatherToAllPlayers() {
    Players.for_each([this](Player *player) {
        player->sendWeather(weather);
    });
}

<commit_msg>Remove unused variable<commit_after>//  illarionserver - server for the game Illarion
//  Copyright 2011 Illarion e.V.
//
//  This file is part of illarionserver.
//
//  illarionserver is free software: you can redistribute it and/or modify
//  it under the terms of the GNU Affero General Public License as published by
//  the Free Software Foundation, either version 3 of the License, or
//  (at your option) any later version.
//
//  illarionserver 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 Affero General Public License for more details.
//
//  You should have received a copy of the GNU Affero General Public License
//  along with illarionserver.  If not, see <http://www.gnu.org/licenses/>.

#include "World.hpp"
#include "data/TilesTable.hpp"
#include "TableStructs.hpp"
#include "Player.hpp"
#include "NPC.hpp"
#include "Monster.hpp"
#include "Field.hpp"
#include "netinterface/protocol/ServerCommands.hpp"
#include "Logger.hpp"
#include "data/Data.hpp"

void World::sendMessageToAdmin(const std::string &message) {
    Players.for_each([&message](Player *player) {
        if (player->hasGMRight(gmr_getgmcalls)) {
            ServerCommandPointer cmd = std::make_shared<SayTC>(player->getPosition(), message);
            player->Connection->addCommand(cmd);
        }
    });
}

std::string World::languagePrefix(int Language) {
    if (Language==0) {
        return "";
    } else if (Language==1) {
        return "[hum] ";
    } else if (Language==2) {
        return "[dwa] ";
    } else if (Language==3) {
        return "[elf] ";
    } else if (Language==4) {
        return "[liz] ";
    } else if (Language==5) {
        return "[orc] ";
    } else if (Language==6) {
        return "[hal] ";
    } else if (Language==7) {
        return "[fai] ";
    } else if (Language==8) {
        return "[gno] ";
    } else if (Language==9) {
        return "[gob] ";
    } else if (Language==10) {
        return "[anc] ";
    } else {
        return "";
    }
}

std::string World::languageNumberToSkillName(int languageNumber) {
    switch (languageNumber) {
    case 0:
        return "common language";

    case 1:
        return "human language";

    case 2:
        return "dwarf language";

    case 3:
        return "elf language";

    case 4:
        return "lizard language";

    case 5:
        return "orc language";

    case 6:
        return "halfling language";

    case 7:
        return "fairy language";

    case 8:
        return "gnome language";

    case 9:
        return "goblin language";

    case 10:
        return "ancient language";

    default:
        return "";

    }
}

Range World::getTalkRange(Character::talk_type tt) const {
    Range range;

    switch (tt) {
    case Character::tt_say:
        range.radius = 14;
        break;

    case Character::tt_whisper:
        range.radius = 2;
        range.zRadius = 0;
        break;

    case Character::tt_yell:
        range.radius = 30;
        break;
    }

    return range;
}

void World::sendMessageToAllPlayers(const std::string &message) {
    Players.for_each([&message](Player *player) {
        player->inform(message, Player::informBroadcast);
    });
}

void World::broadcast(const std::string &german, const std::string &english) {
    Players.for_each([&german, &english](Player *player) {
        player->inform(german, english, Player::informBroadcast);
    });
}

void World::sendMessageToAllCharsInRange(const std::string &german, const std::string &english, Character::talk_type tt, Character *cc) {
    auto range = getTalkRange(tt);
    std::string spokenMessage_german, spokenMessage_english, tempMessage;
    bool is_action = german.substr(0, 3) == "#me";

    if (!is_action) {
        // alter message because of the speakers inability to speak...
        spokenMessage_german = cc->alterSpokenMessage(german, cc->getLanguageSkill(cc->getActiveLanguage()));
        spokenMessage_english = cc->alterSpokenMessage(english, cc->getLanguageSkill(cc->getActiveLanguage()));
    }

    // tell all OTHER players... (but tell them what they understand due to their inability to do so)
    // tell the player himself what he wanted to say
    std::string prefix = languagePrefix(cc->getActiveLanguage());

    for (const auto &player : Players.findAllCharactersInRangeOf(cc->getPosition(), range)) {
        if (!is_action && player->getId() != cc->getId()) {
            tempMessage = prefix + player->alterSpokenMessage(player->nls(spokenMessage_german, spokenMessage_english), player->getLanguageSkill(cc->getActiveLanguage()));
            player->receiveText(tt, tempMessage, cc);
        } else {
            if (is_action) {
                player->receiveText(tt, player->nls(german, english), cc);
            } else {
                player->receiveText(tt, prefix + player->nls(german, english), cc);
            }
        }
    }

    if (cc->getType() == Character::player) {
        // tell all npcs
        for (const auto &npc : Npc.findAllCharactersInRangeOf(cc->getPosition(), range)) {
            tempMessage=prefix + npc->alterSpokenMessage(english, npc->getLanguageSkill(cc->getActiveLanguage()));
            npc->receiveText(tt, tempMessage, cc);
        }

        // tell all monsters
        for (const auto &monster : Monsters.findAllCharactersInRangeOf(cc->getPosition(), range)) {
            monster->receiveText(tt, english, cc);
        }
    }
}

void World::sendLanguageMessageToAllCharsInRange(const std::string &message, Character::talk_type tt, Language lang, Character *cc) {
    auto range = getTalkRange(tt);

    // get all Players
    std::vector<Player *> players = Players.findAllCharactersInRangeOf(cc->getPosition(), range);
    // get all NPCs
    std::vector<NPC *> npcs = Npc.findAllCharactersInRangeOf(cc->getPosition(), range);
    // get all Monsters
    std::vector<Monster *> monsters = Monsters.findAllCharactersInRangeOf(cc->getPosition(), range);

    // alter message because of the speakers inability to speak...
    std::string spokenMessage,tempMessage;
    spokenMessage=cc->alterSpokenMessage(message,cc->getLanguageSkill(cc->getActiveLanguage()));

    // tell all OTHER players... (but tell them what they understand due to their inability to do so)
    // tell the player himself what he wanted to say
    if (message.substr(0, 3) == "#me") {
        for (const auto &player : players) {
            if (player->getPlayerLanguage() == lang) {
                player->receiveText(tt, message, cc);
            }
        }
    } else {
        for (const auto &player : players) {
            if (player->getPlayerLanguage() == lang) {
                if (player->getId() != cc->getId()) {
                    tempMessage=languagePrefix(cc->getActiveLanguage()) + player->alterSpokenMessage(spokenMessage, player->getLanguageSkill(cc->getActiveLanguage()));
                    player->receiveText(tt, tempMessage, cc);
                } else {
                    player->receiveText(tt, languagePrefix(cc->getActiveLanguage())+message, cc);
                }
            }
        }
    }

    if (cc->getType() == Character::player) {
        // tell all npcs
        for (const auto &npc : npcs) {
            tempMessage=languagePrefix(cc->getActiveLanguage()) + npc->alterSpokenMessage(spokenMessage, npc->getLanguageSkill(cc->getActiveLanguage()));
            npc->receiveText(tt, tempMessage, cc);
        }

        // tell all monsters
        for (const auto &monster : monsters) {
            monster->receiveText(tt, message, cc);
        }
    }
}

void World::sendMessageToAllCharsInRange(const std::string &message, Character::talk_type tt, Character *cc) {
    sendMessageToAllCharsInRange(message, message, tt, cc);
}

void World::makeGFXForAllPlayersInRange(const position &pos, int radius ,unsigned short int gfx) {
    Range range;
    range.radius = radius;

    for (const auto &player : Players.findAllCharactersInRangeOf(pos, range)) {
        ServerCommandPointer cmd = std::make_shared<GraphicEffectTC>(pos, gfx);
        player->Connection->addCommand(cmd);
    }
}

void World::makeSoundForAllPlayersInRange(const position &pos, int radius, unsigned short int sound) {
    Range range;
    range.radius = radius;

    for (const auto &player : Players.findAllCharactersInRangeOf(pos, range)) {
        ServerCommandPointer cmd = std::make_shared<SoundTC>(pos, sound);
        player->Connection->addCommand(cmd);
    }
}

void World::lookAtMapItem(Player *player, const position &pos,
                          uint8_t stackPos) {
    try {
        Field &field = fieldAt(pos);
        ScriptItem item = field.getStackItem(stackPos);

        if (item.getId()) {
            item.type = ScriptItem::it_field;
            item.pos = pos;
            item.itempos = stackPos;
            item.owner = player;

            ItemLookAt lookAt = item.getLookAt(player);

            if (lookAt.isValid()) {
                itemInform(player, item, lookAt);
            } else {
                lookAtTile(player, field.getTileId(), pos);
            }
        } else {
            lookAtTile(player, field.getTileId(), pos);
        }
    } catch (FieldNotFound &) {
    }
}

void World::lookAtTile(Player *cp, unsigned short int tile, const position &pos) {
    const TilesStruct &tileStruct = Data::Tiles[tile];
    ServerCommandPointer cmd = std::make_shared<LookAtTileTC>(pos, cp->nls(tileStruct.German, tileStruct.English));
    cp->Connection->addCommand(cmd);
}

void World::lookAtShowcaseItem(Player *cp, uint8_t showcase, unsigned char position) {

    ScriptItem titem;

    if (cp->isShowcaseOpen(showcase)) {
        Container *ps = cp->getShowcaseContainer(showcase);

        if (ps != nullptr) {
            Container *tc;

            if (ps->viewItemNr(position, titem, tc)) {
                ScriptItem n_item = titem;

                n_item.type = ScriptItem::it_container;
                n_item.pos = cp->getPosition();
                n_item.owner = cp;
                n_item.itempos = position;
                n_item.inside = ps;

                ItemLookAt lookAt = n_item.getLookAt(cp);

                if (lookAt.isValid()) {
                    itemInform(cp, n_item, lookAt);
                }
            }
        }
    }
}

void World::lookAtInventoryItem(Player *cp, unsigned char position) {
    if (cp->items[ position ].getId() != 0) {

        ScriptItem item(cp->items[ position ]);

        if (position < MAX_BODY_ITEMS) {
            item.type = ScriptItem::it_inventory;
        } else {
            item.type = ScriptItem::it_belt;
        }

        item.itempos = position;
        item.pos = cp->getPosition();
        item.owner = cp;

        ItemLookAt lookAt = item.getLookAt(cp);

        if (lookAt.isValid()) {
            itemInform(cp, item, lookAt);
        }
    }
}

void World::forceIntroducePlayer(Player *cp, Player *Admin) {
    Admin->introducePlayer(cp);
}

void World::introduceMyself(Player *cp) {
    Range range;
    range.radius = 2;
    range.zRadius = 0;

    for (const auto &player : Players.findAllCharactersInRangeOf(cp->getPosition(), range)) {
        player->introducePlayer(cp);
    }
}

void World::sendWeather(Player *cp) {
    cp->sendWeather(weather);
}

void World::sendIGTime(Player *cp) {
    ServerCommandPointer cmd = std::make_shared<UpdateTimeTC>(static_cast<unsigned char>(getTime("hour")),static_cast<unsigned char>(getTime("minute")),static_cast<unsigned char>(getTime("day")),static_cast<unsigned char>(getTime("month")), static_cast<short int>(getTime("year")));
    cp->Connection->addCommand(cmd);
}

void World::sendIGTimeToAllPlayers() {
    Players.for_each([this](Player *player) {
        sendIGTime(player);
    });
}

void World::sendWeatherToAllPlayers() {
    Players.for_each([this](Player *player) {
        player->sendWeather(weather);
    });
}

<|endoftext|>


<commit_before>/******************************************************************************
SparkFun_9DOF_Edison_Block_Example.cpp
Example code for the 9DOF Edison Block
14 Jul 2015 by Mike Hord
https://github.com/sparkfun/SparkFun_9DOF_Block_for_Edison_CPP_Library

Demonstrates the major functionality of the SparkFun 9DOF block for Edison.

** Supports only I2C connection! **

Development environment specifics:
  Code developed in Intel's Eclipse IOT-DK
  This code requires the Intel mraa library to function; for more
  information see https://github.com/intel-iot-devkit/mraa

This code is beerware; if you see me (or any other SparkFun employee) at the
local, and you've found our code helpful, please buy us a round!

Distributed as-is; no warranty is given.
******************************************************************************/

#include "mraa.hpp"

#include <sys/types.h>
#include <time.h>
#include <syslog.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <signal.h>
#include <iostream>
#include "SFE_LSM9DS0.h"
using namespace std;

int running = 1;

void
sig_handler(int signo)
{
    if (signo == SIGINT || signo == SIGTERM || signo == SIGHUP) {
        printf("Closing and cleaning up\n");
        running = 0;
    }
}

int main( int argc, char* argv[] )
{
  LSM9DS0 *imu;

  /* Our process ID and Session ID */
  pid_t pid, sid;

  /* Fork off the parent process */
  pid = fork();
  if (pid < 0) {
     fprintf(stderr, "Can't fork child\n");
     exit(EXIT_FAILURE);
  }
  /* If we got a good PID, then
     we can exit the parent process. */
  if (pid > 0) {
     exit(EXIT_SUCCESS);
  }

  /* Change the file mode mask */
  umask(0);

  setlogmask (LOG_UPTO (LOG_NOTICE));
  openlog (argv[0], LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
  syslog (LOG_NOTICE, "Program started by User %d", getuid ());

  /* Create a new SID for the child process */
  sid = setsid();
  if (sid < 0) {
     /* Log the failure */
     syslog (LOG_ERR, "Can't create new SID for child process");
     exit(EXIT_FAILURE);
  }

  /* Change the current working directory */
/*
  if ((chdir("/")) < 0) {
     exit(EXIT_FAILURE);
  }  */

  /* Close out the standard file descriptors */
  close(STDIN_FILENO);
  close(STDOUT_FILENO);
  close(STDERR_FILENO);

  /* Daemon-specific initialization goes here */
  syslog (LOG_NOTICE, "Program started by User %d", getuid ());

  signal(SIGINT, sig_handler);
  signal(SIGTERM, sig_handler);
  signal(SIGHUP, sig_handler);

  imu = new LSM9DS0(0x6B, 0x1D);
  // The begin() function sets up some basic parameters and turns the device
  //  on; you may not need to do more than call it. It also returns the "whoami"
  //  registers from the chip. If all is good, the return value here should be
  //  0x49d4. Here are the initial settings from this function:
  //  Gyro scale:        245 deg/sec max
  //  Xl scale:          4g max
  //  Mag scale:         2 Gauss max
  //  Gyro sample rate:  95Hz
  //  Xl sample rate:    100Hz
  //  Mag sample rate:   100Hz
  // These can be changed either by calling appropriate functions or by
  //  pasing parameters to the begin() function. There are named constants in
  //  the .h file for all scales and data rates; I won't reproduce them here.
  //  Here's the list of fuctions to set the rates/scale:
  //  setMagScale(mag_scale mScl)      setMagODR(mag_odr mRate)
  //  setGyroScale(gyro_scale gScl)    setGyroODR(gyro_odr gRate)
  //  setAccelScale(accel_scale aScl)  setGyroODR(accel_odr aRate)
  // If you want to make these changes at the point of calling begin, here's
  //  the prototype for that function showing the order to pass things:
  //  begin(gyro_scale gScl, accel_scale aScl, mag_scale mScl,
	//				gyro_odr gODR, accel_odr aODR, mag_odr mODR)
  uint16_t imuResult = imu->begin();
//  cout<<hex<<"Chip ID: 0x"<<imuResult<<dec<<" (should be 0x49d4)"<<endl;

  bool newAccelData = false;
  bool newMagData = false;
  bool newGyroData = false;
  bool overflow = false;

  time_t     now;
  struct tm  ts;
  char       filename[80];
  char	     path[256];
  char      *home_env;
  memset(path, 0, sizeof(path));

  if (argc > 1) {
      strcat(path, argv[1]);
  } else {
      // Get current time
      time(&now);
      // Format time, "ddd yyyy-mm-dd hh:mm:ss zzz"
      ts = *localtime(&now);
      strftime(filename, sizeof(filename), "%Y-%m-%d_%H:%M:%S.csv", &ts);

      home_env = getenv("HOME");
      if (home_env != NULL) {
         strcat(path, home_env);
         strcat(path, "/.cache/obexd/");
      }
      strcat(path, filename);
  }

  // open the file
  FILE* fd2 = fopen (path, "w+");
  if (fd2 == NULL) {
     running = 0;
  }

  // Loop and report data
  while (running)
  {
    // First, let's make sure we're collecting up-to-date information. The
    //  sensors are sampling at 100Hz (for the accelerometer, magnetometer, and
    //  temp) and 95Hz (for the gyro), and we could easily do a bunch of
    //  crap within that ~10ms sampling period.
    while ((newGyroData & newAccelData & newMagData) != true)
    {
      if (newAccelData != true)
      {
        newAccelData = imu->newXData();
      }
      if (newGyroData != true)
      {
        newGyroData = imu->newGData();
      }
      if (newMagData != true)
      {
        newMagData = imu->newMData(); // Temp data is collected at the same
                                      //  rate as magnetometer data.
      }
    }

    newAccelData = false;
    newMagData = false;
    newGyroData = false;

    // Of course, we may care if an overflow occurred; we can check that
    //  easily enough from an internal register on the part. There are functions
    //  to check for overflow per device.
    overflow = imu->xDataOverflow() |
               imu->gDataOverflow() |
               imu->mDataOverflow();

    if (overflow)
    {
      syslog (LOG_INFO, "Warning: Data overflow!!!");
    }

    // Calling these functions causes the data to be read from the IMU into
    //  10 16-bit signed integer public variables, as seen below. There is no
    //  automated check on whether the data is new; you need to do that
    //  manually as above. Also, there's no check on overflow, so you may miss
    //  a sample and not know it.
    imu->readAccel();
    imu->readMag();
    imu->readGyro();
    imu->readTemp();

    // Print the unscaled 16-bit signed values.
/*
    cout<<"-------------------------------------"<<endl;
    cout<<"Gyro x: "<<imu->gx<<endl;
    cout<<"Gyro y: "<<imu->gy<<endl;
    cout<<"Gyro z: "<<imu->gz<<endl;
    cout<<"Accel x: "<<imu->ax<<endl;
    cout<<"Accel y: "<<imu->ay<<endl;
    cout<<"Accel z: "<<imu->az<<endl;
    cout<<"Mag x: "<<imu->mx<<endl;
    cout<<"Mag y: "<<imu->my<<endl;
    cout<<"Mag z: "<<imu->mz<<endl;
    cout<<"Temp: "<<imu->temperature<<endl;
    cout<<"-------------------------------------"<<endl;
*/
    // Print the "real" values in more human comprehensible units.
/*
    cout<<"-------------------------------------"<<endl;
    cout<<"Gyro x: "<<imu->calcGyro(imu->gx)<<" deg/s"<<endl;
    cout<<"Gyro y: "<<imu->calcGyro(imu->gy)<<" deg/s"<<endl;
    cout<<"Gyro z: "<<imu->calcGyro(imu->gz)<<" deg/s"<<endl;
    cout<<"Accel x: "<<imu->calcAccel(imu->ax)<<" g"<<endl;
    cout<<"Accel y: "<<imu->calcAccel(imu->ay)<<" g"<<endl;
    cout<<"Accel z: "<<imu->calcAccel(imu->az)<<" g"<<endl;
    cout<<"Mag x: "<<imu->calcMag(imu->mx)<<" Gauss"<<endl;
    cout<<"Mag y: "<<imu->calcMag(imu->my)<<" Gauss"<<endl;
    cout<<"Mag z: "<<imu->calcMag(imu->mz)<<" Gauss"<<endl;
*/
    fprintf (fd2, "%f,%f,%f,%f,%f,%f,%f,%f,%f\n",
                  imu->calcGyro(imu->gx),
                  imu->calcGyro(imu->gy),
                  imu->calcGyro(imu->gz),
                  imu->calcAccel(imu->ax),
                  imu->calcAccel(imu->ay),
                  imu->calcAccel(imu->az),
                  imu->calcMag(imu->mx),
                  imu->calcMag(imu->my),
                  imu->calcMag(imu->mz));
    fflush(fd2);
    // Temp conversion is left as an example to the reader, as it requires a
    //  good deal of device- and system-specific calibration. The on-board
    //  temp sensor is probably best not used if local temp data is required!
//  cout<<"-------------------------------------"<<endl;
    sleep(1);
  }
  if (fd2 != NULL) {
    fclose(fd2);
  }

  delete imu;
  return MRAA_SUCCESS;
}

<commit_msg>Handle OBEX env for location of files<commit_after>/******************************************************************************
SparkFun_9DOF_Edison_Block_Example.cpp
Example code for the 9DOF Edison Block
14 Jul 2015 by Mike Hord
https://github.com/sparkfun/SparkFun_9DOF_Block_for_Edison_CPP_Library

Demonstrates the major functionality of the SparkFun 9DOF block for Edison.

** Supports only I2C connection! **

Development environment specifics:
  Code developed in Intel's Eclipse IOT-DK
  This code requires the Intel mraa library to function; for more
  information see https://github.com/intel-iot-devkit/mraa

This code is beerware; if you see me (or any other SparkFun employee) at the
local, and you've found our code helpful, please buy us a round!

Distributed as-is; no warranty is given.
******************************************************************************/

#include "mraa.hpp"

#include <sys/types.h>
#include <time.h>
#include <syslog.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h>
#include <signal.h>
#include <iostream>
#include "SFE_LSM9DS0.h"
using namespace std;

int running = 1;

void
sig_handler(int signo)
{
    if (signo == SIGINT || signo == SIGTERM || signo == SIGHUP) {
        printf("Closing and cleaning up\n");
        running = 0;
    }
}

int main( int argc, char* argv[] )
{
  LSM9DS0 *imu;

  /* Our process ID and Session ID */
  pid_t pid, sid;

  /* Fork off the parent process */
  pid = fork();
  if (pid < 0) {
     fprintf(stderr, "Can't fork child\n");
     exit(EXIT_FAILURE);
  }
  /* If we got a good PID, then
     we can exit the parent process. */
  if (pid > 0) {
     exit(EXIT_SUCCESS);
  }

  /* Change the file mode mask */
  umask(0);

  setlogmask (LOG_UPTO (LOG_NOTICE));
  openlog (argv[0], LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
  syslog (LOG_NOTICE, "Program started by User %d", getuid ());

  /* Create a new SID for the child process */
  sid = setsid();
  if (sid < 0) {
     /* Log the failure */
     syslog (LOG_ERR, "Can't create new SID for child process");
     exit(EXIT_FAILURE);
  }

  /* Change the current working directory */
/*
  if ((chdir("/")) < 0) {
     exit(EXIT_FAILURE);
  }  */

  /* Close out the standard file descriptors */
  close(STDIN_FILENO);
  close(STDOUT_FILENO);
  close(STDERR_FILENO);

  /* Daemon-specific initialization goes here */
  syslog (LOG_NOTICE, "Program started by User %d", getuid ());

  signal(SIGINT, sig_handler);
  signal(SIGTERM, sig_handler);
  signal(SIGHUP, sig_handler);

  imu = new LSM9DS0(0x6B, 0x1D);
  // The begin() function sets up some basic parameters and turns the device
  //  on; you may not need to do more than call it. It also returns the "whoami"
  //  registers from the chip. If all is good, the return value here should be
  //  0x49d4. Here are the initial settings from this function:
  //  Gyro scale:        245 deg/sec max
  //  Xl scale:          4g max
  //  Mag scale:         2 Gauss max
  //  Gyro sample rate:  95Hz
  //  Xl sample rate:    100Hz
  //  Mag sample rate:   100Hz
  // These can be changed either by calling appropriate functions or by
  //  pasing parameters to the begin() function. There are named constants in
  //  the .h file for all scales and data rates; I won't reproduce them here.
  //  Here's the list of fuctions to set the rates/scale:
  //  setMagScale(mag_scale mScl)      setMagODR(mag_odr mRate)
  //  setGyroScale(gyro_scale gScl)    setGyroODR(gyro_odr gRate)
  //  setAccelScale(accel_scale aScl)  setGyroODR(accel_odr aRate)
  // If you want to make these changes at the point of calling begin, here's
  //  the prototype for that function showing the order to pass things:
  //  begin(gyro_scale gScl, accel_scale aScl, mag_scale mScl,
	//				gyro_odr gODR, accel_odr aODR, mag_odr mODR)
  uint16_t imuResult = imu->begin();
//  cout<<hex<<"Chip ID: 0x"<<imuResult<<dec<<" (should be 0x49d4)"<<endl;

  bool newAccelData = false;
  bool newMagData = false;
  bool newGyroData = false;
  bool overflow = false;

  time_t     now;
  struct tm  ts;
  char       filename[80];
  char	     path[256];
  char      *home_env;
  memset(path, 0, sizeof(path));

  if (argc > 1) {
      strcat(path, argv[1]);
  } else {
      // Get current time
      time(&now);
      // Format time, "ddd yyyy-mm-dd hh:mm:ss zzz"
      ts = *localtime(&now);
      strftime(filename, sizeof(filename), "%Y-%m-%d_%H:%M:%S.csv", &ts);

      home_env = getenv("OBEX");
      if (home_env != NULL) {
         strcpy(path, home_env);
      } else {
         home_env = getenv("HOME");
         if (home_env != NULL) {
            strcpy(path, home_env);
            strcat(path, "/.cache/obexd/");
         } else {
            strcpy(path, "/home/root/.cache/obexd/");
         }
      }
      strcat(path, filename);
  }

  // open the file
  FILE* fd2 = fopen (path, "w+");
  if (fd2 == NULL) {
     running = 0;
  }

  // Loop and report data
  while (running)
  {
    // First, let's make sure we're collecting up-to-date information. The
    //  sensors are sampling at 100Hz (for the accelerometer, magnetometer, and
    //  temp) and 95Hz (for the gyro), and we could easily do a bunch of
    //  crap within that ~10ms sampling period.
    while ((newGyroData & newAccelData & newMagData) != true)
    {
      if (newAccelData != true)
      {
        newAccelData = imu->newXData();
      }
      if (newGyroData != true)
      {
        newGyroData = imu->newGData();
      }
      if (newMagData != true)
      {
        newMagData = imu->newMData(); // Temp data is collected at the same
                                      //  rate as magnetometer data.
      }
    }

    newAccelData = false;
    newMagData = false;
    newGyroData = false;

    // Of course, we may care if an overflow occurred; we can check that
    //  easily enough from an internal register on the part. There are functions
    //  to check for overflow per device.
    overflow = imu->xDataOverflow() |
               imu->gDataOverflow() |
               imu->mDataOverflow();

    if (overflow)
    {
      syslog (LOG_INFO, "Warning: Data overflow!!!");
    }

    // Calling these functions causes the data to be read from the IMU into
    //  10 16-bit signed integer public variables, as seen below. There is no
    //  automated check on whether the data is new; you need to do that
    //  manually as above. Also, there's no check on overflow, so you may miss
    //  a sample and not know it.
    imu->readAccel();
    imu->readMag();
    imu->readGyro();
    imu->readTemp();

    // Print the unscaled 16-bit signed values.
/*
    cout<<"-------------------------------------"<<endl;
    cout<<"Gyro x: "<<imu->gx<<endl;
    cout<<"Gyro y: "<<imu->gy<<endl;
    cout<<"Gyro z: "<<imu->gz<<endl;
    cout<<"Accel x: "<<imu->ax<<endl;
    cout<<"Accel y: "<<imu->ay<<endl;
    cout<<"Accel z: "<<imu->az<<endl;
    cout<<"Mag x: "<<imu->mx<<endl;
    cout<<"Mag y: "<<imu->my<<endl;
    cout<<"Mag z: "<<imu->mz<<endl;
    cout<<"Temp: "<<imu->temperature<<endl;
    cout<<"-------------------------------------"<<endl;
*/
    // Print the "real" values in more human comprehensible units.
/*
    cout<<"-------------------------------------"<<endl;
    cout<<"Gyro x: "<<imu->calcGyro(imu->gx)<<" deg/s"<<endl;
    cout<<"Gyro y: "<<imu->calcGyro(imu->gy)<<" deg/s"<<endl;
    cout<<"Gyro z: "<<imu->calcGyro(imu->gz)<<" deg/s"<<endl;
    cout<<"Accel x: "<<imu->calcAccel(imu->ax)<<" g"<<endl;
    cout<<"Accel y: "<<imu->calcAccel(imu->ay)<<" g"<<endl;
    cout<<"Accel z: "<<imu->calcAccel(imu->az)<<" g"<<endl;
    cout<<"Mag x: "<<imu->calcMag(imu->mx)<<" Gauss"<<endl;
    cout<<"Mag y: "<<imu->calcMag(imu->my)<<" Gauss"<<endl;
    cout<<"Mag z: "<<imu->calcMag(imu->mz)<<" Gauss"<<endl;
*/
    fprintf (fd2, "%f,%f,%f,%f,%f,%f,%f,%f,%f\n",
                  imu->calcGyro(imu->gx),
                  imu->calcGyro(imu->gy),
                  imu->calcGyro(imu->gz),
                  imu->calcAccel(imu->ax),
                  imu->calcAccel(imu->ay),
                  imu->calcAccel(imu->az),
                  imu->calcMag(imu->mx),
                  imu->calcMag(imu->my),
                  imu->calcMag(imu->mz));
    fflush(fd2);
    // Temp conversion is left as an example to the reader, as it requires a
    //  good deal of device- and system-specific calibration. The on-board
    //  temp sensor is probably best not used if local temp data is required!
//  cout<<"-------------------------------------"<<endl;
    sleep(1);
  }
  if (fd2 != NULL) {
    fclose(fd2);
  }

  delete imu;
  return MRAA_SUCCESS;
}

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2001-2003 Peter J Jones (pjones@pmade.org)
 * 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.
 * 3. Neither the name of the Author nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR
 * 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.
 */

/*
 * The following code demonstrates how to use the xml::node class to build
 * an XML tree and then convert it to XML text.
 *
 * Here is what we want to create:
 *
 *  <abook>
 *	<person id="01" name="Peter Jones">
 *	    <email>pjones@pmade.org</email>
 *	    <phone type="home">555-1212</phone>
 *	</person>
 *  </abook>
 */

// xmlwrapp include
#include <xmlwrapp/xmlwrapp.h>

// standard includes
#include <iostream>
#include <exception>

int main (void) {
    // prepare the XML parser
    xml::init init;

    // create a new XML document and set the root node
    xml::document xmldoc("abook");
    xml::node &root = xmldoc.get_root_node();

    // add a child to the root node, <person>
    xml::node::iterator it = root.insert(root.begin(), xml::node("person"));

    /*
     * set the attributes for this new <person> element using the
     * xml::attributes object returned from xml::node::get_attributes
     */
    it->get_attributes().insert("id", "01");
    it->get_attributes().insert("name", "Peter Jones");

    // add a node and set the content for that new node
    it->push_back(xml::node("email", "pjones@pmade.org"));

    // build a node one member function at a time
    it = it->insert(it->end(), xml::node("phone"));
    it->get_attributes().insert("type", "home");
    it->set_content("555-1212");

    // set some document settings
    xmldoc.set_is_standalone(true);
    xmldoc.set_encoding("ISO-8859-1");

    // convert the document to XML
    std::cout << xmldoc;
    return 0;
}
<commit_msg>update example based on new cdata/comment/pi API<commit_after>/*
 * Copyright (C) 2001-2003 Peter J Jones (pjones@pmade.org)
 * 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.
 * 3. Neither the name of the Author nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR
 * 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.
 */

/*
 * The following code demonstrates how to use the xml::node class to build
 * an XML tree and then convert it to XML text.
 *
 * Here is what we want to create:
 *
 *  <abook>
 *	<person id="01" name="Peter Jones">
 *	    <email>pjones@pmade.org</email>
 *	    <!-- Fake Phone Number -->
 *	    <phone type="home">555-1212</phone>
 *	</person>
 *  </abook>
 */

// xmlwrapp include
#include <xmlwrapp/xmlwrapp.h>

// standard includes
#include <iostream>
#include <exception>

int main (void) {
    // prepare the XML parser
    xml::init init;

    // create a new XML document and set the root node
    xml::document xmldoc("abook");
    xml::node &root = xmldoc.get_root_node();

    // add a child to the root node, <person>
    xml::node::iterator it = root.insert(root.begin(), xml::node("person"));

    /*
     * set the attributes for this new <person> element using the
     * xml::attributes object returned from xml::node::get_attributes
     */
    it->get_attributes().insert("id", "01");
    it->get_attributes().insert("name", "Peter Jones");

    // add a node and set the content for that new node
    it->push_back(xml::node("email", "pjones@pmade.org"));

    // add an XML comment
    it->push_back(xml::node(xml::node::comment(" Fake Phone Number ")));

    // build a node one member function at a time
    it = it->insert(xml::node("phone"));
    it->get_attributes().insert("type", "home");
    it->set_content("555-1212");

    // set some document settings
    xmldoc.set_is_standalone(true);
    xmldoc.set_encoding("ISO-8859-1");

    // convert the document to XML
    std::cout << xmldoc;
    return 0;
}
<|endoftext|>


<commit_before>//===--- Constraint.cpp - Constraint in the Type Checker --------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements the \c Constraint class and its related types,
// which is used by the constraint-based type checker to describe a
// constraint that must be solved.
//
//===----------------------------------------------------------------------===//
#include "Constraint.h"
#include "ConstraintSystem.h"
#include "swift/AST/Types.h"
#include "swift/Basic/Fallthrough.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>

using namespace swift;
using namespace constraints;

Constraint::Constraint(ConstraintKind kind, ArrayRef<Constraint *> constraints,
                       ConstraintLocator *locator,
                       ArrayRef<TypeVariableType *> typeVars)
  : Kind(kind), HasRestriction(false), IsActive(false),
    NumTypeVariables(typeVars.size()), Nested(constraints), Locator(locator)
{
  assert(kind == ConstraintKind::Conjunction ||
         kind == ConstraintKind::Disjunction);
  std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin());
}

Constraint::Constraint(ConstraintKind Kind, Type First, Type Second,
                       Identifier Member, ConstraintLocator *locator,
                       ArrayRef<TypeVariableType *> typeVars)
  : Kind(Kind), HasRestriction(false), IsActive(false),
    NumTypeVariables(typeVars.size()), Types { First, Second, Member },
    Locator(locator)
{
  switch (Kind) {
  case ConstraintKind::Bind:
  case ConstraintKind::Equal:
  case ConstraintKind::Subtype:
  case ConstraintKind::Conversion:
  case ConstraintKind::OperatorConversion:
  case ConstraintKind::Construction:
  case ConstraintKind::ConformsTo:
  case ConstraintKind::CheckedCast:
  case ConstraintKind::SelfObjectOfProtocol:
    assert(Member.empty() && "Relational constraint cannot have a member");
    break;
  case ConstraintKind::ApplicableFunction:
    assert(First->is<FunctionType>()
           && "The left-hand side type should be a function type");
    assert(Member.empty() && "Relational constraint cannot have a member");
    break;

  case ConstraintKind::TypeMember:
  case ConstraintKind::ValueMember:
    assert(!Member.empty() && "Member constraint has no member");
    break;

  case ConstraintKind::Archetype:
  case ConstraintKind::Class:
  case ConstraintKind::DynamicLookupValue:
    assert(Member.empty() && "Type property cannot have a member");
    assert(Second.isNull() && "Type property with second type");
    break;

  case ConstraintKind::BindOverload:
    llvm_unreachable("Wrong constructor for overload binding constraint");

  case ConstraintKind::Conjunction:
    llvm_unreachable("Conjunction constraints should use create()");

  case ConstraintKind::Disjunction:
    llvm_unreachable("Disjunction constraints should use create()");
  }

  std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin());
}

Constraint::Constraint(Type type, OverloadChoice choice,
                       ConstraintLocator *locator,
                       ArrayRef<TypeVariableType *> typeVars)
  : Kind(ConstraintKind::BindOverload), HasRestriction(false),
    IsActive(false), NumTypeVariables(typeVars.size()),
    Overload{type, choice}, Locator(locator)
{
  std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin());
}

Constraint::Constraint(ConstraintKind kind,
                       ConversionRestrictionKind restriction,
                       Type first, Type second, ConstraintLocator *locator,
                       ArrayRef<TypeVariableType *> typeVars)
    : Kind(kind), Restriction(restriction), HasRestriction(true),
      IsActive(false), NumTypeVariables(typeVars.size()),
      Types{ first, second, Identifier() }, Locator(locator)
{
  std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin());
}

ProtocolDecl *Constraint::getProtocol() const {
  assert((Kind == ConstraintKind::ConformsTo ||
          Kind == ConstraintKind::SelfObjectOfProtocol)
          && "Not a conformance constraint");
  return Types.Second->castTo<ProtocolType>()->getDecl();
}

void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const {
  if (Kind == ConstraintKind::Conjunction ||
      Kind == ConstraintKind::Disjunction) {
    bool isConjunction = (Kind == ConstraintKind::Conjunction);
    if (isConjunction)
      Out << "conjunction";
    else
      Out << "disjunction";
    if (Locator) {
      Out << " [[";
      Locator->dump(sm, Out);
      Out << "]]";
    }
    Out << ":";

    bool first = true;
    for (auto constraint : getNestedConstraints()) {
      if (first)
        first = false;
      else if (isConjunction)
        Out << " and ";
      else
        Out << " or ";

      constraint->print(Out, sm);
    }

    return;
  }

  Types.First->print(Out);

  bool skipSecond = false;

  switch (Kind) {
  case ConstraintKind::Bind: Out << " := "; break;
  case ConstraintKind::Equal: Out << " == "; break;
  case ConstraintKind::Subtype: Out << " < "; break;
  case ConstraintKind::Conversion: Out << " <c "; break;
  case ConstraintKind::OperatorConversion: Out << " <oc "; break;
  case ConstraintKind::Construction: Out << " <C "; break;
  case ConstraintKind::ConformsTo: Out << " conforms to "; break;
  case ConstraintKind::CheckedCast: Out << " checked cast to "; break;
  case ConstraintKind::SelfObjectOfProtocol: Out << " Self type of "; break;
  case ConstraintKind::ApplicableFunction: Out << " ==Fn "; break;
  case ConstraintKind::BindOverload: {
    // FIXME: Better output here.
    skipSecond = true;
    break;
  }

  case ConstraintKind::ValueMember:
    Out << "[." << Types.Member.str() << ": value] == ";
    break;
  case ConstraintKind::TypeMember:
    Out << "[." << Types.Member.str() << ": type] == ";
    break;
  case ConstraintKind::Archetype:
    Out << " is an archetype";
    skipSecond = true;
    break;
  case ConstraintKind::Class:
    Out << " is a class";
    skipSecond = true;
    break;
  case ConstraintKind::DynamicLookupValue:
    Out << " is a DynamicLookup value";
    skipSecond = true;
    break;
  case ConstraintKind::Conjunction:
  case ConstraintKind::Disjunction:
    llvm_unreachable("Conjunction/disjunction handled above");
  }

  if (!skipSecond)
    Types.Second->print(Out);

  if (auto restriction = getRestriction()) {
    Out << ' ' << getName(*restriction);
  }

  if (Locator) {
    Out << " [[";
    Locator->dump(sm, Out);
    Out << "]];";
  }
}

void Constraint::dump(SourceManager *sm) const {
  print(llvm::errs(), sm);
}

StringRef swift::constraints::getName(ConversionRestrictionKind kind) {
  switch (kind) {
  case ConversionRestrictionKind::TupleToTuple:
    return "[tuple-to-tuple]";
  case ConversionRestrictionKind::ScalarToTuple:
    return "[scalar-to-tuple]";
  case ConversionRestrictionKind::TupleToScalar:
    return "[tuple-to-scalar]";
  case ConversionRestrictionKind::DeepEquality:
    return "[deep equality]";
  case ConversionRestrictionKind::Superclass:
    return "[superclass]";
  case ConversionRestrictionKind::LValueToRValue:
    return "[lvalue-to-rvalue]";
  case ConversionRestrictionKind::Existential:
    return "[existential]";
  case ConversionRestrictionKind::ValueToOptional:
    return "[value-to-optional]";
  case ConversionRestrictionKind::OptionalToOptional:
    return "[optional-to-optional]";
  case ConversionRestrictionKind::UncheckedOptionalToOptional:
    return "[unchecked-optional-to-optional]";
  case ConversionRestrictionKind::User:
    return "[user]";
  }
  llvm_unreachable("bad conversion restriction kind");
}

/// Recursively gather the set of type variables referenced by this constraint.
static void
gatherReferencedTypeVars(Constraint *constraint,
                         SmallVectorImpl<TypeVariableType *> &typeVars) {
  switch (constraint->getKind()) {
  case ConstraintKind::Conjunction:
  case ConstraintKind::Disjunction:
    for (auto nested : constraint->getNestedConstraints())
      gatherReferencedTypeVars(nested, typeVars);
    return;

  case ConstraintKind::ApplicableFunction:
  case ConstraintKind::Bind:
  case ConstraintKind::Construction:
  case ConstraintKind::Conversion:
  case ConstraintKind::OperatorConversion:
  case ConstraintKind::CheckedCast:
  case ConstraintKind::Equal:
  case ConstraintKind::Subtype:
  case ConstraintKind::TypeMember:
  case ConstraintKind::ValueMember:
    constraint->getSecondType()->getTypeVariables(typeVars);
    SWIFT_FALLTHROUGH;

  case ConstraintKind::Archetype:
  case ConstraintKind::BindOverload:
  case ConstraintKind::Class:
  case ConstraintKind::ConformsTo:
  case ConstraintKind::DynamicLookupValue:
  case ConstraintKind::SelfObjectOfProtocol:
    constraint->getFirstType()->getTypeVariables(typeVars);

    // Special case: the base type of an overloading binding.
    if (constraint->getKind() == ConstraintKind::BindOverload) {
      if (auto baseType = constraint->getOverloadChoice().getBaseType()) {
        baseType->getTypeVariables(typeVars);
      }
    }

    break;
  }
}

/// Unique the given set of type variables.
static void uniqueTypeVariables(SmallVectorImpl<TypeVariableType *> &typeVars) {
  // Remove any duplicate type variables.
  llvm::SmallPtrSet<TypeVariableType *, 4> knownTypeVars;
  typeVars.erase(std::remove_if(typeVars.begin(), typeVars.end(),
                                [&](TypeVariableType *typeVar) {
                                  return !knownTypeVars.insert(typeVar);
                                }),
                 typeVars.end());
}

Constraint *Constraint::create(ConstraintSystem &cs, ConstraintKind kind,
                               Type first, Type second, Identifier member,
                               ConstraintLocator *locator) {
  // Collect type variables.
  SmallVector<TypeVariableType *, 4> typeVars;
  if (first->hasTypeVariable())
    first->getTypeVariables(typeVars);
  if (second && second->hasTypeVariable())
    second->getTypeVariables(typeVars);
  uniqueTypeVariables(typeVars);

  // Create the constraint.
  unsigned size = sizeof(Constraint)
                + typeVars.size() * sizeof(TypeVariableType*);
  void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
  return new (mem) Constraint(kind, first, second, member, locator, typeVars);
}

Constraint *Constraint::createBindOverload(ConstraintSystem &cs, Type type,
                                           OverloadChoice choice,
                                           ConstraintLocator *locator) {
  // Collect type variables.
  SmallVector<TypeVariableType *, 4> typeVars;
  if (type->hasTypeVariable())
    type->getTypeVariables(typeVars);
  if (auto baseType = choice.getBaseType()) {
    baseType->getTypeVariables(typeVars);
  }

  // Create the constraint.
  unsigned size = sizeof(Constraint)
                + typeVars.size() * sizeof(TypeVariableType*);
  void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
  return new (mem) Constraint(type, choice, locator, typeVars);
}

Constraint *Constraint::createRestricted(ConstraintSystem &cs,
                                         ConstraintKind kind,
                                         ConversionRestrictionKind restriction,
                                         Type first, Type second,
                                         ConstraintLocator *locator) {
  // Collect type variables.
  SmallVector<TypeVariableType *, 4> typeVars;
  if (first->hasTypeVariable())
    first->getTypeVariables(typeVars);
  if (second->hasTypeVariable())
    second->getTypeVariables(typeVars);
  uniqueTypeVariables(typeVars);

  // Create the constraint.
  unsigned size = sizeof(Constraint)
                + typeVars.size() * sizeof(TypeVariableType*);
  void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
  return new (mem) Constraint(kind, restriction, first, second, locator,
                              typeVars);
}

Constraint *Constraint::createConjunction(ConstraintSystem &cs,
                                          ArrayRef<Constraint *> constraints,
                                          ConstraintLocator *locator) {
  // Unwrap any conjunctions inside the conjunction constraint.
  SmallVector<TypeVariableType *, 4> typeVars;
  bool unwrappedAny = false;
  SmallVector<Constraint *, 1> unwrapped;
  unsigned index = 0;
  for (auto constraint : constraints) {
    // Gather type variables from this constraint.
    gatherReferencedTypeVars(constraint, typeVars);

    // If we have a nested conjunction, unwrap it.
    if (constraint->getKind() == ConstraintKind::Conjunction) {
      // If we haven't unwrapped anything before, copy all of the constraints
      // we skipped.
      if (!unwrappedAny) {
        unwrapped.append(constraints.begin(), constraints.begin() + index);
        unwrappedAny = true;
      }

      // Add all of the constraints in the conjunction.
      unwrapped.append(constraint->getNestedConstraints().begin(),
                       constraint->getNestedConstraints().end());
    } else if (unwrappedAny) {
      // Since we unwrapped constraints before, add this constraint.
      unwrapped.push_back(constraint);
    }

    // FIXME: If we find any disjunctions in here, should we distribute them?

    ++index;
  }

  // If we unwrapped anything, our list of constraints is the unwrapped list.
  if (unwrappedAny)
    constraints = unwrapped;

  assert(!constraints.empty() && "Empty conjunction constraint");

  // If there is a single constraint, this isn't a disjunction at all.
  if (constraints.size() == 1)
    return constraints.front();

  // Create the conjunction constraint.
  uniqueTypeVariables(typeVars);
  unsigned size = sizeof(Constraint)
                + typeVars.size() * sizeof(TypeVariableType*);
  void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
  return new (mem) Constraint(ConstraintKind::Conjunction,
                              cs.allocateCopy(constraints), locator, typeVars);

}

Constraint *Constraint::createDisjunction(ConstraintSystem &cs,
                                          ArrayRef<Constraint *> constraints,
                                          ConstraintLocator *locator) {
  // Unwrap any disjunctions inside the disjunction constraint; we only allow
  // disjunctions at the top level.
  SmallVector<TypeVariableType *, 4> typeVars;
  bool unwrappedAny = false;
  SmallVector<Constraint *, 1> unwrapped;
  unsigned index = 0;
  for (auto constraint : constraints) {
    // Gather type variables from this constraint.
    gatherReferencedTypeVars(constraint, typeVars);

    // If we have a nested disjunction, unwrap it.
    if (constraint->getKind() == ConstraintKind::Disjunction) {
      // If we haven't unwrapped anything before, copy all of the constraints
      // we skipped.
      if (!unwrappedAny) {
        unwrapped.append(constraints.begin(), constraints.begin() + index);
        unwrappedAny = true;
      }

      // Add all of the constraints in the disjunction.
      unwrapped.append(constraint->getNestedConstraints().begin(),
                       constraint->getNestedConstraints().end());
    } else if (unwrappedAny) {
      // Since we unwrapped constraints before, add this constraint.
      unwrapped.push_back(constraint);
    }
    ++index;
  }

  // If we unwrapped anything, our list of constraints is the unwrapped list.
  if (unwrappedAny)
    constraints = unwrapped;

  assert(!constraints.empty() && "Empty disjunction constraint");

  // If there is a single constraint, this isn't a disjunction at all.
  if (constraints.size() == 1)
    return constraints.front();

  // Create the disjunction constraint.
  uniqueTypeVariables(typeVars);
  unsigned size = sizeof(Constraint)
                + typeVars.size() * sizeof(TypeVariableType*);
  void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
  return new (mem) Constraint(ConstraintKind::Disjunction,
                              cs.allocateCopy(constraints), locator, typeVars);
}

void *Constraint::operator new(size_t bytes, ConstraintSystem& cs,
                               size_t alignment) {
  return ::operator new (bytes, cs, alignment);
}
<commit_msg>Dump BindOverload constaints more verbosely.<commit_after>//===--- Constraint.cpp - Constraint in the Type Checker --------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements the \c Constraint class and its related types,
// which is used by the constraint-based type checker to describe a
// constraint that must be solved.
//
//===----------------------------------------------------------------------===//
#include "Constraint.h"
#include "ConstraintSystem.h"
#include "swift/AST/Types.h"
#include "swift/Basic/Fallthrough.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>

using namespace swift;
using namespace constraints;

Constraint::Constraint(ConstraintKind kind, ArrayRef<Constraint *> constraints,
                       ConstraintLocator *locator,
                       ArrayRef<TypeVariableType *> typeVars)
  : Kind(kind), HasRestriction(false), IsActive(false),
    NumTypeVariables(typeVars.size()), Nested(constraints), Locator(locator)
{
  assert(kind == ConstraintKind::Conjunction ||
         kind == ConstraintKind::Disjunction);
  std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin());
}

Constraint::Constraint(ConstraintKind Kind, Type First, Type Second,
                       Identifier Member, ConstraintLocator *locator,
                       ArrayRef<TypeVariableType *> typeVars)
  : Kind(Kind), HasRestriction(false), IsActive(false),
    NumTypeVariables(typeVars.size()), Types { First, Second, Member },
    Locator(locator)
{
  switch (Kind) {
  case ConstraintKind::Bind:
  case ConstraintKind::Equal:
  case ConstraintKind::Subtype:
  case ConstraintKind::Conversion:
  case ConstraintKind::OperatorConversion:
  case ConstraintKind::Construction:
  case ConstraintKind::ConformsTo:
  case ConstraintKind::CheckedCast:
  case ConstraintKind::SelfObjectOfProtocol:
    assert(Member.empty() && "Relational constraint cannot have a member");
    break;
  case ConstraintKind::ApplicableFunction:
    assert(First->is<FunctionType>()
           && "The left-hand side type should be a function type");
    assert(Member.empty() && "Relational constraint cannot have a member");
    break;

  case ConstraintKind::TypeMember:
  case ConstraintKind::ValueMember:
    assert(!Member.empty() && "Member constraint has no member");
    break;

  case ConstraintKind::Archetype:
  case ConstraintKind::Class:
  case ConstraintKind::DynamicLookupValue:
    assert(Member.empty() && "Type property cannot have a member");
    assert(Second.isNull() && "Type property with second type");
    break;

  case ConstraintKind::BindOverload:
    llvm_unreachable("Wrong constructor for overload binding constraint");

  case ConstraintKind::Conjunction:
    llvm_unreachable("Conjunction constraints should use create()");

  case ConstraintKind::Disjunction:
    llvm_unreachable("Disjunction constraints should use create()");
  }

  std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin());
}

Constraint::Constraint(Type type, OverloadChoice choice,
                       ConstraintLocator *locator,
                       ArrayRef<TypeVariableType *> typeVars)
  : Kind(ConstraintKind::BindOverload), HasRestriction(false),
    IsActive(false), NumTypeVariables(typeVars.size()),
    Overload{type, choice}, Locator(locator)
{
  std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin());
}

Constraint::Constraint(ConstraintKind kind,
                       ConversionRestrictionKind restriction,
                       Type first, Type second, ConstraintLocator *locator,
                       ArrayRef<TypeVariableType *> typeVars)
    : Kind(kind), Restriction(restriction), HasRestriction(true),
      IsActive(false), NumTypeVariables(typeVars.size()),
      Types{ first, second, Identifier() }, Locator(locator)
{
  std::copy(typeVars.begin(), typeVars.end(), getTypeVariablesBuffer().begin());
}

ProtocolDecl *Constraint::getProtocol() const {
  assert((Kind == ConstraintKind::ConformsTo ||
          Kind == ConstraintKind::SelfObjectOfProtocol)
          && "Not a conformance constraint");
  return Types.Second->castTo<ProtocolType>()->getDecl();
}

void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm) const {
  if (Kind == ConstraintKind::Conjunction ||
      Kind == ConstraintKind::Disjunction) {
    bool isConjunction = (Kind == ConstraintKind::Conjunction);
    if (isConjunction)
      Out << "conjunction";
    else
      Out << "disjunction";
    if (Locator) {
      Out << " [[";
      Locator->dump(sm, Out);
      Out << "]]";
    }
    Out << ":";

    bool first = true;
    for (auto constraint : getNestedConstraints()) {
      if (first)
        first = false;
      else if (isConjunction)
        Out << " and ";
      else
        Out << " or ";

      constraint->print(Out, sm);
    }

    return;
  }

  Types.First->print(Out);

  bool skipSecond = false;

  switch (Kind) {
  case ConstraintKind::Bind: Out << " := "; break;
  case ConstraintKind::Equal: Out << " == "; break;
  case ConstraintKind::Subtype: Out << " < "; break;
  case ConstraintKind::Conversion: Out << " <c "; break;
  case ConstraintKind::OperatorConversion: Out << " <oc "; break;
  case ConstraintKind::Construction: Out << " <C "; break;
  case ConstraintKind::ConformsTo: Out << " conforms to "; break;
  case ConstraintKind::CheckedCast: Out << " checked cast to "; break;
  case ConstraintKind::SelfObjectOfProtocol: Out << " Self type of "; break;
  case ConstraintKind::ApplicableFunction: Out << " ==Fn "; break;
  case ConstraintKind::BindOverload: {
    Out << " bound to ";
    auto overload = getOverloadChoice();
    auto printDecl = [&] {
      auto decl = overload.getDecl();
      decl->print(Out);
      if (!sm || !decl->getLoc().isValid()) return;
      Out << " at ";
      decl->getLoc().print(Out, *sm);
    };

    switch (overload.getKind()) {
    case OverloadChoiceKind::Decl:
      Out << "decl ";
      printDecl();
      break;
    case OverloadChoiceKind::TypeDecl:
      Out << "type decl ";
      printDecl();
      break;
    case OverloadChoiceKind::DeclViaDynamic:
      Out << "decl-via-dynamic ";
      printDecl();
      break;
    case OverloadChoiceKind::BaseType:
      Out << "base type";
      break;
    case OverloadChoiceKind::TupleIndex:
      Out << "tuple index " << overload.getTupleIndex();
      break;
    }

    skipSecond = true;
    break;
  }

  case ConstraintKind::ValueMember:
    Out << "[." << Types.Member.str() << ": value] == ";
    break;
  case ConstraintKind::TypeMember:
    Out << "[." << Types.Member.str() << ": type] == ";
    break;
  case ConstraintKind::Archetype:
    Out << " is an archetype";
    skipSecond = true;
    break;
  case ConstraintKind::Class:
    Out << " is a class";
    skipSecond = true;
    break;
  case ConstraintKind::DynamicLookupValue:
    Out << " is a DynamicLookup value";
    skipSecond = true;
    break;
  case ConstraintKind::Conjunction:
  case ConstraintKind::Disjunction:
    llvm_unreachable("Conjunction/disjunction handled above");
  }

  if (!skipSecond)
    Types.Second->print(Out);

  if (auto restriction = getRestriction()) {
    Out << ' ' << getName(*restriction);
  }

  if (Locator) {
    Out << " [[";
    Locator->dump(sm, Out);
    Out << "]];";
  }
}

void Constraint::dump(SourceManager *sm) const {
  print(llvm::errs(), sm);
}

StringRef swift::constraints::getName(ConversionRestrictionKind kind) {
  switch (kind) {
  case ConversionRestrictionKind::TupleToTuple:
    return "[tuple-to-tuple]";
  case ConversionRestrictionKind::ScalarToTuple:
    return "[scalar-to-tuple]";
  case ConversionRestrictionKind::TupleToScalar:
    return "[tuple-to-scalar]";
  case ConversionRestrictionKind::DeepEquality:
    return "[deep equality]";
  case ConversionRestrictionKind::Superclass:
    return "[superclass]";
  case ConversionRestrictionKind::LValueToRValue:
    return "[lvalue-to-rvalue]";
  case ConversionRestrictionKind::Existential:
    return "[existential]";
  case ConversionRestrictionKind::ValueToOptional:
    return "[value-to-optional]";
  case ConversionRestrictionKind::OptionalToOptional:
    return "[optional-to-optional]";
  case ConversionRestrictionKind::UncheckedOptionalToOptional:
    return "[unchecked-optional-to-optional]";
  case ConversionRestrictionKind::User:
    return "[user]";
  }
  llvm_unreachable("bad conversion restriction kind");
}

/// Recursively gather the set of type variables referenced by this constraint.
static void
gatherReferencedTypeVars(Constraint *constraint,
                         SmallVectorImpl<TypeVariableType *> &typeVars) {
  switch (constraint->getKind()) {
  case ConstraintKind::Conjunction:
  case ConstraintKind::Disjunction:
    for (auto nested : constraint->getNestedConstraints())
      gatherReferencedTypeVars(nested, typeVars);
    return;

  case ConstraintKind::ApplicableFunction:
  case ConstraintKind::Bind:
  case ConstraintKind::Construction:
  case ConstraintKind::Conversion:
  case ConstraintKind::OperatorConversion:
  case ConstraintKind::CheckedCast:
  case ConstraintKind::Equal:
  case ConstraintKind::Subtype:
  case ConstraintKind::TypeMember:
  case ConstraintKind::ValueMember:
    constraint->getSecondType()->getTypeVariables(typeVars);
    SWIFT_FALLTHROUGH;

  case ConstraintKind::Archetype:
  case ConstraintKind::BindOverload:
  case ConstraintKind::Class:
  case ConstraintKind::ConformsTo:
  case ConstraintKind::DynamicLookupValue:
  case ConstraintKind::SelfObjectOfProtocol:
    constraint->getFirstType()->getTypeVariables(typeVars);

    // Special case: the base type of an overloading binding.
    if (constraint->getKind() == ConstraintKind::BindOverload) {
      if (auto baseType = constraint->getOverloadChoice().getBaseType()) {
        baseType->getTypeVariables(typeVars);
      }
    }

    break;
  }
}

/// Unique the given set of type variables.
static void uniqueTypeVariables(SmallVectorImpl<TypeVariableType *> &typeVars) {
  // Remove any duplicate type variables.
  llvm::SmallPtrSet<TypeVariableType *, 4> knownTypeVars;
  typeVars.erase(std::remove_if(typeVars.begin(), typeVars.end(),
                                [&](TypeVariableType *typeVar) {
                                  return !knownTypeVars.insert(typeVar);
                                }),
                 typeVars.end());
}

Constraint *Constraint::create(ConstraintSystem &cs, ConstraintKind kind,
                               Type first, Type second, Identifier member,
                               ConstraintLocator *locator) {
  // Collect type variables.
  SmallVector<TypeVariableType *, 4> typeVars;
  if (first->hasTypeVariable())
    first->getTypeVariables(typeVars);
  if (second && second->hasTypeVariable())
    second->getTypeVariables(typeVars);
  uniqueTypeVariables(typeVars);

  // Create the constraint.
  unsigned size = sizeof(Constraint)
                + typeVars.size() * sizeof(TypeVariableType*);
  void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
  return new (mem) Constraint(kind, first, second, member, locator, typeVars);
}

Constraint *Constraint::createBindOverload(ConstraintSystem &cs, Type type,
                                           OverloadChoice choice,
                                           ConstraintLocator *locator) {
  // Collect type variables.
  SmallVector<TypeVariableType *, 4> typeVars;
  if (type->hasTypeVariable())
    type->getTypeVariables(typeVars);
  if (auto baseType = choice.getBaseType()) {
    baseType->getTypeVariables(typeVars);
  }

  // Create the constraint.
  unsigned size = sizeof(Constraint)
                + typeVars.size() * sizeof(TypeVariableType*);
  void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
  return new (mem) Constraint(type, choice, locator, typeVars);
}

Constraint *Constraint::createRestricted(ConstraintSystem &cs,
                                         ConstraintKind kind,
                                         ConversionRestrictionKind restriction,
                                         Type first, Type second,
                                         ConstraintLocator *locator) {
  // Collect type variables.
  SmallVector<TypeVariableType *, 4> typeVars;
  if (first->hasTypeVariable())
    first->getTypeVariables(typeVars);
  if (second->hasTypeVariable())
    second->getTypeVariables(typeVars);
  uniqueTypeVariables(typeVars);

  // Create the constraint.
  unsigned size = sizeof(Constraint)
                + typeVars.size() * sizeof(TypeVariableType*);
  void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
  return new (mem) Constraint(kind, restriction, first, second, locator,
                              typeVars);
}

Constraint *Constraint::createConjunction(ConstraintSystem &cs,
                                          ArrayRef<Constraint *> constraints,
                                          ConstraintLocator *locator) {
  // Unwrap any conjunctions inside the conjunction constraint.
  SmallVector<TypeVariableType *, 4> typeVars;
  bool unwrappedAny = false;
  SmallVector<Constraint *, 1> unwrapped;
  unsigned index = 0;
  for (auto constraint : constraints) {
    // Gather type variables from this constraint.
    gatherReferencedTypeVars(constraint, typeVars);

    // If we have a nested conjunction, unwrap it.
    if (constraint->getKind() == ConstraintKind::Conjunction) {
      // If we haven't unwrapped anything before, copy all of the constraints
      // we skipped.
      if (!unwrappedAny) {
        unwrapped.append(constraints.begin(), constraints.begin() + index);
        unwrappedAny = true;
      }

      // Add all of the constraints in the conjunction.
      unwrapped.append(constraint->getNestedConstraints().begin(),
                       constraint->getNestedConstraints().end());
    } else if (unwrappedAny) {
      // Since we unwrapped constraints before, add this constraint.
      unwrapped.push_back(constraint);
    }

    // FIXME: If we find any disjunctions in here, should we distribute them?

    ++index;
  }

  // If we unwrapped anything, our list of constraints is the unwrapped list.
  if (unwrappedAny)
    constraints = unwrapped;

  assert(!constraints.empty() && "Empty conjunction constraint");

  // If there is a single constraint, this isn't a disjunction at all.
  if (constraints.size() == 1)
    return constraints.front();

  // Create the conjunction constraint.
  uniqueTypeVariables(typeVars);
  unsigned size = sizeof(Constraint)
                + typeVars.size() * sizeof(TypeVariableType*);
  void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
  return new (mem) Constraint(ConstraintKind::Conjunction,
                              cs.allocateCopy(constraints), locator, typeVars);

}

Constraint *Constraint::createDisjunction(ConstraintSystem &cs,
                                          ArrayRef<Constraint *> constraints,
                                          ConstraintLocator *locator) {
  // Unwrap any disjunctions inside the disjunction constraint; we only allow
  // disjunctions at the top level.
  SmallVector<TypeVariableType *, 4> typeVars;
  bool unwrappedAny = false;
  SmallVector<Constraint *, 1> unwrapped;
  unsigned index = 0;
  for (auto constraint : constraints) {
    // Gather type variables from this constraint.
    gatherReferencedTypeVars(constraint, typeVars);

    // If we have a nested disjunction, unwrap it.
    if (constraint->getKind() == ConstraintKind::Disjunction) {
      // If we haven't unwrapped anything before, copy all of the constraints
      // we skipped.
      if (!unwrappedAny) {
        unwrapped.append(constraints.begin(), constraints.begin() + index);
        unwrappedAny = true;
      }

      // Add all of the constraints in the disjunction.
      unwrapped.append(constraint->getNestedConstraints().begin(),
                       constraint->getNestedConstraints().end());
    } else if (unwrappedAny) {
      // Since we unwrapped constraints before, add this constraint.
      unwrapped.push_back(constraint);
    }
    ++index;
  }

  // If we unwrapped anything, our list of constraints is the unwrapped list.
  if (unwrappedAny)
    constraints = unwrapped;

  assert(!constraints.empty() && "Empty disjunction constraint");

  // If there is a single constraint, this isn't a disjunction at all.
  if (constraints.size() == 1)
    return constraints.front();

  // Create the disjunction constraint.
  uniqueTypeVariables(typeVars);
  unsigned size = sizeof(Constraint)
                + typeVars.size() * sizeof(TypeVariableType*);
  void *mem = cs.getAllocator().Allocate(size, alignof(Constraint));
  return new (mem) Constraint(ConstraintKind::Disjunction,
                              cs.allocateCopy(constraints), locator, typeVars);
}

void *Constraint::operator new(size_t bytes, ConstraintSystem& cs,
                               size_t alignment) {
  return ::operator new (bytes, cs, alignment);
}
<|endoftext|>