<commit_before>#include "beacon.h"
#include "util.h"
#include "uint256.h"
#include "key.h"
#include "main.h"

extern std::string SignBlockWithCPID(std::string sCPID, std::string sBlockHash);
extern bool VerifyCPIDSignature(std::string sCPID, std::string sBlockHash, std::string sSignature);
std::string RetrieveBeaconValueWithMaxAge(const std::string& cpid, int64_t iMaxSeconds);
int64_t GetRSAWeightByCPIDWithRA(std::string cpid);

std::string ExtractXML(std::string XMLdata, std::string key, std::string key_end);

namespace
{
    std::string GetNetSuffix()
    {
        return fTestNet ? "testnet" : "";
    }
}

bool GenerateBeaconKeys(const std::string &cpid, std::string &sOutPubKey, std::string &sOutPrivKey)
{
    // First Check the Index - if it already exists, use it
    sOutPrivKey = GetArgument("privatekey" + cpid + GetNetSuffix(), "");
    sOutPubKey  = GetArgument("publickey" + cpid + GetNetSuffix(), "");

    // If current keypair is not empty, but is invalid, allow the new keys to be stored, otherwise return 1: (10-25-2016)
    if (!sOutPrivKey.empty() && !sOutPubKey.empty())
    {
        uint256 hashBlock = GetRandHash();
        std::string sSignature = SignBlockWithCPID(cpid,hashBlock.GetHex());
        bool fResult = VerifyCPIDSignature(cpid, hashBlock.GetHex(), sSignature);
        if (fResult)
        {
            printf("\r\nGenerateNewKeyPair::Current keypair is valid.\r\n");
            return false;
        }
    }

    // Generate the Keypair
    CKey key;
    key.MakeNewKey(false);
    CPrivKey vchPrivKey = key.GetPrivKey();
    sOutPrivKey = HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end());
    sOutPubKey = HexStr(key.GetPubKey().Raw());

    return true;
}

void StoreBeaconKeys(
        const std::string &cpid,
        const std::string &pubKey,
        const std::string &privKey)
{
    WriteKey("publickey" + cpid + GetNetSuffix(), pubKey);
    WriteKey("privatekey" + cpid + GetNetSuffix(), privKey);
}

std::string GetStoredBeaconPrivateKey(const std::string& cpid)
{
    return GetArgument("privatekey" + cpid + GetNetSuffix(), "");
}

std::string GetStoredBeaconPublicKey(const std::string& cpid)
{
    return GetArgument("publickey" + cpid + GetNetSuffix(), "");
}

void ActivateBeaconKeys(
        const std::string &cpid,
        const std::string &pubKey,
        const std::string &privKey)
{
    SetArgument("publickey" + cpid + GetNetSuffix(), pubKey);
    SetArgument("privatekey" + cpid + GetNetSuffix(), privKey);
}

void GetBeaconElements(const std::string& sBeacon, std::string& out_cpid, std::string& out_address, std::string& out_publickey)
{
    if (sBeacon.empty()) return;
    std::string sContract = DecodeBase64(sBeacon);
    std::vector<std::string> vContract = split(sContract.c_str(),";");
    if (vContract.size() < 4) return;
    out_cpid = vContract[0];
    out_address = vContract[2];
    out_publickey = vContract[3];
}

std::string GetBeaconPublicKey(const std::string& cpid, bool bAdvertisingBeacon)
{
    //3-26-2017 - Ensure beacon public key is within 6 months of network age (If advertising, let it be returned as missing after 5 months, to ensure the public key is renewed seamlessly).
    int iMonths = bAdvertisingBeacon ? 5 : 6;
    int64_t iMaxSeconds = 60 * 24 * 30 * iMonths * 60;
    std::string sBeacon = RetrieveBeaconValueWithMaxAge(cpid, iMaxSeconds);
    if (sBeacon.empty()) return "";
    // Beacon data structure: CPID,hashRand,Address,beacon public key: base64 encoded
    std::string sContract = DecodeBase64(sBeacon);
    std::vector<std::string> vContract = split(sContract.c_str(),";");
    if (vContract.size() < 4) return "";
    std::string sBeaconPublicKey = vContract[3];
    return sBeaconPublicKey;
}

int64_t BeaconTimeStamp(const std::string& cpid, bool bZeroOutAfterPOR)
{
    std::string sBeacon = mvApplicationCache["beacon;" + cpid];
    int64_t iLocktime = mvApplicationCacheTimestamp["beacon;" + cpid];
    int64_t iRSAWeight = GetRSAWeightByCPIDWithRA(cpid);
    if (fDebug10)
        printf("\r\n Beacon %s, Weight %" PRId64 ", Locktime %" PRId64 "\r\n",sBeacon.c_str(), iRSAWeight, iLocktime);
    if (bZeroOutAfterPOR && iRSAWeight==0)
        iLocktime = 0;
    return iLocktime;

}

bool HasActiveBeacon(const std::string& cpid)
{
    return GetBeaconPublicKey(cpid, false).empty() == false;
}

std::string RetrieveBeaconValueWithMaxAge(const std::string& cpid, int64_t iMaxSeconds)
{
    const std::string key = "beacon;" + cpid;
    const std::string& value = mvApplicationCache[key];

    // Compare the age of the beacon to the age of the current block. If we have
    // no current block we assume that the beacon is valid.
    int64_t iAge = pindexBest != NULL
          ? pindexBest->nTime - mvApplicationCacheTimestamp[key]
          : 0;

    return (iAge > iMaxSeconds)
          ? ""
          : value;
}

bool VerifyBeaconContractTx(const std::string& txhashBoinc)
{
    // Mandatory block needed.
    // Current bad contracts in chain would cause a fork on sync
    // Previous beacons in the past have 3 elements not 4 thus causing empty contract elements as coded in GetBeaconElements
    if (
               (fTestNet && nBestHeight <= 300000)
            || (!fTestNet && nBestHeight <= 1070000)
       )
        return true; // allow sync from 0 till these blocks when this check comes into effect

    // Check if tx contains beacon advertisement and evaluate for certain conditions
    std::string chkMessageType = ExtractXML(txhashBoinc, "<MT>", "</MT>");
    std::string chkMessageAction = ExtractXML(txhashBoinc, "<MA>", "</MA>");

    if (chkMessageType != "beacon")
        return true; // Not beacon contract

    if (chkMessageAction != "A")
        return true; // Not an add contract for beacon

    std::string chkMessageContract = ExtractXML(txhashBoinc, "<MV>", "</MV>");
    std::string chkMessageContractCPID = ExtractXML(txhashBoinc, "<MK>", "</MK>");
    // Here we GetBeaconElements for the contract in the tx
    std::string tx_out_cpid;
    std::string tx_out_address;
    std::string tx_out_publickey;

    GetBeaconElements(chkMessageContract, tx_out_cpid, tx_out_address, tx_out_publickey);

    if (tx_out_cpid.empty() || tx_out_address.empty() || tx_out_publickey.empty() || chkMessageContractCPID.empty())
        return false; // Incomplete contract

    std::string chkKey = "beacon;" + chkMessageContractCPID;
    std::string chkValue = mvApplicationCache[chkKey];

    if (chkValue.empty())
    {
        if (fDebug10)
            printf("VBCTX : No Previous beacon found for CPID %s\n", chkMessageContractCPID.c_str());

        return true; // No previous beacon in cache
    }

    int64_t chkiAge = pindexBest != NULL
        ? pindexBest->nTime - mvApplicationCacheTimestamp[chkKey]
        : 0;
    int64_t chkSecondsBase = 60 * 24 * 30 * 60;

    // Conditions
    // Condition a) if beacon is younger then 5 months deny tx
    if (chkiAge <= chkSecondsBase * 5 && chkiAge >= 1)
    {
        if (fDebug10)
            printf("VBCTX : Beacon age violation. Beacon Age %" PRId64 " < Required Age %" PRId64 "\n", chkiAge, (chkSecondsBase * 5));

        return false;
    }

    // Condition b) if beacon is younger then 6 months but older then 5 months verify using the same keypair; if not deny tx
    if (chkiAge >= chkSecondsBase * 5 && chkiAge <= chkSecondsBase * 6)
    {
        std::string chk_out_cpid;
        std::string chk_out_address;
        std::string chk_out_publickey;

        // Here we GetBeaconElements for the contract in the current beacon in chain
        GetBeaconElements(chkValue, chk_out_cpid, chk_out_address, chk_out_publickey);

        if (tx_out_publickey != chk_out_publickey)
        {
            if (fDebug10)
                printf("VBCTX : Beacon tx publickey != publickey in chain. %s != %s\n", tx_out_publickey.c_str(), chk_out_publickey.c_str());

            return false;
        }
    }

    // Passed checks
    return true;
}
<commit_msg>Fix for testnet start block<commit_after>#include "beacon.h"
#include "util.h"
#include "uint256.h"
#include "key.h"
#include "main.h"

extern std::string SignBlockWithCPID(std::string sCPID, std::string sBlockHash);
extern bool VerifyCPIDSignature(std::string sCPID, std::string sBlockHash, std::string sSignature);
std::string RetrieveBeaconValueWithMaxAge(const std::string& cpid, int64_t iMaxSeconds);
int64_t GetRSAWeightByCPIDWithRA(std::string cpid);

std::string ExtractXML(std::string XMLdata, std::string key, std::string key_end);

namespace
{
    std::string GetNetSuffix()
    {
        return fTestNet ? "testnet" : "";
    }
}

bool GenerateBeaconKeys(const std::string &cpid, std::string &sOutPubKey, std::string &sOutPrivKey)
{
    // First Check the Index - if it already exists, use it
    sOutPrivKey = GetArgument("privatekey" + cpid + GetNetSuffix(), "");
    sOutPubKey  = GetArgument("publickey" + cpid + GetNetSuffix(), "");

    // If current keypair is not empty, but is invalid, allow the new keys to be stored, otherwise return 1: (10-25-2016)
    if (!sOutPrivKey.empty() && !sOutPubKey.empty())
    {
        uint256 hashBlock = GetRandHash();
        std::string sSignature = SignBlockWithCPID(cpid,hashBlock.GetHex());
        bool fResult = VerifyCPIDSignature(cpid, hashBlock.GetHex(), sSignature);
        if (fResult)
        {
            printf("\r\nGenerateNewKeyPair::Current keypair is valid.\r\n");
            return false;
        }
    }

    // Generate the Keypair
    CKey key;
    key.MakeNewKey(false);
    CPrivKey vchPrivKey = key.GetPrivKey();
    sOutPrivKey = HexStr<CPrivKey::iterator>(vchPrivKey.begin(), vchPrivKey.end());
    sOutPubKey = HexStr(key.GetPubKey().Raw());

    return true;
}

void StoreBeaconKeys(
        const std::string &cpid,
        const std::string &pubKey,
        const std::string &privKey)
{
    WriteKey("publickey" + cpid + GetNetSuffix(), pubKey);
    WriteKey("privatekey" + cpid + GetNetSuffix(), privKey);
}

std::string GetStoredBeaconPrivateKey(const std::string& cpid)
{
    return GetArgument("privatekey" + cpid + GetNetSuffix(), "");
}

std::string GetStoredBeaconPublicKey(const std::string& cpid)
{
    return GetArgument("publickey" + cpid + GetNetSuffix(), "");
}

void ActivateBeaconKeys(
        const std::string &cpid,
        const std::string &pubKey,
        const std::string &privKey)
{
    SetArgument("publickey" + cpid + GetNetSuffix(), pubKey);
    SetArgument("privatekey" + cpid + GetNetSuffix(), privKey);
}

void GetBeaconElements(const std::string& sBeacon, std::string& out_cpid, std::string& out_address, std::string& out_publickey)
{
    if (sBeacon.empty()) return;
    std::string sContract = DecodeBase64(sBeacon);
    std::vector<std::string> vContract = split(sContract.c_str(),";");
    if (vContract.size() < 4) return;
    out_cpid = vContract[0];
    out_address = vContract[2];
    out_publickey = vContract[3];
}

