<commit_before>/**
Copyright (c) 2017, Philip Deegan.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

    * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
    * 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.
    * Neither the name of Philip Deegan 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "maiken.hpp"

const std::string maiken::cpp::GccCompiler::sharedLib(
    const std::string& lib) const {
  return AppVars::INSTANCE().envVar("MKN_LIB_PRE") + lib + "." +
         AppVars::INSTANCE().envVar("MKN_LIB_EXT");
}

maiken::cpp::GccCompiler::GccCompiler(const int& v) : CCompiler(v) {
  m_optimise_c.insert({{0, ""},
                       {1, "-O1"},
                       {2, "-O2"},
                       {3, "-O3"},
                       {4, "-O3 -funroll-loops"},
                       {5, "-O3 -funroll-loops"},
                       {6, "-O3 -funroll-loops"},
                       {7, "-O3 -funroll-loops"},
                       {8, "-O3 -funroll-loops"},
                       {9, "-O3 -funroll-loops -march=native -mtune=native"}});
  m_debug_c.insert({{0, "-DNDEBUG"},
                    {1, "-g1"},
                    {2, "-g2"},
                    {3, "-g3"},
                    {4, "-g3"},
                    {5, "-g3"},
                    {6, "-g3"},
                    {7, "-g3"},
                    {8, "-g3"},
                    {9, "-g3 -pg"}});
  m_optimise_l_bin.insert({{0, ""},
                           {1, ""},
                           {2, ""},
                           {3, ""},
                           {4, ""},
                           {5, ""},
                           {6, ""},
                           {7, ""},
                           {8, ""},
                           {9, ""}});
  m_optimise_l_bin.insert({{0, ""},
                           {1, ""},
                           {2, ""},
                           {3, ""},
                           {4, ""},
                           {5, ""},
                           {6, ""},
                           {7, ""},
                           {8, ""},
                           {9, ""}});
  m_debug_l_bin.insert({{0, ""},
                        {1, ""},
                        {2, ""},
                        {3, ""},
                        {4, ""},
                        {5, ""},
                        {6, ""},
                        {7, ""},
                        {8, ""},
                        {9, ""}});
  m_debug_l_lib.insert({{0, ""},
                        {1, ""},
                        {2, ""},
                        {3, ""},
                        {4, ""},
                        {5, ""},
                        {6, ""},
                        {7, ""},
                        {8, ""},
                        {9, ""}});
  m_warn_c.insert({{0, "-w"},
                   {1, "-Wall"},
                   {2, "-Wall"},
                   {3, "-Wall"},
                   {4, "-Wall"},
                   {5, "-Wall"},
                   {6, "-Wall"},
                   {7, "-Wall"},
                   {8, "-Wall -Wextra"},
                   {9, "-Wall -Wextra -Werror"}});
}

maiken::CompilerProcessCapture maiken::cpp::GccCompiler::buildExecutable(
    const std::string& linker, const std::string& linkerEnd,
    const std::vector<std::string>& objects,
    const std::vector<std::string>& libs,
    const std::vector<std::string>& libPaths, const std::string& out,
    const maiken::compiler::Mode& mode, bool dryRun) const
    KTHROW(kul::Exception) {
  kul::hash::set::String dirs;
  for (const auto& o : objects) dirs.insert(kul::File(o).dir().real());

  std::string cmd = linker;
  std::vector<std::string> bits;
  if (linker.find(" ") != std::string::npos) {
    bits = kul::cli::asArgs(linker);
    cmd = bits[0];
  }
  kul::Process p(cmd);
  for (unsigned int i = 1; i < bits.size(); i++) p.arg(bits[i]);
  for (const std::string& path : libPaths) p.arg("-L" + path);
  if (mode == compiler::Mode::STAT) p.arg("-static");
  {
    auto ll(kul::env::GET("MKN_LIB_LINK_LIB"));
    if ((ll.size() ? kul::String::BOOL(ll) : 0)) {
      if(mode == compiler::Mode::SHAR || mode == compiler::Mode::NONE){
        for (const std::string& path : libPaths){
          for (const std::string& lib : libs){
            kul::File lib_file(sharedLib(lib), path);
            if(lib_file){
              std::stringstream loader;
#if defined(__APPLE__)
              loader << "-Wl,-rpath,"
                     << kul::Dir(lib_file.dir().real()).esc();
              kul::File tmp_out(out);
              tmp_out.mk();
              loader << " -Wl,-rpath,@loader_path/"
                     << tmp_out.relative(lib_file.dir());
              tmp_out.rm();
#else
              loader << "-Wl,-rpath="
                     << kul::Dir(lib_file.dir().real()).esc();
#endif
              p << loader.str();
            }
          }
        }
      }
    }
  }
  std::string exe = out;
  if (KTOSTRING(__KUL_OS__) == std::string("win")) exe += ".exe";
  p.arg("-o").arg(exe);
  for (const std::string& d : dirs) p.arg(kul::File(oStar(objects), d).escm());
  for (const std::string& lib : libs) p.arg("-l" + lib);
  for (const std::string& s : kul::cli::asArgs(linkerEnd)) p.arg(s);

  CompilerProcessCapture pc;
  try {
    if (!dryRun) p.start();
  } catch (const kul::proc::Exception& e) {
    pc.exception(std::current_exception());
  }
  pc.file(out);
  pc.cmd(p.toString());
  return pc;
}

maiken::CompilerProcessCapture maiken::cpp::GccCompiler::buildLibrary(
    const std::string& linker, const std::string& linkerEnd,
    const std::vector<std::string>& objects,
    const std::vector<std::string>& libs,
    const std::vector<std::string>& libPaths, const kul::File& out,
    const maiken::compiler::Mode& mode, bool dryRun) const
    KTHROW(kul::Exception) {
  kul::hash::set::String dirs;
  for (const auto& o : objects) dirs.insert(kul::File(o).dir().real());

  std::string lib = out.dir().join(sharedLib(out.name()));
  if (mode == compiler::Mode::STAT) lib = out.dir().join(staticLib(out.name()));
  lib = kul::File(lib).esc();
  std::string cmd = linker;
  std::vector<std::string> bits;
  if (linker.find(" ") != std::string::npos) {
    bits = kul::cli::asArgs(linker);
    cmd = bits[0];
  }
  kul::Process p(cmd);
  for (unsigned int i = 1; i < bits.size(); i++) p.arg(bits[i]);
  if (mode == compiler::Mode::SHAR) p.arg("-shared").arg("-o");
  p.arg(lib);
  for (const std::string& d : dirs) p.arg(kul::File(oStar(objects), d).escm());
  {
    auto ll(kul::env::GET("MKN_LIB_LINK_LIB"));
    if ((ll.size())) {
      uint16_t llv = kul::String::UINT16(ll);
      if(llv == 1){
        // for (const std::string& path : libPaths) p.arg("-L" + path);
        for (const std::string& lib : libs) p.arg("-l" + lib);
        if(mode == compiler::Mode::SHAR || mode == compiler::Mode::NONE){
          for (const std::string& path : libPaths){
            for (const std::string& lib : libs){
              kul::File lib_file(sharedLib(lib), path);
              if(lib_file){
                std::stringstream loader;
  #if defined(__APPLE__)
                loader << "-Wl,-rpath,"
                       << kul::Dir(lib_file.dir().real()).esc();
                kul::File tmp_out(out);
                tmp_out.mk();
                loader << " -Wl,-rpath,@loader_path/"
                       << tmp_out.relative(lib_file.dir());
                tmp_out.rm();
  #else
                loader << "-Wl,-rpath="
                       << kul::Dir(lib_file.dir().real()).esc();
  #endif
                p << loader.str();
              }
            }
          }
        }
      }else {
        for (const std::string& path : libPaths){
          for (const std::string& lib : libs){
            kul::File lib_file(sharedLib(lib), path);
            if(lib_file) p.arg(lib_file.escm());
          }
        }
      }
#if defined(__APPLE__)
      std::stringstream loader;
      loader << "-Wl,-install_name,@rpath/" << kul::File(lib).name();
      p << loader.str();
#endif
    }
  }
  for (const std::string& s : kul::cli::asArgs(linkerEnd)) p.arg(s);
  CompilerProcessCapture pc;
  try {
    if (!dryRun) p.start();
  } catch (const kul::proc::Exception& e) {
    pc.exception(std::current_exception());
  }
  pc.file(lib);
  pc.cmd(p.toString());
  return pc;
}

maiken::CompilerProcessCapture maiken::cpp::GccCompiler::compileSource(
    const std::string& compiler, const std::vector<std::string>& args,
    const std::vector<std::string>& incs, const std::string& in,
    const std::string& out, const maiken::compiler::Mode& mode,
    bool dryRun) const KTHROW(kul::Exception) {
  std::string cmd = compiler;
  std::vector<std::string> bits;
  if (compiler.find(" ") != std::string::npos) {
    bits = kul::cli::asArgs(compiler);
    cmd = bits[0];
  }
  kul::Process p(cmd);
  for (unsigned int i = 1; i < bits.size(); i++) p.arg(bits[i]);
  for (const std::string& s : incs) {
    kul::Dir d(s);
    if (d)
      p.arg("-I" + s);
    else
      p.arg("-include " + s);
  }
  for (const std::string& s : args) p.arg(s);
  p.arg("-o").arg(out).arg("-c").arg(in);
  CompilerProcessCapture pc;
  if (!kul::LogMan::INSTANCE().inf()) pc.setProcess(p);
  try {
    if (!dryRun) p.start();
  } catch (const kul::proc::Exception& e) {
    pc.exception(std::current_exception());
  }
  pc.file(out);
  pc.cmd(p.toString());
  return pc;
}

void maiken::cpp::GccCompiler::preCompileHeader(
    const std::vector<std::string>& incs, const std::vector<std::string>& args,
    const std::string& in, const std::string& out, bool dryRun) const
    KTHROW(kul::Exception) {
  if (in.rfind(".") == std::string::npos)
    KEXCEPT(Exception, "Unknown header type");

  std::string cmd;  // = compiler + " -x";
  std::string h = in.substr(in.rfind(".") + 1);

  if (h.compare("h") == 0)
    cmd = cc() + " -x c-header ";
  else if (h.compare("hpp") == 0)
    cmd = cxx() + " -x c++-header ";
  else
    KEXCEPT(Exception, "Failed to pre-compile header - uknown file type: " + h);
  cmd += in + " ";
  for (const std::string& s : args) cmd += s + " ";
  for (const std::string& s : incs) cmd += "-I" + s + " ";

  cmd += " -o " + out;
  if (kul::os::exec(cmd) != 0)
    KEXCEPT(Exception, "Failed to pre-compile header");
}<commit_msg>moreso<commit_after>/**
Copyright (c) 2017, Philip Deegan.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

    * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
    * 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.
    * Neither the name of Philip Deegan 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "maiken.hpp"

const std::string maiken::cpp::GccCompiler::sharedLib(
    const std::string& lib) const {
  return AppVars::INSTANCE().envVar("MKN_LIB_PRE") + lib + "." +
         AppVars::INSTANCE().envVar("MKN_LIB_EXT");
}

maiken::cpp::GccCompiler::GccCompiler(const int& v) : CCompiler(v) {
  m_optimise_c.insert({{0, ""},
                       {1, "-O1"},
                       {2, "-O2"},
                       {3, "-O3"},
                       {4, "-O3 -funroll-loops"},
                       {5, "-O3 -funroll-loops"},
                       {6, "-O3 -funroll-loops"},
                       {7, "-O3 -funroll-loops"},
                       {8, "-O3 -funroll-loops"},
                       {9, "-O3 -funroll-loops -march=native -mtune=native"}});
  m_debug_c.insert({{0, "-DNDEBUG"},
                    {1, "-g1"},
                    {2, "-g2"},
                    {3, "-g3"},
                    {4, "-g3"},
                    {5, "-g3"},
                    {6, "-g3"},
                    {7, "-g3"},
                    {8, "-g3"},
                    {9, "-g3 -pg"}});
  m_optimise_l_bin.insert({{0, ""},
                           {1, ""},
                           {2, ""},
                           {3, ""},
                           {4, ""},
                           {5, ""},
                           {6, ""},
                           {7, ""},
                           {8, ""},
                           {9, ""}});
  m_optimise_l_bin.insert({{0, ""},
                           {1, ""},
                           {2, ""},
                           {3, ""},
                           {4, ""},
                           {5, ""},
                           {6, ""},
                           {7, ""},
                           {8, ""},
                           {9, ""}});
  m_debug_l_bin.insert({{0, ""},
                        {1, ""},
                        {2, ""},
                        {3, ""},
                        {4, ""},
                        {5, ""},
                        {6, ""},
                        {7, ""},
                        {8, ""},
                        {9, ""}});
  m_debug_l_lib.insert({{0, ""},
                        {1, ""},
                        {2, ""},
                        {3, ""},
                        {4, ""},
                        {5, ""},
                        {6, ""},
                        {7, ""},
                        {8, ""},
                        {9, ""}});
  m_warn_c.insert({{0, "-w"},
                   {1, "-Wall"},
                   {2, "-Wall"},
                   {3, "-Wall"},
                   {4, "-Wall"},
                   {5, "-Wall"},
                   {6, "-Wall"},
                   {7, "-Wall"},
                   {8, "-Wall -Wextra"},
                   {9, "-Wall -Wextra -Werror"}});
}

maiken::CompilerProcessCapture maiken::cpp::GccCompiler::buildExecutable(
    const std::string& linker, const std::string& linkerEnd,
    const std::vector<std::string>& objects,
    const std::vector<std::string>& libs,
    const std::vector<std::string>& libPaths, const std::string& out,
    const maiken::compiler::Mode& mode, bool dryRun) const
    KTHROW(kul::Exception) {
  kul::hash::set::String dirs;
  for (const auto& o : objects) dirs.insert(kul::File(o).dir().real());

  std::string cmd = linker;
  std::vector<std::string> bits;
  if (linker.find(" ") != std::string::npos) {
    bits = kul::cli::asArgs(linker);
    cmd = bits[0];
  }
  kul::Process p(cmd);
  for (unsigned int i = 1; i < bits.size(); i++) p.arg(bits[i]);
  for (const std::string& path : libPaths) p.arg("-L" + path);
  if (mode == compiler::Mode::STAT) p.arg("-static");
  {
    auto ll(kul::env::GET("MKN_LIB_LINK_LIB"));
    if ((ll.size() ? kul::String::BOOL(ll) : 0)) {
      if(mode == compiler::Mode::SHAR || mode == compiler::Mode::NONE){
        for (const std::string& path : libPaths){
          for (const std::string& lib : libs){
            kul::File lib_file(sharedLib(lib), path);
            if(lib_file){
              std::stringstream loader;
#if defined(__APPLE__)
              loader << "-Wl,-rpath,"
                     << kul::Dir(lib_file.dir().real()).esc();
              kul::File tmp_out(out);
              tmp_out.mk();
              loader << " -Wl,-rpath,@loader_path/"
                     << tmp_out.relative(lib_file.dir());
              tmp_out.rm();
#else
              loader << "-Wl,-rpath="
                     << kul::Dir(lib_file.dir().real()).esc();
#endif
              p << loader.str();
            }
          }
        }
      }
    }
  }
  std::string exe = out;
  if (KTOSTRING(__KUL_OS__) == std::string("win")) exe += ".exe";
  p.arg("-o").arg(exe);
  for (const std::string& d : dirs) p.arg(kul::File(oStar(objects), d).escm());
  for (const std::string& lib : libs) p.arg("-l" + lib);
  for (const std::string& s : kul::cli::asArgs(linkerEnd)) p.arg(s);

  CompilerProcessCapture pc;
  try {
    if (!dryRun) p.start();
  } catch (const kul::proc::Exception& e) {
    pc.exception(std::current_exception());
  }
  pc.file(out);
  pc.cmd(p.toString());
  return pc;
}

maiken::CompilerProcessCapture maiken::cpp::GccCompiler::buildLibrary(
    const std::string& linker, const std::string& linkerEnd,
    const std::vector<std::string>& objects,
    const std::vector<std::string>& libs,
    const std::vector<std::string>& libPaths, const kul::File& out,
    const maiken::compiler::Mode& mode, bool dryRun) const
    KTHROW(kul::Exception) {
  kul::hash::set::String dirs;
  for (const auto& o : objects) dirs.insert(kul::File(o).dir().real());

  std::string lib = out.dir().join(sharedLib(out.name()));
  if (mode == compiler::Mode::STAT) lib = out.dir().join(staticLib(out.name()));
  lib = kul::File(lib).esc();
  std::string cmd = linker;
  std::vector<std::string> bits;
  if (linker.find(" ") != std::string::npos) {
    bits = kul::cli::asArgs(linker);
    cmd = bits[0];
  }
  kul::Process p(cmd);
  for (unsigned int i = 1; i < bits.size(); i++) p.arg(bits[i]);
  if (mode == compiler::Mode::SHAR) p.arg("-shared").arg("-o");
  p.arg(lib);
  for (const std::string& d : dirs) p.arg(kul::File(oStar(objects), d).escm());
  {
    auto ll(kul::env::GET("MKN_LIB_LINK_LIB"));
    if ((ll.size())) {
      uint16_t llv = kul::String::UINT16(ll);
      if(llv == 1){
        for (const std::string& path : libPaths) p.arg("-L" + path);
        for (const std::string& lib : libs) p.arg("-l" + lib);
        if(mode == compiler::Mode::SHAR || mode == compiler::Mode::NONE){
          for (const std::string& path : libPaths){
            for (const std::string& lib : libs){
              kul::File lib_file(sharedLib(lib), path);
              if(lib_file){
                std::stringstream loader;
  #if defined(__APPLE__)
                loader << "-Wl,-rpath,"
                       << kul::Dir(lib_file.dir().real()).esc();
                kul::File tmp_out(out);
                tmp_out.mk();
                loader << " -Wl,-rpath,@loader_path/"
                       << tmp_out.relative(lib_file.dir());
                tmp_out.rm();
  #else
                loader << "-Wl,-rpath="
                       << kul::Dir(lib_file.dir().real()).esc();
  #endif
                p << loader.str();
              }
            }
          }
        }
      }else {
        for (const std::string& path : libPaths){
          for (const std::string& lib : libs){
            kul::File lib_file(sharedLib(lib), path);
            if(lib_file) p.arg(lib_file.escm());
          }
        }
      }
#if defined(__APPLE__)
      std::stringstream loader;
      loader << "-Wl,-install_name,@rpath/" << kul::File(lib).name();
      p << loader.str();
#endif
    }
  }
  for (const std::string& s : kul::cli::asArgs(linkerEnd)) p.arg(s);
  CompilerProcessCapture pc;
  try {
    if (!dryRun) p.start();
  } catch (const kul::proc::Exception& e) {
    pc.exception(std::current_exception());
  }
  pc.file(lib);
  pc.cmd(p.toString());
  return pc;
}

maiken::CompilerProcessCapture maiken::cpp::GccCompiler::compileSource(
    const std::string& compiler, const std::vector<std::string>& args,
    const std::vector<std::string>& incs, const std::string& in,
    const std::string& out, const maiken::compiler::Mode& mode,
    bool dryRun) const KTHROW(kul::Exception) {
  std::string cmd = compiler;
  std::vector<std::string> bits;
  if (compiler.find(" ") != std::string::npos) {
    bits = kul::cli::asArgs(compiler);
    cmd = bits[0];
  }
  kul::Process p(cmd);
  for (unsigned int i = 1; i < bits.size(); i++) p.arg(bits[i]);
  for (const std::string& s : incs) {
    kul::Dir d(s);
    if (d)
      p.arg("-I" + s);
    else
      p.arg("-include " + s);
  }
  for (const std::string& s : args) p.arg(s);
  p.arg("-o").arg(out).arg("-c").arg(in);
  CompilerProcessCapture pc;
  if (!kul::LogMan::INSTANCE().inf()) pc.setProcess(p);
  try {
    if (!dryRun) p.start();
  } catch (const kul::proc::Exception& e) {
    pc.exception(std::current_exception());
  }
  pc.file(out);
  pc.cmd(p.toString());
  return pc;
}

void maiken::cpp::GccCompiler::preCompileHeader(
    const std::vector<std::string>& incs, const std::vector<std::string>& args,
    const std::string& in, const std::string& out, bool dryRun) const
    KTHROW(kul::Exception) {
  if (in.rfind(".") == std::string::npos)
    KEXCEPT(Exception, "Unknown header type");

  std::string cmd;  // = compiler + " -x";
  std::string h = in.substr(in.rfind(".") + 1);

  if (h.compare("h") == 0)
    cmd = cc() + " -x c-header ";
  else if (h.compare("hpp") == 0)
    cmd = cxx() + " -x c++-header ";
  else
    KEXCEPT(Exception, "Failed to pre-compile header - uknown file type: " + h);
  cmd += in + " ";
  for (const std::string& s : args) cmd += s + " ";
  for (const std::string& s : incs) cmd += "-I" + s + " ";

  cmd += " -o " + out;
  if (kul::os::exec(cmd) != 0)
    KEXCEPT(Exception, "Failed to pre-compile header");
}<|endoftext|>


<commit_before>#include "Squad.h"

#include "KBot.h"

namespace KBot {

    using namespace BWAPI;

    std::string to_string(SquadState state) {
        switch (state) {
        case SquadState::scout:
            return "Scout";
        case SquadState::attack:
            return "Attack";
        case SquadState::defend:
            return "Defend";
        default:
            throw std::logic_error("Unknown SquadState!");
        }
    }

    Squad::Squad(KBot &kBot) : m_kBot(&kBot), m_state(SquadState::scout) {}

    void Squad::update() {
        // Draw squad radius and path to enemy
        // TODO: remove empty check
        if (!empty()) {
            Broodwar->drawCircleMap(getPosition(), 400, Colors::Red);
            Broodwar->drawTextMap(getPosition(), "Squad: %s", to_string(m_state).c_str());

            if (m_kBot->getEnemyLocationCount() > 0) {
                const auto enemyLocation = m_kBot->getNextEnemyLocation();
                const auto path = m_kBot->map().GetPath(getPosition(), Position(enemyLocation));
                if (!path.empty()) {
                    // Draw path
                    Broodwar->drawLineMap(getPosition(), Position(path.front()->Center()), Colors::Red);
                    for (std::size_t i = 1; i < path.size(); ++i)
                        Broodwar->drawLineMap(Position(path[i - 1]->Center()), Position(path[i]->Center()), Colors::Red);
                    Broodwar->drawLineMap(Position(path.back()->Center()), Position(enemyLocation), Colors::Red);
                }
                else
                    Broodwar->drawLineMap(getPosition(), Position(enemyLocation), Colors::Red);
            }
        }

        // Draw individual radius
        //for (const auto unit : *this)
        //    Broodwar->drawCircleMap(unit->getPosition(), 200, Colors::Yellow);

        // Prevent spamming by only running our onFrame once every number of latency frames.
        // Latency frames are the number of frames before commands are processed.
        if (Broodwar->getFrameCount() % Broodwar->getLatencyFrames() != 0)
            return;

        // TODO: remove
        const auto enemiesNearBase = Broodwar->getUnitsInRadius(Position(Broodwar->self()->getStartLocation()), 1000, Filter::IsEnemy);

        // Update squad state
        switch (m_state) {
        case SquadState::scout:
            if (m_kBot->getEnemyLocationCount() > 0)
                m_state = SquadState::defend;
            break;
        case SquadState::attack:
            if (m_kBot->getEnemyLocationCount() == 0)
                m_state = SquadState::scout;
            else if (!enemiesNearBase.empty() || size() < 10)
                m_state = SquadState::defend;
            break;
        case SquadState::defend:
            if (enemiesNearBase.empty() && size() >= 20) {
                m_state = SquadState::attack;
            }
            break;
        default:
            throw std::logic_error("Unknown SquadState!");
        }

        for (const auto unit : *this) {
            assert(unit->exists());

            // Ignore the unit if it has one of the following status ailments
            if (unit->isLockedDown() || unit->isMaelstrommed() || unit->isStasised())
                continue;

            // Ignore the unit if it is in one of the following states
            if (unit->isLoaded() || !unit->isPowered() || unit->isStuck())
                continue;

            if (unit->getType() == UnitTypes::Terran_Marine) {
                switch (m_state) {
                case SquadState::scout:
                    if (unit->isIdle())
                        // Scout!
                        unit->attack(Position(m_kBot->getNextEnemyLocation()));
                    break;
                case SquadState::attack:
                    if (unit->getDistance(getPosition()) > 400 && !unit->isUnderAttack()) {
                        // Regroup!
                        const Point<double> vector = unit->getPosition() - getPosition();
                        // Move further to the middle to prevent sticky behavior.
                        auto position = getPosition() + vector * 300 / vector.getLength();
                        if (!Broodwar->isWalkable(WalkPosition(position)))
                            position = Position(m_kBot->getNextEnemyLocation());
                        unit->attack(position);
                        // debug
                        Broodwar->registerEvent([unit, position](Game*) {
                            Broodwar->drawLineMap(unit->getPosition(), position, Colors::Purple);
                        }, [unit](Game*) { return unit->exists(); }, Broodwar->getLatencyFrames());
                    }
                    else if (unit->isIdle())
                        // Attack!
                        unit->attack(Position(m_kBot->getNextEnemyLocation()));
                    break;
                case SquadState::defend:
                    if (unit->getDistance(Position(Broodwar->self()->getStartLocation())) > 1000)
                        // Retreat!
                        unit->attack(Position(Broodwar->self()->getStartLocation()));
                    else if (unit->isIdle() && !enemiesNearBase.empty())
                        // Defend!
                        unit->attack(unit->getClosestUnit(Filter::IsEnemy));
                    break;
                default:
                    throw std::logic_error("Unknown SquadState!");
                }
            }
        }
    }

} // namespace
<commit_msg>Updated squad behavior.<commit_after>#include "Squad.h"

#include "KBot.h"

namespace KBot {

    using namespace BWAPI;

    std::string to_string(SquadState state) {
        switch (state) {
        case SquadState::scout:
            return "Scout";
        case SquadState::attack:
            return "Attack";
        case SquadState::defend:
            return "Defend";
        default:
            throw std::logic_error("Unknown SquadState!");
        }
    }

    Squad::Squad(KBot &kBot) : m_kBot(&kBot), m_state(SquadState::scout) {}

    void Squad::update() {
        // Draw squad radius and path to enemy
        // TODO: remove empty check
        if (!empty()) {
            Broodwar->drawCircleMap(getPosition(), 400, Colors::Red);
            Broodwar->drawTextMap(getPosition(), "Squad: %s", to_string(m_state).c_str());

            if (m_kBot->getEnemyLocationCount() > 0) {
                const auto enemyLocation = m_kBot->getNextEnemyLocation();
                const auto path = m_kBot->map().GetPath(getPosition(), Position(enemyLocation));
                if (!path.empty()) {
                    // Draw path
                    Broodwar->drawLineMap(getPosition(), Position(path.front()->Center()), Colors::Red);
                    for (std::size_t i = 1; i < path.size(); ++i)
                        Broodwar->drawLineMap(Position(path[i - 1]->Center()), Position(path[i]->Center()), Colors::Red);
                    Broodwar->drawLineMap(Position(path.back()->Center()), Position(enemyLocation), Colors::Red);
                }
                else
                    Broodwar->drawLineMap(getPosition(), Position(enemyLocation), Colors::Red);
            }
        }

        // Draw individual radius
        //for (const auto unit : *this)
        //    Broodwar->drawCircleMap(unit->getPosition(), 200, Colors::Yellow);

        // Prevent spamming by only running our onFrame once every number of latency frames.
        // Latency frames are the number of frames before commands are processed.
        if (Broodwar->getFrameCount() % Broodwar->getLatencyFrames() != 0)
            return;

        // TODO: remove
        const auto enemiesNearBase = Broodwar->getUnitsInRadius(Position(Broodwar->self()->getStartLocation()), 1000, Filter::IsEnemy);

        // Update squad state
        const auto oldState = m_state;
        switch (m_state) {
        case SquadState::scout:
            if (m_kBot->getEnemyLocationCount() > 0) {
                if (!enemiesNearBase.empty() || size() < 10)
                    m_state = SquadState::attack;
                else
                    m_state = SquadState::defend;
            }
            break;
        case SquadState::attack:
            if (!enemiesNearBase.empty())
                m_state = SquadState::defend;
            else if (m_kBot->getEnemyLocationCount() == 0)
                m_state = SquadState::scout;
            else if (size() < 10)
                m_state = SquadState::defend;
            break;
        case SquadState::defend:
            if (enemiesNearBase.empty() && size() >= 20) {
                m_state = SquadState::attack;
            }
            break;
        default:
            throw std::logic_error("Unknown SquadState!");
        }
        if (m_state != oldState)
            this->stop(); // reassign orders

        for (const auto unit : *this) {
            assert(unit->exists());

            // Ignore the unit if it has one of the following status ailments
            if (unit->isLockedDown() || unit->isMaelstrommed() || unit->isStasised())
                continue;

            // Ignore the unit if it is in one of the following states
            if (unit->isLoaded() || !unit->isPowered() || unit->isStuck())
                continue;

            if (unit->getType() == UnitTypes::Terran_Marine) {
                switch (m_state) {
                case SquadState::scout:
                    if (unit->isIdle())
                        // Scout!
                        unit->attack(Position(m_kBot->getNextEnemyLocation()));
                    break;
                case SquadState::attack:
                    if (unit->getDistance(getPosition()) > 400 && !unit->isUnderAttack()) {
                        // Regroup!
                        const Point<double> vector = unit->getPosition() - getPosition();
                        // Move further to the middle to prevent sticky behavior.
                        auto position = getPosition() + vector * 300 / vector.getLength();
                        if (!Broodwar->isWalkable(WalkPosition(position)))
                            position = Position(m_kBot->getNextEnemyLocation());
                        unit->attack(position); // FIXME: still pretty spammy
                        // debug
                        Broodwar->registerEvent([unit, position](Game*) {
                            Broodwar->drawLineMap(unit->getPosition(), position, Colors::Purple);
                        }, [unit](Game*) { return unit->exists(); }, Broodwar->getLatencyFrames());
                    }
                    else if (unit->isIdle())
                        // Attack!
                        unit->attack(Position(m_kBot->getNextEnemyLocation()));
                    break;
                case SquadState::defend:
                    if (unit->getDistance(Position(Broodwar->self()->getStartLocation())) > 1000)
                        // Retreat!
                        unit->attack(Position(Broodwar->self()->getStartLocation()));
                    else if (unit->isIdle() && !enemiesNearBase.empty())
                        // Defend!
                        unit->attack(unit->getClosestUnit(Filter::IsEnemy)->getPosition());
                    break;
                default:
                    throw std::logic_error("Unknown SquadState!");
                }
            }
        }
    }

} // namespace
<|endoftext|>


<commit_before>#include <node.h>
#include <node_buffer.h>
#include <v8.h>
#include <nan.h>
#include <cstddef>
#include <cassert>
#include <cstring>

#include "KeccakNISTInterface.h"

#define MAX_DIGEST_SIZE 64
#define ASSERT_IS_STRING_OR_BUFFER(val) \
	if (!val->IsString() && !Buffer::HasInstance(val)) { \
		return NanThrowError(Exception::TypeError(NanNew<String>("Not a string or buffer"))); \
	}

using namespace node;
using namespace v8;
using namespace Node_SHA3;

static void toHex(const char *data_buf, size_t size, char *output);

class SHA3Hash: public ObjectWrap {
public:
	hashState state;
	int32_t bitlen;

	static void
	Initialize(Handle<Object> target) {
		NanScope();
		Local<FunctionTemplate> t = NanNew<FunctionTemplate>(New);
		t->InstanceTemplate()->SetInternalFieldCount(1);
		t->SetClassName(NanNew<String>("SHA3Hash"));

		NODE_SET_PROTOTYPE_METHOD(t, "update", Update);
		NODE_SET_PROTOTYPE_METHOD(t, "digest", Digest);

		NanAssignPersistent(constructor, t->GetFunction());
		target->Set(NanNew<String>("SHA3Hash"), t->GetFunction());
	}

	static
	NAN_METHOD(New) {
		NanScope();
		SHA3Hash *obj;
		int32_t hashlen;

		hashlen = args[0]->IsUndefined() ? 512 : args[0]->Int32Value();
		if (hashlen < 1) {
			Local<Value> exception = Exception::TypeError(NanNew<String>("Unsupported hash length"));
			return NanThrowError(exception);
		}

		if (args.IsConstructCall()) {
			// Invoked as constructor.
			obj = new SHA3Hash();
			obj->Wrap(args.This());
			obj->bitlen = hashlen;
			::Init(&obj->state, hashlen);
			NanReturnValue(args.This());
		} else {
			// Invoked as a plain function.
			const int argc = 1;
			Local<Value> argv[argc] = { NanNew<Number>(hashlen) };
			Local<Function> cons = NanNew<Function>(constructor);
			NanReturnValue(cons->NewInstance(argc, argv));
		}
	}

	static
	NAN_METHOD(Update) {
		NanScope();
		SHA3Hash *obj = ObjectWrap::Unwrap<SHA3Hash>(args.This());

		ASSERT_IS_STRING_OR_BUFFER(args[0]);
		enum encoding enc = ParseEncoding(args[1]);
		ssize_t len = DecodeBytes(args[0], enc);

		if (len < 0) {
			Local<Value> exception = Exception::Error(NanNew<String>("Bad argument"));
			return NanThrowError(exception);
		}

		if (Buffer::HasInstance(args[0])) {
			Local<Object> buffer_obj = args[0]->ToObject();
			const char *buffer_data = Buffer::Data(buffer_obj);
			size_t buffer_length = Buffer::Length(buffer_obj);
			::Update(&obj->state, (const BitSequence *) buffer_data, buffer_length * 8);
		} else {
			char *buf = new char[len];
			ssize_t written = DecodeWrite(buf, len, args[0], enc);
			assert(written == len);
			::Update(&obj->state, (const BitSequence *) buf, len * 8);
			delete[] buf;
		}

		NanReturnValue(args.This());
	}

	static
	NAN_METHOD(Digest) {
		NanScope();
		SHA3Hash *obj = ObjectWrap::Unwrap<SHA3Hash>(args.This());
		hashState state2;
		unsigned char digest[MAX_DIGEST_SIZE];

		memcpy(&state2, &obj->state, sizeof(hashState));
		Final(&state2, digest);

		Local<Value> outString;
		enum encoding enc = ParseEncoding(args[0], BINARY);
		if (enc == HEX) {
			// Hex encoding
			char hexdigest[MAX_DIGEST_SIZE * 2];
			toHex((const char *) digest, obj->bitlen / 8, hexdigest);
			outString = Encode(hexdigest, obj->bitlen / 4, BINARY);
		} else if (enc == BINARY /* || enc == BUFFER */) {
			outString = Encode(digest, obj->bitlen / 8, enc);
		} else {
			Local<Value> exception = Exception::Error(NanNew<String>("Unsupported output encoding"));
			return NanThrowError(exception);
		}

		NanReturnValue(outString);
	}

