<commit_before>// Copyright (c) 2017-2018 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "cbtx.h"
#include "deterministicmns.h"
#include "llmq/quorums.h"
#include "llmq/quorums_blockprocessor.h"
#include "llmq/quorums_commitment.h"
#include "simplifiedmns.h"
#include "specialtx.h"

#include "chainparams.h"
#include "consensus/merkle.h"
#include "univalue.h"
#include "validation.h"

bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
{
    if (tx.nType != TRANSACTION_COINBASE) {
        return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-type");
    }

    if (!tx.IsCoinBase()) {
        return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-invalid");
    }

    CCbTx cbTx;
    if (!GetTxPayload(tx, cbTx)) {
        return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-payload");
    }

    if (cbTx.nVersion == 0 || cbTx.nVersion > CCbTx::CURRENT_VERSION) {
        return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-version");
    }

    if (pindexPrev && pindexPrev->nHeight + 1 != cbTx.nHeight) {
        return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-height");
    }

    if (pindexPrev) {
        bool fDIP0008Active = VersionBitsState(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0008, versionbitscache) == THRESHOLD_ACTIVE;
        if (fDIP0008Active && cbTx.nVersion < 2) {
            return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-version");
        }
    }

    return true;
}

// This can only be done after the block has been fully processed, as otherwise we won't have the finished MN list
bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, CValidationState& state)
{
    if (block.vtx[0]->nType != TRANSACTION_COINBASE) {
        return true;
    }

    static int64_t nTimePayload = 0;
    static int64_t nTimeMerkleMNL = 0;
    static int64_t nTimeMerkleQuorum = 0;

    int64_t nTime1 = GetTimeMicros();

    CCbTx cbTx;
    if (!GetTxPayload(*block.vtx[0], cbTx)) {
        return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-payload");
    }

    int64_t nTime2 = GetTimeMicros(); nTimePayload += nTime2 - nTime1;
    LogPrint("bench", "          - GetTxPayload: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimePayload * 0.000001);

    if (pindex) {
        uint256 calculatedMerkleRoot;
        if (!CalcCbTxMerkleRootMNList(block, pindex->pprev, calculatedMerkleRoot, state)) {
            return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-mnmerkleroot");
        }
        if (calculatedMerkleRoot != cbTx.merkleRootMNList) {
            return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-mnmerkleroot");
        }

        int64_t nTime3 = GetTimeMicros(); nTimeMerkleMNL += nTime3 - nTime2;
        LogPrint("bench", "          - CalcCbTxMerkleRootMNList: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeMerkleMNL * 0.000001);

        if (cbTx.nVersion >= 2) {
            if (!CalcCbTxMerkleRootQuorums(block, pindex->pprev, calculatedMerkleRoot, state)) {
                return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-quorummerkleroot");
            }
            if (calculatedMerkleRoot != cbTx.merkleRootQuorums) {
                return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-quorummerkleroot");
            }
        }

        int64_t nTime4 = GetTimeMicros(); nTimeMerkleQuorum += nTime4 - nTime3;
        LogPrint("bench", "          - CalcCbTxMerkleRootQuorums: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeMerkleQuorum * 0.000001);

    }

    return true;
}

bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev, uint256& merkleRootRet, CValidationState& state)
{
    LOCK(deterministicMNManager->cs);

    static int64_t nTimeDMN = 0;
    static int64_t nTimeSMNL = 0;
    static int64_t nTimeMerkle = 0;

    int64_t nTime1 = GetTimeMicros();

    CDeterministicMNList tmpMNList;
    if (!deterministicMNManager->BuildNewListFromBlock(block, pindexPrev, state, tmpMNList, false)) {
        return false;
    }

    int64_t nTime2 = GetTimeMicros(); nTimeDMN += nTime2 - nTime1;
    LogPrint("bench", "            - BuildNewListFromBlock: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimeDMN * 0.000001);

    CSimplifiedMNList sml(tmpMNList);

    int64_t nTime3 = GetTimeMicros(); nTimeSMNL += nTime3 - nTime2;
    LogPrint("bench", "            - CSimplifiedMNList: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeSMNL * 0.000001);

    bool mutated = false;
    merkleRootRet = sml.CalcMerkleRoot(&mutated);

    int64_t nTime4 = GetTimeMicros(); nTimeMerkle += nTime4 - nTime3;
    LogPrint("bench", "            - CalcMerkleRoot: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeMerkle * 0.000001);

    return !mutated;
}

bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPrev, uint256& merkleRootRet, CValidationState& state)
{
    static int64_t nTimeMinedAndActive = 0;
    static int64_t nTimeMined = 0;
    static int64_t nTimeLoop = 0;
    static int64_t nTimeMerkle = 0;

    int64_t nTime1 = GetTimeMicros();

    auto quorums = llmq::quorumBlockProcessor->GetMinedAndActiveCommitmentsUntilBlock(pindexPrev);
    std::map<Consensus::LLMQType, std::vector<uint256>> qcHashes;
    size_t hashCount = 0;

    int64_t nTime2 = GetTimeMicros(); nTimeMinedAndActive += nTime2 - nTime1;
    LogPrint("bench", "            - GetMinedAndActiveCommitmentsUntilBlock: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimeMinedAndActive * 0.000001);

    for (const auto& p : quorums) {
        auto& v = qcHashes[p.first];
        v.reserve(p.second.size());
        for (const auto& p2 : p.second) {
            llmq::CFinalCommitment qc;
            uint256 minedBlockHash;
            bool found = llmq::quorumBlockProcessor->GetMinedCommitment(p.first, p2->GetBlockHash(), qc, minedBlockHash);
            assert(found);
            v.emplace_back(::SerializeHash(qc));
            hashCount++;
        }
    }

    int64_t nTime3 = GetTimeMicros(); nTimeMined += nTime3 - nTime2;
    LogPrint("bench", "            - GetMinedCommitment: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeMined * 0.000001);

    // now add the commitments from the current block, which are not returned by GetMinedAndActiveCommitmentsUntilBlock
    // due to the use of pindexPrev (we don't have the tip index here)
    for (size_t i = 1; i < block.vtx.size(); i++) {
        auto& tx = block.vtx[i];

        if (tx->nVersion == 3 && tx->nType == TRANSACTION_QUORUM_COMMITMENT) {
            llmq::CFinalCommitmentTxPayload qc;
            if (!GetTxPayload(*tx, qc)) {
                assert(false);
            }
            if (qc.commitment.IsNull()) {
                continue;
            }
            auto qcHash = ::SerializeHash(qc.commitment);
            const auto& params = Params().GetConsensus().llmqs.at((Consensus::LLMQType)qc.commitment.llmqType);
            auto& v = qcHashes[params.type];
            if (v.size() == params.signingActiveQuorumCount) {
                v.pop_back();
            }
            v.emplace_back(qcHash);
            hashCount++;
            assert(v.size() <= params.signingActiveQuorumCount);
        }
    }

    std::vector<uint256> qcHashesVec;
    qcHashesVec.reserve(hashCount);

    for (const auto& p : qcHashes) {
        for (const auto& h : p.second) {
            qcHashesVec.emplace_back(h);
        }
    }
    std::sort(qcHashesVec.begin(), qcHashesVec.end());

    int64_t nTime4 = GetTimeMicros(); nTimeLoop += nTime4 - nTime3;
    LogPrint("bench", "            - Loop: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeLoop * 0.000001);

    bool mutated = false;
    merkleRootRet = ComputeMerkleRoot(qcHashesVec, &mutated);

    int64_t nTime5 = GetTimeMicros(); nTimeMerkle += nTime5 - nTime4;
    LogPrint("bench", "            - ComputeMerkleRoot: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeMerkle * 0.000001);

    return !mutated;
}

std::string CCbTx::ToString() const
{
    return strprintf("CCbTx(nHeight=%d, nVersion=%d, merkleRootMNList=%s, merkleRootQuorums=%s)",
        nVersion, nHeight, merkleRootMNList.ToString(), merkleRootQuorums.ToString());
}

void CCbTx::ToJson(UniValue& obj) const
{
    obj.clear();
    obj.setObject();
    obj.push_back(Pair("version", (int)nVersion));
    obj.push_back(Pair("height", (int)nHeight));
    obj.push_back(Pair("merkleRootMNList", merkleRootMNList.ToString()));
    if (nVersion >= 2) {
        obj.push_back(Pair("merkleRootQuorums", merkleRootQuorums.ToString()));
    }
}
<commit_msg>Cache heavy parts of CalcCbTxMerkleRoot* (#2885)<commit_after>// Copyright (c) 2017-2018 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "cbtx.h"
#include "deterministicmns.h"
#include "llmq/quorums.h"
#include "llmq/quorums_blockprocessor.h"
#include "llmq/quorums_commitment.h"
#include "simplifiedmns.h"
#include "specialtx.h"

#include "chainparams.h"
#include "consensus/merkle.h"
#include "univalue.h"
#include "validation.h"

bool CheckCbTx(const CTransaction& tx, const CBlockIndex* pindexPrev, CValidationState& state)
{
    if (tx.nType != TRANSACTION_COINBASE) {
        return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-type");
    }

    if (!tx.IsCoinBase()) {
        return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-invalid");
    }

    CCbTx cbTx;
    if (!GetTxPayload(tx, cbTx)) {
        return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-payload");
    }

    if (cbTx.nVersion == 0 || cbTx.nVersion > CCbTx::CURRENT_VERSION) {
        return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-version");
    }

    if (pindexPrev && pindexPrev->nHeight + 1 != cbTx.nHeight) {
        return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-height");
    }

    if (pindexPrev) {
        bool fDIP0008Active = VersionBitsState(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0008, versionbitscache) == THRESHOLD_ACTIVE;
        if (fDIP0008Active && cbTx.nVersion < 2) {
            return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-version");
        }
    }

    return true;
}

// This can only be done after the block has been fully processed, as otherwise we won't have the finished MN list
bool CheckCbTxMerkleRoots(const CBlock& block, const CBlockIndex* pindex, CValidationState& state)
{
    if (block.vtx[0]->nType != TRANSACTION_COINBASE) {
        return true;
    }

    static int64_t nTimePayload = 0;
    static int64_t nTimeMerkleMNL = 0;
    static int64_t nTimeMerkleQuorum = 0;

    int64_t nTime1 = GetTimeMicros();

    CCbTx cbTx;
    if (!GetTxPayload(*block.vtx[0], cbTx)) {
        return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-payload");
    }

    int64_t nTime2 = GetTimeMicros(); nTimePayload += nTime2 - nTime1;
    LogPrint("bench", "          - GetTxPayload: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimePayload * 0.000001);

    if (pindex) {
        uint256 calculatedMerkleRoot;
        if (!CalcCbTxMerkleRootMNList(block, pindex->pprev, calculatedMerkleRoot, state)) {
            return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-mnmerkleroot");
        }
        if (calculatedMerkleRoot != cbTx.merkleRootMNList) {
            return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-mnmerkleroot");
        }

        int64_t nTime3 = GetTimeMicros(); nTimeMerkleMNL += nTime3 - nTime2;
        LogPrint("bench", "          - CalcCbTxMerkleRootMNList: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeMerkleMNL * 0.000001);

        if (cbTx.nVersion >= 2) {
            if (!CalcCbTxMerkleRootQuorums(block, pindex->pprev, calculatedMerkleRoot, state)) {
                return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-quorummerkleroot");
            }
            if (calculatedMerkleRoot != cbTx.merkleRootQuorums) {
                return state.DoS(100, false, REJECT_INVALID, "bad-cbtx-quorummerkleroot");
            }
        }

        int64_t nTime4 = GetTimeMicros(); nTimeMerkleQuorum += nTime4 - nTime3;
        LogPrint("bench", "          - CalcCbTxMerkleRootQuorums: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeMerkleQuorum * 0.000001);

    }

    return true;
}

bool CalcCbTxMerkleRootMNList(const CBlock& block, const CBlockIndex* pindexPrev, uint256& merkleRootRet, CValidationState& state)
{
    LOCK(deterministicMNManager->cs);

    static int64_t nTimeDMN = 0;
    static int64_t nTimeSMNL = 0;
    static int64_t nTimeMerkle = 0;

    int64_t nTime1 = GetTimeMicros();

    CDeterministicMNList tmpMNList;
    if (!deterministicMNManager->BuildNewListFromBlock(block, pindexPrev, state, tmpMNList, false)) {
        return false;
    }

    int64_t nTime2 = GetTimeMicros(); nTimeDMN += nTime2 - nTime1;
    LogPrint("bench", "            - BuildNewListFromBlock: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimeDMN * 0.000001);

    CSimplifiedMNList sml(tmpMNList);

    int64_t nTime3 = GetTimeMicros(); nTimeSMNL += nTime3 - nTime2;
    LogPrint("bench", "            - CSimplifiedMNList: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeSMNL * 0.000001);

    static CSimplifiedMNList smlCached;
    static uint256 merkleRootCached;
    static bool mutatedCached{false};

    if (sml.mnList == smlCached.mnList) {
        merkleRootRet = merkleRootCached;
        return !mutatedCached;
    }

    bool mutated = false;
    merkleRootRet = sml.CalcMerkleRoot(&mutated);

    int64_t nTime4 = GetTimeMicros(); nTimeMerkle += nTime4 - nTime3;
    LogPrint("bench", "            - CalcMerkleRoot: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeMerkle * 0.000001);

    smlCached = std::move(sml);
    merkleRootCached = merkleRootRet;
    mutatedCached = mutated;

    return !mutated;
}

bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPrev, uint256& merkleRootRet, CValidationState& state)
{
    static int64_t nTimeMinedAndActive = 0;
    static int64_t nTimeMined = 0;
    static int64_t nTimeLoop = 0;
    static int64_t nTimeMerkle = 0;

    int64_t nTime1 = GetTimeMicros();

    static std::map<Consensus::LLMQType, std::vector<const CBlockIndex*>> quorumsCached;
    static std::map<Consensus::LLMQType, std::vector<uint256>> qcHashesCached;

    auto quorums = llmq::quorumBlockProcessor->GetMinedAndActiveCommitmentsUntilBlock(pindexPrev);
    std::map<Consensus::LLMQType, std::vector<uint256>> qcHashes;
    size_t hashCount = 0;

    int64_t nTime2 = GetTimeMicros(); nTimeMinedAndActive += nTime2 - nTime1;
    LogPrint("bench", "            - GetMinedAndActiveCommitmentsUntilBlock: %.2fms [%.2fs]\n", 0.001 * (nTime2 - nTime1), nTimeMinedAndActive * 0.000001);

    if (quorums == quorumsCached) {
        qcHashes = qcHashesCached;
    } else {
        for (const auto& p : quorums) {
            auto& v = qcHashes[p.first];
            v.reserve(p.second.size());
            for (const auto& p2 : p.second) {
                llmq::CFinalCommitment qc;
                uint256 minedBlockHash;
                bool found = llmq::quorumBlockProcessor->GetMinedCommitment(p.first, p2->GetBlockHash(), qc, minedBlockHash);
                assert(found);
                v.emplace_back(::SerializeHash(qc));
                hashCount++;
            }
        }
        quorumsCached = quorums;
        qcHashesCached = qcHashes;
    }

    int64_t nTime3 = GetTimeMicros(); nTimeMined += nTime3 - nTime2;
    LogPrint("bench", "            - GetMinedCommitment: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeMined * 0.000001);

    // now add the commitments from the current block, which are not returned by GetMinedAndActiveCommitmentsUntilBlock
    // due to the use of pindexPrev (we don't have the tip index here)
    for (size_t i = 1; i < block.vtx.size(); i++) {
        auto& tx = block.vtx[i];

        if (tx->nVersion == 3 && tx->nType == TRANSACTION_QUORUM_COMMITMENT) {
            llmq::CFinalCommitmentTxPayload qc;
            if (!GetTxPayload(*tx, qc)) {
                assert(false);
            }
            if (qc.commitment.IsNull()) {
                continue;
            }
            auto qcHash = ::SerializeHash(qc.commitment);
            const auto& params = Params().GetConsensus().llmqs.at((Consensus::LLMQType)qc.commitment.llmqType);
            auto& v = qcHashes[params.type];
            if (v.size() == params.signingActiveQuorumCount) {
                v.pop_back();
            }
            v.emplace_back(qcHash);
            hashCount++;
            assert(v.size() <= params.signingActiveQuorumCount);
        }
    }

    std::vector<uint256> qcHashesVec;
    qcHashesVec.reserve(hashCount);

    for (const auto& p : qcHashes) {
        for (const auto& h : p.second) {
            qcHashesVec.emplace_back(h);
        }
    }
    std::sort(qcHashesVec.begin(), qcHashesVec.end());

    int64_t nTime4 = GetTimeMicros(); nTimeLoop += nTime4 - nTime3;
    LogPrint("bench", "            - Loop: %.2fms [%.2fs]\n", 0.001 * (nTime4 - nTime3), nTimeLoop * 0.000001);

    bool mutated = false;
    merkleRootRet = ComputeMerkleRoot(qcHashesVec, &mutated);

    int64_t nTime5 = GetTimeMicros(); nTimeMerkle += nTime5 - nTime4;
    LogPrint("bench", "            - ComputeMerkleRoot: %.2fms [%.2fs]\n", 0.001 * (nTime5 - nTime4), nTimeMerkle * 0.000001);

    return !mutated;
}

std::string CCbTx::ToString() const
{
    return strprintf("CCbTx(nHeight=%d, nVersion=%d, merkleRootMNList=%s, merkleRootQuorums=%s)",
        nVersion, nHeight, merkleRootMNList.ToString(), merkleRootQuorums.ToString());
}

void CCbTx::ToJson(UniValue& obj) const
{
    obj.clear();
    obj.setObject();
    obj.push_back(Pair("version", (int)nVersion));
    obj.push_back(Pair("height", (int)nHeight));
    obj.push_back(Pair("merkleRootMNList", merkleRootMNList.ToString()));
    if (nVersion >= 2) {
        obj.push_back(Pair("merkleRootQuorums", merkleRootQuorums.ToString()));
    }
}
<|endoftext|>


<commit_before>#pragma once

#include "../IState.hpp"
#include <SFML/Graphics/Font.hpp>
#include <list>

class LoadingScreen : public IState
{
public:
    LoadingScreen();
    ~LoadingScreen();

    bool load();
    void unload();
    inline std::string getLoadState() const { return ""; }

    inline bool event(const sf::Event&) { return false; }
    void update(float dt);
    inline void draw(sf::RenderTarget&) { }
    void drawUi(sf::RenderTarget& target);

    void setLoadingText(const std::string& text);

private:
    float mTime;
    std::string mCurrentString;
    std::list<std::string> mLastMessages;

    std::shared_ptr<sf::Font> mFont;
    std::shared_ptr<sf::Texture> mSpinner;
};
<commit_msg>Fix compiling on Linux<commit_after>#pragma once

#include "../IState.hpp"
#include <SFML/Graphics/Font.hpp>
#include <memory>
#include <list>

class LoadingScreen : public IState
{
public:
    LoadingScreen();
    ~LoadingScreen();

    bool load();
    void unload();
    inline std::string getLoadState() const { return ""; }

    inline bool event(const sf::Event&) { return false; }
    void update(float dt);
    inline void draw(sf::RenderTarget&) { }
    void drawUi(sf::RenderTarget& target);

    void setLoadingText(const std::string& text);

private:
    float mTime;
    std::string mCurrentString;
    std::list<std::string> mLastMessages;

    std::shared_ptr<sf::Font> mFont;
    std::shared_ptr<sf::Texture> mSpinner;
};
<|endoftext|>


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

#ifndef __STOUT_OS_RAW_ARGV_HPP__
#define __STOUT_OS_RAW_ARGV_HPP__

#include <string.h>

#include <string>
#include <vector>

#include <stout/foreach.hpp>

namespace os {
namespace raw {

/**
 * Represent the argument list expected by `execv` routines. The
 * argument list is an array of pointers that point to null-terminated
 * strings. The array of pointers must be terminated by a nullptr. To
 * use this abstraction, see the following example:
 *
 *   vector<string> args = {"arg0", "arg1"};
 *   os::raw::Argv argv(args);
 *   execvp("my_binary", argv);
 */
class Argv
{
public:
  template <typename Iterable>
  explicit Argv(const Iterable& iterable)
  {
    foreach (const std::string& arg, iterable) {
      args.emplace_back(arg);
    }

    argv = new char*[args.size() + 1];
    for (size_t i = 0; i < args.size(); i++) {
      argv[i] = const_cast<char*>(args[i].c_str());
    }

    argv[args.size()] = nullptr;
  }

  ~Argv()
  {
    delete[] argv;
  }

  operator char**() const
  {
    return argv;
  }

  operator std::vector<std::string>() const
  {
    return args;
  }

private:
  std::vector<std::string> args;

  // NOTE: This points to strings in the vector `args`.
  char** argv;
};

} // namespace raw {
} // namespace os {

#endif // __STOUT_OS_RAW_ARGV_HPP__
<commit_msg>Deleted Argv copy constructor and assignment members.<commit_after>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef __STOUT_OS_RAW_ARGV_HPP__
#define __STOUT_OS_RAW_ARGV_HPP__

#include <string.h>

#include <string>
#include <vector>

#include <stout/foreach.hpp>

namespace os {
namespace raw {

/**
 * Represent the argument list expected by `execv` routines. The
 * argument list is an array of pointers that point to null-terminated
 * strings. The array of pointers must be terminated by a nullptr. To
 * use this abstraction, see the following example:
 *
 *   vector<string> args = {"arg0", "arg1"};
 *   os::raw::Argv argv(args);
 *   execvp("my_binary", argv);
 */
class Argv
{
public:
  Argv(const Argv&) = delete;
  Argv& operator=(const Argv&) = delete;

  template <typename Iterable>
  explicit Argv(const Iterable& iterable)
  {
    foreach (const std::string& arg, iterable) {
      args.emplace_back(arg);
    }

    argv = new char*[args.size() + 1];
    for (size_t i = 0; i < args.size(); i++) {
      argv[i] = const_cast<char*>(args[i].c_str());
    }

    argv[args.size()] = nullptr;
  }

  ~Argv()
  {
    delete[] argv;
  }

  operator char**() const
  {
    return argv;
  }

  operator std::vector<std::string>() const
  {
    return args;
  }

private:
  std::vector<std::string> args;

  // NOTE: This points to strings in the vector `args`.
  char** argv;
};

} // namespace raw {
} // namespace os {

#endif // __STOUT_OS_RAW_ARGV_HPP__
<|endoftext|>


<commit_before>#include "../../../include/cutehmi/internal/singleton.hpp"

#include <QList>

namespace  {
	class SingletonDestroyWrapper
	{
		public:
			SingletonDestroyWrapper(cutehmi::internal::singletonDestroyCallback callback):
				m_callback(callback)
			{
			}

			[[gnu::unused]]
			bool operator ==(const SingletonDestroyWrapper & other) const
			{
				return m_callback == other.m_callback;
			}

			void call()
			{
				m_callback();
			}

			operator uintptr_t() const
			{
				return reinterpret_cast<uintptr_t>(m_callback);
			}

		private:
			cutehmi::internal::singletonDestroyCallback m_callback;
	};

	[[gnu::unused]]
	uint qHash(const SingletonDestroyWrapper & key)
	{
		return ::qHash(static_cast<uintptr_t>(key));
	}

	//<cutehmi::destroySingletonInstances-determined_destruction_order.principle>
	// Container should prserve order in which elements were added, so that singletons can be destroyed in reverse order as they
	// were added. This disqualifies QSet.

	typedef QList<SingletonDestroyWrapper> SingletonDestroyFunctionsContainer;

	// Elements are prepended to this list (see storeSingletonDestroyCallback()).
	SingletonDestroyFunctionsContainer singletonDestroyFunctions;

	//</cutehmi::destroySingletonInstances-determined_destruction_order.principle>
}

namespace cutehmi {
namespace internal {

void destroySingletonInstances()
{
	//<cutehmi::destroySingletonInstances-determined_destruction_order.principle>
	SingletonDestroyFunctionsContainer copy = singletonDestroyFunctions;
	//<cutehmi::Singleton-singleton_class_will_not_call_Destroy_from_destructor.assumption>
	// If Singleton called Destroy() it would invalidate copy and its iterators.
	for (auto it = copy.begin(); it != copy.end(); ++it)
		it->call();		// Call Singleton::Destroy(), which will remove callback from original singletonDestroyFunctions.
	//</cutehmi::Singleton-singleton_class_will_not_call_Destroy_from_destructor.assumption>
	//</cutehmi::destroySingletonInstances-determined_destruction_order.principle>
}

void storeSingletonDestroyCallback(singletonDestroyCallback callback)
{
	//<cutehmi::destroySingletonInstances-determined_destruction_order.principle>
	// Callbacks should be removed in reverse order as they were added.	With prepending removeSingletonDestroyCallback() should be
	// able to remove callbacks pretty fast, if accessed through destroySingletonInstances(), because QList::removeOne() will find
	// each removed callback at the beginning of the list.
	singletonDestroyFunctions.prepend(callback);
	//</cutehmi::destroySingletonInstances-determined_destruction_order.principle>
}

void removeSingletonDestroyCallback(singletonDestroyCallback callback)
{
	singletonDestroyFunctions.removeOne(callback);
}

}
}

//(c)C: Copyright © 2019-2020, Michał Policht <michal@policht.pl>, Yuri Chornoivan <yurchor@ukr.net>. All rights reserved.
//(c)C: SPDX-License-Identifier: LGPL-3.0-or-later OR MIT
//(c)C: This file is a part of CuteHMI.
//(c)C: CuteHMI is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
//(c)C: CuteHMI 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 Lesser General Public License for more details.
//(c)C: You should have received a copy of the GNU Lesser General Public License along with CuteHMI.  If not, see <https://www.gnu.org/licenses/>.
//(c)C: Additionally, this file is licensed under terms of MIT license as expressed below.
//(c)C: 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:
//(c)C: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//(c)C: 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.
<commit_msg>Implement singletonDestroyFunctions() to avoid warning about static non-POD<commit_after>#include "../../../include/cutehmi/internal/singleton.hpp"

#include <QList>

namespace  {

class SingletonDestroyWrapper
{
	public:
		SingletonDestroyWrapper(cutehmi::internal::singletonDestroyCallback callback):
			m_callback(callback)
		{
		}

		[[gnu::unused]]
		bool operator ==(const SingletonDestroyWrapper & other) const
		{
			return m_callback == other.m_callback;
		}

		void call()
		{
			m_callback();
		}

		operator uintptr_t() const
		{
			return reinterpret_cast<uintptr_t>(m_callback);
		}

	private:
		cutehmi::internal::singletonDestroyCallback m_callback;
};

[[gnu::unused]]
uint qHash(const SingletonDestroyWrapper & key)
{
	return ::qHash(static_cast<uintptr_t>(key));
}

//<cutehmi::destroySingletonInstances-determined_destruction_order.principle>
// Container should prserve order in which elements were added, so that singletons can be destroyed in reverse order as they
// were added. This disqualifies QSet.
typedef QList<SingletonDestroyWrapper> SingletonDestroyFunctionsContainer;

// Elements are prepended to this list (see storeSingletonDestroyCallback()).
SingletonDestroyFunctionsContainer & singletonDestroyFunctions() {
	static SingletonDestroyFunctionsContainer container;
	return container;
}
//</cutehmi::destroySingletonInstances-determined_destruction_order.principle>

}

namespace cutehmi {
namespace internal {

void destroySingletonInstances()
{
	//<cutehmi::destroySingletonInstances-determined_destruction_order.principle>
	SingletonDestroyFunctionsContainer copy = singletonDestroyFunctions();
	//<cutehmi::Singleton-singleton_class_will_not_call_Destroy_from_destructor.assumption>
	// If Singleton called Destroy() it would invalidate copy and its iterators.
	for (auto it = copy.begin(); it != copy.end(); ++it)
		it->call();		// Call Singleton::Destroy(), which will remove callback from original singletonDestroyFunctions.
	//</cutehmi::Singleton-singleton_class_will_not_call_Destroy_from_destructor.assumption>
	//</cutehmi::destroySingletonInstances-determined_destruction_order.principle>
}

void storeSingletonDestroyCallback(singletonDestroyCallback callback)
{
	//<cutehmi::destroySingletonInstances-determined_destruction_order.principle>
	// Callbacks should be removed in reverse order as they were added.	With prepending removeSingletonDestroyCallback() should be
	// able to remove callbacks pretty fast, if accessed through destroySingletonInstances(), because QList::removeOne() will find
	// each removed callback at the beginning of the list.
	singletonDestroyFunctions().prepend(callback);
	//</cutehmi::destroySingletonInstances-determined_destruction_order.principle>
}

void removeSingletonDestroyCallback(singletonDestroyCallback callback)
{
	singletonDestroyFunctions().removeOne(callback);
}

}
}

//(c)C: Copyright © 2019-2020, Michał Policht <michal@policht.pl>, Yuri Chornoivan <yurchor@ukr.net>. All rights reserved.
//(c)C: SPDX-License-Identifier: LGPL-3.0-or-later OR MIT
//(c)C: This file is a part of CuteHMI.
//(c)C: CuteHMI is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
//(c)C: CuteHMI 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 Lesser General Public License for more details.
//(c)C: You should have received a copy of the GNU Lesser General Public License along with CuteHMI.  If not, see <https://www.gnu.org/licenses/>.
//(c)C: Additionally, this file is licensed under terms of MIT license as expressed below.
//(c)C: 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:
//(c)C: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//(c)C: 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.
<|endoftext|>


<commit_before>/*
 * Copyright 2011 Esrille Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "Box.h"

#include <jpeglib.h>
#include <png.h>
#include <stdio.h>

#include <GL/gl.h>

#include <boost/bind.hpp>

#include "utf.h"

namespace org { namespace w3c { namespace dom { namespace bootstrap {

// image/png - 89 50 4E 47 0D 0A 1A 0A
// image/gif - "GIF87a" or "GIF89a"
// image/jpeg - FF D8
// image/bmp - "BM"
// image/vnd.microsoft.icon - 00 00 01 00 (.ico), 00 00 02 00 (.cur)

namespace {

unsigned char* readAsPng(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    png_byte header[8];
    if (fread(header, 1, 8, file) != 8 || png_sig_cmp(header, 0, 8))
        return 0;

    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr)
        return 0;
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return 0;
    }
    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return 0;
    }
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return 0;
    }

    png_init_io(png_ptr, file);
    png_set_sig_bytes(png_ptr, 8);

    png_read_info(png_ptr, info_ptr);

    width = png_get_image_width(png_ptr, info_ptr);
    height = png_get_image_height(png_ptr, info_ptr);
    unsigned bit_depth = png_get_bit_depth(png_ptr, info_ptr);
    unsigned color_type = png_get_color_type(png_ptr, info_ptr);

    if (color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png_ptr);
    if (bit_depth == 16)
        png_set_strip_16(png_ptr);
    switch (color_type) {
    case PNG_COLOR_TYPE_RGB:
    case PNG_COLOR_TYPE_GRAY:
    case PNG_COLOR_TYPE_PALETTE:
        format = GL_RGB;
        break;
    default:
        format = GL_RGBA;
        break;
    }
    png_set_interlace_handling(png_ptr);

    png_read_update_info(png_ptr, info_ptr);

    unsigned rowbytes = png_get_rowbytes(png_ptr, info_ptr);
    png_bytep data = (png_bytep) malloc(rowbytes * height);
    png_bytep* row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
    for (unsigned i = 0; i < height; i++)
        row_pointers[i] = &data[rowbytes * i];
    png_read_image(png_ptr, row_pointers);
    free(row_pointers);

    png_read_end(png_ptr, end_info);
    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

    return data;
}

unsigned char* readAsJpeg(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    unsigned char sig[2];
    if (fread(sig, 1, 2, file) != 2 || sig[0] != 0xFF || sig[1] != 0xD8)
        return 0;
    rewind(file);

    JSAMPARRAY img;
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    cinfo.err = jpeg_std_error(&jerr);  // TODO: set our own error handdler
    jpeg_create_decompress(&cinfo);

    jpeg_stdio_src(&cinfo, file);
    jpeg_read_header(&cinfo, true);
    width = cinfo.image_width;
    height = cinfo.image_height;
    jpeg_start_decompress(&cinfo);

    unsigned char* data = (unsigned char*) malloc(height * width * cinfo.out_color_components);
    img = (JSAMPARRAY) malloc(sizeof(JSAMPROW) * height);
    for (unsigned i = 0; i < height; ++i)
        img[i] = (JSAMPROW) &data[cinfo.out_color_components * width * i];

    while(cinfo.output_scanline < cinfo.output_height)
        jpeg_read_scanlines(&cinfo,
                            img + cinfo.output_scanline,
                            cinfo.output_height - cinfo.output_scanline);
    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);

    free(img);

    if (cinfo.out_color_components == 1)
        format = GL_LUMINANCE;
    else
        format = GL_RGB;
    return data;
}

}  // namespace

BoxImage::BoxImage(Box* box) :
    box(box),
    state(Unavailable),
    pixels(0),
    naturalWidth(0),
    naturalHeight(0),
    repeat(0),
    format(GL_RGBA),
    img(static_cast<html::HTMLImageElement*>(0) /* nullptr */)
{
}

BoxImage::BoxImage(Box* box, const std::u16string& base, const std::u16string& url, unsigned repeat) :
    box(box),
    state(Unavailable),
    pixels(0),
    naturalWidth(0),
    naturalHeight(0),
    repeat(repeat),
    format(GL_RGBA),
    img(static_cast<html::HTMLImageElement*>(0) /* nullptr */),
    request(base)
{
    open(url);
}

BoxImage::BoxImage(Box* box, const std::u16string& base, html::HTMLImageElement& img) :
    box(box),
    state(Unavailable),
    pixels(0),
    naturalWidth(0),
    naturalHeight(0),
    repeat(Clamp),
    format(GL_RGBA),
    img(img),
    request(base)
{
    open(img.getSrc());
}

void BoxImage::open(const std::u16string& url)
{
    request.open(u"GET", url);
    request.setHanndler(boost::bind(&BoxImage::notify, this));
    request.send();
    state = Sent;
    if (request.getReadyState() != HttpRequest::DONE)
        return;
    if (request.getErrorFlag()) {
        state = Broken;
        return;
    }
    FILE* file = request.openFile();
    if (!file) {
        state = Broken;
        return;
    }
    pixels = readAsPng(file, naturalWidth, naturalHeight, format);
    if (!pixels) {
        rewind(file);
        pixels = readAsJpeg(file, naturalWidth, naturalHeight, format);
    }
    if (pixels)
        state = CompletelyAvailable;
    else
        state = Broken;
    fclose(file);
}

void BoxImage::notify()
{
    if (state == Sent) {
        if (request.getStatus() == 200)
            box->flags = 1;  // for updating render tree.
        else
            state = Unavailable;
    }
}

}}}}  // org::w3c::dom::bootstrap
<commit_msg>(readAsPng) : Support palette images with transparency.<commit_after>/*
 * Copyright 2011 Esrille Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "Box.h"

#include <jpeglib.h>
#include <png.h>
#include <stdio.h>

#include <GL/gl.h>

#include <boost/bind.hpp>

#include "utf.h"

namespace org { namespace w3c { namespace dom { namespace bootstrap {

// image/png - 89 50 4E 47 0D 0A 1A 0A
// image/gif - "GIF87a" or "GIF89a"
// image/jpeg - FF D8
// image/bmp - "BM"
// image/vnd.microsoft.icon - 00 00 01 00 (.ico), 00 00 02 00 (.cur)

namespace {

unsigned char* readAsPng(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    png_byte header[8];
    if (fread(header, 1, 8, file) != 8 || png_sig_cmp(header, 0, 8))
        return 0;

    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr)
        return 0;
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return 0;
    }
    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return 0;
    }
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return 0;
    }

    png_init_io(png_ptr, file);
    png_set_sig_bytes(png_ptr, 8);

    png_read_info(png_ptr, info_ptr);

    width = png_get_image_width(png_ptr, info_ptr);
    height = png_get_image_height(png_ptr, info_ptr);
    unsigned bit_depth = png_get_bit_depth(png_ptr, info_ptr);
    unsigned color_type = png_get_color_type(png_ptr, info_ptr);

    if (color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png_ptr);
    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
        png_set_tRNS_to_alpha(png_ptr);
        color_type = GL_RGBA;
    }
    if (bit_depth == 16)
        png_set_strip_16(png_ptr);
    switch (color_type) {
    case PNG_COLOR_TYPE_RGB:
    case PNG_COLOR_TYPE_GRAY:
    case PNG_COLOR_TYPE_PALETTE:
        format = GL_RGB;
        break;
    default:
        format = GL_RGBA;
        break;
    }
    png_set_interlace_handling(png_ptr);

    png_read_update_info(png_ptr, info_ptr);

    unsigned rowbytes = png_get_rowbytes(png_ptr, info_ptr);
    png_bytep data = (png_bytep) malloc(rowbytes * height);
    png_bytep* row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
    for (unsigned i = 0; i < height; i++)
        row_pointers[i] = &data[rowbytes * i];
    png_read_image(png_ptr, row_pointers);
    free(row_pointers);

    png_read_end(png_ptr, end_info);
    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

    return data;
}

unsigned char* readAsJpeg(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    unsigned char sig[2];
    if (fread(sig, 1, 2, file) != 2 || sig[0] != 0xFF || sig[1] != 0xD8)
        return 0;
    rewind(file);

    JSAMPARRAY img;
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    cinfo.err = jpeg_std_error(&jerr);  // TODO: set our own error handdler
    jpeg_create_decompress(&cinfo);

    jpeg_stdio_src(&cinfo, file);
    jpeg_read_header(&cinfo, true);
    width = cinfo.image_width;
    height = cinfo.image_height;
    jpeg_start_decompress(&cinfo);

    unsigned char* data = (unsigned char*) malloc(height * width * cinfo.out_color_components);
    img = (JSAMPARRAY) malloc(sizeof(JSAMPROW) * height);
    for (unsigned i = 0; i < height; ++i)
        img[i] = (JSAMPROW) &data[cinfo.out_color_components * width * i];

    while(cinfo.output_scanline < cinfo.output_height)
        jpeg_read_scanlines(&cinfo,
                            img + cinfo.output_scanline,
                            cinfo.output_height - cinfo.output_scanline);
    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);

    free(img);

    if (cinfo.out_color_components == 1)
        format = GL_LUMINANCE;
    else
        format = GL_RGB;
    return data;
}

}  // namespace

BoxImage::BoxImage(Box* box) :
    box(box),
    state(Unavailable),
    pixels(0),
    naturalWidth(0),
    naturalHeight(0),
    repeat(0),
    format(GL_RGBA),
    img(static_cast<html::HTMLImageElement*>(0) /* nullptr */)
{
}

BoxImage::BoxImage(Box* box, const std::u16string& base, const std::u16string& url, unsigned repeat) :
    box(box),
    state(Unavailable),
    pixels(0),
    naturalWidth(0),
    naturalHeight(0),
    repeat(repeat),
    format(GL_RGBA),
    img(static_cast<html::HTMLImageElement*>(0) /* nullptr */),
    request(base)
{
    open(url);
}

BoxImage::BoxImage(Box* box, const std::u16string& base, html::HTMLImageElement& img) :
    box(box),
    state(Unavailable),
    pixels(0),
    naturalWidth(0),
    naturalHeight(0),
    repeat(Clamp),
    format(GL_RGBA),
    img(img),
    request(base)
{
    open(img.getSrc());
}

void BoxImage::open(const std::u16string& url)
{
    request.open(u"GET", url);
    request.setHanndler(boost::bind(&BoxImage::notify, this));
    request.send();
    state = Sent;
    if (request.getReadyState() != HttpRequest::DONE)
        return;
    if (request.getErrorFlag()) {
        state = Broken;
        return;
    }
    FILE* file = request.openFile();
    if (!file) {
        state = Broken;
        return;
    }
    pixels = readAsPng(file, naturalWidth, naturalHeight, format);
    if (!pixels) {
        rewind(file);
        pixels = readAsJpeg(file, naturalWidth, naturalHeight, format);
    }
    if (pixels)
        state = CompletelyAvailable;
    else
        state = Broken;
    fclose(file);
}

void BoxImage::notify()
{
    if (state == Sent) {
        if (request.getStatus() == 200)
            box->flags = 1;  // for updating render tree.
        else
            state = Unavailable;
    }
}

}}}}  // org::w3c::dom::bootstrap
<|endoftext|>


<commit_before>// Filename: luiBaseElement_ext.cxx
// Created by:  tobspr (18Sep14)
//

#include "luiBaseElement_ext.h"
#include "extension.h"

#ifdef HAVE_PYTHON

int Extension<LUIBaseElement>::__setattr__(PyObject *self, PyObject *name, PyObject *value) {
  cout << "__setattr__ (LUIBaseElement) called for '" << name << "'" << endl;

  PyObject *setter_name = PyString_FromString("set_");
  PyString_Concat(&setter_name, name);

  PyObject *result = PyObject_CallMethodObjArgs(self, setter_name, value, NULL);

  if (result == NULL) {
    Py_DECREF(setter_name);
    return -1;
  }

  Py_DECREF(setter_name);
  Py_DECREF(result);
  return 0;
}

PyObject *Extension<LUIBaseElement>::__getattr__(PyObject *self, PyObject *name) {
  cout << "__getattr__ (LUIBaseElement) called for '" << name << "'" << endl;

  PyObject *getter_name = PyString_FromString("get_");
  PyString_Concat(&getter_name, name);

  PyObject *getter = PyObject_GenericGetAttr(self, getter_name);

  if (getter == NULL) {
    Py_DECREF(getter_name);
    return NULL;
  }

  PyObject *return_value = PyObject_CallObject(getter, NULL);
  Py_DECREF(getter_name);
  // Py_DECREF(getter);
  return return_value;
}

#endif

<commit_msg>Updated the luiBaseElement __setattr_<commit_after>// Filename: luiBaseElement_ext.cxx
// Created by:  tobspr (18Sep14)
//

#include "luiBaseElement_ext.h"
#include "extension.h"

#ifdef HAVE_PYTHON

int Extension<LUIBaseElement>::__setattr__(PyObject *self, PyObject *name, PyObject *value) {

  // Try to find a method called "set_<name>"
  PyObject *str = PyObject_Str(name);
  string name_as_str;
  if (str != NULL) {
    name_as_str = PyString_AS_STRING(str);
  }
  cout << "__setattr__ (LUIBaseElement) called for '" << name_as_str << "'" << endl;

  if (str != NULL) {
    Py_DECREF(str);
  }

  PyObject *setter_name = PyString_FromString("set_");
  PyString_Concat(&setter_name, name);

  PyObject *result = PyObject_CallMethodObjArgs(self, setter_name, value, NULL);

  // Did not find any method, that means we save the value in the class dict
  if (result == NULL) {
    Py_DECREF(setter_name);

    // Write to class dictionary
    cout << "Could not find element, saving in class dict" << endl;
    PyObject* __dict__ = PyObject_GenericGetAttr(self, (char *)string("__dict__").c_str());
    PyDict_SetItem(__dict__, name, value);

    Py_DECREF(__dict__);
    return 0;
  }

  Py_DECREF(setter_name);
  Py_DECREF(result);
  return 0;
}

PyObject *Extension<LUIBaseElement>::__getattr__(PyObject *self, PyObject *name) {

  // Try to find a method called "get_<name>"
  PyObject *str = PyObject_Str(name);
  string name_as_str;
  if (str != NULL) {
    name_as_str = PyString_AS_STRING(str);
  }
  cout << "__getattr__ (LUIBaseElement) called for '" << name_as_str << "'" << endl;

  if (str != NULL) {
    Py_DECREF(str);
  }
  PyObject *getter_name = PyString_FromString("get_");
  PyString_Concat(&getter_name, name);

  PyObject *getter = PyObject_GenericGetAttr(self, getter_name);

  // No method found, just return, interrogate will fix this for us
  if (getter == NULL) {
    Py_DECREF(getter_name);
    return NULL;
  }

  // Calls the "get_<name>" and returns the result
  PyObject *return_value = PyObject_CallObject(getter, NULL);
  Py_DECREF(getter_name);
  return return_value;
}

#endif

<|endoftext|>


<commit_before>/*
 * TTBlue Audio Signal Class
 * Copyright © 2008, Timothy Place
 *
 * License: This code is licensed under the terms of the GNU LGPL
 * http://www.gnu.org/licenses/lgpl.html
 */

#include "TTAudioSignal.h"
#define thisTTClass TTAudioSignal

/****************************************************************************************************/

TTAudioSignal::TTAudioSignal(const TTUInt16 initialMaxNumChannels)
 	: TTObject("audiosignal"), isLocallyOwned(false), maxNumChannels(0), vectorSize(0), numChannels(0), sampleVectors(NULL)
{
	registerAttributeWithSetter(vectorSize, kTypeUInt16);
	registerAttributeWithSetter(numChannels, kTypeUInt16);
	registerAttributeWithSetter(maxNumChannels, kTypeUInt16);
	registerAttributeSimple(bitdepth, kTypeUInt8);
	addAttributeProperty(bitdepth, readOnly, kTTVal1);

	registerMessageSimple(clear);
	registerMessageSimple(alloc);
	registerMessageWithArgument(allocWithNewVectorSize);
	registerMessageWithArgument(setVector32);
	registerMessageWithArgument(getVector32);
	registerMessageWithArgument(setVector64);
	registerMessageWithArgument(getVector64);

	setAttributeValue(TT("maxNumChannels"), initialMaxNumChannels);
	setAttributeValue(TT("numChannels"), initialMaxNumChannels);
}

TTAudioSignal::~TTAudioSignal()
{
	chuck();
}

void TTAudioSignal::chuck()
{
	TTUInt32	i;

	if(isLocallyOwned){
		for(i=0; i<maxNumChannels; i++){
			free(sampleVectors[i]);
			sampleVectors[i] = NULL;
		}
		isLocallyOwned = false;
	}
	free(sampleVectors);
	maxNumChannels = 0;
	sampleVectors = NULL;
}

TTErr TTAudioSignal::setmaxNumChannels(const TTValue& newMaxNumChannels)
{
	TTUInt32	i;

	chuck();
	maxNumChannels = newMaxNumChannels;
	if(maxNumChannels) {
		sampleVectors = (TTSampleVector *)malloc(sizeof(TTSampleVector) * maxNumChannels);
		for(i=0; i<maxNumChannels; i++)
			sampleVectors[i] = NULL;
	}
	return kTTErrNone;
}

TTErr TTAudioSignal::setVector(const TTUInt16 channel, const TTUInt16 newVectorSize, const TTSampleVector newVector)
{
	TTUInt32	i;

	// could check against maxnumchannels here

	bitdepth = 64;
	vectorSize = newVectorSize;

	if(isLocallyOwned){
		for(i=0; i<maxNumChannels; i++){
			free(sampleVectors[i]);
			sampleVectors[i] = NULL;
		}
		isLocallyOwned = false;
	}
	sampleVectors[channel] = newVector;
	return kTTErrNone;
}

TTErr TTAudioSignal::setVector64(const TTValue& v)
{
	TTUInt16		channel;
	TTUInt16		newVectorSize;
	TTPtr			newVector;

	if(v.getSize() == 3){
		v.get(0, channel);
		v.get(1, newVectorSize);
		v.get(2, &newVector);
		return setVector(channel, newVectorSize, TTSampleVector(newVector));
	}
	return kTTErrGeneric;
}

/*
	It sucks if someone sets a 32-bit audio vector, since we have translate it into a 64-bit buffer.
	There may be a better way to do this...

	For now, we don't simply reference the data passed in.  Instead we allocate our own buffer and copy the data.
	Unfortunately, this is very slow.

	Also note that we are relying on the vector size already being set!

	If we passed the vs in to this method, we could avoid having to realloc the memory every single time.
	This would probably be a very good idea.
*/
TTErr TTAudioSignal::setVector(const TTUInt16 channel, const TTUInt16 newVectorSize, const TTFloat32* newVector)
{
	TTUInt32	i;

	// 1. could check against maxnumchannels here

	// 2. allocate the vector if need be
	if(bitdepth != 32 || !isLocallyOwned || newVectorSize != vectorSize)
	{
		bitdepth = 32;
		vectorSize = newVectorSize;
		alloc();
	}

	// 3. copy the vector (from 32-bits to 64-bits)
	for(i=0; i<vectorSize; i++)
		sampleVectors[channel][i] = newVector[i];

	return kTTErrNone;
}

TTErr TTAudioSignal::setVector32(const TTValue& v)
{
	TTUInt16		channel;
	TTUInt16		newVectorSize;
	TTPtr			newVector;

	if(v.getSize() == 3){
		v.get(0, channel);
		v.get(1, newVectorSize);
		v.get(2, &newVector);
		return setVector(channel, newVectorSize, (TTFloat32*)newVector);
	}
	return kTTErrGeneric;
}

TTErr TTAudioSignal::getVector(const TTUInt16 channel, const TTUInt16 vectorSize, TTSampleVector returnedVector)
{
	returnedVector = sampleVectors[channel];
	return kTTErrNone;
}

TTErr TTAudioSignal::getVector64(TTValue& v)
{
	TTUInt16		channel;
	TTUInt16		theVectorSize;
	TTPtr			returnedVector;

	if(v.getSize() == 3){
		v.get(0, channel);
		v.get(1, theVectorSize);
		v.get(2, &returnedVector);
		return setVector(channel, theVectorSize, TTSampleVector(returnedVector));
	}
	return kTTErrGeneric;
}

TTErr TTAudioSignal::getVector(const TTUInt16 channel, const TTUInt16 theVectorSize, TTFloat32* returnedVector)
{
	TTUInt16 i;

	for(i=0; i<theVectorSize; i++)
		returnedVector[i] = (TTFloat32)sampleVectors[channel][i];
	return kTTErrNone;
}

TTErr TTAudioSignal::getVector32(TTValue& v)
{
	TTUInt16		channel;
	TTUInt16		theVectorSize;
	TTPtr			returnedVector;

	if(v.getSize() == 3){
		v.get(0, channel);
		v.get(1, theVectorSize);
		v.get(2, &returnedVector);
		return setVector(channel, theVectorSize, (TTFloat32*)returnedVector);
	}
	return kTTErrGeneric;
}

TTErr TTAudioSignal::alloc()
{
	TTUInt32	i;
	if(isLocallyOwned){
		for(i=0; i<maxNumChannels; i++){
			free(sampleVectors[i]);
			sampleVectors[i] = NULL;
		}
	}

	for(i=0; i<maxNumChannels; i++) {
		sampleVectors[i] = (TTSampleVector)malloc(sizeof(TTSampleValue) * vectorSize);
	}
	isLocallyOwned = maxNumChannels > 0 ? true : false;
	return kTTErrNone;
}

TTErr TTAudioSignal::allocWithVectorSize(const TTUInt16 newVectorSize)
{
	if(newVectorSize != vectorSize){
		vectorSize = newVectorSize;
		return alloc();
	}
	else
		return kTTErrNone;
}

TTErr TTAudioSignal::allocWithNewVectorSize(const TTValue& newVectorSize)
{
	return allocWithVectorSize(TTUInt16(newVectorSize));
}

TTUInt16 TTAudioSignal::getMinChannelCount(const TTAudioSignal& signal1, const TTAudioSignal& signal2)
{
	if(signal1.numChannels > signal2.numChannels)
		return signal2.numChannels;
	else
		return signal1.numChannels;
}

TTUInt16 TTAudioSignal::getMinChannelCount(const TTAudioSignal& signal1, const TTAudioSignal& signal2, const TTAudioSignal& signal3)
{
	TTUInt16	numChannels = signal1.numChannels;

	if(signal2.numChannels < numChannels)
		numChannels = signal2.numChannels;
	if(signal3.numChannels < numChannels)
		numChannels = signal3.numChannels;

	return numChannels;
}

TTUInt16 TTAudioSignal::getMaxChannelCount(const TTAudioSignal& signal1, const TTAudioSignal& signal2)
{
	if(signal1.numChannels < signal2.numChannels)
		return signal2.numChannels;
	else
		return signal1.numChannels;
}

TTUInt16 TTAudioSignal::getMaxChannelCount(const TTAudioSignal& signal1, const TTAudioSignal& signal2, const TTAudioSignal& signal3)
{
	TTUInt16	numChannels = signal1.numChannels;

	if(signal2.numChannels > numChannels)
		numChannels = signal2.numChannels;
	if(signal3.numChannels > numChannels)
		numChannels = signal3.numChannels;

	return numChannels;
}

TTUInt16 TTAudioSignal::getNumChannels(const TTAudioSignal& signal)
{
	return signal.numChannels;
}

// TODO: The old tt audio signal could point to external memory, or allocate its own for the vectors
// This enum was used to keep trac of which was the case:
// enum selectors{
//	k_mode_local = 1,
//	k_mode_external = 0,
//};

// TODO: implement clear() method -- ZERO OUT A VECTOR'S CONTENTS
TTErr TTAudioSignal::clear()
{
	TTUInt8		channel;
	TTUInt16	i;

	if(!sampleVectors)
		return kTTErrGeneric;

	for(channel=0; channel<numChannels; channel++){
		for(i=0; i<vectorSize; i++)
			sampleVectors[channel][i] = 0.0;
	}
	return kTTErrNone;
}

// TODO: implement fill() method --- SET ALL VALUES IN THE SIGNAL TO A CONSTANT

<commit_msg>Addressing a shadowed variable warning.<commit_after>/*
 * TTBlue Audio Signal Class
 * Copyright © 2008, Timothy Place
 *
 * License: This code is licensed under the terms of the GNU LGPL
 * http://www.gnu.org/licenses/lgpl.html
 */

#include "TTAudioSignal.h"
#define thisTTClass TTAudioSignal

/****************************************************************************************************/

TTAudioSignal::TTAudioSignal(const TTUInt16 initialMaxNumChannels)
 	: TTObject("audiosignal"), isLocallyOwned(false), maxNumChannels(0), vectorSize(0), numChannels(0), sampleVectors(NULL)
{
	registerAttributeWithSetter(vectorSize, kTypeUInt16);
	registerAttributeWithSetter(numChannels, kTypeUInt16);
	registerAttributeWithSetter(maxNumChannels, kTypeUInt16);
	registerAttributeSimple(bitdepth, kTypeUInt8);
	addAttributeProperty(bitdepth, readOnly, kTTVal1);

	registerMessageSimple(clear);
	registerMessageSimple(alloc);
	registerMessageWithArgument(allocWithNewVectorSize);
	registerMessageWithArgument(setVector32);
	registerMessageWithArgument(getVector32);
	registerMessageWithArgument(setVector64);
	registerMessageWithArgument(getVector64);

	setAttributeValue(TT("maxNumChannels"), initialMaxNumChannels);
	setAttributeValue(TT("numChannels"), initialMaxNumChannels);
}

TTAudioSignal::~TTAudioSignal()
{
	chuck();
}

void TTAudioSignal::chuck()
{
	TTUInt32	i;

	if(isLocallyOwned){
		for(i=0; i<maxNumChannels; i++){
			free(sampleVectors[i]);
			sampleVectors[i] = NULL;
		}
		isLocallyOwned = false;
	}
	free(sampleVectors);
	maxNumChannels = 0;
	sampleVectors = NULL;
}

TTErr TTAudioSignal::setmaxNumChannels(const TTValue& newMaxNumChannels)
{
	TTUInt32	i;

	chuck();
	maxNumChannels = newMaxNumChannels;
	if(maxNumChannels) {
		sampleVectors = (TTSampleVector *)malloc(sizeof(TTSampleVector) * maxNumChannels);
		for(i=0; i<maxNumChannels; i++)
			sampleVectors[i] = NULL;
	}
	return kTTErrNone;
}

TTErr TTAudioSignal::setVector(const TTUInt16 channel, const TTUInt16 newVectorSize, const TTSampleVector newVector)
{
	TTUInt32	i;

	// could check against maxnumchannels here

	bitdepth = 64;
	vectorSize = newVectorSize;

	if(isLocallyOwned){
		for(i=0; i<maxNumChannels; i++){
			free(sampleVectors[i]);
			sampleVectors[i] = NULL;
		}
		isLocallyOwned = false;
	}
	sampleVectors[channel] = newVector;
	return kTTErrNone;
}

TTErr TTAudioSignal::setVector64(const TTValue& v)
{
	TTUInt16		channel;
	TTUInt16		newVectorSize;
	TTPtr			newVector;

	if(v.getSize() == 3){
		v.get(0, channel);
		v.get(1, newVectorSize);
		v.get(2, &newVector);
		return setVector(channel, newVectorSize, TTSampleVector(newVector));
	}
	return kTTErrGeneric;
}

/*
	It sucks if someone sets a 32-bit audio vector, since we have translate it into a 64-bit buffer.
	There may be a better way to do this...

	For now, we don't simply reference the data passed in.  Instead we allocate our own buffer and copy the data.
	Unfortunately, this is very slow.

	Also note that we are relying on the vector size already being set!

	If we passed the vs in to this method, we could avoid having to realloc the memory every single time.
	This would probably be a very good idea.
*/
TTErr TTAudioSignal::setVector(const TTUInt16 channel, const TTUInt16 newVectorSize, const TTFloat32* newVector)
{
	TTUInt32	i;

	// 1. could check against maxnumchannels here

	// 2. allocate the vector if need be
	if(bitdepth != 32 || !isLocallyOwned || newVectorSize != vectorSize)
	{
		bitdepth = 32;
		vectorSize = newVectorSize;
		alloc();
	}

	// 3. copy the vector (from 32-bits to 64-bits)
	for(i=0; i<vectorSize; i++)
		sampleVectors[channel][i] = newVector[i];

	return kTTErrNone;
}

TTErr TTAudioSignal::setVector32(const TTValue& v)
{
	TTUInt16		channel;
	TTUInt16		newVectorSize;
	TTPtr			newVector;

	if(v.getSize() == 3){
		v.get(0, channel);
		v.get(1, newVectorSize);
		v.get(2, &newVector);
		return setVector(channel, newVectorSize, (TTFloat32*)newVector);
	}
	return kTTErrGeneric;
}

TTErr TTAudioSignal::getVector(const TTUInt16 channel, const TTUInt16 returnedVectorSize, TTSampleVector returnedVector)
{
	returnedVector = sampleVectors[channel];
	return kTTErrNone;
}

TTErr TTAudioSignal::getVector64(TTValue& v)
{
	TTUInt16		channel;
	TTUInt16		theVectorSize;
	TTPtr			returnedVector;

	if(v.getSize() == 3){
		v.get(0, channel);
		v.get(1, theVectorSize);
		v.get(2, &returnedVector);
		return setVector(channel, theVectorSize, TTSampleVector(returnedVector));
	}
	return kTTErrGeneric;
}

TTErr TTAudioSignal::getVector(const TTUInt16 channel, const TTUInt16 theVectorSize, TTFloat32* returnedVector)
{
	TTUInt16 i;

	for(i=0; i<theVectorSize; i++)
		returnedVector[i] = (TTFloat32)sampleVectors[channel][i];
	return kTTErrNone;
}

TTErr TTAudioSignal::getVector32(TTValue& v)
{
	TTUInt16		channel;
	TTUInt16		theVectorSize;
	TTPtr			returnedVector;

	if(v.getSize() == 3){
		v.get(0, channel);
		v.get(1, theVectorSize);
		v.get(2, &returnedVector);
		return setVector(channel, theVectorSize, (TTFloat32*)returnedVector);
	}
	return kTTErrGeneric;
}

TTErr TTAudioSignal::alloc()
{
	TTUInt32	i;
	if(isLocallyOwned){
		for(i=0; i<maxNumChannels; i++){
			free(sampleVectors[i]);
			sampleVectors[i] = NULL;
		}
	}

	for(i=0; i<maxNumChannels; i++) {
		sampleVectors[i] = (TTSampleVector)malloc(sizeof(TTSampleValue) * vectorSize);
	}
	isLocallyOwned = maxNumChannels > 0 ? true : false;
	return kTTErrNone;
}

TTErr TTAudioSignal::allocWithVectorSize(const TTUInt16 newVectorSize)
{
	if(newVectorSize != vectorSize){
		vectorSize = newVectorSize;
		return alloc();
	}
	else
		return kTTErrNone;
}

TTErr TTAudioSignal::allocWithNewVectorSize(const TTValue& newVectorSize)
{
	return allocWithVectorSize(TTUInt16(newVectorSize));
}

TTUInt16 TTAudioSignal::getMinChannelCount(const TTAudioSignal& signal1, const TTAudioSignal& signal2)
{
	if(signal1.numChannels > signal2.numChannels)
		return signal2.numChannels;
	else
		return signal1.numChannels;
}

TTUInt16 TTAudioSignal::getMinChannelCount(const TTAudioSignal& signal1, const TTAudioSignal& signal2, const TTAudioSignal& signal3)
{
	TTUInt16	numChannels = signal1.numChannels;

	if(signal2.numChannels < numChannels)
		numChannels = signal2.numChannels;
	if(signal3.numChannels < numChannels)
		numChannels = signal3.numChannels;

	return numChannels;
}

TTUInt16 TTAudioSignal::getMaxChannelCount(const TTAudioSignal& signal1, const TTAudioSignal& signal2)
{
	if(signal1.numChannels < signal2.numChannels)
		return signal2.numChannels;
	else
		return signal1.numChannels;
}

TTUInt16 TTAudioSignal::getMaxChannelCount(const TTAudioSignal& signal1, const TTAudioSignal& signal2, const TTAudioSignal& signal3)
{
	TTUInt16	numChannels = signal1.numChannels;

	if(signal2.numChannels > numChannels)
		numChannels = signal2.numChannels;
	if(signal3.numChannels > numChannels)
		numChannels = signal3.numChannels;

	return numChannels;
}

TTUInt16 TTAudioSignal::getNumChannels(const TTAudioSignal& signal)
{
	return signal.numChannels;
}

// TODO: The old tt audio signal could point to external memory, or allocate its own for the vectors
// This enum was used to keep trac of which was the case:
// enum selectors{
//	k_mode_local = 1,
//	k_mode_external = 0,
//};

// TODO: implement clear() method -- ZERO OUT A VECTOR'S CONTENTS
TTErr TTAudioSignal::clear()
{
	TTUInt8		channel;
	TTUInt16	i;

	if(!sampleVectors)
		return kTTErrGeneric;

	for(channel=0; channel<numChannels; channel++){
		for(i=0; i<vectorSize; i++)
			sampleVectors[channel][i] = 0.0;
	}
	return kTTErrNone;
}

// TODO: implement fill() method --- SET ALL VALUES IN THE SIGNAL TO A CONSTANT

<|endoftext|>


<commit_before>/*
 * Jamoma Dataspace Library
 * Copyright © 2007
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTDataspaceConverter.h"

#define thisTTClass			TTDataspaceConverter
#define thisTTClassName		"dataspace"
#define thisTTClassTags		"dataspace.converter"

TT_OBJECT_CONSTRUCTOR,
	mDataspaceTTObject(NULL),
	mDataspaceObject(NULL)
{
	addAttributeWithSetter(Dataspace, kTypeSymbol);
	addAttributeWithGetterAndSetter(InputUnit, kTypeSymbol);
	addAttributeWithGetterAndSetter(OutputUnit, kTypeSymbol);

	addMessageWithArgument(dictionary);
	addMessageWithArgument(convert);

	addMessageWithArgument(getAvailableUnits);
	addMessageWithArgument(getAvailableDataspaces);

	setAttributeValue(TT("dataspace"), TT("none"));
}

TTDataspaceConverter::~TTDataspaceConverter()
{
	TTObjectRelease((TTObjectPtr*)&mDataspaceTTObject);
}

TTErr TTDataspaceConverter::setDataspace(const TTValue& newValue)
{
	TTSymbolPtr		name;
	TTErr			err;
	TTString		objectName = "dataspace.";

	newValue.get(0, &name);

	// TODO: validate the name provided before proceeding
	objectName += name->getString();
	err = TTObjectInstantiate(TT(objectName.c_str()), &mDataspaceTTObject, kTTValNONE);
	if (err) {
        // Rather than crashing:
            //throw TTException("Error trying to load dataspace with that name");
        // we set it to "none" and post an error message to the log
        TTLogError("Error trying to load %s, set to none\n", objectName.c_str());
        objectName = "dataspace.none";
        TTObjectInstantiate(TT(objectName.c_str()), &mDataspaceTTObject, kTTValNONE);
    }
	mDataspaceObject = dynamic_cast<TTDataspacePtr>(mDataspaceTTObject);
	mDataspace = name;

	return err;
}

TTErr TTDataspaceConverter::convert(TTValue& io)
{
	TTValue	output;
	TTErr	err;

	err = mDataspaceObject->convert(io, output);
	io = output;

	return err;
}

TTErr TTDataspaceConverter::dictionary(TTValue& input)
{
	TTDictionaryPtr	d = NULL;
	TTValue			v;
	TTErr			err;

	input.get(0, (TTPtr*)(&d));
	d->getValue(v);
	err = convert(v);
	d->setValue(v);

	return err;
}

TTErr TTDataspaceConverter::getInputUnit(TTValue& inUnitName)
{
	inUnitName = mDataspaceObject->getInputUnit();
	return kTTErrNone;
}

TTErr TTDataspaceConverter::setInputUnit(const TTValue& inUnitName)
{
	return mDataspaceObject->setInputUnit(inUnitName);
}

TTErr TTDataspaceConverter::getOutputUnit(TTValue& outUnitName)
{
	outUnitName = mDataspaceObject->getOutputUnit();
	return kTTErrNone;
}

TTErr TTDataspaceConverter::setOutputUnit(const TTValue& outUnitName)
{
	return mDataspaceObject->setOutputUnit(outUnitName);
}

TTErr TTDataspaceConverter::getAvailableUnits(TTValue& unitNames)
{
	return mDataspaceObject->getAvailableUnits(unitNames);
}

TTErr TTDataspaceConverter::getAvailableDataspaces(TTValue& dataspaceNames)
{
	TTErr err;

	err = TTGetRegisteredClassNamesForTags(dataspaceNames, TT("dataspace"));
	if (!err) {
		// strip the leading "dataspace." prefix off all the names
		for (int i=0; i < dataspaceNames.getSize(); i++) {
			TTSymbolPtr s;
			TTString	str;

			dataspaceNames.get(i, &s);
			str = s->getString();
			str.erase(0, 10);
			s = TT(str);
			dataspaceNames.set(i, s);
		}
	}
	return err;
}

<commit_msg>windows: replacing getString with getCString in TTDataspaceConverter.cpp to prevent crashes<commit_after>/*
 * Jamoma Dataspace Library
 * Copyright © 2007
 *
 * License: This code is licensed under the terms of the "New BSD License"
 * http://creativecommons.org/licenses/BSD/
 */

#include "TTDataspaceConverter.h"

#define thisTTClass			TTDataspaceConverter
#define thisTTClassName		"dataspace"
#define thisTTClassTags		"dataspace.converter"

TT_OBJECT_CONSTRUCTOR,
	mDataspaceTTObject(NULL),
	mDataspaceObject(NULL)
{
	addAttributeWithSetter(Dataspace, kTypeSymbol);
	addAttributeWithGetterAndSetter(InputUnit, kTypeSymbol);
	addAttributeWithGetterAndSetter(OutputUnit, kTypeSymbol);

	addMessageWithArgument(dictionary);
	addMessageWithArgument(convert);

	addMessageWithArgument(getAvailableUnits);
	addMessageWithArgument(getAvailableDataspaces);

	setAttributeValue(TT("dataspace"), TT("none"));
}

TTDataspaceConverter::~TTDataspaceConverter()
{
	TTObjectRelease((TTObjectPtr*)&mDataspaceTTObject);
}

TTErr TTDataspaceConverter::setDataspace(const TTValue& newValue)
{
	TTSymbolPtr		name;
	TTErr			err;
	TTString		objectName = "dataspace.";

	newValue.get(0, &name);

	// TODO: validate the name provided before proceeding
	objectName += name->getString();
	err = TTObjectInstantiate(TT(objectName.c_str()), &mDataspaceTTObject, kTTValNONE);
	if (err) {
        // Rather than crashing:
            //throw TTException("Error trying to load dataspace with that name");
        // we set it to "none" and post an error message to the log
        TTLogError("Error trying to load %s, set to none\n", objectName.c_str());
        objectName = "dataspace.none";
        TTObjectInstantiate(TT(objectName.c_str()), &mDataspaceTTObject, kTTValNONE);
    }
	mDataspaceObject = dynamic_cast<TTDataspacePtr>(mDataspaceTTObject);
	mDataspace = name;

	return err;
}

TTErr TTDataspaceConverter::convert(TTValue& io)
{
	TTValue	output;
	TTErr	err;

	err = mDataspaceObject->convert(io, output);
	io = output;

	return err;
}

TTErr TTDataspaceConverter::dictionary(TTValue& input)
{
	TTDictionaryPtr	d = NULL;
	TTValue			v;
	TTErr			err;

	input.get(0, (TTPtr*)(&d));
	d->getValue(v);
	err = convert(v);
	d->setValue(v);

	return err;
}

TTErr TTDataspaceConverter::getInputUnit(TTValue& inUnitName)
{
	inUnitName = mDataspaceObject->getInputUnit();
	return kTTErrNone;
}

TTErr TTDataspaceConverter::setInputUnit(const TTValue& inUnitName)
{
	return mDataspaceObject->setInputUnit(inUnitName);
}

TTErr TTDataspaceConverter::getOutputUnit(TTValue& outUnitName)
{
	outUnitName = mDataspaceObject->getOutputUnit();
	return kTTErrNone;
}

TTErr TTDataspaceConverter::setOutputUnit(const TTValue& outUnitName)
{
	return mDataspaceObject->setOutputUnit(outUnitName);
}

TTErr TTDataspaceConverter::getAvailableUnits(TTValue& unitNames)
{
	return mDataspaceObject->getAvailableUnits(unitNames);
}

TTErr TTDataspaceConverter::getAvailableDataspaces(TTValue& dataspaceNames)
{
	TTErr err;

	err = TTGetRegisteredClassNamesForTags(dataspaceNames, TT("dataspace"));
	if (!err) {
		// strip the leading "dataspace." prefix off all the names
		for (int i=0; i < dataspaceNames.getSize(); i++) {
			TTSymbolPtr s;
			//TTString	str;
			const char* cStr;

			dataspaceNames.get(i, &s);
			/*
			str = s->getString();	// this causes crashes on Windows, need to use C string instead
			str.erase(0, 10);
			*/
			cStr = s->getCString() + 10;
			s = TT(cStr);
			dataspaceNames.set(i, s);
		}
	}
	return err;
}

<|endoftext|>


<commit_before>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "test_roudi_service_discovery.hpp"

class RoudiFindService_test : public RouDiServiceDiscoveryTest
{
  public:
    void SetUp()
    {
    }

    void TearDown()
    {
    }

    iox::runtime::PoshRuntime* senderRuntime{&iox::runtime::PoshRuntime::getInstance("/sender")};
    iox::runtime::PoshRuntime* receiverRuntime{&iox::runtime::PoshRuntime::getInstance("/receiver")};
};

TEST_F(RoudiFindService_test, OfferSingleMethodServiceSingleInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    iox::runtime::InstanceContainer instanceContainer;
    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));
}

///@todo #359 offereService should return bool signalling success/failure
TEST_F(RoudiFindService_test, DISABLED_OfferServiceWithDefaultServiceDescriptionFails)
{
    iox::runtime::InstanceContainer instanceContainer;
    bool isServiceOffered;

    ///@todo #359 offerService should not allow invalid ServiceDescriptions
    // isServiceOffered = senderRuntime->offerService(iox::capro::ServiceDescription());
    this->InterOpWait();

    ASSERT_EQ(false, isServiceOffered);
}

TEST_F(RoudiFindService_test, ReofferedServiceWithValidServiceDescriptionCanBeFound)
{
    iox::runtime::InstanceContainer instanceContainer;
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();

    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));
}

TEST_F(RoudiFindService_test, OfferExsistingServiceMultipleTimesIsRedundant)
{
    InstanceContainer instanceContainer;
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();

    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));
}