std::string GetBeaconPublicKey(const std::string& cpid, bool bAdvertisingBeacon)
{
    //3-26-2017 - Ensure beacon public key is within 6 months of network age (If advertising, let it be returned as missing after 5 months, to ensure the public key is renewed seamlessly).
    int iMonths = bAdvertisingBeacon ? 5 : 6;
    int64_t iMaxSeconds = 60 * 24 * 30 * iMonths * 60;
    std::string sBeacon = RetrieveBeaconValueWithMaxAge(cpid, iMaxSeconds);
    if (sBeacon.empty()) return "";
    // Beacon data structure: CPID,hashRand,Address,beacon public key: base64 encoded
    std::string sContract = DecodeBase64(sBeacon);
    std::vector<std::string> vContract = split(sContract.c_str(),";");
    if (vContract.size() < 4) return "";
    std::string sBeaconPublicKey = vContract[3];
    return sBeaconPublicKey;
}

int64_t BeaconTimeStamp(const std::string& cpid, bool bZeroOutAfterPOR)
{
    std::string sBeacon = mvApplicationCache["beacon;" + cpid];
    int64_t iLocktime = mvApplicationCacheTimestamp["beacon;" + cpid];
    int64_t iRSAWeight = GetRSAWeightByCPIDWithRA(cpid);
    if (fDebug10)
        printf("\r\n Beacon %s, Weight %" PRId64 ", Locktime %" PRId64 "\r\n",sBeacon.c_str(), iRSAWeight, iLocktime);
    if (bZeroOutAfterPOR && iRSAWeight==0)
        iLocktime = 0;
    return iLocktime;

}

bool HasActiveBeacon(const std::string& cpid)
{
    return GetBeaconPublicKey(cpid, false).empty() == false;
}

std::string RetrieveBeaconValueWithMaxAge(const std::string& cpid, int64_t iMaxSeconds)
{
    const std::string key = "beacon;" + cpid;
    const std::string& value = mvApplicationCache[key];

    // Compare the age of the beacon to the age of the current block. If we have
    // no current block we assume that the beacon is valid.
    int64_t iAge = pindexBest != NULL
          ? pindexBest->nTime - mvApplicationCacheTimestamp[key]
          : 0;

    return (iAge > iMaxSeconds)
          ? ""
          : value;
}

bool VerifyBeaconContractTx(const std::string& txhashBoinc)
{
    // Mandatory block needed.
    // Current bad contracts in chain would cause a fork on sync
    // Previous beacons in the past have 3 elements not 4 thus causing empty contract elements as coded in GetBeaconElements
    if (
               (fTestNet && nBestHeight <= 378000)
            || (!fTestNet && nBestHeight <= 1070000)
       )
        return true; // allow sync from 0 till these blocks when this check comes into effect

    // Check if tx contains beacon advertisement and evaluate for certain conditions
    std::string chkMessageType = ExtractXML(txhashBoinc, "<MT>", "</MT>");
    std::string chkMessageAction = ExtractXML(txhashBoinc, "<MA>", "</MA>");

    if (chkMessageType != "beacon")
        return true; // Not beacon contract

    if (chkMessageAction != "A")
        return true; // Not an add contract for beacon

    std::string chkMessageContract = ExtractXML(txhashBoinc, "<MV>", "</MV>");
    std::string chkMessageContractCPID = ExtractXML(txhashBoinc, "<MK>", "</MK>");
    // Here we GetBeaconElements for the contract in the tx
    std::string tx_out_cpid;
    std::string tx_out_address;
    std::string tx_out_publickey;

    GetBeaconElements(chkMessageContract, tx_out_cpid, tx_out_address, tx_out_publickey);

    if (tx_out_cpid.empty() || tx_out_address.empty() || tx_out_publickey.empty() || chkMessageContractCPID.empty())
        return false; // Incomplete contract

    std::string chkKey = "beacon;" + chkMessageContractCPID;
    std::string chkValue = mvApplicationCache[chkKey];

    if (chkValue.empty())
    {
        if (fDebug10)
            printf("VBCTX : No Previous beacon found for CPID %s\n", chkMessageContractCPID.c_str());

        return true; // No previous beacon in cache
    }

    int64_t chkiAge = pindexBest != NULL
        ? pindexBest->nTime - mvApplicationCacheTimestamp[chkKey]
        : 0;
    int64_t chkSecondsBase = 60 * 24 * 30 * 60;

    // Conditions
    // Condition a) if beacon is younger then 5 months deny tx
    if (chkiAge <= chkSecondsBase * 5 && chkiAge >= 1)
    {
        if (fDebug10)
            printf("VBCTX : Beacon age violation. Beacon Age %" PRId64 " < Required Age %" PRId64 "\n", chkiAge, (chkSecondsBase * 5));

        return false;
    }

    // Condition b) if beacon is younger then 6 months but older then 5 months verify using the same keypair; if not deny tx
    if (chkiAge >= chkSecondsBase * 5 && chkiAge <= chkSecondsBase * 6)
    {
        std::string chk_out_cpid;
        std::string chk_out_address;
        std::string chk_out_publickey;

        // Here we GetBeaconElements for the contract in the current beacon in chain
        GetBeaconElements(chkValue, chk_out_cpid, chk_out_address, chk_out_publickey);

        if (tx_out_publickey != chk_out_publickey)
        {
            if (fDebug10)
                printf("VBCTX : Beacon tx publickey != publickey in chain. %s != %s\n", tx_out_publickey.c_str(), chk_out_publickey.c_str());

            return false;
        }
    }

    // Passed checks
    return true;
}
<|endoftext|>


<commit_before><commit_msg>fdo#78427 PDF Import: Improve detection of bold italic font<commit_after><|endoftext|>


<commit_before>
/*  o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o

    CTool Library
    Copyright (C) 1998-2001	Shaun Flisakowski

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

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o  */

/*  o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o
    o+
    o+     File:         location.h
    o+
    o+     Programmer:   Brian Chess
    o+     Date:         May 31, 1999
    o+
    o+     Keep track of the line, column, and filename of a token
    o+
    o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o  */

#ifndef CT_LOCATION_H
#define CT_LOCATION_H

#include <string>

class Location
{
 public:
  const int line, column;
  const std::string& file;

  Location(int l, int c, const std::string& f):line(l),column(c),file(f) {}
  ~Location() {}

  void printLocation(std::ostream& p) const;
};

extern  Location NoLocation;

#endif

<commit_msg>the file reference is not stable<commit_after>
/*  o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o

    CTool Library
    Copyright (C) 1998-2001	Shaun Flisakowski

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

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o  */

/*  o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o
    o+
    o+     File:         location.h
    o+
    o+     Programmer:   Brian Chess
    o+     Date:         May 31, 1999
    o+
    o+     Keep track of the line, column, and filename of a token
    o+
    o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o+o  */

#ifndef CT_LOCATION_H
#define CT_LOCATION_H

#include <string>

class Location
{
 public:
  const int line, column;
  const std::string file;

  Location(int l, int c, const std::string& f):line(l),column(c),file(f) {}
  ~Location() {}

  void printLocation(std::ostream& p) const;
};

extern  Location NoLocation;

#endif

<|endoftext|>


<commit_before>
#include "BitSet.h"

#include <cstdlib>
#include <cstring>
#include <new>

#ifdef USE_MSVC_POPCOUNT
#include <intrin.h>
#endif

using namespace Meadows;

BitSet::BitSet() : numBits(0), bits{} {}

BitSet::BitSet(std::size_t numBits) : numBits(numBits) {
    size_t memoryRequirement = getMemoryRequirement();
    bits = (uint32_t*) std::malloc(memoryRequirement);
    std::memset(bits, 0, memoryRequirement);
    if (bits == nullptr) {
        throw std::bad_alloc();
    }
}

BitSet &BitSet::operator=(const BitSet& other) {
    numBits = other.numBits;
    size_t size = getMemoryRequirement();
    bits = (uint32_t*) std::realloc(bits, size);
    if (bits == nullptr) {
        throw std::bad_alloc();
    }
    std::memcpy(bits, other.bits, size);
    return *this;
}

uint32_t BitSet::operator[](std::size_t n) {
    return bits[n / 32] & (1 << (n % 32));
}

void BitSet::set(std::size_t n) {
    bits[n / 32] |= (1 << (n % 32));
}

std::size_t BitSet::numSetBitsBefore(std::size_t n) {
    std::size_t count = 0;
    // Count the bits in the uint32_t values before the (n/32)th value
    for (std::size_t i = 0; i<n/32; i++) {
        uint32_t num = bits[i];
#ifdef USE_GCC_POPCOUNT
        count += __builtin_popcount(num);
#elif USE_MSVC_POPCOUNT
        // If the popcnt instruction is not supported by the hardware, this will fail
        count += __popcnt(num);
#else
       count += popCount(num);
#endif
    }

    // Count the bits of the (n/32)th value, up to the nth bit
    for (std::size_t j = 0; j < (n % 32); j++) {
        if (bits[n / 32] & (1 << j))
            count++;
    }

    return count;
}

