text:
// Copyright (c) Benjamin Kietzman (github.com/bkietz)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

#ifndef DBUS_QUEUE_HPP
#define DBUS_QUEUE_HPP

#include <deque>
#include <boost/asio.hpp>
#include <boost/asio/detail/mutex.hpp>

#include <dbus/functional.hpp>

namespace dbus {
namespace detail {

template<typename Message>
class queue
{
public:
  typedef ::boost::asio::detail::mutex mutex_type;
  typedef Message message_type;
  typedef function<
    void(boost::system::error_code, Message)> handler_type;

private:
  boost::asio::io_service& io;
  mutex_type mutex;
  std::deque<message_type> messages;
  std::deque<handler_type> handlers;

public:

  queue(boost::asio::io_service& io_service)
    : io(io_service)
  {}

private:
  class closure
  {
    handler_type handler_;
    message_type message_;
    boost::system::error_code error_;

  public:
    void operator()() { handler_(error_, message_); }
    closure(
	BOOST_ASIO_MOVE_ARG(handler_type) h,
	Message m,
        boost::system::error_code e = boost::system::error_code())
      : handler_(h),
        message_(m),
        error_(e)
    {}
  };

public:

  void push(message_type m)
  {
    mutex_type::scoped_lock lock(mutex);
    if(handlers.empty())
      messages.push_back(m);
    else
    {
      handler_type h = handlers.front();
      handlers.pop_front();

      lock.unlock();

      io.post(closure(BOOST_ASIO_MOVE_CAST(handler_type)(h), m));
    }
  }

  template<typename MessageHandler>
  inline BOOST_ASIO_INITFN_RESULT_TYPE(MessageHandler,
      void(boost::system::error_code, message_type))
  async_pop(BOOST_ASIO_MOVE_ARG(MessageHandler) h)
  {
    typedef ::boost::asio::detail::async_result_init<
      MessageHandler, void(boost::system::error_code, message_type)> init_type;

    mutex_type::scoped_lock lock(mutex);
    if(messages.empty())
    {
      init_type init(BOOST_ASIO_MOVE_CAST(MessageHandler)(h));

      handlers.push_back(init.handler);

      lock.unlock();

      return init.result.get();

    } else {
      message_type m = messages.front();
      messages.pop_front();

      lock.unlock();

      init_type init(BOOST_ASIO_MOVE_CAST(MessageHandler)(h));

      io.post(closure(BOOST_ASIO_MOVE_CAST(handler_type)(init.handler), m));

      return init.result.get();
    }
  }
};

} // namespace detail
} // namespace dbus

#endif // DBUS_QUEUE_HPP

max_stars_repo_name: bkietz/boost-dbus

max_issues_repo_name: bkietz/boost-dbus

max_forks_repo_name: bkietz/boost-dbus


text:
#include <array>
#include <cstdint>
#include <ostream>
#include <string>

#include <boost/format.hpp>

#include <zcpm/core/processor.hpp>
#include <zcpm/core/registers.hpp>

#include "writer.hpp"

namespace
{

    const std::array<const char*, 8> ByteRegMask{ "B", "C", "D", "E", "H", "L", "(HL)", "A" };
    const std::array<const char*, 4> WordRegMask{ "BC", "DE", "HL", "SP" };
    const std::array<const char*, 4> WordRegMaskQq{ "BC", "DE", "HL", "AF" };
    const std::array<const char*, 8> CondMask{ "NZ", "Z", "NC", "C", "PO", "PE", "P", "M" };
    const std::array<const char*, 8> DDByteRegMask{ "B", "C", "D", "E", "IXH", "IXL", "(HL)", "A" };
    const std::array<const char*, 8> FDByteRegMask{ "B", "C", "D", "E", "IYH", "IYL", "(HL)", "A" };
    const std::map<uint8_t, const char*> DdFdCbLogicals = {
        { 0x06, "RLC" }, { 0x0E, "RRC" }, { 0x16, "RL" },  { 0x1E, "RR" },
        { 0x26, "SLA" }, { 0x2E, "SRA" }, { 0x36, "SLL" }, { 0x3E, "SRL" },
    };

    // A 8-bit literal as a 2 digit hex string
    auto byte(uint8_t x)
    {
        return (boost::format("%02X") % static_cast<unsigned int>(x)).str();
    }

    // A 16-bit literal as a 4 digit hex string
    auto word(uint8_t low, uint8_t high)
    {
        return (boost::format("%04X") % (high << 8 | low)).str();
    }

    std::string byte_array_to_string(const std::vector<uint8_t>& bytes)
    {
        std::string result;
        for (const auto& b : bytes)
        {
            if (!result.empty())
            {
                result += " ";
            }
            result += byte(b);
        }
        return "[" + result + "]";
    }

    // Dereference NN from (string)
    auto nn_string(uint8_t low, uint8_t high, const std::string& s)
    {
        return (boost::format("(%04X),%s") % (high << 8 | low) % s).str();
    }

    // Dereference (string) from NN
    auto string_nn(uint8_t low, uint8_t high, const std::string& s)
    {
        return (boost::format("%s,(%04X)") % s % (high << 8 | low)).str();
    }

    // Dereference N from (string)
    auto n_string(uint8_t n, const std::string& s)
    {
        return (boost::format("(%02X),%s") % static_cast<unsigned int>(n) % s).str();
    }

    // Dereference (string) from N
    // auto string_n(uint8_t n, const std::string& s)
    //{
    //  return (boost::format("%s,(%02X)") % s % static_cast<unsigned int>(n)).str();
    //}

    auto hl_ss(uint8_t ss)
    {
        return (boost::format("HL,%s") % WordRegMask[ss]).str();
    }

    auto byte_register(uint8_t r)
    {
        return ByteRegMask[r];
    }

    auto qq_word_register(uint8_t qq)
    {
        return WordRegMaskQq[qq];
    }

    // r,n where r is a byte register and n is a 8-bit literal
    auto r_n(uint8_t r, uint8_t n)
    {
        return (boost::format("%s,%02X") % ByteRegMask[r] % static_cast<unsigned int>(n)).str();
    }

    // r,r where r1 and r2 are both byte registers
    auto r_r(uint8_t r1, uint8_t r2)
    {
        return (boost::format("%s,%s") % ByteRegMask[r1] % ByteRegMask[r2]).str();
    }

    // dd,nn where dd is a word register and nn is a 16-bit literal
    auto dd_nn(uint8_t dd, uint8_t nn_low, uint8_t nn_high)
    {
        const uint16_t nn = (nn_high << 8) | nn_low;
        return (boost::format("%s,%04X") % WordRegMask[dd] % nn).str();
    }

    // (nn),dd where dd is a word register and nn is a 16-bit literal
    auto inn_dd(uint8_t dd, uint8_t nn_low, uint8_t nn_high)
    {
        const uint16_t nn = (nn_high << 8) | nn_low;
        return (boost::format("(%04X),%s") % nn % WordRegMask[dd]).str();
    }

    // dd,(nn) where dd is a word register and nn is a 16-bit literal
    auto dd_inn(uint8_t dd, uint8_t nn_low, uint8_t nn_high)
    {
        const uint16_t nn = (nn_high << 8) | nn_low;
        return (boost::format("%s,(%04X)") % WordRegMask[dd] % nn).str();
    }

    // cc,pq where cc is a 3-bit condition and pq is a 16-bit literal
    auto cc_pq(uint8_t cc, uint8_t pq_low, uint8_t pq_high)
    {
        const uint16_t pq = (pq_high << 8) | pq_low;
        return (boost::format("%s,%04X") % CondMask[cc] % pq).str();
    }

    // Relative target as a 4 digit hex value (PC+e)
    auto offset(uint16_t pc, uint8_t e)
    {
        const int8_t ee = e;
        const uint16_t dest = pc + 2 + ee;
        return (boost::format("%04X") % dest).str();
    }

    // cc,e where cc is a 2-bit condition and e is a relative jump, which
    // we combine with pc for display purposes for compatibility with DebugZ
    auto cc_offset(uint8_t cc, uint8_t e, uint16_t pc)
    {
        const int8_t ee = e;
        const uint16_t dest = pc + 2 + ee;
        return (boost::format("%s,%04X") % CondMask[cc] % dest).str();
    }

    // "r,(reg+d)"  where r is a 8-bit register index and reg is an index register name and d is an offset
    auto r_ind_offset(uint8_t r, const std::string& reg, uint8_t offset)
    {
        const int8_t o = offset;
        return (boost::format("%s,(%s+%02X)") % ByteRegMask[r] % reg % static_cast<short>(o)).str();
    }

    // "(reg+d),r"  where r is a 8-bit register index and reg is an index register name and d is an offset
    auto ind_offset_r(uint8_t r, const std::string& reg, uint8_t offset)
    {
        const int8_t o = offset;
        return (boost::format("(%s+%02X),%s") % reg % static_cast<short>(o) % ByteRegMask[r]).str();
    }

    // TODO: Collate string constants

    std::tuple<size_t, std::string, std::string> disassemble_cb(uint8_t op2, uint8_t /*op3*/, uint8_t /*op4*/)
    {
        // First check for specific opcodes
        switch (op2)
        {
        // TODO: none handled here yet
        default:
            // Fall through to bytefield checks below
            break;
        }

        // Now check for bytefields
        if ((op2 & 0xC0) == 0x80)
        {
            const uint16_t b = (op2 >> 3) & 0x07;
            const uint8_t r = op2 & 0x07;
            return { 2, "RES", (boost::format("%d,") % b).str() + ByteRegMask[r] };
        }
        if ((op2 & 0xC0) == 0xC0)
        {
            const uint16_t b = (op2 >> 3) & 0x07;
            const uint8_t r = op2 & 0x07;
            return { 2, "SET", (boost::format("%d,") % b).str() + ByteRegMask[r] };
        }
        if ((op2 & 0xF8) == 0x00)
        {
            const uint8_t r = op2 & 0x07;
            return { 2, "RLC", ByteRegMask[r] };
        }
        if ((op2 & 0xF8) == 0x08)
        {
            const uint8_t r = op2 & 0x07;
            return { 2, "RRC", ByteRegMask[r] };
        }
        if ((op2 & 0xF8) == 0x10)
        {
            const uint8_t r = op2 & 0x07;
            return { 2, "RL", ByteRegMask[r] };
        }
        if ((op2 & 0xF8) == 0x18)
        {
            const uint8_t r = op2 & 0x07;
            return { 2, "RR", ByteRegMask[r] };
        }
        if ((op2 & 0xF8) == 0x20)
        {
            const uint8_t r = op2 & 0x07;
            return { 2, "SLA", ByteRegMask[r] };
        }
        if ((op2 & 0xF8) == 0x28)
        {
            const uint8_t r = op2 & 0x07;
            return { 2, "SRA", ByteRegMask[r] };
        }
        if ((op2 & 0xF8) == 0x30)
        {
            const uint8_t r = op2 & 0x07;
            return { 2, "SLL", ByteRegMask[r] };
        }
        if ((op2 & 0xF8) == 0x38)
        {
            const uint8_t r = op2 & 0x07;
            return { 2, "SRL", ByteRegMask[r] };
        }

        // No match
        return { 0, (boost::format("?? CB %02X") % static_cast<unsigned short>(op2)).str(), "" };
    }