private:
	static Persistent<Function> constructor;
};

Persistent<Function> SHA3Hash::constructor;

static const char hex_chars[] = {
	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
	'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
	'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
	'u', 'v', 'w', 'x', 'y', 'z'
};

static void
toHex(const char *data_buf, size_t size, char *output) {
	size_t i;

	for (i = 0; i < size; i++) {
		output[i * 2] = hex_chars[(unsigned char) data_buf[i] / 16];
		output[i * 2 + 1] = hex_chars[(unsigned char) data_buf[i] % 16];
	}
}

static void
init(Handle<Object> target) {
	SHA3Hash::Initialize(target);
}

NODE_MODULE(sha3, init)
<commit_msg>Only allow hash lengths of 224, 256, 384, 512<commit_after>#include <node.h>
#include <node_buffer.h>
#include <v8.h>
#include <nan.h>
#include <cstddef>
#include <cassert>
#include <cstring>

#include "KeccakNISTInterface.h"

#define MAX_DIGEST_SIZE 64
#define ASSERT_IS_STRING_OR_BUFFER(val) \
	if (!val->IsString() && !Buffer::HasInstance(val)) { \
		return NanThrowError(Exception::TypeError(NanNew<String>("Not a string or buffer"))); \
	}

using namespace node;
using namespace v8;
using namespace Node_SHA3;