uint32_t BitSet::popCount(uint32_t num) const {
    // SWAR algorithm from https://www.playingwithpointers.com/swar.html
    num = num - ((num >> 1) & 0x55555555);
    num = (num & 0x33333333) + ((num >> 2) & 0x33333333);
    num = (((num + (num >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
    return num;
}

BitSet::~BitSet() {
    std::free(bits);
}

std::size_t BitSet::getMemoryRequirement() {
    return (numBits % 32 + numBits) / sizeof(uint32_t);
}
<commit_msg>Fix crash when allocating memory for a bitset fails<commit_after>
#include "BitSet.h"

#include <cstdlib>
#include <cstring>
#include <new>

#ifdef USE_MSVC_POPCOUNT
#include <intrin.h>
#endif

using namespace Meadows;

BitSet::BitSet() : numBits(0), bits{} {}

BitSet::BitSet(std::size_t numBits) : numBits(numBits) {
    size_t memoryRequirement = getMemoryRequirement();
    bits = (uint32_t*) std::malloc(memoryRequirement);
    if (bits == nullptr) {
        throw std::bad_alloc();
    }
    std::memset(bits, 0, memoryRequirement);
}

BitSet &BitSet::operator=(const BitSet& other) {
    numBits = other.numBits;
    size_t size = getMemoryRequirement();
    bits = (uint32_t*) std::realloc(bits, size);
    if (bits == nullptr) {
        throw std::bad_alloc();
    }
    std::memcpy(bits, other.bits, size);
    return *this;
}

uint32_t BitSet::operator[](std::size_t n) {
    return bits[n / 32] & (1 << (n % 32));
}

void BitSet::set(std::size_t n) {
    bits[n / 32] |= (1 << (n % 32));
}

std::size_t BitSet::numSetBitsBefore(std::size_t n) {
    std::size_t count = 0;
    // Count the bits in the uint32_t values before the (n/32)th value
    for (std::size_t i = 0; i<n/32; i++) {
        uint32_t num = bits[i];
#ifdef USE_GCC_POPCOUNT
        count += __builtin_popcount(num);
#elif USE_MSVC_POPCOUNT
        // If the popcnt instruction is not supported by the hardware, this will fail
        count += __popcnt(num);
#else
       count += popCount(num);
#endif
    }

    // Count the bits of the (n/32)th value, up to the nth bit
    for (std::size_t j = 0; j < (n % 32); j++) {
        if (bits[n / 32] & (1 << j))
            count++;
    }

    return count;
}

uint32_t BitSet::popCount(uint32_t num) const {
    // SWAR algorithm from https://www.playingwithpointers.com/swar.html
    num = num - ((num >> 1) & 0x55555555);
    num = (num & 0x33333333) + ((num >> 2) & 0x33333333);
    num = (((num + (num >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
    return num;
}

BitSet::~BitSet() {
    std::free(bits);
}

std::size_t BitSet::getMemoryRequirement() {
    return (numBits % 32 + numBits) / sizeof(uint32_t);
}
<|endoftext|>


<commit_before>#pragma once

#include <string>

using std::string;

template<typename T>
class CError
{
	using ErrorType = typename T::Error;
public:
	CError() :
		m_Type(ErrorType::NONE)
	{ }
	~CError() = default;

	operator bool() const
	{
		return m_Type != ErrorType::NONE;
	}

	const string &msg() const
	{
		return m_Message;
	}
	const ErrorType type() const
	{
		return m_Type;
	}
	const string &module() const
	{
		return T::ModuleName;
	}

	void set(ErrorType type, string &&msg)
	{
		m_Type = type;
		m_Message.assign(std::move(msg));
	}

private:
	ErrorType m_Type;
	string m_Message;
};<commit_msg>add "set" method with formatting options<commit_after>#pragma once

#include <string>
#include <format.h>

using std::string;

template<typename T>
class CError
{
	using ErrorType = typename T::Error;
public:
	CError() :
		m_Type(ErrorType::NONE)
	{ }
	~CError() = default;

	operator bool() const
	{
		return m_Type != ErrorType::NONE;
	}

	const string &msg() const
	{
		return m_Message;
	}
	const ErrorType type() const
	{
		return m_Type;
	}
	const string &module() const
	{
		return T::ModuleName;
	}

	void set(ErrorType type, string &&msg)
	{
		m_Type = type;
		m_Message.assign(std::move(msg));
	}
	template<typename... Args>
	void set(ErrorType type, string &&format, Args &&...args)
	{
		m_Type = type;
		m_Message.assign(fmt::format(format, std::forward<Args>(args)...));
	}

private:
	ErrorType m_Type;
	string m_Message;
};<|endoftext|>


<commit_before>//
//  Camera.cpp
//  Cinder-EDSDK
//
//  Created by Jean-Pierre Mouilleseaux on 08 Dec 2013.
//  Copyright 2013 Chorded Constructions. All rights reserved.
//

#include "Camera.h"

using namespace ci;
using namespace ci::app;

namespace Cinder { namespace EDSDK {

CameraRef Camera::create(EdsCameraRef camera) {
    return CameraRef(new Camera(camera))->shared_from_this();
}

Camera::Camera(EdsCameraRef camera) {
    if (camera == NULL) {
        throw Exception();
    }

    EdsRetain(camera);
    mCamera = camera;

    EdsError error = EdsGetDeviceInfo(mCamera, &mDeviceInfo);
    if (error != EDS_ERR_OK) {
        console() << "ERROR - failed to get device info" << std::endl;
        // TODO - NULL out mDeviceInfo
    }

    mHasOpenSession = false;

    // set event handlers
    error = EdsSetObjectEventHandler(mCamera, kEdsObjectEvent_All, Camera::handleObjectEvent, this);
    if (error != EDS_ERR_OK) {
        console() << "ERROR - failed to set object event handler" << std::endl;
    }
    error = EdsSetPropertyEventHandler(mCamera, kEdsPropertyEvent_All, Camera::handlePropertyEvent, this);
    if (error != EDS_ERR_OK) {
        console() << "ERROR - failed to set property event handler" << std::endl;
    }
    error = EdsSetCameraStateEventHandler(mCamera, kEdsStateEvent_All, Camera::handleStateEvent, this);
    if (error != EDS_ERR_OK) {
        console() << "ERROR - failed to set object event handler" << std::endl;
    }
}

Camera::~Camera() {
    mHandler = NULL;

    if (mHasOpenSession) {
        requestCloseSession();
    }

    EdsRelease(mCamera);
    mCamera = NULL;
}

#pragma mark -

CameraHandler* Camera::getHandler() const {
    return mHandler;
}

void Camera::setHandler(CameraHandler* handler) {
    mHandler = handler;
}

std::string Camera::getName() const {
    return std::string(mDeviceInfo.szDeviceDescription);
}

std::string Camera::getPortName() const {
    return std::string(mDeviceInfo.szPortName);
}

bool Camera::hasOpenSession() const {
    return mHasOpenSession;
}

EdsError Camera::requestOpenSession(SessionSettings* settings) {
    if (mHasOpenSession) {
        return EDS_ERR_SESSION_ALREADY_OPEN;
    }

    EdsError error = EdsOpenSession(mCamera);
    if (error != EDS_ERR_OK) {
        console() << "ERROR - failed to open camera session" << std::endl;
        return error;
    }
    mHasOpenSession = true;

    EdsUInt32 saveTo = (settings != NULL) ? settings->getPictureSaveLocation() : kEdsSaveTo_Host;
    error = EdsSetPropertyData(mCamera, kEdsPropID_SaveTo, 0, sizeof(saveTo) , &saveTo);
    if (error != EDS_ERR_OK) {
        console() << "ERROR - failed to set save destination host/device" << std::endl;
        return error;
    }

    if (saveTo == kEdsSaveTo_Host || saveTo == kEdsSaveTo_Camera) {
        // TODO - EdsSetCapacity
    }

    mShouldKeepAlive = (settings != NULL) ? settings->getShouldKeepAlive() : mShouldKeepAlive;

    return EDS_ERR_OK;
}

EdsError Camera::requestCloseSession() {
    if (!mHasOpenSession) {
        return EDS_ERR_SESSION_NOT_OPEN;
    }

    EdsError error = EdsCloseSession(mCamera);
    if (error != EDS_ERR_OK) {
        console() << "ERROR - failed to close camera session" << std::endl;
        return error;
    }

    mHasOpenSession = false;
    return EDS_ERR_OK;
}

EdsError Camera::requestTakePicture(/*Options* options*/) {
    return EDS_ERR_UNIMPLEMENTED;
}

EdsError Camera::requestDownloadFile() {
    return EDS_ERR_UNIMPLEMENTED;
}

EdsError Camera::requestReadFile() {
    return EDS_ERR_UNIMPLEMENTED;
}

#pragma mark - CALLBACKS

EdsError EDSCALLBACK Camera::handleObjectEvent(EdsUInt32 inEvent, EdsBaseRef inRef, EdsVoid* inContext) {
    return EDS_ERR_OK;
}

EdsError EDSCALLBACK Camera::handlePropertyEvent(EdsUInt32 inEvent, EdsUInt32 inPropertyID, EdsUInt32 inParam, EdsVoid* inContext) {
    return EDS_ERR_OK;
}

EdsError EDSCALLBACK Camera::handleStateEvent(EdsUInt32 inEvent, EdsUInt32 inParam, EdsVoid* inContext) {
    Camera* camera = (Camera*)inContext;
    switch (inEvent) {
        case kEdsStateEvent_WillSoonShutDown:
            if (camera->mHasOpenSession && camera->mShouldKeepAlive) {
                EdsError error = EdsSendCommand(camera->mCamera, kEdsCameraCommand_ExtendShutDownTimer, 0);
                if (error != EDS_ERR_OK) {
                    console() << "ERROR - failed to extend shut down timer" << std::endl;
                }
            }
            break;
        case kEdsStateEvent_Shutdown:
            camera->mHandler->didRemoveCamera(camera);
            // TODO - how do we get this to the CameraBrowser, singleton?
            break;
        default:
            break;
    }

    return EDS_ERR_OK;
}

}}
<commit_msg>be sure to update session open state on camera disconnect<commit_after>//
//  Camera.cpp
//  Cinder-EDSDK
//
//  Created by Jean-Pierre Mouilleseaux on 08 Dec 2013.
//  Copyright 2013 Chorded Constructions. All rights reserved.
//

#include "Camera.h"

using namespace ci;
using namespace ci::app;

namespace Cinder { namespace EDSDK {

CameraRef Camera::create(EdsCameraRef camera) {
    return CameraRef(new Camera(camera))->shared_from_this();
}

Camera::Camera(EdsCameraRef camera) {
    if (camera == NULL) {
        throw Exception();
    }

    EdsRetain(camera);
    mCamera = camera;

    EdsError error = EdsGetDeviceInfo(mCamera, &mDeviceInfo);
    if (error != EDS_ERR_OK) {
        console() << "ERROR - failed to get device info" << std::endl;
        // TODO - NULL out mDeviceInfo
    }

    mHasOpenSession = false;

    // set event handlers
    error = EdsSetObjectEventHandler(mCamera, kEdsObjectEvent_All, Camera::handleObjectEvent, this);
    if (error != EDS_ERR_OK) {
        console() << "ERROR - failed to set object event handler" << std::endl;
    }
    error = EdsSetPropertyEventHandler(mCamera, kEdsPropertyEvent_All, Camera::handlePropertyEvent, this);
    if (error != EDS_ERR_OK) {
        console() << "ERROR - failed to set property event handler" << std::endl;
    }
    error = EdsSetCameraStateEventHandler(mCamera, kEdsStateEvent_All, Camera::handleStateEvent, this);
    if (error != EDS_ERR_OK) {
        console() << "ERROR - failed to set object event handler" << std::endl;
    }
}

Camera::~Camera() {
    mHandler = NULL;

    if (mHasOpenSession) {
        requestCloseSession();
    }

    EdsRelease(mCamera);
    mCamera = NULL;
}

#pragma mark -

CameraHandler* Camera::getHandler() const {
    return mHandler;
}

void Camera::setHandler(CameraHandler* handler) {
    mHandler = handler;
}

std::string Camera::getName() const {
    return std::string(mDeviceInfo.szDeviceDescription);
}

std::string Camera::getPortName() const {
    return std::string(mDeviceInfo.szPortName);
}

bool Camera::hasOpenSession() const {
    return mHasOpenSession;
}

EdsError Camera::requestOpenSession(SessionSettings* settings) {
    if (mHasOpenSession) {
        return EDS_ERR_SESSION_ALREADY_OPEN;
    }

    EdsError error = EdsOpenSession(mCamera);
    if (error != EDS_ERR_OK) {
        console() << "ERROR - failed to open camera session" << std::endl;
        return error;
    }
    mHasOpenSession = true;

    EdsUInt32 saveTo = (settings != NULL) ? settings->getPictureSaveLocation() : kEdsSaveTo_Host;
    error = EdsSetPropertyData(mCamera, kEdsPropID_SaveTo, 0, sizeof(saveTo) , &saveTo);
    if (error != EDS_ERR_OK) {
        console() << "ERROR - failed to set save destination host/device" << std::endl;
        return error;
    }

    if (saveTo == kEdsSaveTo_Host || saveTo == kEdsSaveTo_Camera) {
        // TODO - EdsSetCapacity
    }

    mShouldKeepAlive = (settings != NULL) ? settings->getShouldKeepAlive() : mShouldKeepAlive;

    return EDS_ERR_OK;
}

EdsError Camera::requestCloseSession() {
    if (!mHasOpenSession) {
        return EDS_ERR_SESSION_NOT_OPEN;
    }

    EdsError error = EdsCloseSession(mCamera);
    if (error != EDS_ERR_OK) {
        console() << "ERROR - failed to close camera session" << std::endl;
        return error;
    }

    mHasOpenSession = false;
    return EDS_ERR_OK;
}

EdsError Camera::requestTakePicture(/*Options* options*/) {
    return EDS_ERR_UNIMPLEMENTED;
}

EdsError Camera::requestDownloadFile() {
    return EDS_ERR_UNIMPLEMENTED;
}

EdsError Camera::requestReadFile() {
    return EDS_ERR_UNIMPLEMENTED;
}

#pragma mark - CALLBACKS

EdsError EDSCALLBACK Camera::handleObjectEvent(EdsUInt32 inEvent, EdsBaseRef inRef, EdsVoid* inContext) {
    return EDS_ERR_OK;
}

EdsError EDSCALLBACK Camera::handlePropertyEvent(EdsUInt32 inEvent, EdsUInt32 inPropertyID, EdsUInt32 inParam, EdsVoid* inContext) {
    return EDS_ERR_OK;
}

EdsError EDSCALLBACK Camera::handleStateEvent(EdsUInt32 inEvent, EdsUInt32 inParam, EdsVoid* inContext) {
    Camera* camera = (Camera*)inContext;
    switch (inEvent) {
        case kEdsStateEvent_WillSoonShutDown:
            if (camera->mHasOpenSession && camera->mShouldKeepAlive) {
                EdsError error = EdsSendCommand(camera->mCamera, kEdsCameraCommand_ExtendShutDownTimer, 0);
                if (error != EDS_ERR_OK) {
                    console() << "ERROR - failed to extend shut down timer" << std::endl;
                }
            }
            break;
        case kEdsStateEvent_Shutdown:
            camera->mHasOpenSession = false;
            camera->mHandler->didRemoveCamera(camera);
            // TODO - how do we get this to the CameraBrowser, singleton?
            break;
        default:
            break;
    }

    return EDS_ERR_OK;
}

}}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016, Egor Pugin
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     1. Redistributions of source code must retain the above copyright
 *        notice, this list of conditions and the following disclaimer.
 *     2. Redistributions in binary form must reproduce the above copyright
 *        notice, this list of conditions and the following disclaimer in the
 *        documentation and/or other materials provided with the distribution.
 *     3. Neither the name of the copyright holder 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 HOLDER 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.
 */

void Checks::load(const yaml &root)
{
    auto load_string_set = [&root](auto &a, auto &&str)
    {
        auto s = get_sequence<String>(root, str);
        a.insert(s.begin(), s.end());
    };

    auto load_string_map = [&root](auto &a, auto &&str)
    {
        get_map_and_iterate(root, str, [&a](const auto &v)
        {
            auto f = v.first.template as<String>();
            auto s = v.second.template as<String>();
            a[f] = s;
        });
    };

    load_string_set(functions, "check_function_exists");
    load_string_set(includes, "check_include_exists");
    load_string_set(types, "check_type_size");
    load_string_set(libraries, "check_library_exists");

    // add some common types
    types.insert("size_t");
    types.insert("void *");

    get_map_and_iterate(root, "check_symbol_exists", [this](const auto &root)
    {
        auto f = root.first.template as<String>();
        auto s = root.second.template as<String>();
        if (root.second.IsSequence())
            symbols[f] = get_sequence_set<String>(root.second);
        else if (root.second.IsScalar())
            symbols[f].insert(s);
        else
            throw std::runtime_error("Symbol headers should be a scalar or a set");
    });

#define LOAD_MAP(x) load_string_map(x, "check_" ## #x)
    LOAD_MAP(c_source_compiles);
    LOAD_MAP(c_source_runs);
    LOAD_MAP(cxx_source_compiles);
    LOAD_MAP(cxx_source_runs);
#undef LOAD_MAP
    load_string_map(custom, "checks");
}

bool Checks::empty() const
{
#define CHECK_ACTION(array) && array.empty()
    return 1
#include "checks.inl"
        ;
#undef CHECK_ACTION
}

void Checks::merge(const Checks &rhs)
{
#define CHECK_ACTION(array) array.insert(rhs.array.begin(), rhs.array.end());
#include "checks.inl"
#undef CHECK_ACTION
}
<commit_msg>Switch to polymorphic checks.<commit_after>/*
 * Copyright (c) 2016, Egor Pugin
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     1. Redistributions of source code must retain the above copyright
 *        notice, this list of conditions and the following disclaimer.
 *     2. Redistributions in binary form must reproduce the above copyright
 *        notice, this list of conditions and the following disclaimer in the
 *        documentation and/or other materials provided with the distribution.
 *     3. Neither the name of the copyright holder 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 HOLDER 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.
 */

struct CheckFunction : public CheckData {};
struct CheckInclude : public CheckData {};
struct CheckType : public CheckData {};
struct CheckSymbol : public CheckData {};
struct CheckLibrary : public CheckData {};
struct CheckCSourceCompiles : public CheckData {};
struct CheckCSourceRuns : public CheckData {};
struct CheckCXXSourceCompiles : public CheckData {};
struct CheckCXXSourceRuns : public CheckData {};
struct CheckCustom : public CheckData {};

void Checks::load(const yaml &root)
{
    auto load_string_set = [&root](auto &a, auto &&str)
    {
        auto s = get_sequence<String>(root, str);
        a.insert(s.begin(), s.end());
    };

    auto load_string_map = [&root](auto &a, auto &&str)
    {
        get_map_and_iterate(root, str, [&a](const auto &v)
        {
            auto f = v.first.template as<String>();
            auto s = v.second.template as<String>();
            a[f] = s;
        });
    };

    load_string_set(functions, "check_function_exists");
    load_string_set(includes, "check_include_exists");
    load_string_set(types, "check_type_size");
    load_string_set(libraries, "check_library_exists");

    // add some common types
    types.insert("size_t");
    types.insert("void *");

    get_map_and_iterate(root, "check_symbol_exists", [this](const auto &root)
    {
        auto f = root.first.template as<String>();
        auto s = root.second.template as<String>();
        if (root.second.IsSequence())
            symbols[f] = get_sequence_set<String>(root.second);
        else if (root.second.IsScalar())
            symbols[f].insert(s);
        else
            throw std::runtime_error("Symbol headers should be a scalar or a set");
    });

#define LOAD_MAP(x) load_string_map(x, "check_" ## #x)
    LOAD_MAP(c_source_compiles);
    LOAD_MAP(c_source_runs);
    LOAD_MAP(cxx_source_compiles);
    LOAD_MAP(cxx_source_runs);
#undef LOAD_MAP
    load_string_map(custom, "checks");
}

bool Checks::empty() const
{
#define CHECK_ACTION(array) && array.empty()
    return 1
#include "checks.inl"
        ;
#undef CHECK_ACTION
}

void Checks::merge(const Checks &rhs)
{
#define CHECK_ACTION(array) array.insert(rhs.array.begin(), rhs.array.end());
#include "checks.inl"
#undef CHECK_ACTION
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2013.
// 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)
//=======================================================================

#include <string>
#include <iostream>

#include "config.hpp"
#include "args.hpp"
#include "budget_exception.hpp"

#include "debts.hpp"
#include "accounts.hpp"
#include "expenses.hpp"
#include "overview.hpp"

using namespace budget;

int main(int argc, const char* argv[]) {
    //Verify that the data folder exists
    if(!verify_folder()){
        return 0;
    }

    if(argc == 1){
        month_overview();
    } else {
        auto args = parse_args(argc, argv);

        auto& command = args[0];

        try {
            if(command == "help"){
                std::cout << "Usage: budget command [options]" << std::endl;

                //TODO Display complete help
            } else if(command == "debt"){
                handle_debts(args);
            } else if(command == "account"){
                handle_accounts(args);
            } else if(command == "expense"){
                handle_expenses(args);
            } else {
                std::cout << "Unhandled command \"" << command << "\"" << std::endl;

                return 1;
            }
        } catch (const budget_exception& exception){
            std::cout << exception.message() << std::endl;

            return 1;
        }
    }

    return 0;
}
<commit_msg>Handle overview module<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2013.
// 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)
//=======================================================================

#include <string>
#include <iostream>

#include "config.hpp"
#include "args.hpp"
#include "budget_exception.hpp"

#include "debts.hpp"
#include "accounts.hpp"
#include "expenses.hpp"
#include "overview.hpp"

using namespace budget;

int main(int argc, const char* argv[]) {
    //Verify that the data folder exists
    if(!verify_folder()){
        return 0;
    }

    if(argc == 1){
        month_overview();
    } else {
        auto args = parse_args(argc, argv);

        auto& command = args[0];

        try {
            if(command == "help"){
                std::cout << "Usage: budget command [options]" << std::endl;

                //TODO Display complete help
            } else if(command == "debt"){
                handle_debts(args);
            } else if(command == "account"){
                handle_accounts(args);
            } else if(command == "expense"){
                handle_expenses(args);
            } else if(command == "overview"){
                handle_overview(args);
            } else {
                std::cout << "Unhandled command \"" << command << "\"" << std::endl;

                return 1;
            }
        } catch (const budget_exception& exception){
            std::cout << exception.message() << std::endl;

            return 1;
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>#include <array>

#include "builtin.hh"
#include "util.hh"
#include "number.hh"
#include "procedure.hh"
#include "lisp_ptr.hh"
#include "eval.hh"
#include "builtin_util.hh"
#include "printer.hh"

using namespace std;
using namespace Procedure;

namespace {

void plus_2(){
  auto args = pick_args<2>();

  VM.return_value = {};

  Number* n1 = args[0].get<Number*>();
  if(!n1){
    fprintf(zs::err, "native func '+': first arg is not number! %s\n",
            stringify(args[0].tag()));
    return;
  }

  Number* n2 = args[1].get<Number*>();
  if(!n2){
    fprintf(zs::err, "native func '+': second arg is not number! %s\n",
            stringify(args[1].tag()));
    return;
  }

  Number* newn = new Number(n1->get<long>() + n2->get<long>());
  VM.return_value = Lisp_ptr(newn);
}

template <Ptr_tag p>
void type_check_pred(){
  auto arg = pick_args_1();
  VM.return_value = Lisp_ptr{arg.tag() == p};
}

void type_check_pair(){
  auto arg = pick_args_1();
  VM.return_value = Lisp_ptr{(arg.tag() == Ptr_tag::cons) && !nullp(arg)};
}

void type_check_procedure(){
  auto arg = pick_args_1();
  VM.return_value = Lisp_ptr{(arg.tag() == Ptr_tag::i_procedure)
                             || (arg.tag() == Ptr_tag::n_procedure)};
}

Lisp_ptr whole_macro_or_expand(Cons* c){
  if(!c->cdr() || nullp(c->cdr())){
    return c->car();
  }

  const auto if_sym = intern(VM.symtable, "if");
  auto else_clause = whole_macro_or_expand(c->cdr().get<Cons*>());

  return make_cons_list({Lisp_ptr(if_sym),
        c->car(),
        Lisp_ptr(vm_op_nop),
        else_clause});
}

Lisp_ptr whole_macro_and_expand(Cons* c){
  if(!c->cdr() || nullp(c->cdr())){
    return c->car();
  }

  const auto if_sym = intern(VM.symtable, "if");
  auto then_clause = whole_macro_and_expand(c->cdr().get<Cons*>());

  return make_cons_list({Lisp_ptr(if_sym),
        c->car(),
        then_clause,
        Lisp_ptr(vm_op_nop)});
}

Lisp_ptr whole_macro_cond_expand(Cons* head){
  if(!head) return {}; // unspecified in R5RS.

  auto clause = head->car();
  if(!clause.get<Cons*>()){
    fprintf(zs::err, "macro cond: informal clause syntax! '");
    print(zs::err, head->car());
    fprintf(zs::err, "'\n");
    return {};
  }

  Lisp_ptr test_form;
  Lisp_ptr then_form;

  int ret = bind_cons_list(clause,
                           [&](Cons* c){
                             test_form = c->car();
                             if(nullp(c->cdr())){
                               then_form = Lisp_ptr(vm_op_nop);
                             }
                           },
                           [&](Cons* c){
                             if(auto sym = c->car().get<Symbol*>()){
                               if(sym->name() == "=>"){
                                 fprintf(zs::err, "macto cond: sorry, cond's => syntax is not implemented..\n");
                                 then_form = {};
                                 return;
                               }
                             }
                             then_form = push_cons_list(Lisp_ptr(intern(VM.symtable, "begin")), Lisp_ptr(c));
                           });
  assert(ret >= 1); // should be handled by previous tests.
  (void)ret;

  if(auto sym = test_form.get<Symbol*>()){
    if(sym->name() == "else"){
      return then_form;
    }
  }

  const auto if_sym = intern(VM.symtable, "if");
  auto else_form = whole_macro_cond_expand(head->cdr().get<Cons*>());

  return make_cons_list({Lisp_ptr(if_sym),
        test_form,
        then_form,
        else_form});
}

template<typename T, typename Expander>
inline
void whole_macro_conditional(T default_value, Expander e){
  auto arg = pick_args_1();
  if(!arg) return;

  Cons* head;

  int len = bind_cons_list(arg,
                           [](Cons*){},
                           [&](Cons* c){
                             head = c;
                           });
  if(len < 2){
    VM.return_value = Lisp_ptr(default_value);
    return;
  }

  VM.return_value = e(head);
}

void whole_macro_and(){
  whole_macro_conditional(true, whole_macro_and_expand);
}

void whole_macro_or(){
  whole_macro_conditional(false, whole_macro_or_expand);
}

void whole_macro_cond(){
  whole_macro_conditional(Lisp_ptr{}, whole_macro_cond_expand);
}

Lisp_ptr whole_macro_case_keys_expand(Symbol* sym, Cons* keys){
  const auto eqv_sym = intern(VM.symtable, "eqv?");
  auto eqv_expr = make_cons_list({Lisp_ptr(eqv_sym), Lisp_ptr(sym), keys->car()});

  if(!keys->cdr() || nullp(keys->cdr())){
    return eqv_expr;
  }

  const auto if_sym = intern(VM.symtable, "if");
  auto else_clause = whole_macro_case_keys_expand(sym, keys->cdr().get<Cons*>());

  return make_cons_list({Lisp_ptr(if_sym),
        eqv_expr,
        Lisp_ptr(true),
        else_clause});
}

Lisp_ptr whole_macro_case_expand(Symbol* sym, Lisp_ptr cases_ptr){
  if(cases_ptr.tag() != Ptr_tag::cons){
    fprintf(zs::err, "macro case: informal case syntax (dot-list?): ");
    print(zs::err, cases_ptr);
    fputc('\n', zs::err);
    return {};
  }

  auto cases = cases_ptr.get<Cons*>();
  if(!cases)
    return Cons::NIL;

  auto clause = cases->car().get<Cons*>();
  if(!clause){
    fprintf(zs::err, "macro case: informal clause contained: ");
    print(zs::err, cases->car());
    fputc('\n', zs::err);
    return {};
  }

  auto keys_ptr = clause->car();
  Symbol* keys_sym;
  Lisp_ptr new_keys;

  if(auto keys_lst = keys_ptr.get<Cons*>()){
    new_keys = whole_macro_case_keys_expand(sym, keys_lst);
  }else if((keys_sym = keys_ptr.get<Symbol*>())
           && keys_sym->name() == "else"){
    new_keys = keys_ptr;
  }else{
    fprintf(zs::err, "macro case: informal clause key: ");
    print(zs::err, keys_ptr);
    fputc('\n', zs::err);
    return {};
  }

  auto new_clause = new Cons(new_keys, clause->cdr());

  return Lisp_ptr(new Cons(Lisp_ptr(new_clause),
                           whole_macro_case_expand(sym, cases->cdr())));
}

void whole_macro_case(){
  auto arg = pick_args_1();
  if(!arg) return;

  Lisp_ptr key, clauses;

  int len = bind_cons_list(arg,
                           [](Cons*){},
                           [&](Cons* c){
                             key = c->car();
                             clauses = c->cdr();
                           });
  if(len < 3){
    fprintf(zs::err, "macro case: invalid syntax! (no key found)\n");
    VM.return_value = Lisp_ptr();
    return;
  }

  // TODO: collect this by garbage collector!
  auto key_sym = new Symbol(new string("case_key_symbol"));

  VM.return_value =
    make_cons_list({Lisp_ptr(intern(VM.symtable, "let")),
          make_cons_list({
              make_cons_list({Lisp_ptr(key_sym),key})
                }),
          Lisp_ptr(new Cons(Lisp_ptr(intern(VM.symtable, "cond")),
                            whole_macro_case_expand(key_sym, clauses)))
          });
}

bool eq_internal(Lisp_ptr a, Lisp_ptr b){
  if(a.tag() != b.tag()) return false;

  if(a.tag() == Ptr_tag::boolean){
    return a.get<bool>() == b.get<bool>();
  }else if(a.tag() == Ptr_tag::character){
     // this can be moved into eqv? in R5RS, but char is contained in Lisp_ptr.
    return a.get<char>() == b.get<char>();
  }else{
    return a.get<void*>() == b.get<void*>();
  }
}

bool eqv_internal(Lisp_ptr a, Lisp_ptr b){
  if(a.tag() == Ptr_tag::number && b.tag() == Ptr_tag::number){
    return eqv(*a.get<Number*>(), *b.get<Number*>());
  }else{
    return eq_internal(a, b);
  }
}

void eq(){
  auto args = pick_args<2>();
  VM.return_value = Lisp_ptr{eq_internal(args[0], args[1])};
}

void eqv(){
  auto args = pick_args<2>();
  VM.return_value = Lisp_ptr{eqv_internal(args[0], args[1])};
}

void eval_func(){
  auto args = pick_args<2>();

  // TODO: uses arg2 as Env struct.
  VM.code.push(args[0]);
}

constexpr struct Entry {
  const char* name;
  const NProcedure func;

  constexpr Entry(const char* n, const NProcedure& f)
    : name(n), func(f){}
} builtin_func[] = {
  // syntaxes
  {"quote", {
      whole_function_quote,
      Calling::whole_function, {1, false}}},
  {"lambda", {
      whole_function_lambda,
      Calling::whole_function, {1, true}}},
  {"if", {
      whole_function_if,
      Calling::whole_function, {3, false}}},
  {"set!", {
      whole_function_set,
      Calling::whole_function, {2, false}}},
  {"define", {
      whole_function_define,
      Calling::whole_function, {2, true}}},
  {"quasiquote", {
      whole_function_quasiquote,
      Calling::whole_function, {1, false}}},
  {"begin", {
      whole_function_begin,
      Calling::whole_function, {1, true}}},

  {"cond", {
      whole_macro_cond,
      Calling::whole_macro, {1, true}}},
  {"case", {
      whole_macro_case,
      Calling::whole_macro, {2, true}}},
  {"and", {
      whole_macro_and,
      Calling::whole_macro, {0, true}}},
  {"or", {
      whole_macro_or,
      Calling::whole_macro, {0, true}}},
  {"let", {
      whole_function_let,
      Calling::whole_function, {1, true}}},
  {"let*", {
      whole_function_let_star,
      Calling::whole_function, {1, true}}},
  {"letrec", {
      whole_function_letrec,
      Calling::whole_function, {1, true}}},
  {"do", {
      whole_function_unimplemented,
      Calling::whole_function, {0, true}}},
  {"delay", {
      whole_function_unimplemented,
      Calling::whole_function, {0, true}}},

  {"unquote", {
      whole_function_pass_through,
      Calling::whole_function, {0, true}}},
  {"unquote-splicing", {
      whole_function_pass_through,
      Calling::whole_function, {0, true}}},
  {"else", {
      whole_function_error,
      Calling::whole_function, {0, false}}},
  {"=>", {
      whole_function_error,
      Calling::whole_function, {0, false}}},

  // functions
  {"+", {
      plus_2,
      Calling::function, {2, true}}},
  {"list", {
      procedure_list,
      Calling::function, {1, true}}},
  {"list*", {
      procedure_list_star,
      Calling::function, {1, true}}},
  {"vector", {
      procedure_vector,
      Calling::function, {1, true}}},
  {"boolean?", {
      type_check_pred<Ptr_tag::boolean>,
      Calling::function, {1, false}}},
  {"symbol?", {
      type_check_pred<Ptr_tag::symbol>,
      Calling::function, {1, false}}},
  {"char?", {
      type_check_pred<Ptr_tag::character>,
      Calling::function, {1, false}}},
  {"vector?", {
      type_check_pred<Ptr_tag::vector>,
      Calling::function, {1, false}}},
  {"procedure?", {
      type_check_procedure,
      Calling::function, {1, false}}},
  {"pair?", {
      type_check_pair,
      Calling::function, {1, false}}},
  {"number?", {
      type_check_pred<Ptr_tag::number>,
      Calling::function, {1, false}}},
  {"string?", {
      type_check_pred<Ptr_tag::string>,
      Calling::function, {1, false}}},
  {"port?", {
      type_check_pred<Ptr_tag::port>,
      Calling::function, {1, false}}},
  {"eqv?", {
      eqv,
      Calling::function, {2, false}}},
  {"eq?", {
      eq,
      Calling::function, {2, false}}},
  {"eval", {
      eval_func,
      Calling::function, {2, false}}}
};

} //namespace

void install_builtin(){
  for(auto& e : builtin_func){
    VM.set(intern(VM.symtable, e.name), Lisp_ptr{&e.func});
  }
}
<commit_msg>removed redundant contructor call<commit_after>#include <array>

#include "builtin.hh"
#include "util.hh"
#include "number.hh"
#include "procedure.hh"
#include "lisp_ptr.hh"
#include "eval.hh"
#include "builtin_util.hh"
#include "printer.hh"

using namespace std;
using namespace Procedure;

namespace {

void plus_2(){
  auto args = pick_args<2>();

  VM.return_value = {};

  Number* n1 = args[0].get<Number*>();
  if(!n1){
    fprintf(zs::err, "native func '+': first arg is not number! %s\n",
            stringify(args[0].tag()));
    return;
  }

  Number* n2 = args[1].get<Number*>();
  if(!n2){
    fprintf(zs::err, "native func '+': second arg is not number! %s\n",
            stringify(args[1].tag()));
    return;
  }

  Number* newn = new Number(n1->get<long>() + n2->get<long>());
  VM.return_value = newn;
}

template <Ptr_tag p>
void type_check_pred(){
  auto arg = pick_args_1();
  VM.return_value = Lisp_ptr{arg.tag() == p};
}

void type_check_pair(){
  auto arg = pick_args_1();
  VM.return_value = Lisp_ptr{(arg.tag() == Ptr_tag::cons) && !nullp(arg)};
}

void type_check_procedure(){
  auto arg = pick_args_1();
  VM.return_value = Lisp_ptr{(arg.tag() == Ptr_tag::i_procedure)
                             || (arg.tag() == Ptr_tag::n_procedure)};
}

Lisp_ptr whole_macro_or_expand(Cons* c){
  if(!c->cdr() || nullp(c->cdr())){
    return c->car();
  }

  const auto if_sym = intern(VM.symtable, "if");
  auto else_clause = whole_macro_or_expand(c->cdr().get<Cons*>());

  return make_cons_list({if_sym,
        c->car(),
        vm_op_nop,
        else_clause});
}

Lisp_ptr whole_macro_and_expand(Cons* c){
  if(!c->cdr() || nullp(c->cdr())){
    return c->car();
  }

  const auto if_sym = intern(VM.symtable, "if");
  auto then_clause = whole_macro_and_expand(c->cdr().get<Cons*>());

  return make_cons_list({if_sym,
        c->car(),
        then_clause,
        vm_op_nop});
}

Lisp_ptr whole_macro_cond_expand(Cons* head){
  if(!head) return {}; // unspecified in R5RS.

  auto clause = head->car();
  if(!clause.get<Cons*>()){
    fprintf(zs::err, "macro cond: informal clause syntax! '");
    print(zs::err, head->car());
    fprintf(zs::err, "'\n");
    return {};
  }

  Lisp_ptr test_form;
  Lisp_ptr then_form;

  int ret = bind_cons_list(clause,
                           [&](Cons* c){
                             test_form = c->car();
                             if(nullp(c->cdr())){
                               then_form = vm_op_nop;
                             }
                           },
                           [&](Cons* c){
                             if(auto sym = c->car().get<Symbol*>()){
                               if(sym->name() == "=>"){
                                 fprintf(zs::err, "macto cond: sorry, cond's => syntax is not implemented..\n");
                                 then_form = {};
                                 return;
                               }
                             }
                             then_form = push_cons_list(intern(VM.symtable, "begin"), c);
                           });
  assert(ret >= 1); // should be handled by previous tests.
  (void)ret;

  if(auto sym = test_form.get<Symbol*>()){
    if(sym->name() == "else"){
      return then_form;
    }
  }

  const auto if_sym = intern(VM.symtable, "if");
  auto else_form = whole_macro_cond_expand(head->cdr().get<Cons*>());

  return make_cons_list({if_sym,
        test_form,
        then_form,
        else_form});
}

template<typename T, typename Expander>
inline
void whole_macro_conditional(T default_value, Expander e){
  auto arg = pick_args_1();
  if(!arg) return;

  Cons* head;

  int len = bind_cons_list(arg,
                           [](Cons*){},
                           [&](Cons* c){
                             head = c;
                           });
  if(len < 2){
    VM.return_value = Lisp_ptr(default_value);
    return;
  }

  VM.return_value = e(head);
}

void whole_macro_and(){
  whole_macro_conditional(true, whole_macro_and_expand);
}

void whole_macro_or(){
  whole_macro_conditional(false, whole_macro_or_expand);
}

void whole_macro_cond(){
  whole_macro_conditional(Lisp_ptr{}, whole_macro_cond_expand);
}

Lisp_ptr whole_macro_case_keys_expand(Symbol* sym, Cons* keys){
  const auto eqv_sym = intern(VM.symtable, "eqv?");
  auto eqv_expr = make_cons_list({eqv_sym, sym, keys->car()});

  if(!keys->cdr() || nullp(keys->cdr())){
    return eqv_expr;
  }

  const auto if_sym = intern(VM.symtable, "if");
  auto else_clause = whole_macro_case_keys_expand(sym, keys->cdr().get<Cons*>());

  return make_cons_list({if_sym,
        eqv_expr,
        Lisp_ptr(true),
        else_clause});
}

Lisp_ptr whole_macro_case_expand(Symbol* sym, Lisp_ptr cases_ptr){
  if(cases_ptr.tag() != Ptr_tag::cons){
    fprintf(zs::err, "macro case: informal case syntax (dot-list?): ");
    print(zs::err, cases_ptr);
    fputc('\n', zs::err);
    return {};
  }

  auto cases = cases_ptr.get<Cons*>();
  if(!cases)
    return Cons::NIL;

  auto clause = cases->car().get<Cons*>();
  if(!clause){
    fprintf(zs::err, "macro case: informal clause contained: ");
    print(zs::err, cases->car());
    fputc('\n', zs::err);
    return {};
  }

  auto keys_ptr = clause->car();
  Symbol* keys_sym;
  Lisp_ptr new_keys;

  if(auto keys_lst = keys_ptr.get<Cons*>()){
    new_keys = whole_macro_case_keys_expand(sym, keys_lst);
  }else if((keys_sym = keys_ptr.get<Symbol*>())
           && keys_sym->name() == "else"){
    new_keys = keys_ptr;
  }else{
    fprintf(zs::err, "macro case: informal clause key: ");
    print(zs::err, keys_ptr);
    fputc('\n', zs::err);
    return {};
  }

  auto new_clause = new Cons(new_keys, clause->cdr());

  return {new Cons(new_clause,
                   whole_macro_case_expand(sym, cases->cdr()))};
}

void whole_macro_case(){
  auto arg = pick_args_1();
  if(!arg) return;

  Lisp_ptr key, clauses;

  int len = bind_cons_list(arg,
                           [](Cons*){},
                           [&](Cons* c){
                             key = c->car();
                             clauses = c->cdr();
                           });
  if(len < 3){
    fprintf(zs::err, "macro case: invalid syntax! (no key found)\n");
    VM.return_value = Lisp_ptr();
    return;
  }

  // TODO: collect this by garbage collector!
  auto key_sym = new Symbol(new string("case_key_symbol"));

  VM.return_value =
    make_cons_list({intern(VM.symtable, "let"),
          make_cons_list({
              make_cons_list({key_sym, key})
                }),
          new Cons(intern(VM.symtable, "cond"),
                   whole_macro_case_expand(key_sym, clauses))
          });
}

bool eq_internal(Lisp_ptr a, Lisp_ptr b){
  if(a.tag() != b.tag()) return false;

  if(a.tag() == Ptr_tag::boolean){
    return a.get<bool>() == b.get<bool>();
  }else if(a.tag() == Ptr_tag::character){
     // this can be moved into eqv? in R5RS, but char is contained in Lisp_ptr.
    return a.get<char>() == b.get<char>();
  }else{
    return a.get<void*>() == b.get<void*>();
  }
}

bool eqv_internal(Lisp_ptr a, Lisp_ptr b){
  if(a.tag() == Ptr_tag::number && b.tag() == Ptr_tag::number){
    return eqv(*a.get<Number*>(), *b.get<Number*>());
  }else{
    return eq_internal(a, b);
  }
}

void eq(){
  auto args = pick_args<2>();
  VM.return_value = Lisp_ptr{eq_internal(args[0], args[1])};
}

void eqv(){
  auto args = pick_args<2>();
  VM.return_value = Lisp_ptr{eqv_internal(args[0], args[1])};
}

void eval_func(){
  auto args = pick_args<2>();

  // TODO: uses arg2 as Env struct.
  VM.code.push(args[0]);
}

constexpr struct Entry {
  const char* name;
  const NProcedure func;

  constexpr Entry(const char* n, const NProcedure& f)
    : name(n), func(f){}
} builtin_func[] = {
  // syntaxes
  {"quote", {
      whole_function_quote,
      Calling::whole_function, {1, false}}},
  {"lambda", {
      whole_function_lambda,
      Calling::whole_function, {1, true}}},
  {"if", {
      whole_function_if,
      Calling::whole_function, {3, false}}},
  {"set!", {
      whole_function_set,
      Calling::whole_function, {2, false}}},
  {"define", {
      whole_function_define,
      Calling::whole_function, {2, true}}},
  {"quasiquote", {
      whole_function_quasiquote,
      Calling::whole_function, {1, false}}},
  {"begin", {
      whole_function_begin,
      Calling::whole_function, {1, true}}},

  {"cond", {
      whole_macro_cond,
      Calling::whole_macro, {1, true}}},
  {"case", {
      whole_macro_case,
      Calling::whole_macro, {2, true}}},
  {"and", {
      whole_macro_and,
      Calling::whole_macro, {0, true}}},
  {"or", {
      whole_macro_or,
      Calling::whole_macro, {0, true}}},
  {"let", {
      whole_function_let,
      Calling::whole_function, {1, true}}},
  {"let*", {
      whole_function_let_star,
      Calling::whole_function, {1, true}}},
  {"letrec", {
      whole_function_letrec,
      Calling::whole_function, {1, true}}},
  {"do", {
      whole_function_unimplemented,
      Calling::whole_function, {0, true}}},
  {"delay", {
      whole_function_unimplemented,
      Calling::whole_function, {0, true}}},

  {"unquote", {
      whole_function_pass_through,
      Calling::whole_function, {0, true}}},
  {"unquote-splicing", {
      whole_function_pass_through,
      Calling::whole_function, {0, true}}},
  {"else", {
      whole_function_error,
      Calling::whole_function, {0, false}}},
  {"=>", {
      whole_function_error,
      Calling::whole_function, {0, false}}},

  // functions
  {"+", {
      plus_2,
      Calling::function, {2, true}}},
  {"list", {
      procedure_list,
      Calling::function, {1, true}}},
  {"list*", {
      procedure_list_star,
      Calling::function, {1, true}}},
  {"vector", {
      procedure_vector,
      Calling::function, {1, true}}},
  {"boolean?", {
      type_check_pred<Ptr_tag::boolean>,
      Calling::function, {1, false}}},
  {"symbol?", {
      type_check_pred<Ptr_tag::symbol>,
      Calling::function, {1, false}}},
  {"char?", {
      type_check_pred<Ptr_tag::character>,
      Calling::function, {1, false}}},
  {"vector?", {
      type_check_pred<Ptr_tag::vector>,
      Calling::function, {1, false}}},
  {"procedure?", {
      type_check_procedure,
      Calling::function, {1, false}}},
  {"pair?", {
      type_check_pair,
      Calling::function, {1, false}}},
  {"number?", {
      type_check_pred<Ptr_tag::number>,
      Calling::function, {1, false}}},
  {"string?", {
      type_check_pred<Ptr_tag::string>,
      Calling::function, {1, false}}},
  {"port?", {
      type_check_pred<Ptr_tag::port>,
      Calling::function, {1, false}}},
  {"eqv?", {
      eqv,
      Calling::function, {2, false}}},
  {"eq?", {
      eq,
      Calling::function, {2, false}}},
  {"eval", {
      eval_func,
      Calling::function, {2, false}}}
};

} //namespace

void install_builtin(){
  for(auto& e : builtin_func){
    VM.set(intern(VM.symtable, e.name), {&e.func});
  }
}
<|endoftext|>


<commit_before>#include "TriacDimmer.h"
#include <Arduino.h>
#include <assert.h>
#include <util/atomic.h>

uint16_t TriacDimmer::detail::pulse_length;
uint16_t TriacDimmer::detail::min_trigger;
float TriacDimmer::detail::on_thresh;
float TriacDimmer::detail::off_thresh;

volatile bool TriacDimmer::detail::ch_A_en;
volatile uint16_t TriacDimmer::detail::ch_A_up;
volatile uint16_t TriacDimmer::detail::ch_A_dn;
volatile uint16_t ch_A_dn_buf;

volatile bool TriacDimmer::detail::ch_B_en;
volatile uint16_t TriacDimmer::detail::ch_B_up;
volatile uint16_t TriacDimmer::detail::ch_B_dn;
volatile uint16_t ch_B_dn_buf;

volatile uint16_t TriacDimmer::detail::period = 16667;

void TriacDimmer::begin(uint16_t pulse_length, uint16_t min_trigger, float on_thresh, float off_thresh){
	// Don't need atomic writes since the ISRs haven't started yet.
	TriacDimmer::detail::pulse_length = pulse_length;
	TriacDimmer::detail::min_trigger = min_trigger;
	TriacDimmer::detail::on_thresh = on_thresh;
	TriacDimmer::detail::off_thresh = off_thresh;

	TCCR1A = 0;
	TCCR1B = _BV(ICNC1)  //input capture noise cancel
			| _BV(ICES1) //positive edge
			| _BV(CS11); // /8 prescaler

	pinMode(8, INPUT);

	TIFR1 = _BV(ICF1); //clear IC interrupt flag
	TIMSK1 = _BV(ICIE1); //enable input capture interrupt
}

void TriacDimmer::end(){
	TIMSK1 = 0; //disable the interrupts first!
	TIFR1 = 0xFF; //clear all flags
	TCCR1A = 0; //clear to reset state
	TCCR1B = 0;
}

void TriacDimmer::setBrightness(uint8_t pin, float value){
	assert(pin == 9 || pin == 10);

	if (value > TriacDimmer::detail::on_thresh) {
		digitalWrite(pin, HIGH);
		TriacDimmer::disable(pin);
	} else if (value < TriacDimmer::detail::off_thresh) {
		digitalWrite(pin, HIGH);
		TriacDimmer::disable(pin);
	} else {
		if ((pin & 0x01) == 0x01){ // if (pin == 9){
			TriacDimmer::detail::setChannelA(1 - value);
			TriacDimmer::detail::ch_A_en = true;
		} else { // if (pin == 10){
			TriacDimmer::detail::setChannelB(1 - value);
			TriacDimmer::detail::ch_B_en = true;
		}
	}
	pinMode(pin, OUTPUT); // only set to output once configured.
}

void TriacDimmer::disable(uint8_t pin) {
	assert(pin == 9 || pin == 10);

	if ((pin & 0x01) == 0x01){ // if (pin == 9){
		TriacDimmer::detail::disableChannelA();
	} else { // if (pin == 10){
		TriacDimmer::detail::disableChannelB();
	}
}

float TriacDimmer::getCurrentBrightness(uint8_t pin){
	assert(pin == 9 || pin == 10);

	if ((pin & 0x01) == 0x01){ // if (pin == 9){
		return 1 - TriacDimmer::detail::getChannelA();
	} else { // if (pin == 10){
		return 1 - TriacDimmer::detail::getChannelB();
	}
}

void TriacDimmer::detail::setChannelA(float value){
	uint16_t p, u, d;
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		// Don't need atomic read for pulse_length or min_trigger since they're not updated from an ISR.
		p = TriacDimmer::detail::period;
	}
	u = p * value;
	d = constrain(u + TriacDimmer::detail::pulse_length, TriacDimmer::detail::min_trigger, p);
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		TriacDimmer::detail::ch_A_up = u;
		TriacDimmer::detail::ch_A_dn = d;
	}
}

void TriacDimmer::detail::setChannelB(float value){
	uint16_t p, u, d;
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		// Don't need atomic read for pulse_length or min_trigger since they're not updated from an ISR.
		p = TriacDimmer::detail::period;
	}
	u = p * value;
	d = constrain(u + TriacDimmer::detail::pulse_length, TriacDimmer::detail::min_trigger, p);
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		TriacDimmer::detail::ch_B_up = u;
		TriacDimmer::detail::ch_B_dn = d;
	}
}

float TriacDimmer::detail::getChannelA(){
	uint16_t p, u;
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		p = TriacDimmer::detail::period;
		u = TriacDimmer::detail::ch_A_up;
	}
	return (float)p / u;
}

float TriacDimmer::detail::getChannelB(){
	uint16_t p, u;
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		p = TriacDimmer::detail::period;
		u = TriacDimmer::detail::ch_B_up;
	}
	return (float)p / u;
}

void TriacDimmer::detail::disableChannelA(){
	TriacDimmer::detail::ch_A_en = false;
	TCCR1A &=~ _BV(COM1A0) | _BV(COM1A1);
}

void TriacDimmer::detail::disableChannelB(){
	TriacDimmer::detail::ch_B_en = false;
	TCCR1A &=~ _BV(COM1B0) | _BV(COM1B1);
}

ISR(TIMER1_CAPT_vect){
	TIMSK1 &=~ (_BV(OCIE1A) | _BV(OCIE1B)); //clear interrupts, in case they haven't run yet
	TCCR1A &=~ (_BV(COM1A0) | _BV(COM1B0));
	TCCR1C = _BV(FOC1A) | _BV(FOC1B); //ensure outputs are properly cleared

	OCR1A = ICR1 + TriacDimmer::detail::ch_A_up;
	OCR1B = ICR1 + TriacDimmer::detail::ch_B_up;
	ch_A_dn_buf = TriacDimmer::detail::ch_A_dn;
	ch_B_dn_buf = TriacDimmer::detail::ch_B_dn;

	TCCR1A |=
		( TriacDimmer::detail::ch_A_en ? _BV(COM1A0) | _BV(COM1A1) : 0 ) |
		( TriacDimmer::detail::ch_B_en ? _BV(COM1B0) | _BV(COM1B1) : 0 ); //set OC1x on compare match, only if enabled
	TIFR1 = _BV(OCF1A) | _BV(OCF1B); //clear compare match flags
	TIMSK1 |= _BV(OCIE1A) | _BV(OCIE1B); //enable input capture and compare match interrupts

	static uint16_t last_icr = 0;
	TriacDimmer::detail::period = ICR1 - last_icr;
	last_icr = ICR1;

	if((signed)(TCNT1 - OCR1A) >= 0){
		TCCR1C = _BV(FOC1A); //interrupt ran late, trigger match manually
	}
	if((signed)(TCNT1 - OCR1B) >= 0){
		TCCR1C = _BV(FOC1B); //interrupt ran late, trigger match manually
	}
}

ISR(TIMER1_COMPA_vect){
	TIMSK1 &=~ _BV(OCIE1A); //disable match interrupt
	TCCR1A &=~ _BV(COM1A0); //clear OC1x on compare match

	OCR1A = ICR1 + ch_A_dn_buf;

	if((signed)(TCNT1 - OCR1A) >= 0){
		TCCR1C = _BV(FOC1A); //interrupt ran late, trigger match manually
	}
}

ISR(TIMER1_COMPB_vect){
	TIMSK1 &=~ _BV(OCIE1B); //disable match interrupt
	TCCR1A &=~ _BV(COM1B0); //clear OC1x on compare match

	OCR1B = ICR1 + ch_B_dn_buf;

	if((signed)(TCNT1 - OCR1B) >= 0){
		TCCR1C = _BV(FOC1B); //interrupt ran late, trigger match manually
	}
}

<commit_msg>error with pin state<commit_after>#include "TriacDimmer.h"
#include <Arduino.h>
#include <assert.h>
#include <util/atomic.h>

uint16_t TriacDimmer::detail::pulse_length;
uint16_t TriacDimmer::detail::min_trigger;
float TriacDimmer::detail::on_thresh;
float TriacDimmer::detail::off_thresh;

volatile bool TriacDimmer::detail::ch_A_en;
volatile uint16_t TriacDimmer::detail::ch_A_up;
volatile uint16_t TriacDimmer::detail::ch_A_dn;
volatile uint16_t ch_A_dn_buf;

volatile bool TriacDimmer::detail::ch_B_en;
volatile uint16_t TriacDimmer::detail::ch_B_up;
volatile uint16_t TriacDimmer::detail::ch_B_dn;
volatile uint16_t ch_B_dn_buf;

volatile uint16_t TriacDimmer::detail::period = 16667;

void TriacDimmer::begin(uint16_t pulse_length, uint16_t min_trigger, float on_thresh, float off_thresh){
	// Don't need atomic writes since the ISRs haven't started yet.
	TriacDimmer::detail::pulse_length = pulse_length;
	TriacDimmer::detail::min_trigger = min_trigger;
	TriacDimmer::detail::on_thresh = on_thresh;
	TriacDimmer::detail::off_thresh = off_thresh;

	TCCR1A = 0;
	TCCR1B = _BV(ICNC1)  //input capture noise cancel
			| _BV(ICES1) //positive edge
			| _BV(CS11); // /8 prescaler

	pinMode(8, INPUT);

	TIFR1 = _BV(ICF1); //clear IC interrupt flag
	TIMSK1 = _BV(ICIE1); //enable input capture interrupt
}

void TriacDimmer::end(){
	TIMSK1 = 0; //disable the interrupts first!
	TIFR1 = 0xFF; //clear all flags
	TCCR1A = 0; //clear to reset state
	TCCR1B = 0;
}

void TriacDimmer::setBrightness(uint8_t pin, float value){
	assert(pin == 9 || pin == 10);

	if (value > TriacDimmer::detail::on_thresh) {
		digitalWrite(pin, HIGH);
		TriacDimmer::disable(pin);
	} else if (value < TriacDimmer::detail::off_thresh) {
		digitalWrite(pin, LOW);
		TriacDimmer::disable(pin);
	} else {
		if ((pin & 0x01) == 0x01){ // if (pin == 9){
			TriacDimmer::detail::setChannelA(1 - value);
			TriacDimmer::detail::ch_A_en = true;
		} else { // if (pin == 10){
			TriacDimmer::detail::setChannelB(1 - value);
			TriacDimmer::detail::ch_B_en = true;
		}
	}
	pinMode(pin, OUTPUT); // only set to output once configured.
}

void TriacDimmer::disable(uint8_t pin) {
	assert(pin == 9 || pin == 10);

	if ((pin & 0x01) == 0x01){ // if (pin == 9){
		TriacDimmer::detail::disableChannelA();
	} else { // if (pin == 10){
		TriacDimmer::detail::disableChannelB();
	}
}

float TriacDimmer::getCurrentBrightness(uint8_t pin){
	assert(pin == 9 || pin == 10);

	if ((pin & 0x01) == 0x01){ // if (pin == 9){
		return 1 - TriacDimmer::detail::getChannelA();
	} else { // if (pin == 10){
		return 1 - TriacDimmer::detail::getChannelB();
	}
}

void TriacDimmer::detail::setChannelA(float value){
	uint16_t p, u, d;
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		// Don't need atomic read for pulse_length or min_trigger since they're not updated from an ISR.
		p = TriacDimmer::detail::period;
	}
	u = p * value;
	d = constrain(u + TriacDimmer::detail::pulse_length, TriacDimmer::detail::min_trigger, p);
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		TriacDimmer::detail::ch_A_up = u;
		TriacDimmer::detail::ch_A_dn = d;
	}
}

void TriacDimmer::detail::setChannelB(float value){
	uint16_t p, u, d;
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		// Don't need atomic read for pulse_length or min_trigger since they're not updated from an ISR.
		p = TriacDimmer::detail::period;
	}
	u = p * value;
	d = constrain(u + TriacDimmer::detail::pulse_length, TriacDimmer::detail::min_trigger, p);
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		TriacDimmer::detail::ch_B_up = u;
		TriacDimmer::detail::ch_B_dn = d;
	}
}

float TriacDimmer::detail::getChannelA(){
	uint16_t p, u;
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		p = TriacDimmer::detail::period;
		u = TriacDimmer::detail::ch_A_up;
	}
	return (float)p / u;
}

float TriacDimmer::detail::getChannelB(){
	uint16_t p, u;
	ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
		p = TriacDimmer::detail::period;
		u = TriacDimmer::detail::ch_B_up;
	}
	return (float)p / u;
}