    std::tuple<size_t, std::string, std::string> disassemble_ddfd(const std::string& xy,
                                                                  uint8_t op1,
                                                                  uint8_t op2,
                                                                  uint8_t op3,
                                                                  uint8_t op4)
    {
        // First check for specific opcodes
        switch (op2)
        {
        case 0x09: return { 2, "ADD", xy + ",BC" };
        case 0x19: return { 2, "ADD", xy + ",DE" };
        case 0x21: return { 4, "LD", (boost::format("%S,%04X") % xy % ((op4 << 8) | op3)).str() };
        case 0x22: return { 4, "LD", (boost::format("(%04X),%S") % ((op4 << 8) | op3) % xy).str() };
        case 0x23: return { 2, "INC", xy };
        case 0x24: return { 2, "INC", xy + "H" };
        case 0x25: return { 2, "DEC", xy + "H" };
        case 0x26: return { 3, "LD", (boost::format("%SH,%02X") % xy % static_cast<uint16_t>(op3)).str() };
        case 0x29: return { 2, "ADD", xy + "," + xy };
        case 0x2A: return { 4, "LD", (boost::format("%S,(%04X)") % xy % ((op4 << 8) | op3)).str() };
        case 0x2B: return { 2, "DEC", xy };
        case 0x2C: return { 2, "INC", xy + "L" };
        case 0x2D: return { 2, "DEC", xy + "L" };
        case 0x2E: return { 3, "LD", (boost::format("%SL,%02X") % xy % static_cast<uint16_t>(op3)).str() };
        case 0x34: return { 3, "INC", (boost::format("(%S+%02X)") % xy % static_cast<uint16_t>(op3)).str() };
        case 0x35: return { 3, "DEC", (boost::format("(%S+%02X)") % xy % static_cast<uint16_t>(op3)).str() };
        case 0x36:
            return {
                4,
                "LD",
                (boost::format("(%S+%02X),%02X") % xy % static_cast<uint16_t>(op3) % static_cast<uint16_t>(op4)).str()
            };
        case 0x39: return { 2, "ADD", xy + ",SP" };
        case 0x86: return { 3, "ADD", (boost::format("A,(%S+%02X)") % xy % static_cast<uint16_t>(op3)).str() };
        case 0x96: return { 3, "SUB", (boost::format("A,(%S+%02X)") % xy % static_cast<uint16_t>(op3)).str() };
        case 0xCB:
        {
            // TODO: move to a new method of its own? We'll see how well this scales...
            if (DdFdCbLogicals.contains(op4))
            {
                return { 4,
                         DdFdCbLogicals.at(op4),
                         (boost::format("(%S+%02X)") % xy % static_cast<uint16_t>(op3)).str() };
            }
            else if ((op4 & 0xC0) == 0x80)
            {
                const auto b = (op4 >> 3) & 0x07;
                return { 4, "RES", (boost::format("%d,(%S+%02X)") % b % xy % static_cast<uint16_t>(op3)).str() };
            }
            else if ((op4 & 0xC0) == 0x40)
            {
                const auto b = (op4 >> 3) & 0x07;
                return { 4, "BIT", (boost::format("%d,(%S+%02X)") % b % xy % static_cast<uint16_t>(op3)).str() };
            }
            else if ((op4 & 0xC0) == 0xC0)
            {
                const auto b = (op4 >> 3) & 0x07;
                return { 4, "SET", (boost::format("%d,(%S+%02X)") % b % xy % static_cast<uint16_t>(op3)).str() };
            }
            else
            {
                // Unimplemented sequence
                const auto message = boost::format("Unimplemented %02X %02X %02X %02X") % static_cast<uint16_t>(op1) %
                                     static_cast<uint16_t>(op2) % static_cast<uint16_t>(op3) %
                                     static_cast<uint16_t>(op4);
                throw std::logic_error(message.str());
            }
        }
        case 0xE1: return { 2, "POP", xy };
        case 0xE5: return { 2, "PUSH", xy };
        default:
            // Fall through to bytefield checks below
            break;
        }

        // Now check for bytefields
        if ((op2 & 0xC0) == 0x40)
        {
            // Refer 'Undocumented Z80', page 24
            const auto p1 = (op2 >> 3) & 0x07;
            const auto p2 = op2 & 0x07;
            const auto table = (op1 == 0xDD) ? DDByteRegMask : FDByteRegMask;
            if (p1 == 0x06)
            {
                const auto lhs = boost::format("(%S+%02X)") % xy % static_cast<uint16_t>(op3);
                return { 3, "LD", lhs.str() + "," + std::string(ByteRegMask[p2]) };
            }
            else if (p2 == 0x06)
            {
                const auto rhs = boost::format("(%S+%02X)") % xy % static_cast<uint16_t>(op3);
                return { 3, "LD", std::string(ByteRegMask[p1]) + "," + rhs.str() };
            }
            else
            {
                return { 2, "LD", std::string(table[p1]) + "," + std::string(table[p2]) };
            }
        }
        if ((op4 & 0xC0) == 0x40)
        {
            const auto b = (op4 >> 3) & 0x07;
            return { 4, "BIT", (boost::format("%X,(%S+%02X)") % xy % b % static_cast<uint16_t>(op3)).str() };
        }
        if ((op2 & 0xC7) == 0x46)
        {
            const uint8_t r = (op2 >> 3) & 0x07;
            return { 3, "LD", r_ind_offset(r, xy, op3) };
        }
        if ((op2 & 0xF8) == 0x70)
        {
            const uint8_t r = op2 & 0x07;
            return { 3, "LD", ind_offset_r(r, xy, op3) };
        }

        // Unimplemented sequence
        const auto message = boost::format("Unimplemented %02X %02X %02X %02X") % static_cast<uint16_t>(op1) %
                             static_cast<uint16_t>(op2) % static_cast<uint16_t>(op3) % static_cast<uint16_t>(op4);
        throw std::logic_error(message.str());
    }

    std::tuple<size_t, std::string, std::string> disassemble_ed(uint8_t op2, uint8_t op3, uint8_t op4)
    {
        // First check for specific opcodes
        switch (op2)
        {
        case 0x44: return { 2, "NEG", "" };
        case 0x67: return { 2, "RRD", "" };
        case 0x6F: return { 2, "RLD", "" };
        case 0xA0: return { 2, "LDI", "" };
        case 0xA1: return { 2, "CPI", "" };
        case 0xA8: return { 2, "LDD", "" };
        case 0xA9: return { 2, "CPD", "" };
        case 0xB0: return { 2, "LDIR", "" };
        case 0xB1: return { 2, "CPIR", "" };
        case 0xB8: return { 2, "LDDR", "" };
        case 0xB9: return { 2, "CPDR", "" };
        default:
            // Fall through to bytefield checks below
            break;
        }

        // Now check for bytefields
        if ((op2 & 0xCF) == 0x42)
        {
            const uint8_t ss = (op2 >> 4) & 0x03;
            return { 2, "SBC", "HL," + std::string(WordRegMask[ss]) };
        }
        if ((op2 & 0xCF) == 0x43)
        {
            const uint8_t dd = (op2 >> 4) & 0x03;
            return { 4, "LD", inn_dd(dd, op3, op4) };
        }
        if ((op2 & 0xCF) == 0x4A)
        {
            const uint8_t ss = (op2 >> 4) & 0x03;
            return { 2, "ADC", "HL," + std::string(WordRegMask[ss]) };
        }
        if ((op2 & 0xCF) == 0x4B)
        {
            const uint8_t dd = (op2 >> 4) & 0x03;
            return { 4, "LD", dd_inn(dd, op3, op4) };
        }

        // No match
        return { 0, (boost::format("?? ED %02X") % static_cast<unsigned short>(op2)).str(), "" };
    }