static void toHex(const char *data_buf, size_t size, char *output);

class SHA3Hash: public ObjectWrap {
public:
	hashState state;
	int32_t bitlen;

	static void
	Initialize(Handle<Object> target) {
		NanScope();
		Local<FunctionTemplate> t = NanNew<FunctionTemplate>(New);
		t->InstanceTemplate()->SetInternalFieldCount(1);
		t->SetClassName(NanNew<String>("SHA3Hash"));

		NODE_SET_PROTOTYPE_METHOD(t, "update", Update);
		NODE_SET_PROTOTYPE_METHOD(t, "digest", Digest);

		NanAssignPersistent(constructor, t->GetFunction());
		target->Set(NanNew<String>("SHA3Hash"), t->GetFunction());
	}

	static
	NAN_METHOD(New) {
		NanScope();
		SHA3Hash *obj;
		int32_t hashlen;

		hashlen = args[0]->IsUndefined() ? 512 : args[0]->Int32Value();
		switch (hashlen) {
			case 224:
			case 256:
			case 384:
			case 512:
				break;
			default:
				Local<Value> exception = Exception::TypeError(NanNew<String>("Unsupported hash length"));
				return NanThrowError(exception);
		}

		if (args.IsConstructCall()) {
			// Invoked as constructor.
			obj = new SHA3Hash();
			obj->Wrap(args.This());
			obj->bitlen = hashlen;
			::Init(&obj->state, hashlen);
			NanReturnValue(args.This());
		} else {
			// Invoked as a plain function.
			const int argc = 1;
			Local<Value> argv[argc] = { NanNew<Number>(hashlen) };
			Local<Function> cons = NanNew<Function>(constructor);
			NanReturnValue(cons->NewInstance(argc, argv));
		}
	}