void TriacDimmer::detail::disableChannelA(){
	TriacDimmer::detail::ch_A_en = false;
	TCCR1A &=~ _BV(COM1A0) | _BV(COM1A1);
}

void TriacDimmer::detail::disableChannelB(){
	TriacDimmer::detail::ch_B_en = false;
	TCCR1A &=~ _BV(COM1B0) | _BV(COM1B1);
}

ISR(TIMER1_CAPT_vect){
	TIMSK1 &=~ (_BV(OCIE1A) | _BV(OCIE1B)); //clear interrupts, in case they haven't run yet
	TCCR1A &=~ (_BV(COM1A0) | _BV(COM1B0));
	TCCR1C = _BV(FOC1A) | _BV(FOC1B); //ensure outputs are properly cleared

	OCR1A = ICR1 + TriacDimmer::detail::ch_A_up;
	OCR1B = ICR1 + TriacDimmer::detail::ch_B_up;
	ch_A_dn_buf = TriacDimmer::detail::ch_A_dn;
	ch_B_dn_buf = TriacDimmer::detail::ch_B_dn;

	TCCR1A |=
		( TriacDimmer::detail::ch_A_en ? _BV(COM1A0) | _BV(COM1A1) : 0 ) |
		( TriacDimmer::detail::ch_B_en ? _BV(COM1B0) | _BV(COM1B1) : 0 ); //set OC1x on compare match, only if enabled
	TIFR1 = _BV(OCF1A) | _BV(OCF1B); //clear compare match flags
	TIMSK1 |= _BV(OCIE1A) | _BV(OCIE1B); //enable input capture and compare match interrupts

	static uint16_t last_icr = 0;
	TriacDimmer::detail::period = ICR1 - last_icr;
	last_icr = ICR1;

	if((signed)(TCNT1 - OCR1A) >= 0){
		TCCR1C = _BV(FOC1A); //interrupt ran late, trigger match manually
	}
	if((signed)(TCNT1 - OCR1B) >= 0){
		TCCR1C = _BV(FOC1B); //interrupt ran late, trigger match manually
	}
}