    // Given 4 bytes at the current PC (plus the PC), returns two human-readable "words" of disassembly,
    // plus the count of bytes actually used (as each disassembled instruction can be 1-4 bytes)
    std::tuple<size_t, std::string, std::string> disassemble(uint8_t op1,
                                                             uint8_t op2,
                                                             uint8_t op3,
                                                             uint8_t op4,
                                                             uint16_t pc)
    {
        // First check for specific opcodes
        switch (op1)
        {
        case 0x00: return { 1, "NOP", "" };
        case 0x02: return { 1, "LD", "(BC),A" }; // Special case, can't use the usual lookups
        case 0x07: return { 1, "RLCA", "" };
        case 0x0A: return { 1, "LD", "A,(BC)" }; // Special case, can't use the usual lookups
        case 0x0E:
        {
            const uint8_t r = (op1 >> 3) & 0x07;
            const uint8_t n = op2;
            return { 2, "LD", r_n(r, n) };
        }
        case 0x0F: return { 1, "RRCA", "" };
        case 0x10: return { 2, "DJNZ", offset(pc, op2) };
        case 0x12: return { 1, "LD", "(DE),A" }; // Special case, can't use the usual lookups
        case 0x17: return { 1, "RLA", "" };
        case 0x18: return { 2, "JR", offset(pc, op2) };
        case 0x1A: return { 1, "LD", "A,(DE)" }; // Special case, can't use the usual lookups
        case 0x1F: return { 1, "RRA", "" };
        case 0x22: return { 3, "LD", nn_string(op2, op3, "HL") };
        case 0x27: return { 1, "DAA", "" };
        case 0x2A: return { 3, "LD", string_nn(op2, op3, "HL") };
        case 0x2F: return { 1, "CPL", "" };
        case 0x32: return { 3, "LD", nn_string(op2, op3, "A") };
        case 0x37: return { 1, "SCF", "" };
        case 0x3A: return { 3, "LD", string_nn(op2, op3, "A") };
        case 0x3F: return { 1, "CCF", "" };
        case 0xC3: return { 3, "JP", word(op2, op3) };
        case 0xC6: return { 2, "ADD", "A," + byte(op2) };
        case 0x08: return { 1, "EX", "AF,AF'" };
        case 0xC9: return { 1, "RET", "" };
        case 0xCB: return disassemble_cb(op2, op3, op4);
        case 0xCD: return { 3, "CALL", word(op2, op3) };
        case 0xCE: return { 2, "ADC", "A," + byte(op2) };
        case 0xD3: return { 2, "OUT", n_string(op2, "A") };
        case 0xDD: return disassemble_ddfd("IX", op1, op2, op3, op4);
        case 0xD6: return { 2, "SUB", byte(op2) };
        case 0xD9: return { 1, "EXX", "" };
        case 0xDE: return { 2, "SBC", "A," + byte(op2) };
        case 0xE3: return { 1, "EX", "(SP),HL" };
        case 0xE6: return { 2, "AND", byte(op2) };
        case 0xEE: return { 2, "XOR", byte(op2) };
        case 0xF3: return { 1, "DI", "" };
        case 0xF6: return { 2, "OR", byte(op2) };
        case 0xFB: return { 1, "EI", "" };
        case 0xE9: return { 1, "JP", "(HL)" };
        case 0xEB: return { 1, "EX", "DE,HL" };
        case 0xED: return disassemble_ed(op2, op3, op4);
        case 0xF9: return { 1, "LD", "SP,HL" };
        case 0xFD: return disassemble_ddfd("IY", op1, op2, op3, op4);
        case 0xFE: return { 2, "CP", byte(op2) };
        default:
            // Fall through to bytefield checks below
            break;
        }

        // Byte field checks

        if ((op1 & 0xC0) == 0x40)
        {
            const uint8_t r1 = (op1 >> 3) & 0x07;
            const uint8_t r2 = op1 & 0x07;
            return { 1, "LD", r_r(r1, r2) };
        }

        if ((op1 & 0xC7) == 0x04)
        {
            const uint8_t r = (op1 >> 3) & 0x07;
            return { 1, "INC", ByteRegMask[r] };
        }
        if ((op1 & 0xC7) == 0x05)
        {
            const uint8_t r = (op1 >> 3) & 0x07;
            return { 1, "DEC", ByteRegMask[r] };
        }
        if ((op1 & 0xC7) == 0x06)
        {
            const uint8_t r = (op1 >> 3) & 0x07;
            return { 2, "LD", r_n(r, op2) };
        }
        if ((op1 & 0xC7) == 0xC0)
        {
            const uint8_t cc = (op1 >> 3) & 0x07;
            return { 1, "RET", CondMask[cc] };
        }
        if ((op1 & 0xC7) == 0xC2)
        {
            const uint8_t cc = (op1 >> 3) & 0x07;
            return { 3, "JP", cc_pq(cc, op2, op3) };
        }
        if ((op1 & 0xC7) == 0xC4)
        {
            const uint8_t cc = (op1 >> 3) & 0x07;
            return { 3, "CALL", cc_pq(cc, op2, op3) };
        }
        if ((op1 & 0xC7) == 0xC7)
        {
            const uint8_t p = (op1 >> 3) & 0x07;
            return { 1, "RST", byte(p << 3) };
        }

        if ((op1 & 0xCF) == 0x01)
        {
            const uint8_t dd = (op1 >> 4) & 0x03;
            return { 3, "LD", dd_nn(dd, op2, op3) };
        }
        if ((op1 & 0xCF) == 0x03)
        {
            const uint8_t rr = (op1 >> 4) & 0x03;
            return { 1, "INC", WordRegMask[rr] };
        }
        if ((op1 & 0xCF) == 0x09)
        {
            const uint8_t ss = (op1 >> 4) & 0x03;
            return { 1, "ADD", hl_ss(ss) };
        }
        if ((op1 & 0xCF) == 0x0B)
        {
            const uint8_t rr = (op1 >> 4) & 0x03;
            return { 1, "DEC", WordRegMask[rr] };
        }
        if ((op1 & 0xCF) == 0xC1)
        {
            const uint8_t qq = (op1 >> 4) & 0x03;
            return { 1, "POP", qq_word_register(qq) };
        }
        if ((op1 & 0xCF) == 0xC5)
        {
            const uint8_t qq = (op1 >> 4) & 0x03;
            return { 1, "PUSH", qq_word_register(qq) };
        }

        if ((op1 & 0xE7) == 0x20)
        {
            const uint8_t cc = (op1 >> 3) & 0x03;
            return { 2, "JR", cc_offset(cc, op2, pc) };
        }

        if ((op1 & 0xF8) == 0x80)
        {
            const uint8_t r = op1 & 0x07;
            return { 1, "ADD", "A," + std::string(ByteRegMask[r]) };
        }
        if ((op1 & 0xF8) == 0x88)
        {
            const uint8_t r = op1 & 0x07;
            return { 1, "ADC", ByteRegMask[r] };
        }
        if ((op1 & 0xF8) == 0x90)
        {
            const uint8_t r = op1 & 0x07;
            return { 1, "SUB", ByteRegMask[r] };
        }
        if ((op1 & 0xF8) == 0x98)
        {
            const uint8_t r = op1 & 0x07;
            return { 1, "SBC", ByteRegMask[r] };
        }
        if ((op1 & 0xF8) == 0xA0)
        {
            const uint8_t r = op1 & 0x07;
            return { 1, "AND", ByteRegMask[r] };
        }
        if ((op1 & 0xF8) == 0xA8)
        {
            const uint8_t r = op1 & 0x07;
            return { 1, "XOR", byte_register(r) };
        }
        if ((op1 & 0xF8) == 0xB0)
        {
            const uint8_t r = op1 & 0x07;
            return { 1, "OR", byte_register(r) };
        }
        if ((op1 & 0xF8) == 0xB8)
        {
            const uint8_t r = op1 & 0x07;
            return { 1, "CP", ByteRegMask[r] };
        }

        // Unhandled instruction
        return { 0,
                 (boost::format("?TODO(%02X,%02X,%02X)") % static_cast<unsigned short>(op1) %
                  static_cast<unsigned short>(op2) % static_cast<unsigned short>(op3))
                     .str(),
                 "" };
    }
} // namespace

Writer::Writer(const zcpm::IDebuggable* p_debuggable, zcpm::IMemory& memory, std::ostream& os)
    : m_pdebuggable(p_debuggable), m_memory(memory), m_os(os)
{
    BOOST_ASSERT(p_debuggable);
}

void Writer::examine() const
{
    m_memory.check_memory_accesses(false);

    const auto registers = m_pdebuggable->get_registers();
    const auto [op1, op2, op3, op4, skipped] = m_pdebuggable->get_opcodes_at(registers.PC, 0);
    if (!skipped.empty())
    {
        display(registers, byte_array_to_string(skipped) + " SKIPPED", "");
    }
    const auto num_skipped = skipped.size();

    try
    {
        const auto [_, s1, s2] = disassemble(op1, op2, op3, op4, registers.PC + num_skipped);

        display(registers, s1, s2, num_skipped);

        m_memory.check_memory_accesses(true);
    }
    catch (const std::logic_error& e)
    {
        // A failure to parse; display enough information to help the maintainer:
        // Memory content around the offending area, aligned on 16's
        dump((registers.PC - 16) & 0xFFF0, 64);
        throw;
    }
}

void Writer::list(int start, size_t instructions) const
{
    const auto registers = m_pdebuggable->get_registers();
    const uint16_t base = (start < 0) ? registers.PC : start;

    size_t offset = 0;
    for (size_t i = 0; i < instructions; ++i)
    {
        const auto [op1, op2, op3, op4, skipped] = m_pdebuggable->get_opcodes_at(base, offset);
        if (!skipped.empty())
        {
            display(registers, byte_array_to_string(skipped) + " SKIPPED", "");
            offset += skipped.size();
        }
        const auto num_skipped = skipped.size();
        const auto [nbytes, s1, s2] = disassemble(op1, op2, op3, op4, registers.PC + num_skipped);
        display(base + offset + num_skipped, s1, s2);
        offset += nbytes + num_skipped;
    }
}

void Writer::dump(int start, size_t bytes) const
{
    if (bytes == 0)
    {
        return;
    }

    const auto registers = m_pdebuggable->get_registers();
    const uint16_t base = (start < 0) ? registers.PC : start;

    std::string hex_bytes, ascii_bytes;
    for (size_t offset = 0; offset < bytes; ++offset)
    {
        if ((offset % 16) == 0)
        {
            m_os << boost::format("%04X:") % (base + offset);
        }
        const auto b = m_memory.read_byte(base + offset);
        hex_bytes += (boost::format(" %02X") % static_cast<unsigned short>(b)).str();
        ascii_bytes += std::string(1, ((b < 0x20) || (b > 0x7f)) ? '.' : b);
        if (((offset + 1) % 16) == 0)
        {
            m_os << hex_bytes << ' ' << ascii_bytes << std::endl;
            hex_bytes.clear();
            ascii_bytes.clear();
        }
    }
    if (!hex_bytes.empty() || !ascii_bytes.empty())
    {
        const auto nbytes = ascii_bytes.length();
        const auto padding = std::string((16 - nbytes) * 3, ' ');
        m_os << hex_bytes << padding << ' ' << ascii_bytes << std::endl;
    }
}

void Writer::display(uint16_t address, const std::string& s1, const std::string& s2) const
{
    m_os << boost::format("%04X     %-5s%s") % address % s1 % s2 << std::endl;
}

void Writer::display(const zcpm::Registers& registers,
                     const std::string& s1,
                     const std::string& s2,
                     const uint16_t offset) const
{
    m_os << boost::format("%s A=%02X B=%04X D=%04X H=%04X S=%04X P=%04X  %-5s%s") %
                flags_to_string(registers.AF & 0xFF) % static_cast<unsigned short>(registers.AF >> 8) % registers.BC %
                registers.DE % registers.HL % registers.SP % ((registers.PC + offset) & 0xFFFF) % s1 % s2;

    m_os << std::endl;
    m_os << boost::format("%s '=%02X '=%04X '=%04X '=%04X X=%04X Y=%04X") % flags_to_string(registers.altAF & 0xFF) %
                static_cast<unsigned short>(registers.altAF >> 8) % registers.altBC % registers.altDE %
                registers.altHL % registers.IX % registers.IY
         << std::endl;
}

std::string Writer::flags_to_string(uint8_t f) const
{
    std::string result("------");

    if (f & zcpm::Processor::C_FLAG_MASK)
    {
        result[0] = 'C';
    }
    if (f & zcpm::Processor::N_FLAG_MASK)
    {
        result[1] = 'S';
    }
    if (f & zcpm::Processor::PV_FLAG_MASK)
    {
        result[2] = 'E';
    }
    if (f & zcpm::Processor::H_FLAG_MASK)
    {
        result[3] = 'F';
    }
    if (f & zcpm::Processor::Z_FLAG_MASK)
    {
        result[4] = 'Z';
    }
    if (f & zcpm::Processor::S_FLAG_MASK)
    {
        result[5] = 'M';
    }

    return result;
}

ext: cpp

max_stars_repo_name: VictorRandomCode/zcpm

max_stars_repo_licenses: Xnet Linux-OpenIB X11

max_issues_repo_name: VictorRandomCode/zcpm

max_issues_repo_licenses: Xnet Linux-OpenIB X11

max_forks_repo_name: VictorRandomCode/zcpm

max_forks_repo_licenses: Xnet Linux-OpenIB X11


text:
// The Reactive C++ Toolbox.
// Copyright (C) 2013-2019 Swirly Cloud Limited
// Copyright (C) 2020 Reactive Markets Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "Endpoint.hpp"

#include <toolbox/util/String.hpp>

#include <boost/test/unit_test.hpp>

using namespace std;
using namespace toolbox;

BOOST_AUTO_TEST_SUITE(SocketSuite)