	static
	NAN_METHOD(Update) {
		NanScope();
		SHA3Hash *obj = ObjectWrap::Unwrap<SHA3Hash>(args.This());

		ASSERT_IS_STRING_OR_BUFFER(args[0]);
		enum encoding enc = ParseEncoding(args[1]);
		ssize_t len = DecodeBytes(args[0], enc);

		if (len < 0) {
			Local<Value> exception = Exception::Error(NanNew<String>("Bad argument"));
			return NanThrowError(exception);
		}

		if (Buffer::HasInstance(args[0])) {
			Local<Object> buffer_obj = args[0]->ToObject();
			const char *buffer_data = Buffer::Data(buffer_obj);
			size_t buffer_length = Buffer::Length(buffer_obj);
			::Update(&obj->state, (const BitSequence *) buffer_data, buffer_length * 8);
		} else {
			char *buf = new char[len];
			ssize_t written = DecodeWrite(buf, len, args[0], enc);
			assert(written == len);
			::Update(&obj->state, (const BitSequence *) buf, len * 8);
			delete[] buf;
		}

		NanReturnValue(args.This());
	}

	static
	NAN_METHOD(Digest) {
		NanScope();
		SHA3Hash *obj = ObjectWrap::Unwrap<SHA3Hash>(args.This());
		hashState state2;
		unsigned char digest[MAX_DIGEST_SIZE];

		memcpy(&state2, &obj->state, sizeof(hashState));
		Final(&state2, digest);

		Local<Value> outString;
		enum encoding enc = ParseEncoding(args[0], BINARY);
		if (enc == HEX) {
			// Hex encoding
			char hexdigest[MAX_DIGEST_SIZE * 2];
			toHex((const char *) digest, obj->bitlen / 8, hexdigest);
			outString = Encode(hexdigest, obj->bitlen / 4, BINARY);
		} else if (enc == BINARY /* || enc == BUFFER */) {
			outString = Encode(digest, obj->bitlen / 8, enc);
		} else {
			Local<Value> exception = Exception::Error(NanNew<String>("Unsupported output encoding"));
			return NanThrowError(exception);
		}

		NanReturnValue(outString);
	}

private:
	static Persistent<Function> constructor;
};

Persistent<Function> SHA3Hash::constructor;

static const char hex_chars[] = {
	'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
	'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
	'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
	'u', 'v', 'w', 'x', 'y', 'z'
};

static void
toHex(const char *data_buf, size_t size, char *output) {
	size_t i;

	for (i = 0; i < size; i++) {
		output[i * 2] = hex_chars[(unsigned char) data_buf[i] / 16];
		output[i * 2 + 1] = hex_chars[(unsigned char) data_buf[i] % 16];
	}
}

static void
init(Handle<Object> target) {
	SHA3Hash::Initialize(target);
}

NODE_MODULE(sha3, init)
<|endoftext|>


<commit_before>/*
 * Copyright 2017 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

// ok is an experimental test harness, maybe to replace DM.  Key features:
//   * work is balanced across separate processes for stability and isolation;
//   * ok is entirely opt-in.  No more maintaining huge --blacklists.

#include "SkGraphics.h"
#include "SkImage.h"
#include "ok.h"
#include <chrono>
#include <list>
#include <stdio.h>
#include <stdlib.h>
#include <vector>

#if !defined(__has_include)
    #define  __has_include(x) 0
#endif

static thread_local const char* tls_currently_running = "";

#if __has_include(<execinfo.h>) && __has_include(<fcntl.h>) && __has_include(<signal.h>)
    #include <execinfo.h>
    #include <fcntl.h>
    #include <signal.h>

    static int log_fd = 2/*stderr*/;

    static void log(const char* msg) {
        write(log_fd, msg, strlen(msg));
    }

    static void setup_crash_handler() {
        static void (*original_handlers[32])(int);
        for (int sig : std::vector<int>{ SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV }) {
            original_handlers[sig] = signal(sig, [](int sig) {
                lockf(log_fd, F_LOCK, 0);
                    log("\ncaught signal ");
                    switch (sig) {
                    #define CASE(s) case s: log(#s); break
                        CASE(SIGABRT);
                        CASE(SIGBUS);
                        CASE(SIGFPE);
                        CASE(SIGILL);
                        CASE(SIGSEGV);
                    #undef CASE
                    }
                    log(" while running '");
                    log(tls_currently_running);
                    log("'\n");

                    void* stack[128];
                    int frames = backtrace(stack, sizeof(stack)/sizeof(*stack));
                    backtrace_symbols_fd(stack, frames, log_fd);
                lockf(log_fd, F_ULOCK, 0);

                signal(sig, original_handlers[sig]);
                raise(sig);
            });
        }
    }

    static void defer_logging() {
        log_fd = fileno(tmpfile());
        atexit([] {
            lseek(log_fd, 0, SEEK_SET);
            char buf[1024];
            while (size_t bytes = read(log_fd, buf, sizeof(buf))) {
                write(2, buf, bytes);
            }
        });
    }

    void ok_log(const char* msg) {
        lockf(log_fd, F_LOCK, 0);
            log("[");
            log(tls_currently_running);
            log("]\t");
            log(msg);
            log("\n");
        lockf(log_fd, F_ULOCK, 0);
    }