ISR(TIMER1_COMPA_vect){
	TIMSK1 &=~ _BV(OCIE1A); //disable match interrupt
	TCCR1A &=~ _BV(COM1A0); //clear OC1x on compare match

	OCR1A = ICR1 + ch_A_dn_buf;

	if((signed)(TCNT1 - OCR1A) >= 0){
		TCCR1C = _BV(FOC1A); //interrupt ran late, trigger match manually
	}
}

ISR(TIMER1_COMPB_vect){
	TIMSK1 &=~ _BV(OCIE1B); //disable match interrupt
	TCCR1A &=~ _BV(COM1B0); //clear OC1x on compare match

	OCR1B = ICR1 + ch_B_dn_buf;

	if((signed)(TCNT1 - OCR1B) >= 0){
		TCCR1C = _BV(FOC1B); //interrupt ran late, trigger match manually
	}
}

<|endoftext|>


<commit_before>#include <iostream>
#include <cassert>
#include "IR.h"
#include "TypeChecker.h"

using namespace Bish;

void TypeChecker::visit(ReturnStatement *node) {
    if (visited(node) || node->type() != UndefinedTy) return;
    visited_set.insert(node);
    node->value->accept(this);
    node->set_type(node->value->type());
    // Propagate type of this return statement to the parent function.
    Function *f = dynamic_cast<Function*>(node->parent()->parent());
    assert(f);
    if (f->type() != UndefinedTy) {
        assert(f->type() == node->value->type() && "Invalid return type for function.");
    }
    propagate_if_undef(f, node);
}