BOOST_AUTO_TEST_CASE(GetUnixAddrInfoCase)
{
    auto path = "/tmp/foo.sock"s;
    const auto ai = get_unix_addrinfo(path, SOCK_DGRAM);
    BOOST_TEST(ai->ai_flags == 0);
    BOOST_TEST(ai->ai_family == AF_UNIX);
    BOOST_TEST(ai->ai_socktype == SOCK_DGRAM);
    BOOST_TEST(ai->ai_protocol == 0);
    BOOST_TEST(ai->ai_addrlen == offsetof(sockaddr_un, sun_path) + path.size() + 1);
    BOOST_TEST(ai->ai_addr->sa_family == AF_UNIX);
    BOOST_TEST(!ai->ai_canonname);
    BOOST_TEST(!ai->ai_next);
    BOOST_TEST(to_string(*ai->ai_addr) == path);

    path.assign(sizeof(sockaddr_un{}.sun_path), 'x');
    BOOST_CHECK_THROW(get_unix_addrinfo(path, SOCK_DGRAM), invalid_argument);
}

BOOST_AUTO_TEST_SUITE_END()

max_stars_repo_name: mmitkevich/toolbox-cpp

max_issues_repo_name: mmitkevich/toolbox-cpp

max_forks_repo_name: mmitkevich/toolbox-cpp


text:
#include <common.hpp>
#include <boost/python/suite/indexing/vector_indexing_suite.hpp>

void export_vector_cell()
{
	class_<std::vector<parser_t::cell_t> >("VectorCell")
		.def(vector_indexing_suite<std::vector<parser_t::cell_t> >())
	;
}

max_stars_repo_name: academicRobot/mmstructlib

max_issues_repo_name: academicRobot/mmstructlib

max_forks_repo_name: academicRobot/mmstructlib


text:
/*
 * db-tests.cpp
 *
 *  Created on: May 3, 2020
 *      Author: hkooper
 */
#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE "HQN Sqlite3 tests"
#include "../src/server/db.hpp"

#include <boost/test/unit_test.hpp>
namespace utf = boost::unit_test;

BOOST_AUTO_TEST_SUITE(Hqn_sqlie_sute_1)
;

std::string conf_file = "etc/harlequeen.cfg";
hqn::config::config cfg(conf_file);

BOOST_AUTO_TEST_CASE(init_1, * utf::label("init1")) {
	hqn::db::db sqlite(cfg.get_server_prefs());
	sqlite.init();
	BOOST_CHECK(sqlite.valid());
}
BOOST_AUTO_TEST_SUITE_END();

max_stars_repo_name: ironharley/h-queen

max_issues_repo_name: ironharley/h-queen

max_forks_repo_name: ironharley/h-queen


text:
// Copyright (c) 2016 The DarkCrystal developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "SignMessageDialog.h"
#include "ui_signmessagedialog.h"

#include <QClipboard>
#include <QFileDialog>
#include <QTextStream>
#include <QTabWidget>

#include "Common/Base58.h"
#include "Common/StringTools.h"
#include "CurrencyAdapter.h"
#include "WalletAdapter.h"
#include "MainWindow.h"
#include <boost/utility/value_init.hpp>
#include "crypto/crypto.h"

namespace WalletGui {

SignMessageDialog::SignMessageDialog(QWidget* _parent) : QDialog(_parent), m_ui(new Ui::SignMessageDialog) {
  m_ui->setupUi(this);
  connect(&WalletAdapter::instance(), &WalletAdapter::walletInitCompletedSignal, this, &SignMessageDialog::walletOpened, Qt::QueuedConnection);
  connect(&WalletAdapter::instance(), &WalletAdapter::walletCloseCompletedSignal, this, &SignMessageDialog::walletClosed, Qt::QueuedConnection);
  m_ui->m_verificationResult->setText("");
}

SignMessageDialog::~SignMessageDialog() {
}

void SignMessageDialog::sign() {
  m_ui->m_tabWidget->setCurrentIndex(0);
  changeTitle(0);
}

void SignMessageDialog::verify() {
  m_ui->m_tabWidget->setCurrentIndex(1);
  changeTitle(1);
}

void SignMessageDialog::changeTitle(int _variant) {
  this->setWindowTitle(_variant == 0 ? tr("Sign message") : tr("Verify signed message"));
}

void SignMessageDialog::walletOpened() {
  m_address = WalletAdapter::instance().getAddress();
}

void SignMessageDialog::walletClosed() {
  m_ui->m_messageEdit->clear();
}

void SignMessageDialog::messageChanged() {
  if (m_ui->m_tabWidget->currentIndex() != 0) { return; }
  std::string message = m_ui->m_messageEdit->toPlainText().toUtf8().constData();
  Crypto::Hash hash;
  Crypto::cn_fast_hash(message.data(), message.size(), hash);
  CryptoNote::AccountKeys keys;
  WalletAdapter::instance().getAccountKeys(keys);
  Crypto::Signature signature;
  Crypto::generate_signature(hash, keys.address.spendPublicKey, keys.spendSecretKey, signature);
  QString sig = QString::fromStdString(std::string("SigV1") + Tools::Base58::encode(std::string((const char *)&signature, sizeof(signature))));
  m_ui->m_signatureEdit->setText(sig);
}

void SignMessageDialog::verifyMessage() {
  m_ui->m_verificationResult->setText("");
  CryptoNote::AccountPublicAddress acc = boost::value_initialized<CryptoNote::AccountPublicAddress>();
  std::string addr_str = m_ui->m_addressEdit->text().trimmed().toStdString();
  std::string message = m_ui->m_verifyMessageEdit->toPlainText().toUtf8().constData();
  std::string signature = m_ui->m_verifySignatureEdit->toPlainText().toStdString();
  if(addr_str.empty() || message.empty() || signature.empty())
    return;
  if(CurrencyAdapter::instance().getCurrency().parseAccountAddressString(addr_str, acc)) {
    Crypto::Hash hash;
    Crypto::cn_fast_hash(message.data(), message.size(), hash);
    const size_t header_len = strlen("SigV1");
    std::string decoded;
    Crypto::Signature s;
    if (!(signature.size() < header_len) && signature.substr(0, header_len) == "SigV1" &&
      Tools::Base58::decode(signature.substr(header_len), decoded) && sizeof(s) == decoded.size()) {
      memcpy(&s, decoded.data(), sizeof(s));
      if (Crypto::check_signature(hash, acc.spendPublicKey, s)) {
        m_ui->m_verificationResult->setText(tr("Signature is valid"));
        m_ui->m_verificationResult->setStyleSheet("QLabel { color : green; }");
      } else {
        m_ui->m_verificationResult->setText(tr("Signature is invalid!"));
        m_ui->m_verificationResult->setStyleSheet("QLabel { color : red; }");
      }
    } else {
      m_ui->m_verificationResult->setText(tr("Signature is invalid!"));
      m_ui->m_verificationResult->setStyleSheet("QLabel { color : red; }");
    }
  } else {
    m_ui->m_verificationResult->setText(tr("Address is invalid!"));
    m_ui->m_verificationResult->setStyleSheet("QLabel { color : red; }");
  }
}

}

max_stars_repo_name: dcrsprotocol/dcrswallet

max_issues_repo_name: dcrsprotocol/dcrswallet

max_forks_repo_name: dcrsprotocol/dcrswallet


text:
// json.hpp
/*
 *  NoFussJSON v1.0
 *
 *  Copyright (c) 2018, 2020 Leigh Johnston.
 *
 *  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 Leigh Johnston nor the names of any
 *       other contributors to this software 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.
*/

#pragma once

#include <neolib/neolib.hpp>
#include <cstddef>
#include <list>
#include <string>
#include <unordered_map>
#include <vector>
#include <type_traits>
#include <istream>
#include <ostream>
#include <utility>
#include <memory>
#include <exception>
#include <optional>
#include <variant>
#include <boost/functional/hash.hpp>
#include <neolib/core/allocator.hpp>
#include <neolib/core/quick_string.hpp>

namespace neolib
{
    struct json_error : std::runtime_error { json_error(const std::string& aReason) : std::runtime_error{ aReason } {} };
    struct json_path_not_found : std::runtime_error { json_path_not_found(const std::string& aPath) : std::runtime_error{ "JSON path not found: " + aPath } {} };
    struct json_no_owning_node : std::logic_error { json_no_owning_node() : std::logic_error{ "JSON no owning node" } {} };

    enum class json_syntax
    {
        Standard,
        StandardNoKeywords,
        Relaxed,
        Functional
    };

    enum class json_encoding
    {
        Utf8,
        Utf16LE,
        Utf16BE,
        Utf32LE,
        Utf32BE
    };

    namespace json_detail
    {
        template <std::size_t CharSize>
        struct default_encoding_helper;
        template <> struct default_encoding_helper<1> { static const json_encoding DEFAULT_ENCODING = json_encoding::Utf8; };
        template <> struct default_encoding_helper<2> { static const json_encoding DEFAULT_ENCODING = json_encoding::Utf16LE; };
        template <> struct default_encoding_helper<4> { static const json_encoding DEFAULT_ENCODING = json_encoding::Utf32LE; };

        template <typename CharT>
        struct default_encoding    { static const json_encoding DEFAULT_ENCODING = default_encoding_helper<sizeof(CharT)>::DEFAULT_ENCODING; };
    }

    enum class json_type
    {
        Unknown,
        Object,
        Array,
        Double,
        Int64,
        Uint64,
        Int,
        Uint,
        String,
        Bool,
        Null,
        Keyword
    };

    inline std::string to_string(json_type aType)
    {
        switch (aType)
        {
        default:
        case json_type::Unknown:
            return "Unknown";
        case json_type::Object:
            return "Object";
        case json_type::Array:
            return "Array";
        case json_type::Double:
            return "Double";
        case json_type::Int64:
            return "Int64";
        case json_type::Uint64:
            return "Uint64";
        case json_type::Int:
            return "Int";
        case json_type::Uint:
            return "Uint";
        case json_type::String:
            return "String";
        case json_type::Bool:
            return "Bool";
        case json_type::Null:
            return "Null";
        case json_type::Keyword:
            return "Keyword";
        }
    }

    struct json_document_source_location
    {
        uint32_t line;
        uint32_t column;
    };

