text:
/*
    This file is part of FISCO-BCOS.

    FISCO-BCOS 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 3 of the License, or
    (at your option) any later version.

    FISCO-BCOS 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 FISCO-BCOS.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file PermissionPrecompiled.h
 *  @author caryliao
 *  @date 20181205
 */
#include "PermissionPrecompiled.h"
#include "libstorage/Table.h"
#include "libstoragestate/StorageState.h"
#include <json/json.h>
#include <libblockverifier/ExecutiveContext.h>
#include <libethcore/ABI.h>
#include <libprecompiled/TableFactoryPrecompiled.h>
#include <boost/lexical_cast.hpp>

using namespace std;
using namespace dev;
using namespace dev::blockverifier;
using namespace dev::storage;
using namespace dev::precompiled;

const char* const AUP_METHOD_INS = "insert(string,string)";
const char* const AUP_METHOD_REM = "remove(string,string)";
const char* const AUP_METHOD_QUE = "queryByName(string)";
const char* const AUP_METHOD_GRANT_WRITE_CONTRACT = "grantWrite(address,address)";
const char* const AUP_METHOD_REVOKE_WRITE_CONTRACT = "revokeWrite(address,address)";
const char* const AUP_METHOD_QUERY_CONTRACT = "queryPermission(address)";

PermissionPrecompiled::PermissionPrecompiled()
{
    name2Selector[AUP_METHOD_INS] = getFuncSelector(AUP_METHOD_INS);
    name2Selector[AUP_METHOD_REM] = getFuncSelector(AUP_METHOD_REM);
    name2Selector[AUP_METHOD_QUE] = getFuncSelector(AUP_METHOD_QUE);
    if (g_BCOSConfig.version() >= V2_3_0)
    {
        name2Selector[AUP_METHOD_GRANT_WRITE_CONTRACT] =
            getFuncSelector(AUP_METHOD_GRANT_WRITE_CONTRACT);
        name2Selector[AUP_METHOD_REVOKE_WRITE_CONTRACT] =
            getFuncSelector(AUP_METHOD_REVOKE_WRITE_CONTRACT);
        name2Selector[AUP_METHOD_QUERY_CONTRACT] = getFuncSelector(AUP_METHOD_QUERY_CONTRACT);
    }
}

std::string PermissionPrecompiled::toString()
{
    return "Permission";
}

PrecompiledExecResult::Ptr PermissionPrecompiled::call(
    ExecutiveContext::Ptr context, bytesConstRef param, Address const& origin, Address const&)
{
    // parse function name
    uint32_t func = getParamFunc(param);
    bytesConstRef data = getParamData(param);

    dev::eth::ContractABI abi;
    auto callResult = m_precompiledExecResultFactory->createPrecompiledResult();
    int result = 0;
    if (func == name2Selector[AUP_METHOD_INS])
    {  // FIXME: modify insert(string,string) ==> insert(string,address)
        // insert(string tableName,string addr)
        std::string tableName, addr;
        abi.abiOut(data, tableName, addr);
        if (g_BCOSConfig.version() >= V2_5_0)
        {
            boost::to_lower(addr);
        }
        do
        {
            Table::Ptr table = openTable(context, SYS_ACCESS_TABLE);
            if (g_BCOSConfig.version() >= V2_5_0)
            {
                if (tableName == SYS_ACCESS_TABLE)
                {
                    result = CODE_COMMITTEE_PERMISSION;
                    PRECOMPILED_LOG(WARNING)
                        << LOG_BADGE("PermissionPrecompiled")
                        << LOG_DESC("Committee permission controlled by ChainGovernancePrecompiled")
                        << LOG_KV("return", result);
                    break;
                }
                auto condition = table->newCondition();
                condition->EQ(SYS_AC_ADDRESS, addr);
                auto entries = table->select(SYS_ACCESS_TABLE, condition);
                if (entries->size() != 0u && (tableName == SYS_TABLES || tableName == SYS_CNS))
                {  // committee
                    result = CODE_OPERATOR_CANNOT_BE_COMMITTEE_MEMBER;
                    if (g_BCOSConfig.version() >= V2_6_0)
                    {
                        result = CODE_COMMITTEE_MEMBER_CANNOT_BE_OPERATOR;
                    }
                    PRECOMPILED_LOG(WARNING)
                        << LOG_BADGE("PermissionPrecompiled")
                        << LOG_DESC("committee member should not have operator permission")
                        << LOG_KV("account", addr)
                        << LOG_KV("return", CODE_COMMITTEE_MEMBER_CANNOT_BE_OPERATOR);
                    break;
                }
            }
            addPrefixToUserTable(tableName);

            auto condition = table->newCondition();
            condition->EQ(SYS_AC_ADDRESS, addr);
            auto entries = table->select(tableName, condition);
            if (entries->size() != 0u)
            {
                PRECOMPILED_LOG(WARNING) << LOG_BADGE("PermissionPrecompiled")
                                         << LOG_DESC("tableName and address exist");
                result = CODE_TABLE_AND_ADDRESS_EXIST;
                break;
            }
            if (tableName.size() > USER_TABLE_NAME_MAX_LENGTH)
            {
                PRECOMPILED_LOG(ERROR)
                    << LOG_BADGE("PermissionPrecompiled") << LOG_DESC("tableName overflow")
                    << LOG_KV("tableName", tableName);
                result = CODE_TABLE_NAME_OVERFLOW;
                break;
            }

            try
            {
                Address address(addr);
                (void)address;
            }
            catch (...)
            {
                PRECOMPILED_LOG(ERROR) << LOG_BADGE("PermissionPrecompiled")
                                       << LOG_DESC("address invalid") << LOG_KV("account", addr);
                result = CODE_ADDRESS_INVALID;
                break;
            }

            auto entry = table->newEntry();
            entry->setField(SYS_AC_TABLE_NAME, tableName);
            entry->setField(SYS_AC_ADDRESS, addr);
            entry->setField(SYS_AC_ENABLENUM,
                boost::lexical_cast<std::string>(context->blockInfo().number + 1));
            int count = table->insert(tableName, entry, std::make_shared<AccessOptions>(origin));
            result = count;
            PRECOMPILED_LOG(INFO) << LOG_BADGE("PermissionPrecompiled") << LOG_DESC("insert func")
                                  << LOG_KV("tableName", tableName) << LOG_KV("address", addr)
                                  << LOG_KV("return", count);
        } while (0);

        getErrorCodeOut(callResult->mutableExecResult(), result);
    }
    else if (func == name2Selector[AUP_METHOD_REM])
    {  // remove(string tableName,string addr)
        std::string tableName, addr;
        abi.abiOut(data, tableName, addr);
        if (g_BCOSConfig.version() >= V2_5_0)
        {
            boost::to_lower(addr);
        }
        int result = 0;
        Table::Ptr table = openTable(context, SYS_ACCESS_TABLE);
        auto condition = table->newCondition();
        condition->EQ(SYS_AC_ADDRESS, addr);
        auto entries = table->select(SYS_ACCESS_TABLE, condition);
        if (g_BCOSConfig.version() >= V2_5_0 && tableName == SYS_ACCESS_TABLE)
        {
            result = CODE_COMMITTEE_PERMISSION;
            PRECOMPILED_LOG(WARNING)
                << LOG_BADGE("PermissionPrecompiled")
                << LOG_DESC("Committee permission controlled by ChainGovernancePrecompiled")
                << LOG_KV("return", result);
        }
        else if (g_BCOSConfig.version() >= V2_6_0 && entries->size() != 0u &&
                 (tableName == SYS_CONSENSUS || tableName == SYS_CONFIG))
        {
            result = storage::CODE_NO_AUTHORIZED;
            PRECOMPILED_LOG(WARNING)
                << LOG_BADGE("PermissionPrecompiled")
                << LOG_DESC("Committee permission should not be removed by PermissionPrecompiled")
                << LOG_KV("return", result);
        }
        else
        {
            addPrefixToUserTable(tableName);
            result = revokeTablePermission(context, tableName, addr, origin);
        }
        PRECOMPILED_LOG(DEBUG) << LOG_BADGE("PermissionPrecompiled") << LOG_DESC("remove")
                               << LOG_KV("tableName", tableName) << LOG_KV("account", addr)
                               << LOG_KV("ret", result);
        getErrorCodeOut(callResult->mutableExecResult(), result);
    }
    else if (func == name2Selector[AUP_METHOD_QUE])
    {  // queryByName(string table_name)
        std::string tableName;
        abi.abiOut(data, tableName);
        addPrefixToUserTable(tableName);

        PRECOMPILED_LOG(DEBUG) << LOG_BADGE("PermissionPrecompiled") << LOG_DESC("queryByName func")
                               << LOG_KV("tableName", tableName);

        auto result = queryPermission(context, tableName);
        callResult->setExecResult(abi.abiIn("", result));
    }
    else if (func == name2Selector[AUP_METHOD_GRANT_WRITE_CONTRACT])
    {  // grantWrite(address,address)
        Address contractAddress, user;
        abi.abiOut(data, contractAddress, user);
        string addr = user.hexPrefixed();
        string tableName = precompiled::getContractTableName(contractAddress);
        PRECOMPILED_LOG(INFO) << LOG_BADGE("PermissionPrecompiled") << LOG_DESC("grantWrite")
                              << LOG_KV("tableName", tableName) << LOG_KV("user", addr);
        do
        {
            Table::Ptr table = openTable(context, SYS_ACCESS_TABLE);
            auto condition = table->newCondition();
            condition->EQ(SYS_AC_ADDRESS, addr);
            auto entries = table->select(tableName, condition);
            if (entries->size() != 0u)
            {
                PRECOMPILED_LOG(WARNING) << LOG_BADGE("PermissionPrecompiled")
                                         << LOG_DESC("tableName and address exist");
                result = CODE_TABLE_AND_ADDRESS_EXIST;
                break;
            }
            if (tableName.size() > USER_TABLE_NAME_MAX_LENGTH)
            {
                PRECOMPILED_LOG(ERROR)
                    << LOG_BADGE("PermissionPrecompiled") << LOG_DESC("tableName overflow")
                    << LOG_KV("tableName", tableName);
                result = CODE_TABLE_NAME_OVERFLOW;
                break;
            }
            if (!openTable(context, tableName))
            {
                PRECOMPILED_LOG(ERROR)
                    << LOG_BADGE("PermissionPrecompiled") << LOG_DESC("contract not exist")
                    << LOG_KV("contract", tableName);
                result = CODE_CONTRACT_NOT_EXIST;
                break;
            }
            if (g_BCOSConfig.version() >= V2_5_0 && !checkPermission(context, tableName, origin))
            {
                PRECOMPILED_LOG(INFO) << LOG_BADGE("PermissionPrecompiled")
                                      << LOG_DESC("only deployer of contract can grantWrite")
                                      << LOG_KV("tableName", tableName)
                                      << LOG_KV("origin", origin.hex()) << LOG_KV("user", addr);
                result = storage::CODE_NO_AUTHORIZED;
                break;
            }
            auto entry = table->newEntry();
            entry->setField(SYS_AC_TABLE_NAME, tableName);
            entry->setField(SYS_AC_ADDRESS, addr);
            entry->setField(SYS_AC_ENABLENUM,
                boost::lexical_cast<std::string>(context->blockInfo().number + 1));
            auto accessOption = std::make_shared<AccessOptions>(origin);
            if (g_BCOSConfig.version() >= V2_6_0)
            {
                accessOption = std::make_shared<AccessOptions>(origin, false);
            }
            int count = table->insert(tableName, entry, accessOption);
            result = count;
            PRECOMPILED_LOG(INFO) << LOG_BADGE("PermissionPrecompiled grantWrite")
                                  << LOG_KV("return", result);
        } while (0);

        getErrorCodeOut(callResult->mutableExecResult(), result);
    }
    else if (func == name2Selector[AUP_METHOD_REVOKE_WRITE_CONTRACT])
    {  // revokeWrite(address,address)
        Address contractAddress, user;
        abi.abiOut(data, contractAddress, user);
        string addr = user.hexPrefixed();
        string tableName = precompiled::getContractTableName(contractAddress);
        int result = revokeContractTablePermission(context, tableName, addr, origin);
        callResult->setExecResult(abi.abiIn("", s256(result)));
    }
    else if (func == name2Selector[AUP_METHOD_QUERY_CONTRACT])
    {  // queryPermission(address)
        Address contractAddress;
        abi.abiOut(data, contractAddress);
        string tableName = precompiled::getContractTableName(contractAddress);
        PRECOMPILED_LOG(DEBUG) << LOG_BADGE("PermissionPrecompiled") << LOG_DESC("queryPermission")
                               << LOG_KV("tableName", tableName);
        auto result = queryPermission(context, tableName);
        callResult->setExecResult(abi.abiIn("", result));
    }
    else
    {
        PRECOMPILED_LOG(ERROR) << LOG_BADGE("PermissionPrecompiled")
                               << LOG_DESC("call undefined function") << LOG_KV("func", func);
    }
    return callResult;
}