void TypeChecker::visit(Function *node) {
    if (visited(node) || node->type() != UndefinedTy) return;
    visited_set.insert(node);
    for (std::vector<Variable *>::const_iterator I = node->args.begin(),
             E = node->args.end(); I != E; ++I) {
        (*I)->accept(this);
    }
    if (node->body) node->body->accept(this);
}

void TypeChecker::visit(FunctionCall *node) {
    if (visited(node) || node->type() != UndefinedTy) return;
    visited_set.insert(node);
    node->function->accept(this);
    for (std::vector<IRNode *>::const_iterator I = node->args.begin(),
           E = node->args.end(); I != E; ++I) {
      (*I)->accept(this);
    }
    node->set_type(node->function->type());
}

void TypeChecker::visit(ExternCall *node) {
    if (visited(node) || node->type() != UndefinedTy) return;
    visited_set.insert(node);
    node->set_type(UndefinedTy);
}

void TypeChecker::visit(IORedirection *node) {
    if (node->type() != UndefinedTy) return;
    node->a->accept(this);
    node->b->accept(this);
    node->set_type(UndefinedTy);
}

void TypeChecker::visit(Assignment *node) {
    if (visited(node) || node->type() != UndefinedTy) return;
    visited_set.insert(node);
    node->variable->accept(this);
    node->value->accept(this);
    if (node->variable->type() != UndefinedTy && node->value->type() != UndefinedTy) {
        assert(node->variable->type() == node->value->type() &&
               "Invalid type in assignment.");
    } else {
        node->variable->set_type(node->value->type());
    }
    node->set_type(node->variable->type());
}