    namespace json_detail
    {
        template <typename T>
        class basic_json_node
        {
            typedef basic_json_node<T> self_type;
            template <json_syntax Syntax, typename Alloc , typename CharT, typename Traits, typename CharAlloc>
            friend class basic_json_value;
        public:
            typedef T json_value;
            typedef typename json_value::value_type value_type;
        private:
            typedef typename json_value::value_allocator value_allocator;
        public:
            basic_json_node() :
                iParent{ nullptr },
                iPrevious{ nullptr },
                iNext{ nullptr },
                iFirstChild{ nullptr },
                iLastChild{ nullptr }
            {
            }
            basic_json_node(json_value& aParent) :
                iParent{ &aParent },
                iPrevious{ nullptr },
                iNext{ nullptr },
                iFirstChild{ nullptr },
                iLastChild{ nullptr }
            {
            }
            ~basic_json_node()
            {
                while (iLastChild != nullptr)
                    destruct_child(iLastChild);
            }
        public:
            json_value* buy_child(json_value& aParent, const value_type& aValue)
            {
                return construct_child(allocate_child(), aParent, aValue);
            }
            json_value* buy_child(json_value& aParent, value_type&& aValue)
            {
                return construct_child(allocate_child(), aParent, std::move(aValue));
            }
        public:
            bool has_parent() const
            {
                return iParent != nullptr;
            }
            const json_value* parent() const
            {
                return iParent;
            }
            json_value* parent()
            {
                return iParent;
            }
            bool has_children() const
            {
                return iFirstChild != nullptr;
            }
            const json_value* first_child() const
            {
                return iFirstChild;
            }
            json_value* first_child()
            {
                return iFirstChild;
            }
            const json_value* last_child() const
            {
                return iLastChild;
            }
            json_value* last_child()
            {
                return iLastChild;
            }
            bool is_last_sibling() const
            {
                return iNext == nullptr;
            }
            const json_value* next_sibling() const
            {
                return iNext;
            }
            json_value* next_sibling()
            {
                return iNext;
            }
            const json_value* next_parent_sibling() const
            {
                auto tryParent = iParent;
                if (tryParent == nullptr)
                    return nullptr;
                while (tryParent->has_parent() && tryParent->is_last_sibling())
                    tryParent = &tryParent->parent();
                return tryParent->next_sibling();
            }
            json_value* next_parent_sibling()
            {
                return const_cast<json_value*>(to_const(*this).next_parent_sibling());
            }
        private:
            json_value* allocate_child()
            {
                return std::allocator_traits<value_allocator>::allocate(allocator(), 1);
            }
            void deallocate_child(json_value* aAddress)
            {
                std::allocator_traits<value_allocator>::deallocate(allocator(), aAddress, 1);
            }
            template <typename... Args>
            json_value* construct_child(json_value* aAddress, json_value& aParent, Args&&... aArguments)
            {
                std::allocator_traits<value_allocator>::construct(allocator(), aAddress, aParent, std::forward<Args>(aArguments)...);
                json_value& child = *aAddress;
                if (iLastChild == nullptr)
                {
                    iFirstChild = &child;
                    iLastChild = &child;
                }
                else
                {
                    iLastChild->iNode.iNext = &child;
                    child.iNode.iPrevious = iLastChild;
                    iLastChild = &child;
                }
                return &child;
            }
            void destruct_child(json_value* aAddress)
            {
                json_value& child = *aAddress;
                if (child.iNode.iPrevious != nullptr)
                    child.iNode.iPrevious->iNode.iNext = child.iNode.iNext;
                if (child.iNode.iNext != nullptr)
                    child.iNode.iNext->iNode.iPrevious = child.iNode.iPrevious;
                if (iLastChild == &child)
                    iLastChild = child.iNode.iPrevious;
                if (iFirstChild == &child)
                    iFirstChild = child.iNode.iNext;
                child.~json_value();
                deallocate_child(aAddress);
            }
        private:
            static value_allocator& allocator()
            {
                static value_allocator sAllocator;
                return sAllocator;
            }
            json_value* iParent;
            json_value* iPrevious;
            json_value* iNext;
            json_value* iFirstChild;
            json_value* iLastChild;
        };
    }

    template <typename T>
    class basic_json_object
    {
        typedef basic_json_object<T> self_type;
        template <json_syntax Syntax, typename Alloc, typename CharT, typename Traits, typename CharAlloc>
        friend class basic_json;
        template <json_syntax Syntax, typename Alloc, typename CharT, typename Traits, typename CharAlloc>
        friend class basic_json_value;
    public:
        typedef T json_value;
        typedef typename json_value::value_type value_type;
        typedef typename json_value::json_string json_string;
    private:
        typedef typename json_value::value_allocator allocator_type;
        typedef std::unordered_multimap<
            json_string,
            json_value*,
            boost::hash<json_string>,
            std::equal_to<json_string>,
            typename std::allocator_traits<allocator_type>::template rebind_alloc<std::pair<const json_string, json_value*>>> dictionary_type;
    public:
        basic_json_object() :
            iContents{ nullptr }
        {
        }
        basic_json_object(json_value& aOwner) :
            iContents{ &aOwner }
        {
        }
    public:
        bool has(const json_string& aKey) const
        {
            return cache().find(aKey) != cache().end();
        }
        const json_value& at(const json_string& aKey) const
        {
            auto existing = cache().find(aKey);
            if (existing != cache().end())
                return *existing->second;
            throw std::out_of_range("neolib::basic_json_object::at: key not found");
        }
        json_value& at(const json_string& aKey)
        {
            return const_cast<json_value&>(to_const(*this).at(aKey));
        }
        template <typename U>
        std::enable_if_t<!std::is_arithmetic_v<U>, const U&> at_or(const json_string& aKey, const U& aDefault) const
        {
            if (has(aKey))
                return at(aKey).template as<U>();
            return aDefault;
        }
        template <typename U>
        std::enable_if_t<!std::is_arithmetic_v<U>, U&> at_or(const json_string& aKey, U& aDefault)
        {
            if (has(aKey))
                return at(aKey).template as<U>();
            return aDefault;
        }
        template <typename U>
        std::enable_if_t<std::is_arithmetic_v<U>, U> at_or(const json_string& aKey, const U& aDefault) const
        {
            if (has(aKey))
                return at(aKey).template as<U>();
            return aDefault;
        }
        template <typename U>
        std::enable_if_t<std::is_arithmetic_v<U>, U&> at_or(const json_string& aKey, U& aDefault)
        {
            if (has(aKey))
                return at(aKey).template as<U>();
            return aDefault;
        }
        json_value& operator[](const json_string& aKey)
        {
            auto existing = cache().find(aKey);
            if (existing != cache().end())
                return *existing->second;
            auto& newChild = contents().emplace_back(value_type{});
            newChild.set_name(aKey.to_std_string());
            cache().emplace(newChild.name(), &newChild);
            return newChild;
        }
    public:
        json_value& contents() const
        {
            if (iContents == nullptr)
                throw json_no_owning_node();
            return *iContents;
        }
        void set_contents(json_value& aOwner)
        {
            iContents = &aOwner;
        }
    private:
        const dictionary_type& cache() const
        {
            if (iLazyDictionary != nullptr)
                return *iLazyDictionary;
            iLazyDictionary = std::make_unique<dictionary_type>(); // todo: use allocator_type
            for (auto i = contents().begin(); i != contents().end(); ++i)
                iLazyDictionary->emplace(i.value().name(), &i.value());
            return *iLazyDictionary;
        }
        dictionary_type& cache()
        {
            return const_cast<dictionary_type&>(to_const(*this).cache());
        }
    private:
        json_value* iContents;
        mutable std::unique_ptr<dictionary_type> iLazyDictionary;
    };

    template <typename T>
    class basic_json_array
    {
        typedef basic_json_array<T> self_type;
        template <json_syntax Syntax, typename Alloc, typename CharT, typename Traits, typename CharAlloc>
        friend class basic_json;
        template <json_syntax Syntax, typename Alloc, typename CharT, typename Traits, typename CharAlloc>
        friend class basic_json_value;
    public:
        typedef T json_value;
        typedef typename json_value::value_type value_type;
        typedef typename json_value::json_string json_string;
    private:
        typedef typename json_value::value_allocator allocator_type;
        typedef std::vector<json_value*> array_type;
    public:
        basic_json_array() :
            iContents{ nullptr }
        {
        }
        basic_json_array(json_value& aOwner) :
            iContents{ &aOwner }
        {
        }
    public:
        typename array_type::const_iterator cbegin() const
        {
            return cache().begin();
        }
        typename array_type::const_iterator cend() const
        {
            return cache().end();
        }
        typename array_type::const_iterator begin() const
        {
            return cache().begin();
        }
        typename array_type::const_iterator end() const
        {
            return cache().end();
        }
        typename array_type::iterator begin()
        {
            return cache().begin();
        }
        typename array_type::iterator end()
        {
            return cache().end();
        }
    public:
        json_value& push_back(const value_type& aValue)
        {
            auto& newChild = contents().emplace_back(aValue);
            cache().emplace_back(&newChild);
            return back();
        }
        json_value& push_back(value_type&& aValue)
        {
            auto& newChild = contents().emplace_back(std::move(aValue));
            cache().emplace_back(&newChild);
            return back();
        }
        json_value& back()
        {
            return *cache().back();
        }
        json_value& operator[](std::size_t aIndex)
        {
            return *cache().at(aIndex);
        }
    public:
        json_value& contents() const
        {
            if (iContents == nullptr)
                throw json_no_owning_node();
            return *iContents;
        }
        void set_contents(json_value& aOwner)
        {
            iContents = &aOwner;
        }
    private:
        const array_type& cache() const
        {
            if (iLazyArray != nullptr)
                return *iLazyArray;
            iLazyArray = std::make_unique<array_type>(); // todo: use allocator_type
            for (auto& e : contents())
                iLazyArray->emplace_back(&e);
            return *iLazyArray;
        }
        array_type& cache()
        {
            return const_cast<array_type&>(to_const(*this).cache());
        }
    private:
        json_value* iContents;
        mutable std::unique_ptr<array_type> iLazyArray;
    };

    template <typename T>
    struct basic_json_keyword
    {
    public:
        typedef T json_value;
        typedef typename json_value::json_string json_string;
    public:
        json_string text;
    };

    template <typename T>
    struct basic_json_null
    {
    public:
        typedef T json_value;
    public:
        bool operator==(std::nullptr_t) const { return true; }
        bool operator!=(std::nullptr_t) const { return false; }
    };

    template <json_syntax Syntax = json_syntax::Standard, typename Alloc = std::allocator<json_type>, typename CharT = char, typename Traits = std::char_traits<CharT>, typename CharAlloc = std::allocator<CharT>>
    class basic_json;