#else
    static void setup_crash_handler() {}
    static void defer_logging() {}

    void ok_log(const char* msg) {
        fprintf(stderr, "%s\n", msg);
    }
#endif

struct EngineType {
    const char *name, *help;
    std::unique_ptr<Engine> (*factory)(Options);
};
static std::vector<EngineType> engine_types;

struct StreamType {
    const char *name, *help;
    std::unique_ptr<Stream> (*factory)(Options);
};
static std::vector<StreamType> stream_types;

struct DstType {
    const char *name, *help;
    std::unique_ptr<Dst> (*factory)(Options);
};
static std::vector<DstType> dst_types;

struct ViaType {
    const char *name, *help;
    std::unique_ptr<Dst> (*factory)(Options, std::unique_ptr<Dst>);
};
static std::vector<ViaType> via_types;

template <typename T>
static std::string help_for(std::vector<T> registered) {
    std::string help;
    for (auto r : registered) {
        help += "\n    ";
        help += r.name;
        help += ": ";
        help += r.help;
    }
    return help;
}

int main(int argc, char** argv) {
    SkGraphics::Init();
    setup_crash_handler();

    std::unique_ptr<Engine>                   engine;
    std::unique_ptr<Stream>                   stream;
    std::function<std::unique_ptr<Dst>(void)> dst_factory = []{
        // A default Dst that's enough for unit tests and not much else.
        struct : Dst {
            Status draw(Src* src)  override { return src->draw(nullptr); }
            sk_sp<SkImage> image() override { return nullptr; }
        } dst;
        return move_unique(dst);
    };

    auto help = [&] {
        std::string engine_help = help_for(engine_types),
                    stream_help = help_for(stream_types),
                       dst_help = help_for(   dst_types),
                       via_help = help_for(   via_types);

        printf("%s [engine] src[:k=v,...] dst[:k=v,...] [via[:k=v,...] ...]          \n"
                " engine: how to execute tasks%s                                     \n"
                " src: content to draw%s                                             \n"
                " dst: how to draw that content%s                                    \n"
                " via: wrappers around dst%s                                         \n"
                " Most srcs, dsts and vias have options, e.g. skp:dir=skps sw:ct=565 \n",
                argv[0],
                engine_help.c_str(), stream_help.c_str(), dst_help.c_str(), via_help.c_str());
        return 1;
    };

    for (int i = 1; i < argc; i++) {
        if (0 == strcmp("-h",     argv[i])) { return help(); }
        if (0 == strcmp("--help", argv[i])) { return help(); }

        for (auto e : engine_types) {
            size_t len = strlen(e.name);
            if (0 == strncmp(e.name, argv[i], len)) {
                switch (argv[i][len]) {
                    case  ':': len++;
                    case '\0': engine = e.factory(Options{argv[i]+len});
                }
            }
        }

        for (auto s : stream_types) {
            size_t len = strlen(s.name);
            if (0 == strncmp(s.name, argv[i], len)) {
                switch (argv[i][len]) {
                    case  ':': len++;
                    case '\0': stream = s.factory(Options{argv[i]+len});
                }
            }
        }
        for (auto d : dst_types) {
            size_t len = strlen(d.name);
            if (0 == strncmp(d.name, argv[i], len)) {
                switch (argv[i][len]) {
                    case  ':': len++;
                    case '\0': dst_factory = [=]{
                                   return d.factory(Options{argv[i]+len});
                               };
                }
            }
        }
        for (auto v : via_types) {
            size_t len = strlen(v.name);
            if (0 == strncmp(v.name, argv[i], len)) {
                if (!dst_factory) { return help(); }
                switch (argv[i][len]) {
                    case  ':': len++;
                    case '\0': dst_factory = [=]{
                                   return v.factory(Options{argv[i]+len}, dst_factory());
                               };
                }
            }
        }
    }
    if (!stream) { return help(); }

    if (!engine) { engine = engine_types.back().factory(Options{}); }

    // If we know engine->spawn() will never crash, we can defer logging until we exit.
    if (engine->crashproof()) {
        defer_logging();
    }

    int ok = 0, failed = 0, crashed = 0, skipped = 0;

    auto update_stats = [&](Status s) {
        switch (s) {
            case Status::OK:      ok++;      break;
            case Status::Failed:  failed++;  break;
            case Status::Crashed: crashed++; break;
            case Status::Skipped: skipped++; break;
            case Status::None:              return;
        }
        const char* leader = "\r";
        auto print = [&](int count, const char* label) {
            if (count) {
                printf("%s%d %s", leader, count, label);
                leader = ", ";
            }
        };
        print(ok,      "ok");
        print(failed,  "failed");
        print(crashed, "crashed");
        print(skipped, "skipped");
        fflush(stdout);
    };

    std::list<std::future<Status>> live;
    const auto the_past = std::chrono::steady_clock::now();

    auto wait_one = [&] {
        if (live.empty()) {
            return Status::None;
        }

        for (;;) {
            for (auto it = live.begin(); it != live.end(); it++) {
                if (it->wait_until(the_past) != std::future_status::timeout) {
                    Status s = it->get();
                    live.erase(it);
                    return s;
                }
            }
        }
    };

    auto spawn = [&](std::function<Status(void)> fn) {
        std::future<Status> status;
        for (;;) {
            status = engine->spawn(fn);
            if (status.valid()) {
                break;
            }
            update_stats(wait_one());
        }
        live.push_back(std::move(status));
    };

    for (std::unique_ptr<Src> owned = stream->next(); owned; owned = stream->next()) {
        Src* raw = owned.release();  // Can't move std::unique_ptr into a lambda in C++11. :(
        spawn([=] {
            std::unique_ptr<Src> src{raw};

            std::string name = src->name();
            tls_currently_running = name.c_str();

            return dst_factory()->draw(src.get());
        });
    }

    for (Status s = Status::OK; s != Status::None; ) {
        s = wait_one();
        update_stats(s);
    }
    printf("\n");
    return (failed || crashed) ? 1 : 0;
}

Register::Register(const char* name, const char* help,
                   std::unique_ptr<Engine> (*factory)(Options)) {
    engine_types.push_back(EngineType{name, help, factory});
}
Register::Register(const char* name, const char* help,
                   std::unique_ptr<Stream> (*factory)(Options)) {
    stream_types.push_back(StreamType{name, help, factory});
}
Register::Register(const char* name, const char* help,
                   std::unique_ptr<Dst> (*factory)(Options)) {
    dst_types.push_back(DstType{name, help, factory});
}
Register::Register(const char* name, const char* help,
                   std::unique_ptr<Dst> (*factory)(Options, std::unique_ptr<Dst>)) {
    via_types.push_back(ViaType{name, help, factory});
}

Options::Options(std::string str) {
    std::string k,v, *curr = &k;
    for (auto c : str) {
        switch(c) {
            case ',': (*this)[k] = v;
                      curr = &(k = "");
                      break;
            case '=': curr = &(v = "");
                      break;
            default: *curr += c;
        }
    }
    (*this)[k] = v;
}

std::string& Options::operator[](std::string k) { return this->kv[k]; }

std::string Options::operator()(std::string k, std::string fallback) const {
    for (auto it = kv.find(k); it != kv.end(); ) {
        return it->second;
    }
    return fallback;
}
<commit_msg>print running task in both ok_log()<commit_after>/*
 * Copyright 2017 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

// ok is an experimental test harness, maybe to replace DM.  Key features:
//   * work is balanced across separate processes for stability and isolation;
//   * ok is entirely opt-in.  No more maintaining huge --blacklists.

#include "SkGraphics.h"
#include "SkImage.h"
#include "ok.h"
#include <chrono>
#include <list>
#include <stdio.h>
#include <stdlib.h>
#include <vector>

#if !defined(__has_include)
    #define  __has_include(x) 0
#endif

static thread_local const char* tls_currently_running = "";

#if __has_include(<execinfo.h>) && __has_include(<fcntl.h>) && __has_include(<signal.h>)
    #include <execinfo.h>
    #include <fcntl.h>
    #include <signal.h>

    static int log_fd = 2/*stderr*/;

    static void log(const char* msg) {
        write(log_fd, msg, strlen(msg));
    }

    static void setup_crash_handler() {
        static void (*original_handlers[32])(int);
        for (int sig : std::vector<int>{ SIGABRT, SIGBUS, SIGFPE, SIGILL, SIGSEGV }) {
            original_handlers[sig] = signal(sig, [](int sig) {
                lockf(log_fd, F_LOCK, 0);
                    log("\ncaught signal ");
                    switch (sig) {
                    #define CASE(s) case s: log(#s); break
                        CASE(SIGABRT);
                        CASE(SIGBUS);
                        CASE(SIGFPE);
                        CASE(SIGILL);
                        CASE(SIGSEGV);
                    #undef CASE
                    }
                    log(" while running '");
                    log(tls_currently_running);
                    log("'\n");

                    void* stack[128];
                    int frames = backtrace(stack, sizeof(stack)/sizeof(*stack));
                    backtrace_symbols_fd(stack, frames, log_fd);
                lockf(log_fd, F_ULOCK, 0);

                signal(sig, original_handlers[sig]);
                raise(sig);
            });
        }
    }

    static void defer_logging() {
        log_fd = fileno(tmpfile());
        atexit([] {
            lseek(log_fd, 0, SEEK_SET);
            char buf[1024];
            while (size_t bytes = read(log_fd, buf, sizeof(buf))) {
                write(2, buf, bytes);
            }
        });
    }

    void ok_log(const char* msg) {
        lockf(log_fd, F_LOCK, 0);
            log("[");
            log(tls_currently_running);
            log("]\t");
            log(msg);
            log("\n");
        lockf(log_fd, F_ULOCK, 0);
    }

#else
    static void setup_crash_handler() {}
    static void defer_logging() {}

    void ok_log(const char* msg) {
        fprintf(stderr, "[%s]\t%s\n", tls_currently_running, msg);
    }
#endif

struct EngineType {
    const char *name, *help;
    std::unique_ptr<Engine> (*factory)(Options);
};
static std::vector<EngineType> engine_types;

struct StreamType {
    const char *name, *help;
    std::unique_ptr<Stream> (*factory)(Options);
};
static std::vector<StreamType> stream_types;

struct DstType {
    const char *name, *help;
    std::unique_ptr<Dst> (*factory)(Options);
};
static std::vector<DstType> dst_types;

struct ViaType {
    const char *name, *help;
    std::unique_ptr<Dst> (*factory)(Options, std::unique_ptr<Dst>);
};
static std::vector<ViaType> via_types;