void TypeChecker::visit(BinOp *node) {
    if (visited(node) || node->type() != UndefinedTy) return;
    visited_set.insert(node);
    node->a->accept(this);
    node->b->accept(this);
    propagate_if_undef(node->a, node->b);
    assert(node->a->type() == node->b->type());
    switch (node->op) {
    case BinOp::Eq:
    case BinOp::NotEq:
    case BinOp::LT:
    case BinOp::LTE:
    case BinOp::GT:
    case BinOp::GTE:
    case BinOp::And:
    case BinOp::Or:
        node->set_type(BooleanTy);
        break;
    case BinOp::Add:
    case BinOp::Sub:
    case BinOp::Mul:
    case BinOp::Div:
    case BinOp::Mod:
        node->set_type(node->a->type());
        break;
    }
}

void TypeChecker::visit(UnaryOp *node) {
    if (visited(node)) return;
    visited_set.insert(node);
    node->a->accept(this);
    node->set_type(node->a->type());
}

void TypeChecker::visit(Integer *node) {
    node->set_type(IntegerTy);
}

void TypeChecker::visit(Fractional *node) {
    node->set_type(FractionalTy);
}

void TypeChecker::visit(String *node) {
    node->set_type(StringTy);
}

void TypeChecker::visit(Boolean *node) {
    node->set_type(BooleanTy);
}