///@todo #387 findService to return InstanceContainer directly
TEST_F(RoudiFindService_test, DISABLED_FindSameServiceMultipleTimesReturnsSingleInstance)
{
    InstanceContainer instanceContainer;
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();

    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);
    this->InterOpWait();

    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(instanceContainer.at(0), Eq(IdString("instance1")));

    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);
    this->InterOpWait();

    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(instanceContainer.at(0), Eq(IdString("instance1")));
}

TEST_F(RoudiFindService_test, DISABLED_OfferMultiMethodServiceSingleInstance_PERFORMANCETEST42)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service2", "instance1"});
    senderRuntime->offerService({"service3", "instance1"});

    this->InterOpWait();
    iox::runtime::InstanceContainer instanceContainer;

    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));

    instanceContainer.clear();
    receiverRuntime->findService({"service2", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));

    instanceContainer.clear();
    receiverRuntime->findService({"service3", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));
}

TEST_F(RoudiFindService_test, SubscribeAnyInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service1", "instance2"});
    senderRuntime->offerService({"service1", "instance3"});

    this->InterOpWait();
    InstanceContainer instanceContainer;
    InstanceContainer instanceContainerExp;
    InitContainer(instanceContainerExp, {"instance1", "instance2", "instance3"});

    receiverRuntime->findService({"service1", "65535"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(3u));
    EXPECT_TRUE(instanceContainer == instanceContainerExp);
}

TEST_F(RoudiFindService_test, OfferSingleMethodServiceMultiInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service1", "instance2"});
    senderRuntime->offerService({"service1", "instance3"});
    this->InterOpWait();

    iox::runtime::InstanceContainer instanceContainer;
    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));

    instanceContainer.clear();
    receiverRuntime->findService({"service1", "instance2"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance2")));

    instanceContainer.clear();
    receiverRuntime->findService({"service1", "instance3"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance3")));
}

TEST_F(RoudiFindService_test, OfferMultiMethodServiceMultiInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service1", "instance2"});
    senderRuntime->offerService({"service1", "instance3"});
    senderRuntime->offerService({"service2", "instance1"});
    senderRuntime->offerService({"service2", "instance2"});
    senderRuntime->offerService({"service2", "instance3"});
    this->InterOpWait();

    iox::runtime::InstanceContainer instanceContainer;
    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));

    instanceContainer.clear();
    receiverRuntime->findService({"service1", "instance2"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance2")));

    instanceContainer.clear();
    receiverRuntime->findService({"service1", "instance3"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance3")));

    instanceContainer.clear();
    receiverRuntime->findService({"service2", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));

    instanceContainer.clear();
    receiverRuntime->findService({"service2", "instance2"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance2")));

    instanceContainer.clear();
    receiverRuntime->findService({"service2", "instance3"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance3")));
}

TEST_F(RoudiFindService_test, StopOfferSingleMethodServiceSingleInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    this->InterOpWait();

    iox::runtime::InstanceContainer instanceContainer;
    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(0u));
}

TEST_F(RoudiFindService_test, StopOfferMultiMethodServiceSingleInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service2", "instance1"});
    senderRuntime->offerService({"service3", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    senderRuntime->stopOfferService({"service3", "instance1"});
    this->InterOpWait();

    iox::runtime::InstanceContainer instanceContainer;
    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(0u));

    instanceContainer.clear();
    receiverRuntime->findService({"service2", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));

    instanceContainer.clear();
    receiverRuntime->findService({"service3", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(0u));
}

TEST_F(RoudiFindService_test, StopOfferServiceRedundantCall)
{
    iox::runtime::InstanceContainer instanceContainer;
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    this->InterOpWait();

    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(0u));
}

TEST_F(RoudiFindService_test, StopNonExistingService)
{
    iox::runtime::InstanceContainer instanceContainer;
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service2", "instance2"});
    this->InterOpWait();

    receiverRuntime->findService({"service1", "instance1"}, instanceContainer);

    ASSERT_THAT(instanceContainer.size(), Eq(1));
    ASSERT_THAT(*instanceContainer.begin(), Eq(IdString("instance1")));
}

TEST_F(RoudiFindService_test, FindNonExistingServices)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service2", "instance1"});
    senderRuntime->offerService({"service3", "instance1"});
    this->InterOpWait();

    iox::runtime::InstanceContainer instanceContainer;
    receiverRuntime->findService({"service1", "schlomo"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(0u));

    receiverRuntime->findService({"ignatz", "instance1"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(0u));

    receiverRuntime->findService({"ignatz", "schlomo"}, instanceContainer);
    ASSERT_THAT(instanceContainer.size(), Eq(0u));
}
TEST_F(RoudiFindService_test, InterfacePort)
{
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();

    auto interfacePortData = receiverRuntime->getMiddlewareInterface(iox::capro::Interfaces::SOMEIP);
    iox::popo::InterfacePort interfacePort(interfacePortData);

    this->InterOpWait();

    bool serviceFound = false;

    while (auto maybeCaProMessage = interfacePort.tryGetCaProMessage())
    {
        auto caproMessage = maybeCaProMessage.value();
        if ((caproMessage.m_serviceDescription.getServiceIDString() == IdString("service1"))
            && (caproMessage.m_serviceDescription.getInstanceIDString() == IdString("instance1"))
            && ((caproMessage.m_serviceDescription.getEventIDString() == IdString(iox::capro::AnyEventString))))
        {
            serviceFound = true;
            break;
        }
    }

    EXPECT_THAT(serviceFound, Eq(true));
}

TEST_F(RoudiFindService_test, findServiceMaxInstances)
{
    size_t noOfInstances = iox::MAX_NUMBER_OF_INSTANCES;
    InstanceContainer instanceContainerExp;

    for (size_t i = 0; i < noOfInstances; i++)
    {
        // Service & Instance string is kept short , to reduce the response size in find service request ,
        // (message queue has a limit of 512)
        std::string instance = "i" + std::to_string(i);
        senderRuntime->offerService({"s", IdString(iox::cxx::TruncateToCapacity, instance)});
        instanceContainerExp.push_back(IdString(iox::cxx::TruncateToCapacity, instance));
        this->InterOpWait();
    }

    iox::runtime::InstanceContainer instanceContainer;
    auto status = receiverRuntime->findService({"s", "65535"}, instanceContainer);

    EXPECT_THAT(instanceContainer.size(), Eq(iox::MAX_NUMBER_OF_INSTANCES));
    EXPECT_TRUE(instanceContainer == instanceContainerExp);
    ASSERT_THAT(status.has_error(), Eq(false));
}

TEST_F(RoudiFindService_test, findServiceInstanceContainerOverflowError)
{
    size_t noOfInstances = (iox::MAX_NUMBER_OF_INSTANCES + 1);
    InstanceContainer instanceContainerExp;
    for (size_t i = 0; i < noOfInstances; i++)
    {
        std::string instance = "i" + std::to_string(i);
        senderRuntime->offerService({"s", IdString(iox::cxx::TruncateToCapacity, instance)});
        instanceContainerExp.push_back(IdString(iox::cxx::TruncateToCapacity, instance));
        this->InterOpWait();
    }

    iox::runtime::InstanceContainer instanceContainer;
    auto status = receiverRuntime->findService({"s", "65535"}, instanceContainer);

    EXPECT_THAT(instanceContainer.size(), Eq(iox::MAX_NUMBER_OF_INSTANCES));
    EXPECT_TRUE(instanceContainer == instanceContainerExp);
    ASSERT_THAT(status.has_error(), Eq(true));
}
<commit_msg>iox-#240 adapted signature change of findservice()<commit_after>// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "test_roudi_service_discovery.hpp"

class RoudiFindService_test : public RouDiServiceDiscoveryTest
{
  public:
    void SetUp()
    {
    }

    void TearDown()
    {
    }

    iox::runtime::PoshRuntime* senderRuntime{&iox::runtime::PoshRuntime::getInstance("/sender")};
    iox::runtime::PoshRuntime* receiverRuntime{&iox::runtime::PoshRuntime::getInstance("/receiver")};
};

TEST_F(RoudiFindService_test, OfferSingleMethodServiceSingleInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();

    auto instanceContainer = receiverRuntime->findService({"service1", "instance1"});

    ASSERT_THAT(instanceContainer.get_value().size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.get_value().begin(), Eq(IdString("instance1")));
}

///@todo #359 offereService should return bool signalling success/failure
TEST_F(RoudiFindService_test, DISABLED_OfferServiceWithDefaultServiceDescriptionFails)
{
    iox::runtime::InstanceContainer instanceContainer;
    bool isServiceOffered;

    ///@todo #359 offerService should not allow invalid ServiceDescriptions
    // isServiceOffered = senderRuntime->offerService(iox::capro::ServiceDescription());
    this->InterOpWait();

    ASSERT_EQ(false, isServiceOffered);
}

TEST_F(RoudiFindService_test, ReofferedServiceWithValidServiceDescriptionCanBeFound)
{
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();

    auto instanceContainer = receiverRuntime->findService({"service1", "instance1"});

    ASSERT_THAT(instanceContainer.get_value().size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.get_value().begin(), Eq(IdString("instance1")));
}

TEST_F(RoudiFindService_test, OfferExsistingServiceMultipleTimesIsRedundant)
{
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();

    auto instanceContainer = receiverRuntime->findService({"service1", "instance1"});

    ASSERT_THAT(instanceContainer.get_value().size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.get_value().begin(), Eq(IdString("instance1")));
}

TEST_F(RoudiFindService_test, FindSameServiceMultipleTimesReturnsSingleInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();

    auto instanceContainer = receiverRuntime->findService({"service1", "instance1"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.get_value().begin(), Eq(IdString("instance1")));

    instanceContainer = receiverRuntime->findService({"service1", "instance1"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.get_value().begin(), Eq(IdString("instance1")));
}

TEST_F(RoudiFindService_test, DISABLED_OfferMultiMethodServiceSingleInstance_PERFORMANCETEST42)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service2", "instance1"});
    senderRuntime->offerService({"service3", "instance1"});
    this->InterOpWait();

    auto instanceContainer = receiverRuntime->findService({"service1", "instance1"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.get_value().begin(), Eq(IdString("instance1")));

    instanceContainer = receiverRuntime->findService({"service2", "instance1"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.get_value().begin(), Eq(IdString("instance1")));

    instanceContainer = receiverRuntime->findService({"service3", "instance1"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.get_value().begin(), Eq(IdString("instance1")));
}

TEST_F(RoudiFindService_test, SubscribeAnyInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service1", "instance2"});
    senderRuntime->offerService({"service1", "instance3"});
    this->InterOpWait();
    InstanceContainer instanceContainerExp;
    InitContainer(instanceContainerExp, {"instance1", "instance2", "instance3"});

    auto instanceContainer = receiverRuntime->findService({"service1", "65535"});

    ASSERT_THAT(instanceContainer.get_value().size(), Eq(3u));
    EXPECT_TRUE(instanceContainer.get_value() == instanceContainerExp);
}

TEST_F(RoudiFindService_test, OfferSingleMethodServiceMultiInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service1", "instance2"});
    senderRuntime->offerService({"service1", "instance3"});
    this->InterOpWait();

    auto instanceContainer = receiverRuntime->findService({"service1", "instance1"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.get_value().begin(), Eq(IdString("instance1")));

    instanceContainer = receiverRuntime->findService({"service1", "instance2"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.get_value().begin(), Eq(IdString("instance2")));

    instanceContainer = receiverRuntime->findService({"service1", "instance3"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.get_value().begin(), Eq(IdString("instance3")));
}

TEST_F(RoudiFindService_test, OfferMultiMethodServiceMultiInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service1", "instance2"});
    senderRuntime->offerService({"service1", "instance3"});
    senderRuntime->offerService({"service2", "instance1"});
    senderRuntime->offerService({"service2", "instance2"});
    senderRuntime->offerService({"service2", "instance3"});
    this->InterOpWait();

    auto instanceContainer = receiverRuntime->findService({"service1", "instance1"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.get_value().begin(), Eq(IdString("instance1")));

    instanceContainer = receiverRuntime->findService({"service1", "instance2"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.get_value().begin(), Eq(IdString("instance2")));

    instanceContainer = receiverRuntime->findService({"service1", "instance3"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.get_value().begin(), Eq(IdString("instance3")));

    instanceContainer = receiverRuntime->findService({"service2", "instance1"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.get_value().begin(), Eq(IdString("instance1")));

    instanceContainer = receiverRuntime->findService({"service2", "instance2"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.get_value().begin(), Eq(IdString("instance2")));

    instanceContainer = receiverRuntime->findService({"service2", "instance3"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.get_value().begin(), Eq(IdString("instance3")));
}

TEST_F(RoudiFindService_test, StopOfferSingleMethodServiceSingleInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    this->InterOpWait();

    auto instanceContainer = receiverRuntime->findService({"service1", "instance1"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(0u));
}

TEST_F(RoudiFindService_test, StopOfferMultiMethodServiceSingleInstance)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service2", "instance1"});
    senderRuntime->offerService({"service3", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    senderRuntime->stopOfferService({"service3", "instance1"});
    this->InterOpWait();

    auto instanceContainer = receiverRuntime->findService({"service1", "instance1"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(0u));

    instanceContainer = receiverRuntime->findService({"service2", "instance1"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(1u));
    ASSERT_THAT(*instanceContainer.get_value().begin(), Eq(IdString("instance1")));

    instanceContainer = receiverRuntime->findService({"service3", "instance1"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(0u));
}

TEST_F(RoudiFindService_test, StopOfferServiceRedundantCall)
{
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service1", "instance1"});
    this->InterOpWait();

    auto instanceContainer = receiverRuntime->findService({"service1", "instance1"});

    ASSERT_THAT(instanceContainer.get_value().size(), Eq(0u));
}

TEST_F(RoudiFindService_test, StopNonExistingService)
{
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();
    senderRuntime->stopOfferService({"service2", "instance2"});
    this->InterOpWait();

    auto instanceContainer = receiverRuntime->findService({"service1", "instance1"});

    ASSERT_THAT(instanceContainer.get_value().size(), Eq(1));
    ASSERT_THAT(*instanceContainer.get_value().begin(), Eq(IdString("instance1")));
}

TEST_F(RoudiFindService_test, FindNonExistingServices)
{
    senderRuntime->offerService({"service1", "instance1"});
    senderRuntime->offerService({"service2", "instance1"});
    senderRuntime->offerService({"service3", "instance1"});
    this->InterOpWait();

    auto instanceContainer = receiverRuntime->findService({"service1", "schlomo"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(0u));

    instanceContainer = receiverRuntime->findService({"ignatz", "instance1"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(0u));

    instanceContainer = receiverRuntime->findService({"ignatz", "schlomo"});
    ASSERT_THAT(instanceContainer.get_value().size(), Eq(0u));
}

TEST_F(RoudiFindService_test, InterfacePort)
{
    senderRuntime->offerService({"service1", "instance1"});
    this->InterOpWait();

    auto interfacePortData = receiverRuntime->getMiddlewareInterface(iox::capro::Interfaces::SOMEIP);
    iox::popo::InterfacePort interfacePort(interfacePortData);
    this->InterOpWait();
    bool serviceFound = false;

    while (auto maybeCaProMessage = interfacePort.tryGetCaProMessage())
    {
        auto caproMessage = maybeCaProMessage.value();
        if ((caproMessage.m_serviceDescription.getServiceIDString() == IdString("service1"))
            && (caproMessage.m_serviceDescription.getInstanceIDString() == IdString("instance1"))
            && ((caproMessage.m_serviceDescription.getEventIDString() == IdString(iox::capro::AnyEventString))))
        {
            serviceFound = true;
            break;
        }
    }

    EXPECT_THAT(serviceFound, Eq(true));
}

TEST_F(RoudiFindService_test, findServiceMaxInstances)
{
    size_t noOfInstances = iox::MAX_NUMBER_OF_INSTANCES;
    InstanceContainer instanceContainerExp;
    for (size_t i = 0; i < noOfInstances; i++)
    {
        // Service & Instance string is kept short , to reduce the response size in find service request ,
        // (message queue has a limit of 512)
        std::string instance = "i" + std::to_string(i);
        senderRuntime->offerService({"s", IdString(iox::cxx::TruncateToCapacity, instance)});
        instanceContainerExp.push_back(IdString(iox::cxx::TruncateToCapacity, instance));
        this->InterOpWait();
    }

    auto instanceContainer = receiverRuntime->findService({"s", "65535"});

    EXPECT_THAT(instanceContainer.get_value().size(), Eq(iox::MAX_NUMBER_OF_INSTANCES));
    EXPECT_TRUE(instanceContainer.get_value() == instanceContainerExp);
    ASSERT_THAT(instanceContainer.has_error(), Eq(false));
}

TEST_F(RoudiFindService_test, findServiceInstanceContainerOverflowError)
{
    size_t noOfInstances = (iox::MAX_NUMBER_OF_INSTANCES + 1);
    InstanceContainer instanceContainerExp;
    for (size_t i = 0; i < noOfInstances; i++)
    {
        std::string instance = "i" + std::to_string(i);
        senderRuntime->offerService({"s", IdString(iox::cxx::TruncateToCapacity, instance)});
        instanceContainerExp.push_back(IdString(iox::cxx::TruncateToCapacity, instance));
        this->InterOpWait();
    }

    auto instanceContainer = receiverRuntime->findService({"s", "65535"});

    ASSERT_THAT(instanceContainer.has_error(), Eq(true));
}
<|endoftext|>