template <typename T>
static std::string help_for(std::vector<T> registered) {
    std::string help;
    for (auto r : registered) {
        help += "\n    ";
        help += r.name;
        help += ": ";
        help += r.help;
    }
    return help;
}

int main(int argc, char** argv) {
    SkGraphics::Init();
    setup_crash_handler();

    std::unique_ptr<Engine>                   engine;
    std::unique_ptr<Stream>                   stream;
    std::function<std::unique_ptr<Dst>(void)> dst_factory = []{
        // A default Dst that's enough for unit tests and not much else.
        struct : Dst {
            Status draw(Src* src)  override { return src->draw(nullptr); }
            sk_sp<SkImage> image() override { return nullptr; }
        } dst;
        return move_unique(dst);
    };

    auto help = [&] {
        std::string engine_help = help_for(engine_types),
                    stream_help = help_for(stream_types),
                       dst_help = help_for(   dst_types),
                       via_help = help_for(   via_types);

        printf("%s [engine] src[:k=v,...] dst[:k=v,...] [via[:k=v,...] ...]          \n"
                " engine: how to execute tasks%s                                     \n"
                " src: content to draw%s                                             \n"
                " dst: how to draw that content%s                                    \n"
                " via: wrappers around dst%s                                         \n"
                " Most srcs, dsts and vias have options, e.g. skp:dir=skps sw:ct=565 \n",
                argv[0],
                engine_help.c_str(), stream_help.c_str(), dst_help.c_str(), via_help.c_str());
        return 1;
    };

    for (int i = 1; i < argc; i++) {
        if (0 == strcmp("-h",     argv[i])) { return help(); }
        if (0 == strcmp("--help", argv[i])) { return help(); }

        for (auto e : engine_types) {
            size_t len = strlen(e.name);
            if (0 == strncmp(e.name, argv[i], len)) {
                switch (argv[i][len]) {
                    case  ':': len++;
                    case '\0': engine = e.factory(Options{argv[i]+len});
                }
            }
        }

        for (auto s : stream_types) {
            size_t len = strlen(s.name);
            if (0 == strncmp(s.name, argv[i], len)) {
                switch (argv[i][len]) {
                    case  ':': len++;
                    case '\0': stream = s.factory(Options{argv[i]+len});
                }
            }
        }
        for (auto d : dst_types) {
            size_t len = strlen(d.name);
            if (0 == strncmp(d.name, argv[i], len)) {
                switch (argv[i][len]) {
                    case  ':': len++;
                    case '\0': dst_factory = [=]{
                                   return d.factory(Options{argv[i]+len});
                               };
                }
            }
        }
        for (auto v : via_types) {
            size_t len = strlen(v.name);
            if (0 == strncmp(v.name, argv[i], len)) {
                if (!dst_factory) { return help(); }
                switch (argv[i][len]) {
                    case  ':': len++;
                    case '\0': dst_factory = [=]{
                                   return v.factory(Options{argv[i]+len}, dst_factory());
                               };
                }
            }
        }
    }
    if (!stream) { return help(); }

    if (!engine) { engine = engine_types.back().factory(Options{}); }

    // If we know engine->spawn() will never crash, we can defer logging until we exit.
    if (engine->crashproof()) {
        defer_logging();
    }

    int ok = 0, failed = 0, crashed = 0, skipped = 0;

    auto update_stats = [&](Status s) {
        switch (s) {
            case Status::OK:      ok++;      break;
            case Status::Failed:  failed++;  break;
            case Status::Crashed: crashed++; break;
            case Status::Skipped: skipped++; break;
            case Status::None:              return;
        }
        const char* leader = "\r";
        auto print = [&](int count, const char* label) {
            if (count) {
                printf("%s%d %s", leader, count, label);
                leader = ", ";
            }
        };
        print(ok,      "ok");
        print(failed,  "failed");
        print(crashed, "crashed");
        print(skipped, "skipped");
        fflush(stdout);
    };

    std::list<std::future<Status>> live;
    const auto the_past = std::chrono::steady_clock::now();

    auto wait_one = [&] {
        if (live.empty()) {
            return Status::None;
        }

        for (;;) {
            for (auto it = live.begin(); it != live.end(); it++) {
                if (it->wait_until(the_past) != std::future_status::timeout) {
                    Status s = it->get();
                    live.erase(it);
                    return s;
                }
            }
        }
    };

    auto spawn = [&](std::function<Status(void)> fn) {
        std::future<Status> status;
        for (;;) {
            status = engine->spawn(fn);
            if (status.valid()) {
                break;
            }
            update_stats(wait_one());
        }
        live.push_back(std::move(status));
    };

    for (std::unique_ptr<Src> owned = stream->next(); owned; owned = stream->next()) {
        Src* raw = owned.release();  // Can't move std::unique_ptr into a lambda in C++11. :(
        spawn([=] {
            std::unique_ptr<Src> src{raw};

            std::string name = src->name();
            tls_currently_running = name.c_str();

            return dst_factory()->draw(src.get());
        });
    }

    for (Status s = Status::OK; s != Status::None; ) {
        s = wait_one();
        update_stats(s);
    }
    printf("\n");
    return (failed || crashed) ? 1 : 0;
}

Register::Register(const char* name, const char* help,
                   std::unique_ptr<Engine> (*factory)(Options)) {
    engine_types.push_back(EngineType{name, help, factory});
}
Register::Register(const char* name, const char* help,
                   std::unique_ptr<Stream> (*factory)(Options)) {
    stream_types.push_back(StreamType{name, help, factory});
}
Register::Register(const char* name, const char* help,
                   std::unique_ptr<Dst> (*factory)(Options)) {
    dst_types.push_back(DstType{name, help, factory});
}
Register::Register(const char* name, const char* help,
                   std::unique_ptr<Dst> (*factory)(Options, std::unique_ptr<Dst>)) {
    via_types.push_back(ViaType{name, help, factory});
}

Options::Options(std::string str) {
    std::string k,v, *curr = &k;
    for (auto c : str) {
        switch(c) {
            case ',': (*this)[k] = v;
                      curr = &(k = "");
                      break;
            case '=': curr = &(v = "");
                      break;
            default: *curr += c;
        }
    }
    (*this)[k] = v;
}

std::string& Options::operator[](std::string k) { return this->kv[k]; }

std::string Options::operator()(std::string k, std::string fallback) const {
    for (auto it = kv.find(k); it != kv.end(); ) {
        return it->second;
    }
    return fallback;
}
<|endoftext|>


<commit_before>//
// Created by Darren Otgaar on 2016/10/28.
//

#include "os.hpp"
#include <dirent.h>
#include <sys/stat.h>

using namespace zap;

bool is_file(const std::string& filename) {
    struct stat buf;
    return stat(filename.c_str(), &buf) == 0 && S_ISREG(buf.st_mode);
}

bool is_dir(const std::string& path) {
    struct stat buf;
    return stat(path.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode);
}