    template <json_syntax Syntax = json_syntax::Standard, typename Alloc = std::allocator<json_type>, typename CharT = char, typename Traits = std::char_traits<CharT>, typename CharAlloc = std::allocator<CharT>>
    class basic_json_value
    {
        typedef basic_json_value<Syntax, Alloc, CharT, Traits, CharAlloc> self_type;
        friend class basic_json<Syntax, Alloc, CharT, Traits, CharAlloc>;
        template <typename T>
        friend class json_detail::basic_json_node;
    public:
        struct no_name : std::logic_error { no_name() : std::logic_error("neolib::basic_json_value::no_name") {} };
        struct bad_conversion : std::runtime_error { bad_conversion() : std::runtime_error("neolib::basic_json_value::bad_conversion") {} };
    public:
        static constexpr json_syntax syntax = Syntax;
        typedef Alloc allocator_type;
        typedef CharT character_type;
        typedef Traits character_traits_type;
        typedef CharAlloc character_allocator_type;
    public:
        typedef self_type node_value_type;
    public:
        typedef typename std::allocator_traits<allocator_type>::template rebind_alloc<self_type> value_allocator;
    public:
        typedef const self_type* const_pointer;
        typedef self_type* pointer;
        typedef const self_type& const_reference;
        typedef self_type& reference;
    private:
        template <typename IteratorTraits>
        class iterator_base;
    public:
        class const_iterator;
        class iterator;
    public:
        typedef basic_quick_string<character_type, character_traits_type, character_allocator_type> json_string;
        typedef basic_json_object<self_type> json_object;
        typedef basic_json_array<self_type> json_array;
        typedef double json_double;
        typedef int64_t json_int64;
        typedef uint64_t json_uint64;
        typedef int32_t json_int;
        typedef uint32_t json_uint;
        typedef bool json_bool;
        typedef basic_json_null<self_type> json_null;
        typedef basic_json_keyword<self_type> json_keyword;
    public:
        typedef std::variant<std::monostate, json_string, json_keyword> name_t;
    public:
        typedef std::optional<json_string> optional_json_string;
    public:
        typedef std::variant<std::monostate, json_object, json_array, json_double, json_int64, json_uint64, json_int, json_uint, json_string, json_bool, json_null, json_keyword> value_type;
    private:
        typedef json_detail::basic_json_node<basic_json_value> node_type;
    public:
        basic_json_value() :
            iNode{}, iValue{}, iDocumentSourceLocation{}
        {
        }
        basic_json_value(reference aParent, const value_type& aValue) :
            iNode{ aParent }, iValue{ aValue }, iDocumentSourceLocation{}
        {
            update_contents();
        }
        basic_json_value(reference aParent, value_type&& aValue) :
            iNode{ aParent }, iValue{ std::move(aValue) }, iDocumentSourceLocation{}
        {
            update_contents();
        }
    public:
        basic_json_value(const basic_json_value&) = delete;
        basic_json_value(basic_json_value&&) = delete;
    public:
        template <typename T>
        std::enable_if_t<!std::is_arithmetic_v<T>, const T&> as() const
        {
            return std::get<T>(iValue);
        }
        template <typename T>
        std::enable_if_t<!std::is_arithmetic_v<T>, T&> as()
        {
            return std::get<T>(iValue);
        }
        template <typename T>
        std::enable_if_t<std::is_arithmetic_v<T>, T> as() const
        {
            T result = {};
            std::visit([&result](auto&& v)
            {
                if constexpr (std::is_convertible_v<std::decay_t<decltype(v)>, std::decay_t<T>>)
                    result = v;
                else
                    throw bad_conversion();
            }, iValue);
            return result;
        }
        template <typename T>
        std::enable_if_t<std::is_arithmetic_v<T>, T&> as()
        {
            return std::get<T>(iValue);
        }
        const value_type& operator*() const
        {
            return iValue;
        }
        value_type& operator*()
        {
            return iValue;
        }
        reference operator=(const value_type& aValue)
        {
            iValue = aValue;
            update_contents();
            return *this;
        }
        reference operator=(value_type&& aValue)
        {
            iValue = std::move(aValue);
            update_contents();
            return *this;
        }
    public:
        json_type type() const
        {
            return static_cast<json_type>(iValue.index());
        }
        bool is_composite() const
        {
            return type() == json_type::Object || type() == json_type::Array;
        }
        bool is_empty_composite() const
        {
            return is_composite() && !iNode.has_children();
        }
        bool is_populated_composite() const
        {
            return is_composite() && iNode.has_children();
        }
        const json_string& text() const
        {
            if (type() != json_type::Keyword)
                return as<json_string>();
            else
                return as<json_keyword>().text;
        }
        bool has_name() const
        {
            return !std::holds_alternative<std::monostate>(iName);
        }
        bool name_is_keyword() const
        {
            return std::holds_alternative<json_keyword>(iName);
        }
        const json_string& name() const
        {
            if (!name_is_keyword())
                return std::get<json_string>(iName);
            else
                return std::get<json_keyword>(iName).text;
        }
        void set_name(const json_string& aName)
        {
            iName = aName;
        }
        void set_name(const json_keyword& aName)
        {
            iName = aName;
        }
    public:
        bool is_root() const
        {
            return !has_parent();
        }
        bool has_parent() const
        {
            return iNode.has_parent();
        }
        const_reference parent() const
        {
            return *iNode.parent();
        }
        reference parent()
        {
            return *iNode.parent();
        }
        bool has_children() const
        {
            return iNode.has_children();
        }
        const_pointer first_child() const
        {
            return iNode.first_child();
        }
        pointer first_child()
        {
            return iNode.first_child();
        }
        const_pointer last_child() const
        {
            return iNode.last_child();
        }
        pointer last_child()
        {
            return iNode.last_child();
        }
        bool is_last_sibling() const
        {
            return iNode.is_last_sibling();
        }
        const_pointer next_sibling() const
        {
            return iNode.next_sibling();
        }
        pointer next_sibling()
        {
            return iNode.next_sibling();
        }
        const_pointer next_parent_sibling() const
        {
            return iNode.next_parent_sibling();
        }
        pointer next_parent_sibling()
        {
            return iNode.next_parent_sibling();
        }
    public:
        const_iterator cbegin() const
        {
            return begin();
        }
        const_iterator cend() const
        {
            return end();
        }
        const_iterator begin() const
        {
            return first_child();
        }
        const_iterator end() const
        {
            return nullptr;
        }
        iterator begin()
        {
            return first_child();
        }
        iterator end()
        {
            return nullptr;
        }
    public:
        template <typename Visitor>
        void visit(Visitor&& aVisitor, bool aRecurse = true) const
        {
            std::visit([&aVisitor](auto&& arg)
            {
                if constexpr(!std::is_same_v<typename std::remove_cv<typename std::remove_reference<decltype(arg)>::type>::type, std::monostate>)
                    aVisitor(std::forward<decltype(arg)>(arg));
            }, iValue);
            switch (type())
            {
            case json_type::Object:
            case json_type::Array:
                if (aRecurse)
                    for (auto& v : *this)
                        v.visit(std::forward<Visitor>(aVisitor));
                break;
            }
        }
        template <typename Visitor>
        void visit(Visitor&& aVisitor, bool aRecurse = true)
        {
            std::visit([&aVisitor](auto&& arg)
            {
                if constexpr(!std::is_same_v<typename std::remove_cv<typename std::remove_reference<decltype(arg)>::type>::type, std::monostate>)
                    aVisitor(std::forward<decltype(arg)>(arg));
            }, iValue);
            switch (type())
            {
            case json_type::Object:
            case json_type::Array:
                if (aRecurse)
                    for (auto i = begin(); i != end(); ++i)
                        i.value().visit(std::forward<Visitor>(aVisitor));
                break;
            default:
                break;
            }
        }
    public:
        bool empty() const
        {
            return begin() == end();
        }
        std::size_t size() const
        {
            return std::distance(begin(), end()); // todo: this is O(n); have a size member instead for O(1)?
        }
        void clear()
        {
            iNode.~node_type();
            new(&iNode) node_type();
        }
        template <typename... Args>
        reference emplace_back(Args&&... aArguments)
        {
            return *buy_child(std::forward<Args>(aArguments)...);
        }
        template <typename T>
        void push_back(T&& aValue)
        {
            buy_child(std::forward<T>(aValue));
        }
        void pop_back()
        {
            iNode.destruct_child(last_child());
        }
    public:
        const json_document_source_location& document_source_location() const
        {
            return iDocumentSourceLocation;
        }
        void set_document_source_location(const json_document_source_location& aDocumentSourceLocation)
        {
            iDocumentSourceLocation = aDocumentSourceLocation;
        }
    private:
        template <typename... Args>
        pointer buy_child(Args&&... aArguments)
        {
            return iNode.buy_child(*this, std::forward<Args>(aArguments)...);
        }
        void update_contents()
        {
            if (type() == json_type::Object)
                std::get<json_object>(iValue).set_contents(*this);
            else if (type() == json_type::Array)
                std::get<json_array>(iValue).set_contents(*this);
        }
    private:
        node_type iNode;
        name_t iName;
        value_type iValue;
        json_document_source_location iDocumentSourceLocation;
    };

    template <json_syntax Syntax, typename Alloc, typename CharT, typename Traits, typename CharAlloc>
    class basic_json
    {
        typedef basic_json<Syntax, Alloc, CharT, Traits, CharAlloc> self_type;
    public:
        static constexpr json_syntax syntax = Syntax;
        typedef Alloc allocator_type;
        typedef CharT character_type;
        typedef Traits character_traits_type;
        typedef CharAlloc character_allocator_type;
        typedef basic_json_value<syntax, allocator_type, character_type, character_traits_type, character_allocator_type> json_value;
        typedef std::optional<json_value> optional_json_value;
        typedef typename json_value::json_object json_object;
        typedef typename json_value::json_array json_array;
        typedef typename json_value::json_double json_double;
        typedef typename json_value::json_int64 json_int64;
        typedef typename json_value::json_uint64 json_uint64;
        typedef typename json_value::json_int json_int;
        typedef typename json_value::json_uint json_uint;
        typedef typename json_value::json_string json_string;
        typedef typename json_value::json_bool json_bool;
        typedef typename json_value::json_null json_null;
        typedef typename json_value::json_keyword json_keyword;
    public:
        typedef typename json_value::value_type value_type;
        typedef value_type* pointer;
        typedef const value_type* const_pointer;
        typedef value_type& reference;
        typedef const value_type& const_reference;
    private:
        template <typename IteratorTraits>
        class iterator_base;
    public:
        class const_iterator;
        class iterator;
    private:
        typedef std::basic_string<CharT, Traits, CharAlloc> string_type;
        struct element
        {
            enum type_e
            {
                Unknown,
                String,
                Number,
                Keyword,
                EscapedUnicode,
                Name
            };
            type_e type;
            type_e auxType;
            character_type* start;
            character_type* auxStart;
            typename json_value::name_t name;
        };
    public:
        basic_json();
        basic_json(const std::string& aPath, bool aValidateUtf = false);
        template <typename Elem, typename ElemTraits>
        basic_json(std::basic_istream<Elem, ElemTraits>& aInput, bool aValidateUtf = false);
    public:
        void clear();
        bool read(const std::string& aPath, bool aValidateUtf = false);
        template <typename Elem, typename ElemTraits>
        bool read(std::basic_istream<Elem, ElemTraits>& aInput, bool aValidateUtf = false);
        bool write(const std::string& aPath, const string_type& aIndent = string_type(2, character_type{' '}));
        template <typename Elem, typename ElemTraits>
        bool write(std::basic_ostream<Elem, ElemTraits>& aOutput, const string_type& aIndent = string_type(2, character_type{' '}));
    public:
        json_encoding encoding() const;
        const json_string& document() const;
        const string_type& error_text() const;
    public:
        bool has_root() const;
        const json_value& croot() const;
        const json_value& root() const;
        json_value& root();
        const json_value& at(const json_string& aPath) const;
        json_value& at(const json_string& aPath);
        template <typename Visitor>
        void visit(Visitor&& aVisitor) const;
        template <typename Visitor>
        void visit(Visitor&& aVisitor);
        const_iterator cbegin() const;
        const_iterator cend() const;
        const_iterator begin() const;
        const_iterator end() const;
        iterator begin();
        iterator end();
    public:
        static string_type to_error_text(const json_document_source_location& aDocumentSourceLocation, const string_type& aExtraInfo = {});
        static string_type to_error_text(const json_value& aNode, const string_type& aExtraInfo = {});
    private:
        json_string& document();
        string_type to_error_text(const string_type& aExtraInfo = {}) const;
    private:
        template <typename Elem, typename ElemTraits>
        bool do_read(std::basic_istream<Elem, ElemTraits>& aInput, bool aValidateUtf = false);
        bool do_parse();
        json_type context() const;
        template <typename T>
        json_value* buy_value(element& aCurrentElement, T&& aValue);
        void create_parse_error(const string_type& aExtraInfo = {}) const;
    private:
        json_encoding iEncoding;
        json_string iDocumentText;
        json_document_source_location iCursor;
        mutable string_type iErrorText;
        mutable optional_json_value iRoot;
        std::vector<json_value*> iCompositeValueStack;
        std::optional<char16_t> iUtf16HighSurrogate;
    };