string PermissionPrecompiled::queryPermission(
    std::shared_ptr<dev::blockverifier::ExecutiveContext> context, const string& tableName)
{
    Table::Ptr table = openTable(context, SYS_ACCESS_TABLE);

    auto condition = table->newCondition();
    auto entries = table->select(tableName, condition);
    Json::Value AuthorityInfos(Json::arrayValue);
    if (entries)
    {
        for (size_t i = 0; i < entries->size(); i++)
        {
            auto entry = entries->get(i);
            if (!entry)
                continue;
            Json::Value AuthorityInfo;
            AuthorityInfo[SYS_AC_TABLE_NAME] = tableName;
            AuthorityInfo[SYS_AC_ADDRESS] = entry->getField(SYS_AC_ADDRESS);
            AuthorityInfo[SYS_AC_ENABLENUM] = entry->getField(SYS_AC_ENABLENUM);
            AuthorityInfos.append(AuthorityInfo);
        }
    }
    Json::FastWriter fastWriter;
    return fastWriter.write(AuthorityInfos);
}

int PermissionPrecompiled::revokeWritePermission(
    std::shared_ptr<dev::blockverifier::ExecutiveContext> context, const string& tableName,
    const string& user, Address const& origin, bool _isContractTable)
{
    int result;
    Table::Ptr table = openTable(context, SYS_ACCESS_TABLE);
    auto condition = table->newCondition();
    condition->EQ(SYS_AC_ADDRESS, user);
    auto entries = table->select(tableName, condition);
    if (entries->size() == 0u)
    {
        PRECOMPILED_LOG(WARNING) << LOG_BADGE("PermissionPrecompiled")
                                 << LOG_DESC("tableName and address does not exist");
        return result = CODE_TABLE_AND_ADDRESS_NOT_EXIST;
    }
    if (g_BCOSConfig.version() >= V2_5_0 && _isContractTable &&
        !checkPermission(context, tableName, origin))
    {
        PRECOMPILED_LOG(INFO) << LOG_BADGE("PermissionPrecompiled")
                              << LOG_DESC("only deployer of contract can revokeWrite")
                              << LOG_KV("tableName", tableName) << LOG_KV("origin", origin.hex())
                              << LOG_KV("user", user);
        return storage::CODE_NO_AUTHORIZED;
    }
    auto accessOption = std::make_shared<AccessOptions>(origin);
    if (g_BCOSConfig.version() >= V2_6_0 && _isContractTable)
    {
        accessOption = std::make_shared<AccessOptions>(origin, false);
    }
    result = table->remove(tableName, condition, accessOption);
    PRECOMPILED_LOG(INFO) << LOG_BADGE("PermissionPrecompiled") << LOG_DESC("revokeWrite")
                          << LOG_KV("tableName", tableName) << LOG_KV("user", user)
                          << LOG_KV("return", result);
    return result;
}

void PermissionPrecompiled::addPrefixToUserTable(std::string& table_name)
{
    if (table_name == SYS_ACCESS_TABLE || table_name == SYS_CONSENSUS || table_name == SYS_TABLES ||
        table_name == SYS_CNS || table_name == SYS_CONFIG)
    {
        return;
    }
    else
    {
        table_name = precompiled::getTableName(table_name);
    }
}

bool PermissionPrecompiled::checkPermission(
    ExecutiveContext::Ptr context, std::string const& tableName, Address const& origin)
{
    Table::Ptr table = openTable(context, tableName);
    if (table)
    {
        auto entries = table->select(storagestate::ACCOUNT_AUTHORITY, table->newCondition());
        if (entries->size() > 0)
        {  // the key of authority would be set when support version >= 2.3.0
            for (size_t i = 0; i < entries->size(); i++)
            {
                std::string authority = entries->get(i)->getField(storagestate::STORAGE_VALUE);
                if (origin.hex() == authority)
                {
                    return true;
                }
            }
        }
    }
    return false;
}

max_stars_repo_name: imtypist/FISCO-BCOS

max_issues_repo_name: imtypist/FISCO-BCOS

max_forks_repo_name: imtypist/FISCO-BCOS


text:
/*
@copyright Louis Dionne 2014
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
 */

#include <boost/hana/ext/std/tuple.hpp>

#include <boost/hana/detail/assert.hpp>
#include <boost/hana/detail/constexpr.hpp>
#include <boost/hana/integral.hpp>
#include <boost/hana/monad/laws.hpp>

#include <tuple>
using namespace boost::hana;

BOOST_HANA_CONSTEXPR_LAMBDA auto f = [](auto x) {
    return std::make_tuple(x + int_<1>);
};

BOOST_HANA_CONSTEXPR_LAMBDA auto g = [](auto x) {
    return std::make_tuple(x * int_<3>);
};

int main() {
    BOOST_HANA_CONSTANT_ASSERT(Monad::laws::check(std::make_tuple(), int_<1>, f, g));
    BOOST_HANA_CONSTANT_ASSERT(Monad::laws::check(std::make_tuple(int_<1>), int_<1>, f, g));
    BOOST_HANA_CONSTANT_ASSERT(Monad::laws::check(std::make_tuple(int_<1>, int_<2>), int_<1>, f, g));
    BOOST_HANA_CONSTEXPR_ASSERT(Monad::laws::check(std::make_tuple(1, 2, 3, 4), int_<1>, f, g));
}

ext: cpp

max_stars_repo_name: rbock/hana

max_issues_repo_name: rbock/hana

max_forks_repo_name: rbock/hana


text:
#include "Camera.h"

#include <Eigen>
#include <vector>
#include <iostream>
#include <fstream>
#include <algorithm>
#include <math.h>
#include "Shape.h"
#include "Intersection.h"

#define HEIGHT 600
#define WIDTH 800
#define FLENGTH 1.0
#define PWIDTH 4.0
#define PHEIGHT 3.0
#define MAXRECDEPTH 4
#define INF 100000000

using namespace Eigen;
using namespace std;

float clamp(float a, float b, float c){
    if (c < a)
        return a;
    else if (c > b)
        return b;
    else
        return c;
}

Vector3f getr(Vector3f sray, Vector3f norm){
    Vector3f t2 = sray - 2*(sray.dot(norm)) * norm;
    return t2;
}

//Based on Scratchapixel version
Vector3f getfrac(Vector3f incom, Vector3f norm, float indx){
    float cosi = clamp(-1, 1, incom.dot(norm));
    float et = 1, ea = indx;
    Vector3f n = norm;
    if (cosi < 0)
        cosi = -cosi;
    else{
        swap(et, ea);
        n = -norm;
    }
    float eta = ea/et;
    float k = 1 - eta*eta * (1-cosi * cosi);
    if (k < 0){ //total refrac
        return getr(incom, -norm);
    }
    else{
        return eta * incom + (eta * cosi - sqrt(k)) * n;
    }
}

Camera::Camera(Vector3f la, Vector3f u,
               Vector3f p)
{
    lookat = la;
    up = u;
    pos = p;
    lookat.normalize();
    up.normalize();
    pos.normalize();
    //col major
    Vector3f matn = pos - lookat;
    matn.normalize();
    Vector3f matu = up.cross(matn);
    matu.normalize();
    Vector3f matv = matn.cross(matu);
    this->tra << matu(0), matv(0), matn(0), 0.0f,
                 matu(1), matv(1), matn(1), 0.0f,
                 matu(2), matv(2), matn(2), 0.0f,
                -(pos.dot(matu)), -(pos.dot(matv)),
                -(pos.dot(matn)), 1.0;

}