std::vector<std::string> get_files(const std::string& path) {
    std::vector<std::string> out;

#ifdef _WIN32
    HANDLE dir;
    WIN32_FIND_DATA file_data;

    if((dir = FindFirstFile((directory + "/*").c_str(), &file_data)) == INVALID_HANDLE_VALUE) return;

    do {
        const string file_name = directory + "/" + file_data.cFileName;
        if(file_data.cFileName[0] == '.' || (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) continue;
        out.push_back(file_name);
    } while(FindNextFile(dir, &file_data));

    FindClose(dir);
#else
    DIR* dir;
    struct dirent* ent;
    struct stat st;

    dir = opendir(path.c_str());
    while((ent = readdir(dir)) != nullptr) {
        const std::string file_path = path + "/" + ent->d_name;
        if(ent->d_name[0] == '.' || stat(file_path.c_str(), &st) == -1 || (st.st_mode & S_IFDIR) != 0) continue;
        out.push_back(file_path);
    }
    closedir(dir);
#endif

    return out;
}<commit_msg>- Added switch for Windows OS<commit_after>//
// Created by Darren Otgaar on 2016/10/28.
//

#include "os.hpp"
#ifndef WIN32
#include <dirent.h>
#else
#include <windows.h>
#endif
#include <sys/stat.h>
#include <GLFW/glfw3.h>

using namespace zap;

bool is_file(const std::string& filename) {
#ifndef WIN32
    struct stat buf;
    return stat(filename.c_str(), &buf) == 0 && S_ISREG(buf.st_mode);
#else
	return false;
#endif
}

bool is_dir(const std::string& path) {
#ifndef WIN32
    struct stat buf;
    return stat(path.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode);
#else
	return false;
#endif
}

std::vector<std::string> get_files(const std::string& path) {
    std::vector<std::string> out;

#ifdef WIN32
    HANDLE dir;
    WIN32_FIND_DATA file_data;

    if((dir = FindFirstFile((path + "/*").c_str(), &file_data)) == INVALID_HANDLE_VALUE) return out;

    do {
        const std::string file_name = path + "/" + file_data.cFileName;
        if(file_data.cFileName[0] == '.' || (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) continue;
        out.push_back(file_name);
    } while(FindNextFile(dir, &file_data));

    FindClose(dir);
#else
    DIR* dir;
    struct dirent* ent;
    struct stat st;

    dir = opendir(path.c_str());
    while((ent = readdir(dir)) != nullptr) {
        const std::string file_path = path + "/" + ent->d_name;
        if(ent->d_name[0] == '.' || stat(file_path.c_str(), &st) == -1 || (st.st_mode & S_IFDIR) != 0) continue;
        out.push_back(file_path);
    }
    closedir(dir);
#endif

    return out;
}<|endoftext|>


<commit_before>//..............................................................................
//
//  This file is part of the Jancy toolkit.
//
//  Jancy is distributed under the MIT license.
//  For details see accompanying license.txt file,
//  the public copy of which is also available at:
//  http://tibbo.com/downloads/archive/jancy/license.txt
//
//..............................................................................

#include "pch.h"
#include "jnc_io_UsbEndpoint.h"
#include "jnc_io_UsbInterface.h"
#include "jnc_io_UsbDevice.h"
#include "jnc_io_UsbLib.h"
#include "jnc_Error.h"

namespace jnc {
namespace io {

//..............................................................................

JNC_DEFINE_OPAQUE_CLASS_TYPE (
	UsbEndpoint,
	"io.UsbEndpoint",
	g_usbLibGuid,
	UsbLibCacheSlot_UsbEndpoint,
	UsbEndpoint,
	NULL
	)

JNC_BEGIN_TYPE_FUNCTION_MAP (UsbEndpoint)
	JNC_MAP_CONSTRUCTOR (&jnc::construct <UsbEndpoint>)
	JNC_MAP_DESTRUCTOR (&jnc::destruct <UsbEndpoint>)

	JNC_MAP_AUTOGET_PROPERTY ("m_readParallelism", &UsbEndpoint::setReadParallelism)
	JNC_MAP_AUTOGET_PROPERTY ("m_readBlockSize",   &UsbEndpoint::setReadBlockSize)
	JNC_MAP_AUTOGET_PROPERTY ("m_readBufferSize",  &UsbEndpoint::setReadBufferSize)
	JNC_MAP_AUTOGET_PROPERTY ("m_writeBufferSize", &UsbEndpoint::setWriteBufferSize)
	JNC_MAP_AUTOGET_PROPERTY ("m_options",         &UsbEndpoint::setOptions)

	JNC_MAP_FUNCTION ("close",        &UsbEndpoint::close)
	JNC_MAP_FUNCTION ("write",        &UsbEndpoint::write)
	JNC_MAP_FUNCTION ("read",         &UsbEndpoint::read)
	JNC_MAP_FUNCTION ("wait",         &UsbEndpoint::wait)
	JNC_MAP_FUNCTION ("cancelWait",   &UsbEndpoint::cancelWait)
	JNC_MAP_FUNCTION ("blockingWait", &UsbEndpoint::blockingWait)
JNC_END_TYPE_FUNCTION_MAP ()

//..............................................................................

UsbEndpoint::UsbEndpoint ()
{
	m_readParallelism = Def_ReadParallelism;
	m_readBlockSize = Def_ReadBlockSize;
	m_readBufferSize = Def_ReadBufferSize;
	m_writeBufferSize = Def_WriteBufferSize;
	m_options = Def_Options;

	m_readBuffer.setBufferSize (Def_ReadBufferSize);
	m_writeBuffer.setBufferSize (Def_WriteBufferSize);
}

void
JNC_CDECL
UsbEndpoint::close ()
{
	if (!m_isOpen)
		return;

	m_lock.lock ();
	m_ioThreadFlags |= IoThreadFlag_Closing;
	wakeIoThread ();
	m_lock.unlock ();

	GcHeap* gcHeap = m_runtime->getGcHeap ();
	gcHeap->enterWaitRegion ();
	m_ioThread.waitAndClose ();
	gcHeap->leaveWaitRegion ();

	AsyncIoDevice::close ();
}

size_t
JNC_CDECL
UsbEndpoint::read (
	DataPtr ptr,
	size_t size
	)
{
	if (isOutEndpoint ())
	{
		err::setError ("Cannot read from a USB OUT-endpoint");
		jnc::propagateLastError ();
		return -1;
	}

	return bufferedRead (ptr, size);
}

size_t
JNC_CDECL
UsbEndpoint::write (
	DataPtr ptr,
	size_t size
	)
{
	if (isInEndpoint ())
	{
		err::setError ("Cannot write to a USB IN-endpoint");
		jnc::propagateLastError ();
		return -1;
	}

	return bufferedWrite (ptr, size);
}

void
UsbEndpoint::ioThreadFunc ()
{
	if (isInEndpoint ())
		readLoop ();
	else
		writeLoop ();

	cancelAllActiveTransfers ();
}

void
UsbEndpoint::cancelAllActiveTransfers ()
{
	char buffer [256];
	sl::Array <Transfer*> activeTransferArray (ref::BufKind_Stack, buffer, sizeof (buffer));

	m_lock.lock ();

	sl::Iterator <Transfer> it = m_activeTransferList.getHead ();
	for (; it; it++)
		activeTransferArray.append (*it);

	m_lock.unlock ();

	size_t count = activeTransferArray.getCount ();
	for (size_t i = 0; i < count; i++)
		activeTransferArray [i]->m_usbTransfer.cancel (); // may fail if already completed

	// wait for all transfers to complete

	m_lock.lock ();

	while (!m_activeTransferList.isEmpty ())
	{
		m_lock.unlock ();
		sleepIoThread ();
		m_lock.lock ();
	}

	// put all completed transfer back to the free pool

	while (!m_completedTransferList.isEmpty ())
	{
		Transfer* transfer = m_completedTransferList.removeHead ();
		m_transferPool.put (transfer);
	}

	m_lock.unlock ();
}

void
UsbEndpoint::readLoop ()
{
	ASSERT (isInEndpoint ());

	bool result;

	for (;;)
	{
		sleepIoThread ();

		m_lock.lock ();
		if (m_ioThreadFlags & IoThreadFlag_Closing)
		{
			m_lock.unlock ();
			break;
		}

		while (!m_completedTransferList.isEmpty ())
		{
			Transfer* transfer = m_completedTransferList.removeHead ();
			if (transfer->m_usbTransfer->status != LIBUSB_TRANSFER_COMPLETED)
			{
				m_transferPool.put (transfer);
				setIoErrorEvent_l (axl::io::UsbError (LIBUSB_ERROR_IO));
				return;
			}

			addToReadBuffer (transfer->m_buffer, transfer->m_usbTransfer->actual_length);
			m_transferPool.put (transfer);
		}

		uint_t prevActiveEvents = m_activeEvents;
		m_activeEvents = 0;

		size_t activeReadCount = m_activeTransferList.getCount ();
		if (!m_readBuffer.isFull () && activeReadCount < m_readParallelism)
		{
			size_t newReadCount = m_readParallelism - activeReadCount;
			for (size_t i = 0; i < newReadCount; i++)
			{
				Transfer* transfer = m_transferPool.get ();
				result = transfer->m_buffer.setCount (m_readBlockSize);
				if (!result)
				{
					m_transferPool.put (transfer);
					setIoErrorEvent_l ();
					return;
				}

				m_lock.unlock ();

				result = submitTransfer (transfer, transfer->m_buffer, transfer->m_buffer.getCount ());

				m_lock.lock ();

				if (!result)
				{
					m_transferPool.put (transfer);
					setIoErrorEvent_l ();
					return;
				}

				m_activeTransferList.insertTail (transfer);
			}
		}

		updateReadWriteBufferEvents ();

		if (m_activeEvents != prevActiveEvents)
			processWaitLists_l ();
		else
			m_lock.unlock ();
	}
}

void
UsbEndpoint::writeLoop ()
{
	ASSERT (isOutEndpoint ());

	bool result;

	for (;;)
	{
		sleepIoThread ();

		m_lock.lock ();
		if (m_ioThreadFlags & IoThreadFlag_Closing)
		{
			m_lock.unlock ();
			break;
		}

		if (!m_completedTransferList.isEmpty ())
		{
			Transfer* transfer = *m_completedTransferList.getHead ();
			if (transfer->m_usbTransfer->status != LIBUSB_TRANSFER_COMPLETED)
			{
				m_transferPool.put (transfer);
				setIoErrorEvent_l (axl::io::UsbError (LIBUSB_ERROR_IO));
				break;
			}

			if (transfer->m_usbTransfer->actual_length < m_writeBlock.getCount ()) // shouldn't happen, actually
				m_writeBlock.remove (0, transfer->m_usbTransfer->actual_length);
			else
				m_writeBlock.clear ();

			m_transferPool.put (transfer);
			ASSERT (m_completedTransferList.isEmpty ());
		}

		uint_t prevActiveEvents = m_activeEvents;
		m_activeEvents = 0;

		getNextWriteBlock (&m_writeBlock);

		if (m_activeTransferList.isEmpty () && !m_writeBlock.isEmpty ())
		{
			Transfer* transfer = m_transferPool.get ();
			m_lock.unlock ();

			result = submitTransfer (transfer, m_writeBlock, m_writeBlock.getCount ());

			m_lock.lock ();

			if (!result)
			{
				m_transferPool.put (transfer);
				setIoErrorEvent_l ();
				break;
			}

			m_activeTransferList.insertTail (transfer);
		}

		updateReadWriteBufferEvents ();

		if (m_activeEvents != prevActiveEvents)
			processWaitLists_l ();
		else
			m_lock.unlock ();
	}
}

bool
UsbEndpoint::submitTransfer (
	Transfer* transfer,
	void* p,
	size_t size
	)
{
	UsbEndpointDesc* desc = (UsbEndpointDesc*) m_endpointDescPtr.m_p;

	axl::io::UsbDevice* device = m_parentInterface->m_parentDevice->getDevice ();
	switch (desc->m_transferType)
	{
	case LIBUSB_TRANSFER_TYPE_BULK:
		transfer->m_usbTransfer.fillBulkTransfer (
			device->getOpenHandle (),
			desc->m_endpointId,
			p,
			size,
			onTransferCompleted,
			this
			);
		break;

	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
		transfer->m_usbTransfer.fillInterruptTransfer (
			device->getOpenHandle (),
			desc->m_endpointId,
			p,
			size,
			onTransferCompleted,
			this
			);
		break;

	case LIBUSB_TRANSFER_TYPE_CONTROL:
	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
	case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
		// not yet, fall through...

	default:
		err::setError (err::SystemErrorCode_NotImplemented);
		return false;
	}

	transfer->m_self = this;

	return transfer->m_usbTransfer.submit ();
}

void
LIBUSB_CALL
UsbEndpoint::onTransferCompleted (libusb_transfer* usbTransfer)
{
	Transfer* transfer = (Transfer*) usbTransfer->user_data;
	UsbEndpoint* self = transfer->m_self;

	self->m_lock.lock ();
	ASSERT (transfer->m_usbTransfer == usbTransfer && transfer == *self->m_activeTransferList.getHead ());
	self->m_activeTransferList.remove (transfer);
	self->m_completedTransferList.insertTail (transfer);
	self->wakeIoThread ();
	self->m_lock.unlock ();
}

//..............................................................................

} // namespace io
} // namespace jnc
<commit_msg>[jnc_io_usb] fixed warning re singed-unsigned-comparison<commit_after>//..............................................................................
//
//  This file is part of the Jancy toolkit.
//
//  Jancy is distributed under the MIT license.
//  For details see accompanying license.txt file,
//  the public copy of which is also available at:
//  http://tibbo.com/downloads/archive/jancy/license.txt
//
//..............................................................................

#include "pch.h"
#include "jnc_io_UsbEndpoint.h"
#include "jnc_io_UsbInterface.h"
#include "jnc_io_UsbDevice.h"
#include "jnc_io_UsbLib.h"
#include "jnc_Error.h"

namespace jnc {
namespace io {

//..............................................................................

JNC_DEFINE_OPAQUE_CLASS_TYPE (
	UsbEndpoint,
	"io.UsbEndpoint",
	g_usbLibGuid,
	UsbLibCacheSlot_UsbEndpoint,
	UsbEndpoint,
	NULL
	)

JNC_BEGIN_TYPE_FUNCTION_MAP (UsbEndpoint)
	JNC_MAP_CONSTRUCTOR (&jnc::construct <UsbEndpoint>)
	JNC_MAP_DESTRUCTOR (&jnc::destruct <UsbEndpoint>)

	JNC_MAP_AUTOGET_PROPERTY ("m_readParallelism", &UsbEndpoint::setReadParallelism)
	JNC_MAP_AUTOGET_PROPERTY ("m_readBlockSize",   &UsbEndpoint::setReadBlockSize)
	JNC_MAP_AUTOGET_PROPERTY ("m_readBufferSize",  &UsbEndpoint::setReadBufferSize)
	JNC_MAP_AUTOGET_PROPERTY ("m_writeBufferSize", &UsbEndpoint::setWriteBufferSize)
	JNC_MAP_AUTOGET_PROPERTY ("m_options",         &UsbEndpoint::setOptions)

	JNC_MAP_FUNCTION ("close",        &UsbEndpoint::close)
	JNC_MAP_FUNCTION ("write",        &UsbEndpoint::write)
	JNC_MAP_FUNCTION ("read",         &UsbEndpoint::read)
	JNC_MAP_FUNCTION ("wait",         &UsbEndpoint::wait)
	JNC_MAP_FUNCTION ("cancelWait",   &UsbEndpoint::cancelWait)
	JNC_MAP_FUNCTION ("blockingWait", &UsbEndpoint::blockingWait)
JNC_END_TYPE_FUNCTION_MAP ()

//..............................................................................

UsbEndpoint::UsbEndpoint ()
{
	m_readParallelism = Def_ReadParallelism;
	m_readBlockSize = Def_ReadBlockSize;
	m_readBufferSize = Def_ReadBufferSize;
	m_writeBufferSize = Def_WriteBufferSize;
	m_options = Def_Options;

	m_readBuffer.setBufferSize (Def_ReadBufferSize);
	m_writeBuffer.setBufferSize (Def_WriteBufferSize);
}

void
JNC_CDECL
UsbEndpoint::close ()
{
	if (!m_isOpen)
		return;

	m_lock.lock ();
	m_ioThreadFlags |= IoThreadFlag_Closing;
	wakeIoThread ();
	m_lock.unlock ();

	GcHeap* gcHeap = m_runtime->getGcHeap ();
	gcHeap->enterWaitRegion ();
	m_ioThread.waitAndClose ();
	gcHeap->leaveWaitRegion ();

	AsyncIoDevice::close ();
}

size_t
JNC_CDECL
UsbEndpoint::read (
	DataPtr ptr,
	size_t size
	)
{
	if (isOutEndpoint ())
	{
		err::setError ("Cannot read from a USB OUT-endpoint");
		jnc::propagateLastError ();
		return -1;
	}

	return bufferedRead (ptr, size);
}

size_t
JNC_CDECL
UsbEndpoint::write (
	DataPtr ptr,
	size_t size
	)
{
	if (isInEndpoint ())
	{
		err::setError ("Cannot write to a USB IN-endpoint");
		jnc::propagateLastError ();
		return -1;
	}

	return bufferedWrite (ptr, size);
}

void
UsbEndpoint::ioThreadFunc ()
{
	if (isInEndpoint ())
		readLoop ();
	else
		writeLoop ();

	cancelAllActiveTransfers ();
}

void
UsbEndpoint::cancelAllActiveTransfers ()
{
	char buffer [256];
	sl::Array <Transfer*> activeTransferArray (ref::BufKind_Stack, buffer, sizeof (buffer));

	m_lock.lock ();

	sl::Iterator <Transfer> it = m_activeTransferList.getHead ();
	for (; it; it++)
		activeTransferArray.append (*it);

	m_lock.unlock ();

	size_t count = activeTransferArray.getCount ();
	for (size_t i = 0; i < count; i++)
		activeTransferArray [i]->m_usbTransfer.cancel (); // may fail if already completed

	// wait for all transfers to complete

	m_lock.lock ();

	while (!m_activeTransferList.isEmpty ())
	{
		m_lock.unlock ();
		sleepIoThread ();
		m_lock.lock ();
	}

	// put all completed transfer back to the free pool

	while (!m_completedTransferList.isEmpty ())
	{
		Transfer* transfer = m_completedTransferList.removeHead ();
		m_transferPool.put (transfer);
	}

	m_lock.unlock ();
}

void
UsbEndpoint::readLoop ()
{
	ASSERT (isInEndpoint ());

	bool result;

	for (;;)
	{
		sleepIoThread ();

		m_lock.lock ();
		if (m_ioThreadFlags & IoThreadFlag_Closing)
		{
			m_lock.unlock ();
			break;
		}

		while (!m_completedTransferList.isEmpty ())
		{
			Transfer* transfer = m_completedTransferList.removeHead ();
			if (transfer->m_usbTransfer->status != LIBUSB_TRANSFER_COMPLETED)
			{
				m_transferPool.put (transfer);
				setIoErrorEvent_l (axl::io::UsbError (LIBUSB_ERROR_IO));
				return;
			}

			addToReadBuffer (transfer->m_buffer, transfer->m_usbTransfer->actual_length);
			m_transferPool.put (transfer);
		}

		uint_t prevActiveEvents = m_activeEvents;
		m_activeEvents = 0;

		size_t activeReadCount = m_activeTransferList.getCount ();
		if (!m_readBuffer.isFull () && activeReadCount < m_readParallelism)
		{
			size_t newReadCount = m_readParallelism - activeReadCount;
			for (size_t i = 0; i < newReadCount; i++)
			{
				Transfer* transfer = m_transferPool.get ();
				result = transfer->m_buffer.setCount (m_readBlockSize);
				if (!result)
				{
					m_transferPool.put (transfer);
					setIoErrorEvent_l ();
					return;
				}

				m_lock.unlock ();

				result = submitTransfer (transfer, transfer->m_buffer, transfer->m_buffer.getCount ());

				m_lock.lock ();

				if (!result)
				{
					m_transferPool.put (transfer);
					setIoErrorEvent_l ();
					return;
				}

				m_activeTransferList.insertTail (transfer);
			}
		}

		updateReadWriteBufferEvents ();

		if (m_activeEvents != prevActiveEvents)
			processWaitLists_l ();
		else
			m_lock.unlock ();
	}
}

void
UsbEndpoint::writeLoop ()
{
	ASSERT (isOutEndpoint ());

	bool result;

	for (;;)
	{
		sleepIoThread ();

		m_lock.lock ();
		if (m_ioThreadFlags & IoThreadFlag_Closing)
		{
			m_lock.unlock ();
			break;
		}

		if (!m_completedTransferList.isEmpty ())
		{
			Transfer* transfer = *m_completedTransferList.getHead ();
			if (transfer->m_usbTransfer->status != LIBUSB_TRANSFER_COMPLETED)
			{
				m_transferPool.put (transfer);
				setIoErrorEvent_l (axl::io::UsbError (LIBUSB_ERROR_IO));
				break;
			}

			if ((size_t) transfer->m_usbTransfer->actual_length < m_writeBlock.getCount ()) // shouldn't happen, actually
				m_writeBlock.remove (0, transfer->m_usbTransfer->actual_length);
			else
				m_writeBlock.clear ();

			m_transferPool.put (transfer);
			ASSERT (m_completedTransferList.isEmpty ());
		}

		uint_t prevActiveEvents = m_activeEvents;
		m_activeEvents = 0;

		getNextWriteBlock (&m_writeBlock);

		if (m_activeTransferList.isEmpty () && !m_writeBlock.isEmpty ())
		{
			Transfer* transfer = m_transferPool.get ();
			m_lock.unlock ();

			result = submitTransfer (transfer, m_writeBlock, m_writeBlock.getCount ());

			m_lock.lock ();

			if (!result)
			{
				m_transferPool.put (transfer);
				setIoErrorEvent_l ();
				break;
			}

			m_activeTransferList.insertTail (transfer);
		}

		updateReadWriteBufferEvents ();

		if (m_activeEvents != prevActiveEvents)
			processWaitLists_l ();
		else
			m_lock.unlock ();
	}
}

bool
UsbEndpoint::submitTransfer (
	Transfer* transfer,
	void* p,
	size_t size
	)
{
	UsbEndpointDesc* desc = (UsbEndpointDesc*) m_endpointDescPtr.m_p;

	axl::io::UsbDevice* device = m_parentInterface->m_parentDevice->getDevice ();
	switch (desc->m_transferType)
	{
	case LIBUSB_TRANSFER_TYPE_BULK:
		transfer->m_usbTransfer.fillBulkTransfer (
			device->getOpenHandle (),
			desc->m_endpointId,
			p,
			size,
			onTransferCompleted,
			this
			);
		break;

	case LIBUSB_TRANSFER_TYPE_INTERRUPT:
		transfer->m_usbTransfer.fillInterruptTransfer (
			device->getOpenHandle (),
			desc->m_endpointId,
			p,
			size,
			onTransferCompleted,
			this
			);
		break;

	case LIBUSB_TRANSFER_TYPE_CONTROL:
	case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS:
	case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
		// not yet, fall through...

	default:
		err::setError (err::SystemErrorCode_NotImplemented);
		return false;
	}

	transfer->m_self = this;

	return transfer->m_usbTransfer.submit ();
}

void
LIBUSB_CALL
UsbEndpoint::onTransferCompleted (libusb_transfer* usbTransfer)
{
	Transfer* transfer = (Transfer*) usbTransfer->user_data;
	UsbEndpoint* self = transfer->m_self;

	self->m_lock.lock ();
	ASSERT (transfer->m_usbTransfer == usbTransfer && transfer == *self->m_activeTransferList.getHead ());
	self->m_activeTransferList.remove (transfer);
	self->m_completedTransferList.insertTail (transfer);
	self->wakeIoThread ();
	self->m_lock.unlock ();
}

//..............................................................................

} // namespace io
} // namespace jnc
<|endoftext|>


<commit_before>// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include <stdio.h>

#include "Arduino.h"

extern "C" {
    size_t _write(int handle, const unsigned char *buf, size_t bufSize)
    {
        /* Check for the command to flush all handles */
        if (handle == -1) {
            return 0;
        }

        /* Check for stdout and stderr (only necessary if FILE descriptors are enabled.) */
        if (handle != 1 && handle != 2) {
            return -1;
        }

        size_t nChars = 0;
        for (; bufSize > 0; --bufSize, ++buf, ++nChars) {
            Serial.write(*buf);
        }
        return nChars;
    }
}
<commit_msg>Add reference to _printf_float and _scanf_float so they are linked by linker<commit_after>// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include <stdio.h>

#include "Arduino.h"

asm(".global _printf_float");
asm(".global _scanf_float");

extern "C" {
    size_t _write(int handle, const unsigned char *buf, size_t bufSize)
    {
        /* Check for the command to flush all handles */
        if (handle == -1) {
            return 0;
        }

        /* Check for stdout and stderr (only necessary if FILE descriptors are enabled.) */
        if (handle != 1 && handle != 2) {
            return -1;
        }

        size_t nChars = 0;
        for (; bufSize > 0; --bufSize, ++buf, ++nChars) {
            Serial.write(*buf);
        }
        return nChars;
    }
}
<|endoftext|>