    typedef basic_json<json_syntax::Standard> json;
    typedef json::json_value json_value;
    typedef json::json_object json_object;
    typedef json::json_array json_array;
    typedef json::json_double json_double;
    typedef json::json_int64 json_int64;
    typedef json::json_uint64 json_uint64;
    typedef json::json_int json_int;
    typedef json::json_uint json_uint;
    typedef json::json_string json_string;
    typedef json::json_bool json_bool;
    typedef json::json_null json_null;
    typedef json::json_keyword json_keyword;

    typedef basic_json<json_syntax::Standard, neolib::fast_pool_allocator<json_type>> fast_json;
    typedef fast_json::json_value fast_json_value;
    typedef fast_json::json_object fast_json_object;
    typedef fast_json::json_array fast_json_array;
    typedef fast_json::json_double fast_json_double;
    typedef fast_json::json_int64 fast_json_int64;
    typedef fast_json::json_uint64 fast_json_uint64;
    typedef fast_json::json_int fast_json_int;
    typedef fast_json::json_uint fast_json_uint;
    typedef fast_json::json_string fast_json_string;
    typedef fast_json::json_bool fast_json_bool;
    typedef fast_json::json_null fast_json_null;
    typedef fast_json::json_keyword fast_json_keyword;

    typedef basic_json<json_syntax::Relaxed> rjson;
    typedef rjson::json_value rjson_value;
    typedef rjson::json_object rjson_object;
    typedef rjson::json_array rjson_array;
    typedef rjson::json_double rjson_double;
    typedef rjson::json_int64 rjson_int64;
    typedef rjson::json_uint64 rjson_uint64;
    typedef rjson::json_int rjson_int;
    typedef rjson::json_uint rjson_uint;
    typedef rjson::json_string rjson_string;
    typedef rjson::json_bool rjson_bool;
    typedef rjson::json_null rjson_null;
    typedef rjson::json_keyword rjson_keyword;

    typedef basic_json<json_syntax::Relaxed, neolib::fast_pool_allocator<json_type>> fast_rjson;
    typedef fast_rjson::json_value fast_rjson_value;
    typedef fast_rjson::json_object fast_rjson_object;
    typedef fast_rjson::json_array fast_rjson_array;
    typedef fast_rjson::json_double fast_rjson_double;
    typedef fast_rjson::json_int64 fast_rjson_int64;
    typedef fast_rjson::json_uint64 fast_rjson_uint64;
    typedef fast_rjson::json_int fast_rjson_int;
    typedef fast_rjson::json_uint fast_rjson_uint;
    typedef fast_rjson::json_string fast_rjson_string;
    typedef fast_rjson::json_bool fast_rjson_bool;
    typedef fast_rjson::json_null fast_rjson_null;
    typedef fast_rjson::json_keyword fast_rjson_keyword;

    typedef basic_json<json_syntax::Functional> fjson;
    typedef fjson::json_value fjson_value;
    typedef fjson::json_object fjson_object;
    typedef fjson::json_array fjson_array;
    typedef fjson::json_double fjson_double;
    typedef fjson::json_int64 fjson_int64;
    typedef fjson::json_uint64 fjson_uint64;
    typedef fjson::json_int fjson_int;
    typedef fjson::json_uint fjson_uint;
    typedef fjson::json_string fjson_string;
    typedef fjson::json_bool fjson_bool;
    typedef fjson::json_null fjson_null;
    typedef fjson::json_keyword fjson_keyword;

    typedef basic_json<json_syntax::Functional, neolib::fast_pool_allocator<json_type>> fast_fjson;
    typedef fast_fjson::json_value fast_fjson_value;
    typedef fast_fjson::json_object fast_fjson_object;
    typedef fast_fjson::json_array fast_fjson_array;
    typedef fast_fjson::json_double fast_fjson_double;
    typedef fast_fjson::json_int64 fast_fjson_int64;
    typedef fast_fjson::json_uint64 fast_fjson_uint64;
    typedef fast_fjson::json_int fast_fjson_int;
    typedef fast_fjson::json_uint fast_fjson_uint;
    typedef fast_fjson::json_string fast_fjson_string;
    typedef fast_fjson::json_bool fast_fjson_bool;
    typedef fast_fjson::json_null fast_fjson_null;
    typedef fast_fjson::json_keyword fast_fjson_keyword;
}

#include <neolib/file/json.inl>

ext: hpp


text:
/**
 * @file
 * Declares the scoped resource for temporarily changing an environment variable.
 */
#pragma once

#include <leatherman/util/scoped_resource.hpp>
#include <string>
#include <boost/optional.hpp>

namespace leatherman { namespace util {

    /**
     * This is an RAII wrapper for temporarily changing an environment variable.
     * It sets the environment on construction and restores it on destruction.
     */
    struct scoped_env : scoped_resource<std::tuple<std::string, boost::optional<std::string>>>
    {
        /**
         * Temporarily overrides the value of an environment variable.
         * @param var    The environment variable to update.
         * @param newval The value to set it to during existence of this object.
         */
        explicit scoped_env(std::string var, std::string const& newval);

        /**
         * Temporarily unsets an environment variable.
         */
        explicit scoped_env(std::string var);

     private:
        static void restore(std::tuple<std::string, boost::optional<std::string>> &);
    };

}}  // namespace leatherman::util

max_stars_repo_name: ScottGarman/leatherman

max_issues_repo_name: ScottGarman/leatherman

max_forks_repo_name: ScottGarman/leatherman


text: #include <boost/thread/experimental/task_region.hpp>

max_stars_repo_name: miathedev/BoostForArduino

max_issues_repo_name: miathedev/BoostForArduino

max_forks_repo_name: miathedev/BoostForArduino


text:
/*#############################################################################
#
# Copyright (C) 2012 Network Box Corporation Limited
#   Nick Jones <nick.jones@network-box.com>
#
# Distributed under the Boost Software License, Version 1.0. (See accompanying
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#
###############################################################################
 */

#ifndef LIBAPOA_COMMON_H
#define LIBAPOA_COMMON_H

#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <unistd.h>
#include <time.h>
#include <stdint.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>

#include <list>
#include <set>
#include <map>
#include <functional>

#include <boost/algorithm/string.hpp>
#include <boost/format.hpp>

#include <asio.hpp>

namespace apoa
{

//#############################################################################
class tenum_t
  {
  public:
    tenum_t(int tenum) : tenum_(tenum) {}
    tenum_t(const tenum_t& rvalue) : tenum_(rvalue.tenum_) {}
    ~tenum_t() {tenum_ = -1;}

  public:
    tenum_t& operator=(const tenum_t& rvalue)
      {
      tenum_ = rvalue.tenum_;
      return *this;
      }

  public:
    bool operator<(const tenum_t& rvalue) const {return tenum_ < rvalue.tenum_;}

  public:
    bool operator==(const tenum_t& rvalue) const {return tenum_ == rvalue.tenum_;}
    bool operator!=(const tenum_t& rvalue) const {return tenum_ != rvalue.tenum_;}