Vector3f getrtarg(Vector3f illum, float aol, float ldmax){
    Vector3f cs = aol * illum;
    float rr, gr, br;
    rr = cs[0] / (1 + cs[0]);
    gr = cs[1] / (1 + cs[1]);
    br = cs[2] / (1 + cs[2]);

    float rt,gt,bt;
    rt = rr * ldmax;
    gt = gr * ldmax;
    bt = br * ldmax;

    Vector3f targ;
    targ << rt, gt, bt;
    return targ;

}

float getlogavg(vector<float> illlist){
    float lsum = 0;
    float delta = 0.00001;
    for (float f : illlist){
        lsum += log(delta + f);
    }
    return exp(lsum / ((float)HEIGHT * WIDTH));

}

//go from RGB to Illuminance
//CRT formula
float toill(Vector3f rgb){
    return abs(.27*rgb[0] + .67*rgb[1]+.06*rgb[2]);
}

std::vector<Vector3f> torgb(vector<Vector3f> lum, float ldmax, char whichTR){
        vector<float> illum;
        for (Vector3f vf : lum){
            illum.push_back(toill(vf));
        }
        float lwa = getlogavg(illum);
    if (whichTR == 'w'){
        float powa = pow(lwa,.4);
        float ldterm = pow(ldmax/2, 0.4);
        float brackterm = (1.219 + ldterm) / (1.219 + powa);
        float sf = pow(brackterm,2.5);
        vector<Vector3f> trd;
        for (Vector3f rgb : lum){
            trd.push_back(sf * rgb);
        }
        return trd;
    }
    else{
        float aol = .18/lwa;
        vector<Vector3f> targv;
        for (Vector3f vl : lum){
            targv.push_back(getrtarg(vl,aol,ldmax));
        }
        return targv;
    }
}

void writetofile(vector<Vector3f> image, float ldmax)
{
    ofstream filewtt;
    filewtt.open("output.ppm");
    filewtt << "P3\n" << WIDTH << " ";
    filewtt << HEIGHT << "\n";
    filewtt << 255 << "\n";
    for (Vector3f pix : image){
        int r = abs((int) (pix[0] / ldmax) * 255);
        int g = abs((int) (pix[1] / ldmax) * 255);
        int b = abs((int) (pix[2] / ldmax) * 255);
        filewtt << r << " " << g << " ";
        filewtt << b << " \n";
    }
    filewtt.close();

}

Camera::~Camera()
{
    //dtor
}

Vector3f Camera::getcolor(Ray * r, int recdepth){
    vector<Shape *> clones = wld->getshapes();
    vector<Light *> lits = wld->getlits();
    Vector3f colr;
    bool foundcol = false;
    float newt;
    float champt = INF;
    Shape * coll;
    for (Shape * s : clones){
        if (s->checkcollision(r,newt)){
            foundcol = true;
            if (newt < champt){
                champt = newt;
                coll = s;
            }
        }
        }
        if (!foundcol){
            Vector3f dflt;
            dflt << 0.0, 30, 70;
            colr = dflt;
        }
        else
        {
            //colr = coll->getcolor();
            Vector3f colpt = r->getpos() + r->getdir().normalized() * champt;
            Vector3f SS =  lits.at(0)->getpos() - colpt;
            SS.normalize();
            Ray * shadow = new Ray(colpt,SS);
            bool seelight = true;
            float dummyt; //if dist = 0, hitting self
            for (Shape * s : clones){
                if (s != coll){
                    if (s->checkcollision(shadow, dummyt)){
                        if (dummyt != 0){
                            seelight = false;
                            //ambi
                            Vector3f blk;
                            blk << 0.1,0.1,0.1;
                            colr = blk;
                        }
                    }
                }
            }
            if (seelight){
                Vector3f VV = r->getdir();
                VV.normalize();
                Vector3f NN = coll->getnorm(colpt);
                NN.normalize();
                Vector3f RR = getr(VV,NN);
                Intersection * is = new Intersection();
                is->pt = colpt;
                is->incom = SS;
                is->norm = NN;
                is->reflex = RR;
                is->litlist = lits;
                colr = coll->getcolor(is);
                if (recdepth < MAXRECDEPTH){
                    if (coll->kr > 0){
                        Vector3f refr = getr(VV,NN);
                        refr.normalize();
                        Ray * nr = new Ray(colpt, refr);
                        colr += coll->kr * this->getcolor(nr, recdepth + 1);
                    }
                    if (coll->kt > 0){
                        Vector3f frac = getfrac(VV, NN, 1.01);
                        frac.normalize();
                        Ray * fr = new Ray(colpt, frac);
                        colr += coll->kt * this->getcolor(fr, recdepth + 1);
                    }
                }
            }
        }
        return colr;
}

void Camera::captureworld(World * wld){

    //Yo dawg...
    vector<Vector3f>image;
    this->wld = wld;
    float pixh = PHEIGHT / HEIGHT;
    float pixw = PWIDTH / WIDTH;
    float tx = -PWIDTH/2;
    float ty = PHEIGHT/2;

    Vector3f p;
    p << 0.0, 0.0, 0.0;

    //Generate rays and check
    for (int i = 0; i < HEIGHT; i++){
        float ypx = ty - ((.5 + float(i)) * pixh);
        for (int c = 0; c < WIDTH; c++){
                float xpx =  tx + ((.5 + float(c)) * pixw);
                Vector3f raypos;
                raypos << xpx, ypx, FLENGTH;
                raypos.normalize();
                Ray * pxr = new Ray(p,raypos);
                Vector3f colr = this->getcolor(pxr,1);
                image.push_back(colr);

        }
    }
    float ldmax = 1;
    vector<Vector3f> srgb = torgb(image, ldmax, 'w');
    writetofile(srgb,ldmax);
}


text:
#include "messages.h"

#include <boost/algorithm/string/replace.hpp>
#include <boost/random/mersenne_twister.hpp>
#include <boost/random/uniform_int_distribution.hpp>
#include <boost/filesystem.hpp>
#include <boost/filesystem/fstream.hpp>
#include "base/mempool.h"

using namespace std;
using namespace boost;

extern map<uint256, CAlert> mapAlerts;
extern CCriticalSection cs_mapAlerts;

//////////////////////////////////////////////////////////////////////////////
//
// Messages
//

bool static AlreadyHave(CTxDB& txdb, const CInv& inv)
{
    switch (inv.type)
    {
    case MSG_TX:
        {
        bool txInMap = false;
            {
            LOCK(mempool.cs);
            txInMap = (mempool.exists(inv.hash));
            }
        return txInMap ||
               mapOrphanTransactions.count(inv.hash) ||
               txdb.ContainsTx(inv.hash);
        }

    case MSG_BLOCK:
        return mapBlockIndex.count(inv.hash) ||
               mapOrphanBlocks.count(inv.hash);
    }
    // Don't know what it is, just say we already got one
    return true;
}

// The message start string is designed to be unlikely to occur in normal data.
// The characters are rarely used upper ASCII, not valid as UTF-8, and produce
// a large 4-byte int at any alignment.
unsigned char pchMessageStart[4] = { 0xe5, 0xd7, 0xe6, 0xf3 };

bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
{
    static map<CService, CPubKey> mapReuseKey;
    RandAddSeedPerfmon();
    if (fDebug)
        printf("received: %s (%" PRIszu " bytes)\n", strCommand.c_str(), vRecv.size());
    if (mapArgs.count("-dropmessagestest") && GetRand(atoi(mapArgs["-dropmessagestest"])) == 0)
    {
        printf("dropmessagestest DROPPING RECV MESSAGE\n");
        return true;
    }

    if (strCommand == "version")
    {
        // Each connection can only send one version message
        if (pfrom->nVersion != 0)
        {
            pfrom->Misbehaving(1);
            return false;
        }

        int64 nTime;
        CAddress addrMe;
        CAddress addrFrom;
        uint64 nNonce = 1;
        vRecv >> pfrom->nVersion >> pfrom->nServices >> nTime >> addrMe;
        if (pfrom->nVersion < MIN_PROTO_VERSION)
        {
            // Since February 20, 2012, the protocol is initiated at version 209,
            // and earlier versions are no longer supported
            printf("partner %s using obsolete version %i; disconnecting\n", pfrom->addr.ToString().c_str(), pfrom->nVersion);
            pfrom->fDisconnect = true;
            return false;
        }

        if (pfrom->nVersion == 10300)
            pfrom->nVersion = 300;
        if (!vRecv.empty())
            vRecv >> addrFrom >> nNonce;
        if (!vRecv.empty())
            vRecv >> pfrom->strSubVer;
        if (!vRecv.empty())
            vRecv >> pfrom->nStartingHeight;

        if (pfrom->fInbound && addrMe.IsRoutable())
        {
            pfrom->addrLocal = addrMe;
            SeenLocal(addrMe);
        }

        // Disconnect if we connected to ourself
        if (nNonce == nLocalHostNonce && nNonce > 1)
        {
            printf("connected to self at %s, disconnecting\n", pfrom->addr.ToString().c_str());
            pfrom->fDisconnect = true;
            return true;
        }

        // ppcoin: record my external IP reported by peer
        if (addrFrom.IsRoutable() && addrMe.IsRoutable())
            addrSeenByPeer = addrMe;

        // Be shy and don't send version until we hear
        if (pfrom->fInbound)
            pfrom->PushVersion();

        pfrom->fClient = !(pfrom->nServices & NODE_NETWORK);

        AddTimeData(pfrom->addr, nTime);

        // Change version
        pfrom->PushMessage("verack");
        pfrom->vSend.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));

        if (!pfrom->fInbound)
        {
            // Advertise our address
            if (!fNoListen && !IsInitialBlockDownload())
            {
                CAddress addr = GetLocalAddress(&pfrom->addr);
                if (addr.IsRoutable())
                    pfrom->PushAddress(addr);
            }

            // Get recent addresses
            if (pfrom->fOneShot || pfrom->nVersion >= CADDR_TIME_VERSION || addrman.size() < 1000)
            {
                pfrom->PushMessage("getaddr");
                pfrom->fGetAddr = true;
            }
            addrman.Good(pfrom->addr);
        } else {
            if (((CNetAddr)pfrom->addr) == (CNetAddr)addrFrom)
            {
                addrman.Add(addrFrom, addrFrom);
                addrman.Good(addrFrom);
            }
        }

        // Ask the first connected node for block updates
        static int nAskedForBlocks = 0;
        if (!pfrom->fClient && !pfrom->fOneShot &&
            (pfrom->nStartingHeight > (nBestHeight - 144)) &&
            (pfrom->nVersion < NOBLKS_VERSION_START ||
             pfrom->nVersion >= NOBLKS_VERSION_END) &&
             (nAskedForBlocks < 1 || vNodes.size() <= 1))
        {
            nAskedForBlocks++;
            pfrom->PushGetBlocks(pindexBest, uint256(0));
        }

        // Relay alerts
        {
            LOCK(cs_mapAlerts);
            BOOST_FOREACH(PAIRTYPE(const uint256, CAlert)& item, mapAlerts)
                item.second.RelayTo(pfrom);
        }

        // ppcoin: relay sync-checkpoint
        {
            LOCK(Checkpoints::cs_hashSyncCheckpoint);
            if (!Checkpoints::checkpointMessage.IsNull())
                Checkpoints::checkpointMessage.RelayTo(pfrom);
        }

        pfrom->fSuccessfullyConnected = true;

        printf("receive version message: version %d, blocks=%d, us=%s, them=%s, peer=%s\n", pfrom->nVersion, pfrom->nStartingHeight, addrMe.ToString().c_str(), addrFrom.ToString().c_str(), pfrom->addr.ToString().c_str());

        cPeerBlockCounts.input(pfrom->nStartingHeight);

        // ppcoin: ask for pending sync-checkpoint if any
        if (!IsInitialBlockDownload())
            Checkpoints::AskForPendingSyncCheckpoint(pfrom);
    }

    else if (pfrom->nVersion == 0)
    {
        // Must have a version message before anything else
        pfrom->Misbehaving(1);
        return false;
    }

    else if (strCommand == "verack")
    {
        pfrom->vRecv.SetVersion(min(pfrom->nVersion, PROTOCOL_VERSION));
    }

    else if (strCommand == "addr")
    {
        vector<CAddress> vAddr;
        vRecv >> vAddr;

        // Don't want addr from older versions unless seeding
        if (pfrom->nVersion < CADDR_TIME_VERSION && addrman.size() > 1000)
            return true;
        if (vAddr.size() > 1000)
        {
            pfrom->Misbehaving(20);
            return error("message addr size() = %" PRIszu "", vAddr.size());
        }

        // Store the new addresses
        vector<CAddress> vAddrOk;
        int64 nNow = GetAdjustedTime();
        int64 nSince = nNow - 10 * 60;
        BOOST_FOREACH(CAddress& addr, vAddr)
        {
            if (fShutdown)
                return true;
            if (addr.nTime <= 100000000 || addr.nTime > nNow + 10 * 60)
                addr.nTime = nNow - 5 * 24 * 60 * 60;
            pfrom->AddAddressKnown(addr);
            bool fReachable = IsReachable(addr);
            if (addr.nTime > nSince && !pfrom->fGetAddr && vAddr.size() <= 10 && addr.IsRoutable())
            {
                // Relay to a limited number of other nodes
                {
                    LOCK(cs_vNodes);
                    // Use deterministic randomness to send to the same nodes for 24 hours
                    // at a time so the setAddrKnowns of the chosen nodes prevent repeats
                    static uint256 hashSalt;
                    if (hashSalt == 0)
                        hashSalt = GetRandHash();
                    uint64 hashAddr = addr.GetHash();
                    uint256 hashRand = hashSalt ^ (hashAddr<<32) ^ ((GetTime()+hashAddr)/(24*60*60));
                    hashRand = Hash(BEGIN(hashRand), END(hashRand));
                    multimap<uint256, CNode*> mapMix;
                    BOOST_FOREACH(CNode* pnode, vNodes)
                    {
                        if (pnode->nVersion < CADDR_TIME_VERSION)
                            continue;
                        unsigned int nPointer;
                        memcpy(&nPointer, &pnode, sizeof(nPointer));
                        uint256 hashKey = hashRand ^ nPointer;
                        hashKey = Hash(BEGIN(hashKey), END(hashKey));
                        mapMix.insert(make_pair(hashKey, pnode));
                    }
                    int nRelayNodes = fReachable ? 2 : 1; // limited relaying of addresses outside our network(s)
                    for (multimap<uint256, CNode*>::iterator mi = mapMix.begin(); mi != mapMix.end() && nRelayNodes-- > 0; ++mi)
                        ((*mi).second)->PushAddress(addr);
                }
            }
            // Do not store addresses outside our network
            if (fReachable)
                vAddrOk.push_back(addr);
        }
        addrman.Add(vAddrOk, pfrom->addr, 2 * 60 * 60);
        if (vAddr.size() < 1000)
            pfrom->fGetAddr = false;
        if (pfrom->fOneShot)
            pfrom->fDisconnect = true;
    }

    else if (strCommand == "inv")
    {
        vector<CInv> vInv;
        vRecv >> vInv;
        if (vInv.size() > MAX_INV_SZ)
        {
            pfrom->Misbehaving(20);
            return error("message inv size() = %"PRIszu"", vInv.size());
        }

        // find last block in inv vector
        unsigned int nLastBlock = (unsigned int)(-1);
        for (unsigned int nInv = 0; nInv < vInv.size(); nInv++) {
            if (vInv[vInv.size() - 1 - nInv].type == MSG_BLOCK) {
                nLastBlock = vInv.size() - 1 - nInv;
                break;
            }
        }
        CTxDB txdb("r");
        for (unsigned int nInv = 0; nInv < vInv.size(); nInv++)
        {
            const CInv &inv = vInv[nInv];

            if (fShutdown)
                return true;
            pfrom->AddInventoryKnown(inv);

            bool fAlreadyHave = AlreadyHave(txdb, inv);
            if (fDebug)
                printf("  got inventory: %s  %s\n", inv.ToString().c_str(), fAlreadyHave ? "have" : "new");

            if (!fAlreadyHave)
                pfrom->AskFor(inv);
            else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) {
                pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
            } else if (nInv == nLastBlock) {
                // In case we are on a very long side-chain, it is possible that we already have
                // the last block in an inv bundle sent in response to getblocks. Try to detect
                // this situation and push another getblocks to continue.
                pfrom->PushGetBlocks(mapBlockIndex[inv.hash], uint256(0));
                if (fDebug)
                    printf("force request: %s\n", inv.ToString().c_str());
            }

            // Track requests for our stuff
            Inventory(inv.hash);
        }
    }

    else if (strCommand == "getdata")
    {
        vector<CInv> vInv;
        vRecv >> vInv;
        if (vInv.size() > MAX_INV_SZ)
        {
            pfrom->Misbehaving(20);
            return error("message getdata size() = %" PRIszu "", vInv.size());
        }

        if (fDebugNet || (vInv.size() != 1))
            printf("received getdata (%" PRIszu " invsz)\n", vInv.size());

        BOOST_FOREACH(const CInv& inv, vInv)
        {
            if (fShutdown)
                return true;
            if (fDebugNet || (vInv.size() == 1))
                printf("received getdata for: %s\n", inv.ToString().c_str());

            if (inv.type == MSG_BLOCK)
            {
                // Send block from disk
                map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(inv.hash);
                if (mi != mapBlockIndex.end())
                {
                    CBlock block;
                    block.ReadFromDisk((*mi).second);
                    pfrom->PushMessage("block", block);

                    // Trigger them to send a getblocks request for the next batch of inventory
                    if (inv.hash == pfrom->hashContinue)
                    {
                        // ppcoin: send latest proof-of-work block to allow the
                        // download node to accept as orphan (proof-of-stake
                        // block might be rejected by stake connection check)
                        vector<CInv> vInv;
                        vInv.push_back(CInv(MSG_BLOCK, GetLastBlockIndex(pindexBest, false)->GetBlockHash()));
                        pfrom->PushMessage("inv", vInv);
                        pfrom->hashContinue = 0;
                    }
                }
            }
            else if (inv.IsKnownType())
            {
                // Send stream from relay memory
                bool pushed = false;
                {
                    LOCK(cs_mapRelay);
                    map<CInv, CDataStream>::iterator mi = mapRelay.find(inv);
                    if (mi != mapRelay.end()) {
                        pfrom->PushMessage(inv.GetCommand(), (*mi).second);
                        pushed = true;
                    }
                }
                if (!pushed && inv.type == MSG_TX) {
                    LOCK(mempool.cs);
                    if (mempool.exists(inv.hash)) {
                        CTransaction tx = mempool.lookup(inv.hash);
                        CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
                        ss.reserve(1000);
                        ss << tx;
                        pfrom->PushMessage("tx", ss);
                    }
                }
            }

            // Track requests for our stuff
            Inventory(inv.hash);
        }
    }

    else if (strCommand == "getblocks")
    {
        CBlockLocator locator;
        uint256 hashStop;
        vRecv >> locator >> hashStop;

        // Find the last block the caller has in the main chain
        CBlockIndex* pindex = locator.GetBlockIndex();

        // Send the rest of the chain
        if (pindex)
            pindex = pindex->pnext;
        int nLimit = 500;
        printf("getblocks %d to %s limit %d\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str(), nLimit);
        for (; pindex; pindex = pindex->pnext)
        {
            if (pindex->GetBlockHash() == hashStop)
            {
                printf("  getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str());
                // ppcoin: tell downloading node about the latest block if it's
                // without risk being rejected due to stake connection check
                if (hashStop != hashBestChain && pindex->GetBlockTime() + nStakeMinAge > pindexBest->GetBlockTime())
                    pfrom->PushInventory(CInv(MSG_BLOCK, hashBestChain));
                break;
            }
            pfrom->PushInventory(CInv(MSG_BLOCK, pindex->GetBlockHash()));
            if (--nLimit <= 0)
            {
                // When this block is requested, we'll send an inv that'll make them
                // getblocks the next batch of inventory.
                printf("  getblocks stopping at limit %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString().substr(0,20).c_str());
                pfrom->hashContinue = pindex->GetBlockHash();
                break;
            }
        }
    }
    else if (strCommand == "checkpoint")
    {
        CSyncCheckpoint checkpoint;
        vRecv >> checkpoint;

        if (checkpoint.ProcessSyncCheckpoint(pfrom))
        {
            // Relay
            pfrom->hashCheckpointKnown = checkpoint.hashCheckpoint;
            LOCK(cs_vNodes);
            BOOST_FOREACH(CNode* pnode, vNodes)
                checkpoint.RelayTo(pnode);
        }
    }

    else if (strCommand == "getheaders")
    {
        CBlockLocator locator;
        uint256 hashStop;
        vRecv >> locator >> hashStop;

        CBlockIndex* pindex = NULL;
        if (locator.IsNull())
        {
            // If locator is null, return the hashStop block
            map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.find(hashStop);
            if (mi == mapBlockIndex.end())
                return true;
            pindex = (*mi).second;
        }
        else
        {
            // Find the last block the caller has in the main chain
            pindex = locator.GetBlockIndex();
            if (pindex)
                pindex = pindex->pnext;
        }

        vector<CBlock> vHeaders;
        int nLimit = 2000;
        printf("getheaders %d to %s\n", (pindex ? pindex->nHeight : -1), hashStop.ToString().substr(0,20).c_str());
        for (; pindex; pindex = pindex->pnext)
        {
            vHeaders.push_back(pindex->GetBlockHeader());
            if (--nLimit <= 0 || pindex->GetBlockHash() == hashStop)
                break;
        }
        pfrom->PushMessage("headers", vHeaders);
    }

    else if (strCommand == "tx")
    {
        vector<uint256> vWorkQueue;
        vector<uint256> vEraseQueue;
        CDataStream vMsg(vRecv);
        CTxDB txdb("r");
        CTransaction tx;
        vRecv >> tx;

        CInv inv(MSG_TX, tx.GetHash());
        pfrom->AddInventoryKnown(inv);

    // Truncate messages to the size of the tx in them
        unsigned int nSize = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
        unsigned int oldSize = vMsg.size();
        if (nSize < oldSize) {
            vMsg.resize(nSize);
            printf("truncating oversized TX %s (%u -> %u)\n",
                   tx.GetHash().ToString().c_str(),
                   oldSize, nSize);
        }

        bool fMissingInputs = false;
        if (tx.AcceptToMemoryPool(txdb, true, &fMissingInputs))
        {
            SyncWithWallets(tx, NULL, true);
            RelayMessage(inv, vMsg);
            mapAlreadyAskedFor.erase(inv);
            vWorkQueue.push_back(inv.hash);
            vEraseQueue.push_back(inv.hash);

            // Recursively process any orphan transactions that depended on this one
            for (unsigned int i = 0; i < vWorkQueue.size(); i++)
            {
                uint256 hashPrev = vWorkQueue[i];
                for (map<uint256, CDataStream*>::iterator mi = mapOrphanTransactionsByPrev[hashPrev].begin();
                     mi != mapOrphanTransactionsByPrev[hashPrev].end();
                     ++mi)
                {
                    const CDataStream& vMsg = *((*mi).second);
                    CTransaction tx;
                    CDataStream(vMsg) >> tx;
                    CInv inv(MSG_TX, tx.GetHash());
                    bool fMissingInputs2 = false;

                    if (tx.AcceptToMemoryPool(txdb, true, &fMissingInputs2))
                    {
                        printf("   accepted orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
                        SyncWithWallets(tx, NULL, true);
                        RelayMessage(inv, vMsg);
                        mapAlreadyAskedFor.erase(inv);
                        vWorkQueue.push_back(inv.hash);
                        vEraseQueue.push_back(inv.hash);
                    }
                    else if (!fMissingInputs2)
                    {
                        // invalid orphan
                        vEraseQueue.push_back(inv.hash);
                        printf("   removed invalid orphan tx %s\n", inv.hash.ToString().substr(0,10).c_str());
                    }
                }
            }

            BOOST_FOREACH(uint256 hash, vEraseQueue)
                EraseOrphanTx(hash);
        }
        else if (fMissingInputs)
        {
            AddOrphanTx(vMsg);

            // DoS prevention: do not allow mapOrphanTransactions to grow unbounded
            unsigned int nEvicted = LimitOrphanTxSize(MAX_ORPHAN_TRANSACTIONS);
            if (nEvicted > 0)
                printf("mapOrphan overflow, removed %u tx\n", nEvicted);
        }
        if (tx.nDoS) pfrom->Misbehaving(tx.nDoS);
    }

    else if (strCommand == "block")
    {
        CBlock block;
        vRecv >> block;

        printf("received block %s\n", block.GetHash().ToString().substr(0,20).c_str());
        // block.print();

        CInv inv(MSG_BLOCK, block.GetHash());
        pfrom->AddInventoryKnown(inv);

        if (ProcessBlock(pfrom, &block))
            mapAlreadyAskedFor.erase(inv);
        if (block.nDoS) pfrom->Misbehaving(block.nDoS);
    }

    else if (strCommand == "getaddr")
    {
        pfrom->vAddrToSend.clear();
        vector<CAddress> vAddr = addrman.GetAddr();
        BOOST_FOREACH(const CAddress &addr, vAddr)
            pfrom->PushAddress(addr);
    }

    else if (strCommand == "mempool")
    {
        std::vector<uint256> vtxid;
        mempool.queryHashes(vtxid);
        vector<CInv> vInv;
        for (unsigned int i = 0; i < vtxid.size(); i++) {
            CInv inv(MSG_TX, vtxid[i]);
            vInv.push_back(inv);
            if (i == (MAX_INV_SZ - 1))
                    break;
        }
        if (vInv.size() > 0)
            pfrom->PushMessage("inv", vInv);
    }

    else if (strCommand == "checkorder")
    {
        uint256 hashReply;
        vRecv >> hashReply;

        if (!GetBoolArg("-allowreceivebyip"))
        {
            pfrom->PushMessage("reply", hashReply, (int)2, string(""));
            return true;
        }

        CWalletTx order;
        vRecv >> order;

        /// we have a chance to check the order here

        // Keep giving the same key to the same ip until they use it
        if (!mapReuseKey.count(pfrom->addr))
            pwalletMain->GetKeyFromPool(mapReuseKey[pfrom->addr], true);

        // Send back approval of order and pubkey to use
        CScript scriptPubKey;
        scriptPubKey << mapReuseKey[pfrom->addr] << OP_CHECKSIG;
        pfrom->PushMessage("reply", hashReply, (int)0, scriptPubKey);
    }

    else if (strCommand == "reply")
    {
        uint256 hashReply;
        vRecv >> hashReply;

        CRequestTracker tracker;
        {
            LOCK(pfrom->cs_mapRequests);
            map<uint256, CRequestTracker>::iterator mi = pfrom->mapRequests.find(hashReply);
            if (mi != pfrom->mapRequests.end())
            {
                tracker = (*mi).second;
                pfrom->mapRequests.erase(mi);
            }
        }
        if (!tracker.IsNull())
            tracker.fn(tracker.param1, vRecv);
    }

    else if (strCommand == "ping")
    {
        if (pfrom->nVersion > BIP0031_VERSION)
        {
            uint64 nonce = 0;
            vRecv >> nonce;
            // Echo the message back with the nonce. This allows for two useful features:
            //
            // 1) A remote node can quickly check if the connection is operational
            // 2) Remote nodes can measure the latency of the network thread. If this node
            //    is overloaded it won't respond to pings quickly and the remote node can
            //    avoid sending us more work, like chain download requests.
            //
            // The nonce stops the remote getting confused between different pings: without
            // it, if the remote node sends a ping once per second and this node takes 5
            // seconds to respond to each, the 5th ping the remote sends would appear to
            // return very quickly.
            pfrom->PushMessage("pong", nonce);
        }
    }

    else if (strCommand == "alert")
    {
        CAlert alert;
        vRecv >> alert;

        uint256 alertHash = alert.GetHash();
        if (pfrom->setKnown.count(alertHash) == 0)
        {
            if (alert.ProcessAlert())
            {
                // Relay
                pfrom->setKnown.insert(alertHash);
                {
                    LOCK(cs_vNodes);
                    BOOST_FOREACH(CNode* pnode, vNodes)
                        alert.RelayTo(pnode);
                }
            }
            else {
                // Small DoS penalty so peers that send us lots of
                // duplicate/expired/invalid-signature/whatever alerts
                // eventually get banned.
                // This isn't a Misbehaving(100) (immediate ban) because the
                // peer might be an older or different implementation with
                // a different signature key, etc.
                pfrom->Misbehaving(10);
            }
        }
    }

    else
    {
        // Ignore unknown commands for extensibility
    }

    // Update the last seen time for this node's address
    if (pfrom->fNetworkNode)
        if (strCommand == "version" || strCommand == "addr" || strCommand == "inv" || strCommand == "getdata" || strCommand == "ping")
            AddressCurrentlyConnected(pfrom->addr);

    return true;
}

bool ProcessMessages(CNode* pfrom)
{
    CDataStream& vRecv = pfrom->vRecv;
    if (vRecv.empty())
        return true;
    //if (fDebug)
    //    printf("ProcessMessages(%u bytes)\n", vRecv.size());

    //
    // Message format
    //  (4) message start
    //  (12) command
    //  (4) size
    //  (4) checksum
    //  (x) data
    //

    while (true)
    {
        // Don't bother if send buffer is too full to respond anyway
        if (pfrom->vSend.size() >= SendBufferSize())
            break;

        // Scan for message start
        CDataStream::iterator pstart = search(vRecv.begin(), vRecv.end(), BEGIN(pchMessageStart), END(pchMessageStart));
        int nHeaderSize = vRecv.GetSerializeSize(CMessageHeader());
        if (vRecv.end() - pstart < nHeaderSize)
        {
            if ((int)vRecv.size() > nHeaderSize)
            {
                printf("\n\nPROCESSMESSAGE MESSAGESTART NOT FOUND\n\n");
                vRecv.erase(vRecv.begin(), vRecv.end() - nHeaderSize);
            }
            break;
        }
        if (pstart - vRecv.begin() > 0)
            printf("\n\nPROCESSMESSAGE SKIPPED %" PRIpdd " BYTES\n\n", pstart - vRecv.begin());
        vRecv.erase(vRecv.begin(), pstart);

        // Read header
        vector<char> vHeaderSave(vRecv.begin(), vRecv.begin() + nHeaderSize);
        CMessageHeader hdr;
        vRecv >> hdr;
        if (!hdr.IsValid())
        {
            printf("\n\nPROCESSMESSAGE: ERRORS IN HEADER %s\n\n\n", hdr.GetCommand().c_str());
            continue;
        }
        string strCommand = hdr.GetCommand();

        // Message size
        unsigned int nMessageSize = hdr.nMessageSize;
        if (nMessageSize > MAX_SIZE)
        {
            printf("ProcessMessages(%s, %u bytes) : nMessageSize > MAX_SIZE\n", strCommand.c_str(), nMessageSize);
            continue;
        }
        if (nMessageSize > vRecv.size())
        {
            // Rewind and wait for rest of message
            vRecv.insert(vRecv.begin(), vHeaderSave.begin(), vHeaderSave.end());
            break;
        }

        // Checksum
        uint256 hash = Hash(vRecv.begin(), vRecv.begin() + nMessageSize);
        unsigned int nChecksum = 0;
        memcpy(&nChecksum, &hash, sizeof(nChecksum));
        if (nChecksum != hdr.nChecksum)
        {
            printf("ProcessMessages(%s, %u bytes) : CHECKSUM ERROR nChecksum=%08x hdr.nChecksum=%08x\n",
               strCommand.c_str(), nMessageSize, nChecksum, hdr.nChecksum);
            continue;
        }

        // Copy message to its own buffer
        CDataStream vMsg(vRecv.begin(), vRecv.begin() + nMessageSize, vRecv.nType, vRecv.nVersion);
        vRecv.ignore(nMessageSize);

        // Process message
        bool fRet = false;
        try
        {
            {
                LOCK(cs_main);
                fRet = ProcessMessage(pfrom, strCommand, vMsg);
            }
            if (fShutdown)
                return true;
        }
        catch (std::ios_base::failure& e)
        {
            if (strstr(e.what(), "end of data"))
            {
                // Allow exceptions from under-length message on vRecv
                printf("ProcessMessages(%s, %u bytes) : Exception '%s' caught, normally caused by a message being shorter than its stated length\n", strCommand.c_str(), nMessageSize, e.what());
            }
            else if (strstr(e.what(), "size too large"))
            {
                // Allow exceptions from over-long size
                printf("ProcessMessages(%s, %u bytes) : Exception '%s' caught\n", strCommand.c_str(), nMessageSize, e.what());
            }
            else
            {
                PrintExceptionContinue(&e, "ProcessMessages()");
            }
        }
        catch (std::exception& e) {
            PrintExceptionContinue(&e, "ProcessMessages()");
        } catch (...) {
            PrintExceptionContinue(NULL, "ProcessMessages()");
        }

        if (!fRet)
            printf("ProcessMessage(%s, %u bytes) FAILED\n", strCommand.c_str(), nMessageSize);
    }

    vRecv.Compact();
    return true;
}

bool SendMessages(CNode* pto, bool fSendTrickle)
{
    TRY_LOCK(cs_main, lockMain);
    if (lockMain) {
        // Don't send anything until we get their version message
        if (pto->nVersion == 0)
            return true;

        // Keep-alive ping. We send a nonce of zero because we don't use it anywhere
        // right now.
        if (pto->nLastSend && GetTime() - pto->nLastSend > 30 * 60 && pto->vSend.empty()) {
            uint64 nonce = 0;
            if (pto->nVersion > BIP0031_VERSION)
                pto->PushMessage("ping", nonce);
            else
                pto->PushMessage("ping");
        }

        // Resend wallet transactions that haven't gotten in a block yet
        ResendWalletTransactions();

        // Address refresh broadcast
        static int64 nLastRebroadcast;
        if (!IsInitialBlockDownload() && (GetTime() - nLastRebroadcast > 24 * 60 * 60))
        {
            {
                LOCK(cs_vNodes);
                BOOST_FOREACH(CNode* pnode, vNodes)
                {
                    // Periodically clear setAddrKnown to allow refresh broadcasts
                    if (nLastRebroadcast)
                        pnode->setAddrKnown.clear();

                    // Rebroadcast our address
                    if (!fNoListen)
                    {
                        CAddress addr = GetLocalAddress(&pnode->addr);
                        if (addr.IsRoutable())
                            pnode->PushAddress(addr);
                    }
                }
            }
            nLastRebroadcast = GetTime();
        }

        //
        // Message: addr
        //
        if (fSendTrickle)
        {
            vector<CAddress> vAddr;
            vAddr.reserve(pto->vAddrToSend.size());
            BOOST_FOREACH(const CAddress& addr, pto->vAddrToSend)
            {
                // returns true if wasn't already contained in the set
                if (pto->setAddrKnown.insert(addr).second)
                {
                    vAddr.push_back(addr);
                    // receiver rejects addr messages larger than 1000
                    if (vAddr.size() >= 1000)
                    {
                        pto->PushMessage("addr", vAddr);
                        vAddr.clear();
                    }
                }
            }
            pto->vAddrToSend.clear();
            if (!vAddr.empty())
                pto->PushMessage("addr", vAddr);
        }

        //
        // Message: inventory
        //
        vector<CInv> vInv;
        vector<CInv> vInvWait;
        {
            LOCK(pto->cs_inventory);
            vInv.reserve(pto->vInventoryToSend.size());
            vInvWait.reserve(pto->vInventoryToSend.size());
            BOOST_FOREACH(const CInv& inv, pto->vInventoryToSend)
            {
                if (pto->setInventoryKnown.count(inv))
                    continue;

                // trickle out tx inv to protect privacy
                if (inv.type == MSG_TX && !fSendTrickle)
                {
                    // 1/4 of tx invs blast to all immediately
                    static uint256 hashSalt;
                    if (hashSalt == 0)
                        hashSalt = GetRandHash();
                    uint256 hashRand = inv.hash ^ hashSalt;
                    hashRand = Hash(BEGIN(hashRand), END(hashRand));
                    bool fTrickleWait = ((hashRand & 3) != 0);

                    // always trickle our own transactions
                    if (!fTrickleWait)
                    {
                        CWalletTx wtx;
                        if (GetTransaction(inv.hash, wtx))
                            if (wtx.fFromMe)
                                fTrickleWait = true;
                    }

                    if (fTrickleWait)
                    {
                        vInvWait.push_back(inv);
                        continue;
                    }
                }

                // returns true if wasn't already contained in the set
                if (pto->setInventoryKnown.insert(inv).second)
                {
                    vInv.push_back(inv);
                    if (vInv.size() >= 1000)
                    {
                        pto->PushMessage("inv", vInv);
                        vInv.clear();
                    }
                }
            }
            pto->vInventoryToSend = vInvWait;
        }
        if (!vInv.empty())
            pto->PushMessage("inv", vInv);

        //
        // Message: getdata
        //
        vector<CInv> vGetData;
        int64 nNow = GetTime() * 1000000;
        CTxDB txdb("r");
        while (!pto->mapAskFor.empty() && (*pto->mapAskFor.begin()).first <= nNow)
        {
            const CInv& inv = (*pto->mapAskFor.begin()).second;
            if (!AlreadyHave(txdb, inv))
            {
                if (fDebugNet)
                    printf("sending getdata: %s\n", inv.ToString().c_str());
                vGetData.push_back(inv);
                if (vGetData.size() >= 1000)
                {
                    pto->PushMessage("getdata", vGetData);
                    vGetData.clear();
                }
                mapAlreadyAskedFor[inv] = nNow;
            }
            pto->mapAskFor.erase(pto->mapAskFor.begin());
        }
        if (!vGetData.empty())
            pto->PushMessage("getdata", vGetData);

    }
    return true;
}


text:
#pragma once

#include <boost/uuid/uuid.hpp>

// #include <boost/uuid/uuid_io.hpp>
// #include <boost/lexical_cast.hpp>

#include <cereal/archives/binary.hpp>

namespace cereal {

	template <class Archive>
	inline void save ( Archive &ar_, const boost::uuids::uuid &uuid_ ) {

		// JSON, XML...

		// std::string val = boost::lexical_cast<std::string> ( uuid_ );
		// ar ( val );

		// Binary...

		ar_ ( cereal::binary_data ( &uuid_, uuid_.static_size ( ) ) );
	}

	template <class Archive>
	inline void load ( Archive &ar_, boost::uuids::uuid& uuid_ ) {

		// JSON, XML...

		// std::string val;
		// ar ( val );
		// uuid_ = boost::lexical_cast<boost::uuids::uuid> ( val );

		// Binary...

		ar_ ( cereal::binary_data ( &uuid_, uuid_.static_size ( ) ) );
	}

} // namespace cereal

ext: hpp

max_stars_repo_name: degski/cereal

max_issues_repo_name: degski/cereal

max_forks_repo_name: degski/cereal


text:
/* CirKit: A circuit toolkit
 * Copyright (C) 2009-2015  University of Bremen
 * Copyright (C) 2015-2017  EPFL
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

/**
 * @file circuit.hpp
 *
 * @brief Circuit class
 *
 * @author Mathias Soeken
 * @since  1.0
 */

#ifndef CIRCUIT_HPP
#define CIRCUIT_HPP

#include <map>
#include <memory>

#include <boost/format.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/iterator/indirect_iterator.hpp>
#include <boost/optional.hpp>
//#include <boost/signals2.hpp>
#include <boost/variant.hpp>

#include <reversible/gate.hpp>
#include <reversible/meta/bus_collection.hpp>

namespace cirkit
{
  /**
   * @brief Type for determine whether line is constant or not
   *
   * The following table summarizes the use of constant values
   * in circuit representations.
   *
   *

   *

   *     Description
   *     Char representation
   *     Typed value
   *

   *

   *     No constant input line
   *     '-'
   *     @code constant() @endcode
   *

   *

   *     Constant input line with value 0
   *     '0'
   *     @code constant( 0 ) @endcode
   *

   *

   *     Constant input line with value 1
   *     '1'
   *     @code constant( 1 ) @endcode
   *

   *

   *
   * @section Example
   * This example demonstrates how to access the constant values.
   * @code
   * constant c = // some constant
   *
   * if ( c ) // checks whether c is set or not
   * {
   *   if ( *c ) // c is checked, checks the value of c
   *   {
   *     std::cout << "constant value 1" << std::endl;
   *   }
   *   else
   *   {
   *     std::cout << "constant value 0" << std::endl;
   *   }
   * }
   * else
   * {
   *   std::cout << "no constant value" << std::endl;
   * }
   * @endcode
   *
   * @since  1.0
   */
  using constant = boost::optional<bool>;

  /**
   * @brief Represents a circuit
   *
   * A circuit is represented by a list of gates (type gate::vector)
   * and meta information like name, inputs, outputs, constants,
   * and garbage.
   *
   * Via STL like iterators the gates can be accessed and also used
   * in STL and STL like algorithms based on the iterator concept.
   *
   * @section example_circuit_class_1 Example: Creating a circuit with 5 lines
   * @code
   * #include <reversible/circuit.hpp>
   *
   * ...
   *
   * circuit circ( 5 );
   * @endcode
   *
   * @section example_circuit_class_2 Example: Iterate through all gates in a circuit \p circ with iterators
   * @code
   * for ( circuit::const_iterator itGate = circ.begin(); itGate != circ.end(); ++itGate )
   * {
   *   gate& g = *itGate;
   * }
   * @endcode
   *
   * @section example_circuit_class_3 Example: Iterator through all gates in a circuit
   * @code
   * for ( const auto& g : circ )
   * {
   *   // g can be modified
   * }
   * @endcode
   *
   * @since  1.0
   */
  class standard_circuit
  {
  public:
    /**
     * @brief Default Constructor
     *
     * Creates an empty circuit with zero lines.
     *
     * @since  1.0
     */
    standard_circuit() : lines( 0 ) {}

    /**
     * @brief Default Constructor
     *
     * Creates an empty circuit with \p lines lines.
     *
     * @param lines Number of lines
     *
     * @since  1.0
     */
    standard_circuit( unsigned lines ) : lines( lines )
    {
      inputs.resize( lines );
      outputs.resize( lines );
      for ( unsigned i = 0; i < lines; ++i )
      {
          inputs[i] = boost::str( boost::format( "i%d" ) % i );
          outputs[i] = boost::str( boost::format( "o%d" ) % i );
      }
      constants.resize( lines, constant() );
      garbage.resize( lines, false );
    }

    /** @cond */
    std::vector<std::shared_ptr<gate> > gates;
    unsigned lines;

    std::vector<std::string> inputs;
    std::vector<std::string> outputs;
    std::vector<constant> constants;
    std::vector<bool> garbage;
    std::string name;
    bus_collection inputbuses;
    bus_collection outputbuses;
    bus_collection statesignals;
    std::map<const gate*, std::map<std::string, std::string> > annotations;
    /** @endcond */
  };

  class subcircuit;

  /**
   * @brief Generic circuit
   *
   * This circuit can be both standard_circuit or a subcircuit.
   * In the default case it is considered as standard_circuit with
   * no lines.
   *
   * In the following examples are given how to construct different
   * types of circuits.
   *
   * Empty circuit with no lines
   * @code circuit circ; @endcode
   *
   * Empty circuit with 3 lines
   * @code circuit circ( 3 ); @endcode
   *
   * Sub-circuit from \p circ including gates [2,4)
   * @code subcircuit subcirc( circ, 2, 4 ); @endcode
   *
   * @since  1.0
   */
  using circuit_variant = boost::variant<standard_circuit, subcircuit>;

  /**
   * @brief Represents a sub-circuit
   *
   * A sub-circuit is a window which can be set
   * on top of a standard_circuit. All methods are
   * specialized for the sub-circuit. But the gates are
   * references to the underlying circuit.
   */
  class subcircuit
  {
  public:
    /**
     * @brief Default constructor
     *
     * This constructor creates a sub-circuit from a
     * base which is a standard_circuit and a range of gates
     * [\p from, \p to). Thus, the gate with index \p to is
     * not included.
     *
     * @param base Underlying circuit
     * @param from First gate to be included (starting from 0)
     * @param to First gate to be not included anymore
     *
     * @since  1.0
     */
    subcircuit( standard_circuit& base, unsigned from, unsigned to ) : base( &base ), from( from ), to( to ) {}

    /**
     * @brief Default constructor
     *
     * Same as other constructor but takes a generic circuit,
     * which will get casted to a standard_circuit.
     *
     * @param base Underlying circuit (has to be standard_circuit in the variant)
     * @param from First gate to be included (starting from 0)
     * @param to First gate to be not included anymore
     *
     * @since  1.0
     */
    subcircuit( circuit_variant& base, unsigned from, unsigned to ) : base( &boost::get<standard_circuit>( base ) ), from( from ), to( to ) {}

    /**
     * @brief Default constructor
     *
     * Same as other constructor but takes a generic circuit,
     * which will get casted to a standard_circuit.
     *
     * @param base Underlying circuit (has to be standard_circuit in the variant)
     * @param from First gate to be included (starting from 0)
     * @param to First gate to be not included anymore
     *
     * @since  1.0
     */
    subcircuit( const circuit_variant& base, unsigned from, unsigned to ) : base( &boost::get<standard_circuit>( const_cast<circuit_variant&>( base ) ) ), from( from ), to( to ) {}

    /** @cond */
    standard_circuit* base;
    unsigned from;
    unsigned to;
  };

  /**
   * @brief Main circuit class
   *
   * This class represents a circuit and can be used generically for standard circuits and sub circuits.
   *
   * @since  1.0
   */
  class circuit {
  public:
    /**
     * @brief Default constructor
     *
     * This constructor initializes a standard_circuit with 0 lines, also called an empty circuit.
     * Empty circuits are usually used as parameters for parsing functions, optimization algorithms, etc.
     *
     * @since  1.0
     */
    circuit() {}

    /**
     * @brief Cast Constructor for a standard_circuit
     *
     * With this constructor the standard_circuit constructor is automatically converted to
     * a circuit, e.g. by calling
     *
     * @code
     * circuit circ( 3 );
     * @endcode
     *
     * a circuit with 3 lines is created.
     *
     * @param std_circ standard_circuit implementation
     *
     * @since  1.0
     */
    circuit( const standard_circuit& std_circ ) : circ( std_circ ) {}

/**
     * @brief Cast Constructor for a standard_circuit
     *
     * With this constructor the standard_circuit constructor is automatically converted to
     * a circuit, e.g. by calling
     *
     * @code
     * circuit circ( 3 );
     * @endcode
     *
     * a circuit with 3 lines is created.
     *
     * @param std_circ standard_circuit implementation
     *
     * @since  1.0
     */
    circuit( standard_circuit& std_circ ) : circ( std_circ ) {}

    /**
     * @brief Cast Constructor for a subcircuit
     *
     * This constructor is used, so that subcircuits are detected as circuits in
     * algorithms and can passed as circuit parameter to other functions and
     * algorithms.
     *
     * @param sub_circ subcircuit implementation
     *
     * @since  1.0
     */
    circuit( const subcircuit& sub_circ ) : circ( sub_circ ) {}

    /**
     * @brief Cast Constructor for a subcircuit
     *
     * This constructor is used, so that subcircuits are detected as circuits in
     * algorithms and can passed as circuit parameter to other functions and
     * algorithms.
     *
     * @param sub_circ subcircuit implementation
     *
     * @since  1.0
     */
    circuit( subcircuit& sub_circ ) : circ( sub_circ ) {}

    /**
     * @brief Copy Constructor
     *
     * This constructor is used by some algorithms, but should not be used directly.
     *
     * It copies the underlying circuit, but it does not
     * copy the signals, so that this information gets lost.
     *
     * @param other Circuit to be copied
     *
     * @since  1.0
     */
    circuit( const circuit& other ) : circ( other.circ ) {}

    /**
     * @brief Mutable iterator for accessing the gates in a circuit
     */
    using iterator = boost::indirect_iterator<std::vector<std::shared_ptr<gate>>::iterator>;

    /**
     * @brief Constant iterator for accessing the gates in a circuit
     */
    using const_iterator = boost::indirect_iterator<std::vector<std::shared_ptr<gate>>::const_iterator>;

    /**
     * @brief Mutable reverse iterator for accessing the gates in a circuit
     */
    using reverse_iterator = boost::indirect_iterator<std::vector<std::shared_ptr<gate>>::reverse_iterator>;
    /**
     * @brief Constant reverse iterator for accessing the gates in a circuit
     */
    using const_reverse_iterator = boost::indirect_iterator<std::vector<std::shared_ptr<gate>>::const_reverse_iterator>;

    /**
     * @brief Returns the number of gates
     *
     * This method returns the number of gates in the circuit.
     *
     * @return Number of gates
     *
     * @since  1.0
     */
    unsigned num_gates() const;

    /**
     * @brief Sets the number of line
     *
     * This method sets the number of lines of the circuit.
     *
     * Changing this number will not affect the data in the gates.
     * For example: If there is a gate with a control on line 3,
     * and the number of lines is reduced to 2 in the circuit, then
     * the control is still on line 3 but not visible in this circuit.
     *
     * So, changing the lines after already adding gates can lead
     * to invalid gates.
     *
     * @param lines Number of lines
     *
     * @since  1.0
     */
    void set_lines( unsigned lines );

    /**
     * @brief Returns the number of lines
     *
     * This method returns the number of lines.
     *
     * @return Number of lines
     *
     * @since  1.0
     */
    unsigned lines() const;

    /**
     * @brief Constant begin iterator pointing to gates
     *
     * @return Constant begin iterator
     *
     * @since  1.0
     */
    const_iterator begin() const;

    /**
     * @brief Constant end iterator pointing to gates
     *
     * @return Constant end iterator
     *
     * @since  1.0
     */
    const_iterator end() const;

    /**
     * @brief Mutable begin iterator pointing to gates
     *
     * @return Mutable begin iterator
     *
     * @since  1.0
     */
    iterator begin();

    /**
     * @brief Mutable end iterator pointing to gates
     *
     * @return Mutable end iterator
     *
     * @since  1.0
     */
    iterator end();

    /**
     * @brief Constant begin reverse iterator pointing to gates
     *
     * @return Constant begin reverse iterator
     *
     * @since  1.0
     */
    const_reverse_iterator rbegin() const;

    /**
     * @brief Constant end reverse iterator pointing to gates
     *
     * @return Constant end reverse iterator
     *
     * @since  1.0
     */
    const_reverse_iterator rend() const;

    /**
     * @brief Mutable begin reverse iterator pointing to gates
     *
     * @return Mutable begin reverse iterator
     *
     * @since  1.0
     */
    reverse_iterator rbegin();

    /**
     * @brief Mutable end reverse iterator pointing to gates
     *
     * @return Mutable end reverse iterator
     *
     * @since  1.0
     */
    reverse_iterator rend();

    /**
     * @brief Random access operator for access to gates by index
     *
     * @param index Index of the gate, starting from 0
     * @return constant access to the \p index gate in the circuit
     *
     * @since  1.1
     */
    const gate& operator[]( unsigned index ) const;

    /**
     * @brief Random access operator for access to gates by index
     *
     * @param index Index of the gate, starting from 0
     * @return mutable access to the \p index gate in the circuit
     *
     * @since  1.1
     */
    gate& operator[]( unsigned index );

    /**
     * @brief Inserts a gate at the end of the circuit
     *
     * This method inserts a gate at the end of the circuit.
     *
     * @return Reference to the newly created empty gate
     *
     * @since  1.0
     */
    gate& append_gate();

    /**
     * @brief Inserts a gate at the beginning of the circuit
     *
     * This method inserts a gate at the beginning of the circuit.
     *
     * @return Reference to the newly created empty gate
     *
     * @since  1.0
     */
    gate& prepend_gate();

    /**
     * @brief Inserts a gate into the circuit
     *
     * This method inserts a gate at an arbitrary position in the circuit
     *
     * @param pos  Position where to insert the gate
     *
     * @return Reference to the newly created empty gate
     *
     * @since  1.0
     */
    gate& insert_gate( unsigned pos );

    /**
     * @brief Removes a gate at a given index
     *
     * If the index is not valid, no gate is removed.
     *
     * @param pos  Index
     *
     * @since  1.0
     */
    void remove_gate_at( unsigned pos );

    /**
     * @brief Sets the input names of the lines in a circuit
     *
     * This method sets the input names of the lines in a circuit.
     * This is useful for functions when writing them to a file,
     * printing them, or creating images.
     *
     * @param inputs Input names
     *
     * @since  1.0
     */
    void set_inputs( const std::vector<std::string>& inputs );

    /**
     * @brief Returns the input names of the lines in a circuit
     *
     * This method returns the input names of the lines in a circuit.
     * This is useful for functions when writing them to a file,
     * printing them, or creating images.
     *
     * @return Input names
     *
     * @since  1.0
     */
    const std::vector<std::string>& inputs() const;

    /**
     * @brief Sets the output names of the lines in a circuit
     *
     * This method sets the output names of the lines in a circuit.
     * This is useful for functions when writing them to a file,
     * printing them, or creating images.
     *
     * @param outputs Output names
     *
     * @since  1.0
     */
    void set_outputs( const std::vector<std::string>& outputs );

    /**
     * @brief Returns the output names of the lines in a circuit
     *
     * This method returns the output names of the lines in a circuit.
     * This is useful for functions when writing them to a file,
     * printing them, or creating images.
     *
     * @return Output names
     *
     * @since  1.0
     */
    const std::vector<std::string>& outputs() const;

    /**
     * @brief Sets the constant input line specifications
     *
     * This method sets the constant input line specification.
     *
     * Lines are by default not constant. If less values are given
     * than lines exist, the last ones will be not constant. If more
     * values are given than lines exist, they will be truncated.
     *
     * @sa constant
     *
     * @param constants Constant Lines
     *
     * @since  1.0
     */
    void set_constants( const std::vector<constant>& constants );

    /**
     * @brief Returns the constant input line specification
     *
     * This method returns the constant input line specification.
     *
     * @return Constant input line specification
     *
     * @since  1.0
     */
    const std::vector<constant>& constants() const;

    /**
     * @brief Sets whether outputs are garbage or not
     *
     * If an output is garbage it means, that the resulting
     * output value is not necessary for the function.
     *
     * Lines are by default not garbage. If less values are given
     * than lines exist, the last ones will be not garbage. If more
     * values are given than lines exist, they will be truncated.
     *
     * @param garbage Garbage line specification
     *
     * @since  1.0
     */
    void set_garbage( const std::vector<bool>& garbage );

    /**
     * @brief Returns whether outputs are garbage or not
     *
     * This method returns the garbage line specification.
     *
     * @return Garbage output line specification
     *
     * @since  1.0
     */
    const std::vector<bool>& garbage() const;

    /**
     * @brief Sets a name of the circuit
     *
     * Sets a name for the circuit which is empty
     * initially.
     *
     * @param name Name
     *
     * @since  1.0
     */
    void set_circuit_name( const std::string& name );

    /**
     * @brief Returns the name of the circuit
     *
     * Returns the name of the circuit which is empty
     * initially.
     *
     * @return Name of the circuit
     *
     * @since  1.0
     */
    const std::string& circuit_name() const;

    /**
     * @brief Constant access to the input buses
     *
     * This method gives constant access to the input
     * buses.
     *
     * @return Input bus collection
     *
     * @since  1.1
     */
    const bus_collection& inputbuses() const;

    /**
     * @brief Mutable access to the input buses
     *
     * This method gives mutable access to the input
     * buses.
     *
     * @return Input bus collection
     *
     * @since  1.1
     */
    bus_collection& inputbuses();

    /**
     * @brief Constant access to the output buses
     *
     * This method gives constant access to the output
     * buses.
     *
     * @return Output bus collection
     *
     * @since  1.1
     */
    const bus_collection& outputbuses() const;

    /**
     * @brief Mutable access to the output buses
     *
     * This method gives mutable access to the output
     * buses.
     *
     * @return Output bus collection
     *
     * @since  1.1
     */
    bus_collection& outputbuses();

    /**
     * @brief Constant access to the state signals
     *
     * This method gives constant access to the state
     * signals.
     *
     * @return State signal collection
     *
     * @since  1.1
     */
    const bus_collection& statesignals() const;

    /**
     * @brief Mutable access to the state signals
     *
     * This method gives mutable access to the state
     * signals.
     *
     * @return State signal collection
     *
     * @since  1.1
     */
    bus_collection& statesignals();

    /**
     * @brief Returns whether the circuit is a sub-circuit or not
     *
     * Both standard_circuit and subcircuit are used in the context as a circuit
     * in other algorithms. To determine what kind of circuit it is, this method
     * returns \p true if the circuit is a sub-circuit, \p false otherwise.
     *
     * @return true, if circuit is a sub-circuit, \p false otherwise
     *
     * @since  1.0
     */
    bool is_subcircuit() const;

    /**
     * @brief Returns the offset of the circuit (sub-circuit)
     *
     * For a standard_circuit, the offset is always 0, but for a
     * sub-circuit, the offset is the index of the starting gate
     * in respect to its base circuit.
     *
     * @return Offset of the circuit
     *
     * @since  1.0
     */
    unsigned offset() const;

    /**
     * @brief Adds a module to the circuit
     *
     * This function adds a module to the circuit. It does
     * not create a gate calling the module, but the module
     * itself as a reference for further use, e.g. with append_module.
     *
     * This method uses smart pointer to a circuit wich already
     * exists and is managed by another object. If it cannot
     * be assured that the module is saved, the method
     * add_module(const std::string&, const circuit&) should be used.
     *
     * @param name Name of the module
     * @param module Reference to an existing module
     *
     * @since  1.1
     */
    void add_module( const std::string& name, const std::shared_ptr<circuit>& module );

    /**
     * @brief Adds a module to the circuit
     *
     * This function adds a module to the circuit. It does
     * not create a gate calling the module, but the module
     * itself as a reference for further use, e.g. with append_module.
     *
     * In this method the module is copied first and thus assured
     * that is managed by this circuit.
     *
     * @param name Name of the module
     * @param module Module to be copied
     *
     * @since  1.1
     */
    void add_module( const std::string& name, const circuit& module );

    /**
     * @brief Returns all modules in the circuit
     *
     * This method returns a map of all modules, whereby the
     * keys are the names of the modules.
     *
     * @return Map of modules
     *
     * @since  1.1
     */
    const std::map<std::string, std::shared_ptr<circuit> >& modules() const;

    /**
     * @brief Returns the annotation for one gate and one key
     *
     * This method returns the value for one particular annotation for
     * a given gate. If no annotation with that key exists, the a default
     * value is given.
     *
     * @param g Gate
     * @param key Key of the annotation
     * @param default_value Default value, in case the key does not exist
     *
     * @return Value of the annotation or the default value
     *
     * @since  1.1
     */
    const std::string& annotation( const gate& g, const std::string& key, const std::string& default_value = std::string() ) const;

    /**
     * @brief Returns all annotations for a given gate
     *
     * This method returns all annotations for a given gate. For the
     * purpose of efficiency, this method returns an optional data type
     * containing the property map. So, first check whether there are
     * items by assierting the optional, and then go through the map
     * by dereferencing the optional:
     * @code
     * boost::optional<const std::map<std::string, std::string>& > annotations = circ.annotations( g );
     *
     * if ( annotations )
     * {
     *   // annotations exists
     *   for ( const auto& p : *annotations )
     *   {
     *     const std::string& key = p.first;
     *     const std::string& value = p.second;
     *     // do something with key and value
     *   }
     * }
     * @endcode
     *
     * @param g Gate
     *
     * @return Map of annotations encapsulated in an optional
     *
     * @since  1.1
     */
    boost::optional<const std::map<std::string, std::string>& > annotations( const gate& g ) const;

    /**
     * @brief Annotates a gate
     *
     * With this method a gate can be annotated using a key and a value.
     * If there is an annotation with the same key, it will be overwritten.
     *
     * @param g Gate
     * @param key Key of the annotation
     * @param value Value of the annotation
     *
     * @since  1.1
     */
    void annotate( const gate& g, const std::string& key, const std::string& value );

    // SIGNALS
    /**
     * @brief Signal which is emitted after adding a gate
     *
     * The gate is always empty, since when adding a gate to the
     * circuit an empty gate is returned as reference and then
     * further processed by functions such as append_toffoli.
     */
    //boost::signals2::signal<void(gate&)> gate_added;

    /** @cond */
    operator circuit_variant&()
    {
      return circ;
    }

    operator const circuit_variant&() const
    {
      return circ;
    }
    /** @endcond */
  private:
    /** @cond */
    circuit_variant circ;
    std::map<std::string, std::shared_ptr<circuit> > _modules;
    /** @endcond */
  };

}

#endif /* CIRCUIT_HPP */

// Local Variables:
// c-basic-offset: 2
// eval: (c-set-offset 'substatement-open 0)
// eval: (c-set-offset 'innamespace 0)
// End:

max_stars_repo_name: eletesta/cirkit

max_issues_repo_name: eletesta/cirkit

max_forks_repo_name: eletesta/cirkit