void TypeChecker::propagate_if_undef(IRNode *a, IRNode *b) {
    if (a->type() == UndefinedTy) {
        a->set_type(b->type());
    } else if (b->type() == UndefinedTy) {
        b->set_type(a->type());
    }
}
<commit_msg>Add function argument type checks.<commit_after>#include <iostream>
#include <cassert>
#include "IR.h"
#include "TypeChecker.h"

using namespace Bish;

void TypeChecker::visit(ReturnStatement *node) {
    if (visited(node) || node->type() != UndefinedTy) return;
    visited_set.insert(node);
    node->value->accept(this);
    node->set_type(node->value->type());
    // Propagate type of this return statement to the parent function.
    Function *f = dynamic_cast<Function*>(node->parent()->parent());
    assert(f);
    if (f->type() != UndefinedTy) {
        assert(f->type() == node->value->type() && "Invalid return type for function.");
    }
    propagate_if_undef(f, node);
}

void TypeChecker::visit(Function *node) {
    if (visited(node) || node->type() != UndefinedTy) return;
    visited_set.insert(node);
    for (std::vector<Variable *>::const_iterator I = node->args.begin(),
             E = node->args.end(); I != E; ++I) {
        (*I)->accept(this);
    }
    if (node->body) node->body->accept(this);
}

void TypeChecker::visit(FunctionCall *node) {
    if (visited(node) || node->type() != UndefinedTy) return;
    visited_set.insert(node);
    node->function->accept(this);
    unsigned i = 0;
    assert(node->function->body != NULL && "Calling an undefined function.");
    for (std::vector<IRNode *>::const_iterator I = node->args.begin(),
             E = node->args.end(); I != E; ++I, ++i) {
        (*I)->accept(this);
        if (node->function->args[i]->type() != UndefinedTy) {
            assert((*I)->type() == node->function->args[i]->type() &&
                   "Invalid argument type for function call.");
        }
    }
    node->set_type(node->function->type());
}

void TypeChecker::visit(ExternCall *node) {
    if (visited(node) || node->type() != UndefinedTy) return;
    visited_set.insert(node);
    node->set_type(UndefinedTy);
}

void TypeChecker::visit(IORedirection *node) {
    if (node->type() != UndefinedTy) return;
    node->a->accept(this);
    node->b->accept(this);
    node->set_type(UndefinedTy);
}

void TypeChecker::visit(Assignment *node) {
    if (visited(node) || node->type() != UndefinedTy) return;
    visited_set.insert(node);
    node->variable->accept(this);
    node->value->accept(this);
    if (node->variable->type() != UndefinedTy && node->value->type() != UndefinedTy) {
        assert(node->variable->type() == node->value->type() &&
               "Invalid type in assignment.");
    } else {
        node->variable->set_type(node->value->type());
    }
    node->set_type(node->variable->type());
}

void TypeChecker::visit(BinOp *node) {
    if (visited(node) || node->type() != UndefinedTy) return;
    visited_set.insert(node);
    node->a->accept(this);
    node->b->accept(this);
    propagate_if_undef(node->a, node->b);
    assert(node->a->type() == node->b->type());
    switch (node->op) {
    case BinOp::Eq:
    case BinOp::NotEq:
    case BinOp::LT:
    case BinOp::LTE:
    case BinOp::GT:
    case BinOp::GTE:
    case BinOp::And:
    case BinOp::Or:
        node->set_type(BooleanTy);
        break;
    case BinOp::Add:
    case BinOp::Sub:
    case BinOp::Mul:
    case BinOp::Div:
    case BinOp::Mod:
        node->set_type(node->a->type());
        break;
    }
}

void TypeChecker::visit(UnaryOp *node) {
    if (visited(node)) return;
    visited_set.insert(node);
    node->a->accept(this);
    node->set_type(node->a->type());
}

void TypeChecker::visit(Integer *node) {
    node->set_type(IntegerTy);
}

void TypeChecker::visit(Fractional *node) {
    node->set_type(FractionalTy);
}

void TypeChecker::visit(String *node) {
    node->set_type(StringTy);
}

void TypeChecker::visit(Boolean *node) {
    node->set_type(BooleanTy);
}

void TypeChecker::propagate_if_undef(IRNode *a, IRNode *b) {
    if (a->type() == UndefinedTy) {
        a->set_type(b->type());
    } else if (b->type() == UndefinedTy) {
        b->set_type(a->type());
    }
}
<|endoftext|>


<commit_before>//
//  System.cpp
//  ax_gen
//
//  Created by Jason on 2017-04-05.
//  Copyright © 2017 Jason. All rights reserved.
//

#include "System.h"

namespace ax_gen {

int System::cpuCount() {
	return (int)std::thread::hardware_concurrency();
}

void System::shellOpen(const StrView& path) {
	Log::info("shellOpen> ", path);

#if ax_OS_Windows
	WString pathW;
	pathW.setUtf(path);
	::ShellExecute(nullptr, L"open", pathW.c_str(), nullptr, nullptr, SW_SHOW);

#elif ax_OS_MacOSX

	String cmd("open \"", path, "\"");
	::system(cmd.c_str());

#else
	Log::error("shellOpen does't support on this platform");
#endif

}

int System::createProcess(const StrView& exe, const StrView& args) {
#if ax_OS_Windows
	String cmd("\"", exe, "\" ", args);
	Log::info("run> ", cmd);

	WString exeW;
	exeW.setUtf(exe);

	WString cmdW;
	cmdW.appendUtf(cmd);

	STARTUPINFOW si;
	ZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);

	PROCESS_INFORMATION pi;
	ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));

	if (!::CreateProcess(exeW.c_str(), cmdW.data(), nullptr, nullptr, false, 0, nullptr, nullptr, &si, &pi)) {
		auto dw = GetLastError();
		Log::error("error createProcess", dw);
		return -1;
	}

    WaitForSingleObject(pi.hProcess, INFINITE);

	DWORD exit_code = -1;
	GetExitCodeProcess(pi.hProcess, &exit_code);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
#else

	String cmd("\"", exe, "\" ", args, " 2>&1"); //redirect stderr to stdout
	Log::info("run> ", cmd);

	FILE* fs = ::popen(cmd.c_str(), "r");
	if (!fs) {
		Log::error("error createProcess");
		return -1;
	}

	Vector<char> buf;
	buf.resize(2 * 1024 * 1024);

	while (!feof(fs)) {
		if (fgets(buf.data(), buf.size(), fs) != nullptr) {
			Log::info(StrView_c_str(buf.data()));
		}
	}

	int exit_code = pclose(fs);

#endif //ax_OS

	Log::info("process exit return: ", exit_code);
	return (int)exit_code;
}

} //namespace
<commit_msg>use cout in System::createProcess<commit_after>//
//  System.cpp
//  ax_gen
//
//  Created by Jason on 2017-04-05.
//  Copyright © 2017 Jason. All rights reserved.
//

#include "System.h"

namespace ax_gen {

int System::cpuCount() {
	return (int)std::thread::hardware_concurrency();
}

void System::shellOpen(const StrView& path) {
	Log::info("shellOpen> ", path);

#if ax_OS_Windows
	WString pathW;
	pathW.setUtf(path);
	::ShellExecute(nullptr, L"open", pathW.c_str(), nullptr, nullptr, SW_SHOW);

#elif ax_OS_MacOSX

	String cmd("open \"", path, "\"");
	::system(cmd.c_str());

#else
	Log::error("shellOpen does't support on this platform");
#endif

}

int System::createProcess(const StrView& exe, const StrView& args) {
#if ax_OS_Windows
	String cmd("\"", exe, "\" ", args);
	Log::info("run> ", cmd);

	WString exeW;
	exeW.setUtf(exe);

	WString cmdW;
	cmdW.appendUtf(cmd);

	STARTUPINFOW si;
	ZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb = sizeof(STARTUPINFO);

	PROCESS_INFORMATION pi;
	ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));

	if (!::CreateProcess(exeW.c_str(), cmdW.data(), nullptr, nullptr, false, 0, nullptr, nullptr, &si, &pi)) {
		auto dw = GetLastError();
		Log::error("error createProcess", dw);
		return -1;
	}

    WaitForSingleObject(pi.hProcess, INFINITE);

	DWORD exit_code = -1;
	GetExitCodeProcess(pi.hProcess, &exit_code);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
#else

	String cmd("\"", exe, "\" ", args, " 2>&1"); //redirect stderr to stdout
	Log::info("run> ", cmd);

	FILE* fs = ::popen(cmd.c_str(), "r");
	if (!fs) {
		Log::error("error createProcess");
		return -1;
	}

	Vector<char> buf;
	buf.resize(2 * 1024 * 1024);

	while (!feof(fs)) {
		if (fgets(buf.data(), buf.size(), fs) != nullptr) {
			std::cout << buf.data();
		}
	}

	int exit_code = pclose(fs);

#endif //ax_OS

	Log::info("process exit return: ", exit_code);
	return (int)exit_code;
}

} //namespace
<|endoftext|>