  public:
    int tenum_;
  };

//#############################################################################
pid_t get_pid();
pid_t get_tid();
tenum_t get_tenum();
bool is_process_thread();

//#############################################################################
enum log_level
  {
  log_level_none =                                        0,
  log_level_info =                                        10,
  log_level_debug =                                       100,
  log_level_warning =                                     200,
  log_level_error =                                       500,
  log_level_critical =                                    1000,
  };

//#############################################################################
int get_log_level();
void set_log_level(int level);

//#############################################################################
namespace priv
{
template <typename ARG>
static void push_log_message_arg(
    boost::format& message, const ARG& arg)
  {
  message % arg;
  }

template <typename ARG, typename... ARGS>
static void push_log_message_arg(
    boost::format& message, const ARG& arg, const ARGS&... args)
  {
  message % arg;

  push_log_message_arg(message, args...);
  }
};

//#############################################################################
template <typename... ARGS>
void apoavsprintf(
    std::string& str, const std::string& fmt, const ARGS&... args)
  {
  try
    {
    boost::format message(fmt);
    priv::push_log_message_arg(message, args...);
    str = boost::str(message);
    }
  catch(std::exception const& e)
    {
    str = boost::str(
      boost::format("format error '%1s'") % fmt.data());
    }
  }

inline void apoavsprintf(
    std::string& str, const std::string& fmt, va_list& args)
  {
  str.resize(4096, '\0');
  vsnprintf(const_cast<char*>(str.data()), 4096, fmt.c_str(), args);
  }

//#############################################################################
inline void apoalogstdout(int level, const std::string& message)
  {
  if ((apoa::get_log_level() == 0) || (apoa::get_log_level() <= level))
    {
    return;
    }

  struct timeval tv;
  gettimeofday(&tv, NULL);

  char tm_buf[10];
  if (strftime(tm_buf, 9, "%T", localtime(&tv.tv_sec)) == 0) \
    {
    printf("[%05d] unable to generate apoa::log timestamp\n", get_tid());
    fflush(stdout);

    return;
    }

  std::string prefix = boost::str(boost::format("[%1$05ld] %2$s:%3$06ld") %
    get_tid() % tm_buf % tv.tv_usec);

  std::list<std::string> lines;
  boost::split(lines, message, boost::is_any_of("\n"));
  for (std::list<std::string>::iterator itr = lines.begin();
       itr != lines.end();
       ++itr)
    {
    printf("%s %s\n", prefix.c_str(), itr->c_str());
    fflush(stdout);
    }
  }

inline void apoalogstdout(
    int level, const std::string& fmt, va_list& args)
  {
  if ((apoa::get_log_level() == 0) || (apoa::get_log_level() <= level))
    {
    return;
    }

  std::string str;
  apoavsprintf(str, fmt, args);

  apoalogstdout(level, str);
  }

template <typename... ARGS>
void apoalogstdout(
    int level, const std::string& fmt, const ARGS&... args)
  {
  if ((apoa::get_log_level() == 0) || (apoa::get_log_level() <= level))
    {
    return;
    }

  std::string str;
  apoavsprintf(str, fmt, args...);

  apoalogstdout(level, str);
  }

//#############################################################################
#define APOA_PRINT(fmt, ...) \
  apoa::apoalogstdout(apoa::log_level_info, fmt, ##__VA_ARGS__);

//#############################################################################
asio::io_context& get_process_io_context();
void shutdown_process(int retval = 0);

asio::io_context& get_io_context(apoa::tenum_t tenum = apoa::get_tenum());
void shutdown_thread(apoa::tenum_t tenum = apoa::get_tenum(), int retval = 0);

asio::io_context& get_io_context(pid_t tid);
void shutdown_thread(pid_t tid, int retval);

asio::io_context& get_thread_io_context();

//#############################################################################
class thread_handler;

namespace priv
{

//#############################################################################
class per_thread_registry
  {
  public:
    friend class apoa::thread_handler;

  private:
    typedef std::function<void (void)> per_thread_index_callback;
    typedef std::map<int32_t, per_thread_index_callback>
      per_thread_index_callback_map;

  private:
    static void init()
      {
      std::lock_guard<std::mutex> callback_lock(callback_mutex_);

      thread_set_.insert(0);
      }

  private:
    static void thread_start()
      {
      std::lock_guard<std::mutex> callback_lock(callback_mutex_);

      thread_set_.insert(get_tenum());

      for (per_thread_index_callback_map::iterator itr =
             thread_start_callbacks_.begin();
           itr != thread_start_callbacks_.end();
           ++itr)
        {
        (itr->second)();
        }
      }

    static void thread_finish()
      {
      std::lock_guard<std::mutex> callback_lock(callback_mutex_);

      for (per_thread_index_callback_map::iterator itr =
             thread_finish_callbacks_.begin();
           itr != thread_finish_callbacks_.end();
           ++itr)
        {
        (itr->second)();
        }

      thread_set_.erase(get_tenum());
      }

  protected:
    static int32_t index_id_;

  protected:
    static std::mutex callback_mutex_;

    static per_thread_index_callback_map thread_start_callbacks_;
    static per_thread_index_callback_map thread_finish_callbacks_;

  protected:
    static std::set<tenum_t> thread_set_;
  };

}; // namespace priv

//#############################################################################
template <typename T>
class per_thread_index : public priv::per_thread_registry
  {
  public:
    friend class thread_handler;

  public:
    const static size_t default_index_size =              10;

  public:
    per_thread_index() :
        id_(__sync_add_and_fetch(&index_id_, 1)),
        index_size_(default_index_size)
      {
      index_ = new T*[index_size_];
      memset(index_, 0, sizeof(T*) * index_size_);

      std::lock_guard<std::mutex> callback_lock(callback_mutex_);

      thread_start_callbacks_.insert(
        std::make_pair(
          id_, std::bind(&per_thread_index<T>::on_thread_start, this)));
      thread_finish_callbacks_.insert(
        std::make_pair(
          id_, std::bind(&per_thread_index<T>::on_thread_finish, this)));

      for (std::set<tenum_t>::iterator itr =
             thread_set_.begin();
           itr != thread_set_.end();
           ++itr)
        {
        do_on_thread_start(*itr, NULL);
        }
      }

    per_thread_index(int32_t id) :
        id_(id),
        index_size_(default_index_size)
      {
      index_ = new T*[index_size_];
      memset(index_, 0, sizeof(T*) * index_size_);
      }

    ~per_thread_index()
      {
      if (id_ >= 0)
        {
        std::lock_guard<std::mutex> callback_lock(callback_mutex_);

        thread_start_callbacks_.erase(id_);
        thread_finish_callbacks_.erase(id_);
        }

      std::lock_guard<std::mutex> index_lock(index_mutex_);

      for (ssize_t counter = index_size_ - 1;
           counter >= 0;
           --counter)
        {
        if (index_[counter] != NULL)
          {
          delete index_[counter];
          index_[counter] = NULL;
          }
        }

      delete [] index_;
      index_ = NULL;
      }

  public:
    T& get(apoa::tenum_t tenum = apoa::get_tenum())
      {
      return *index_[tenum.tenum_];
      }

  private:
    void on_thread_start()
      {
      do_on_thread_start(get_tenum(), NULL);
      }

    void do_on_thread_start(apoa::tenum_t tenum, T* t)
      {
      std::lock_guard<std::mutex> index_lock(index_mutex_);

      if (tenum.tenum_ >= index_size_)
        {
        T** new_index = new T*[(index_size_ * 2)];
        memset(new_index, 0, sizeof(T*) * (index_size_ * 2));
        memcpy(new_index, index_, sizeof(T*) * index_size_);

        index_size_ *= 2;

        T** old_index = index_;
        __sync_bool_compare_and_swap(&index_, index_, new_index);

        delete [] old_index;
        }

      if (t == NULL)
        {
        index_[tenum.tenum_] = new T();
        }
      else
        {
        index_[tenum.tenum_] = t;
        }
      }

    void on_thread_finish()
      {
      do_on_thread_finish(get_tenum());
      }

    void do_on_thread_finish(apoa::tenum_t tenum)
      {
      std::lock_guard<std::mutex> index_lock(index_mutex_);

      assert(index_[tenum.tenum_] != NULL);
      delete index_[tenum.tenum_];
      index_[tenum.tenum_] = NULL;
      }

  private:
    int32_t id_;

  private:
    std::mutex index_mutex_;

    size_t index_size_;

    T** index_;
  };

}; // namespace apoa

#endif // LIBAPOA_COMMON_H

max_stars_repo_name: nickfajones/libapoa

max_issues_repo_name: nickfajones/libapoa

max_forks_repo_name: nickfajones/libapoa


text:
/*
    Copyright Joseph Miller (C) 2014-2018.
*/
#include <map>
#include <string>
#include <list>
#include <boost/filesystem.hpp>
#include <boost/regex.hpp>

#include "FileRenamer.h"

/** Base constructor does nothing.
*/
FileRenamer::FileRenamer()
{
}

/** Overloaded constructor renames on instantiation.

@param[in] filePattern is the regular expression to use for determining which files to rename.
@param[in] renamePattern is the regular expression pattern to rename files with.
@param[out] errorString is the error string for issues.
@param[in] includeSubDirectories is used for recursive renames.
    @note default is false.
*/
FileRenamer::FileRenamer( const std::wstring & filePattern, const std::wstring & renamePattern,
                          std::wstring& errorString, const bool includeSubDirectories )
{
    Rename(filePattern, renamePattern, errorString, includeSubDirectories);
}

/** Rename iterates through the file list, checks for regex matches and replaces those matches with regex formatted file names.

@param[in] filePattern is the regular expression to use for determining which files to rename.
@param[in] renamePattern is the regular expression pattern to rename files with.
@param[out] errorString is the error string for issues.
@param[in] includeSubDirectories is used for recursive renames.
    @note default is false.
@return the number of files that were renamed.
*/
unsigned int FileRenamer::Rename( const std::wstring & filePattern, const std::wstring & renamePattern,
                                  std::wstring & errorString, const bool includeSubDirectories ) const
{
	//mapOutput is used to hold original filenames and renamed filenames
	std::map<std::wstring, std::wstring> mapOutput;

	GetFileMap(mapOutput, includeSubDirectories);
	//if there aren't any regular files to rename in the directories, go away
	if(mapOutput.empty())
	{
	    errorString = L"No files to rename.\n";
		return 0;
	}

	unsigned int filesRenamed=0; //return value

	for (auto& mit : mapOutput)
    {
        mit.second = regex_replace(mit.first, boost::wregex(filePattern), renamePattern);
		//if the filename was changed with the pattern...
		if(mit.first != mit.second)
		{
			++filesRenamed;
		}
	}

	DuplicateFilenameCheck(mapOutput, errorString);

	//if there is a warning, throw it, otherwise,
	//start renaming the files and throw an error if we've received one
	if(errorString.empty())
	{
	    for(auto& mit : mapOutput)
        {
			try
			{
				boost::filesystem::rename(mit.first, mit.second);
			}
			catch(...)
			{
				throw;
			}
        }
		return filesRenamed;
	}

	return 0;
}

/** This checks for duplicate filenames between original and files to rename to.

@param[in] mapOutput the file map to check input and output for.
@param[out] errorString the error string if there are duplicate files.
*/
void FileRenamer::DuplicateFilenameCheck(const std::map<std::wstring, std::wstring>& mapOutput, std::wstring& errorString) const
{
    //detect if output filename will match another output filename or if the change isn't a valid filename
	//if true, issue a warning
	for(auto mit = mapOutput.begin();mit != mapOutput.end();++mit)
	{
		for(auto mit2 = next(mit);mit2 != mapOutput.end();++mit2)
		{
			if(mit->second == mit2->second)
			{
				errorString += std::wstring(L"filename: ") + mit->second + std::wstring(L" has multiple matches.\n");
				continue;
			}

            const std::string checkValidity = std::string(mit2->second.begin(), mit2->second.end());
            if(!boost::filesystem::portable_name(checkValidity))
            {
                errorString += std::wstring(L"filename: ") + mit2->second + std::wstring(L" will not be a valid filename.\n");
            }
		}
	}
}

/** This pulls in the file map.

@param[out] mapOutput the file map containing all files in the directory or directories.
@param[in] includeSubDirectories should be true if you wish to recursively include files in subdirectories.
*/
void FileRenamer::GetFileMap(std::map<std::wstring, std::wstring>& mapOutput, const bool includeSubDirectories) const
{
    //TODO: this may need fixed.  Current behavior is that the pattern renamer is going to
	//take the whole pathname into consideration instead of JUST the filename

	if(includeSubDirectories)
	{
		boost::filesystem::recursive_directory_iterator rdi(L".");
		while(rdi != boost::filesystem::recursive_directory_iterator())
		{
			if(boost::filesystem::is_regular_file(*rdi))
			{
				//add the original filename to mapOutput
				const std::wstring out = (*rdi).path().filename().wstring();
				mapOutput.insert(std::pair<std::wstring, std::wstring>(out, out));
			}
			++rdi;
		}
	}
	else
	{
		boost::filesystem::directory_iterator di(L".");
		while(di != boost::filesystem::directory_iterator())
		{
			if(boost::filesystem::is_regular_file(*di))
			{
				//add the original filename to mapOutput
				const std::wstring out = (*di).path().filename().wstring();
				mapOutput.insert(std::pair<std::wstring, std::wstring>(out, out));
			}
			++di;
		}
	}
}

max_stars_repo_name: Grokamole/Regenamer

max_issues_repo_name: Hyatus/Regenamer

max_forks_repo_name: Hyatus/Regenamer