<commit_before>#include "QuadraticSieve.h"
#include "QuadraticSieveScheduler.h"
#include "QuadraticSieveElf.h"
#include "common/ProblemStatement.h"
#include "common/Utils.h"
#include <numeric>

template<typename ElemType>
std::ostream& operator<<(std::ostream& stream, const std::vector<ElemType>& list)
{
    stream << "[";
    bool first = true;
    for (const auto& element : list)
    {
        if (!first)
            stream << ", ";
        stream << element;
        first = false;
    }
    stream << "]";

    return stream;
}

using namespace std;
using namespace std::placeholders;

BigInt receiveBigInt(const Communicator& communicator);
BigInt receiveBigIntFromMaster(const Communicator& communicator);

struct serializedBigIntDeleter
{
    void operator()(uint32_t* memory)
    {
        free(memory);
    }
};

typedef std::pair<std::unique_ptr<uint32_t, serializedBigIntDeleter>, size_t> SerializedBigInt;

inline SerializedBigInt bigIntToArray(const BigInt& number)
{
    size_t arraySize;
    std::unique_ptr<uint32_t, serializedBigIntDeleter> pointer(reinterpret_cast<uint32_t*>(
        mpz_export(nullptr, &arraySize, -1, sizeof(uint32_t), 0, 0, number.get_mpz_t())
    ), serializedBigIntDeleter());
    return make_pair(std::move(pointer), arraySize);
}

inline BigInt arrayToBigInt(const SerializedBigInt& data)
{
    BigInt result;
    mpz_import(result.get_mpz_t(), data.second, -1, sizeof(uint32_t), 0, 0, data.first.get());
    return result;
}

QuadraticSieveScheduler::QuadraticSieveScheduler(const Communicator& communicator, const std::function<ElfPointer()>& factory) :
    SchedulerTemplate(communicator, factory)
{
}

void QuadraticSieveScheduler::provideData(istream& input)
{
    input >> number;

    if (input.fail())
        throw runtime_error("Failed to read BigInt from input stream in " __FILE__);
}

void QuadraticSieveScheduler::outputData(ostream& output)
{
    output << p << endl;
    output << q << endl;
}

void QuadraticSieveScheduler::generateData(const DataGenerationParameters&)
{
    // TODO: Use parameters and generate a random number
    number = 1089911;
}

bool QuadraticSieveScheduler::hasData() const
{
    return number != 0;
}

void QuadraticSieveScheduler::doSimpleDispatch()
{
    tie(p, q) = QuadraticSieveHelper::factor(
        number,
        bind(&QuadraticSieveElf::sieveSmoothSquares, &elf(), _1, _2, _3, _4)
    );
}

void packBigintVector(vector<size_t>& outSizes, vector<uint32_t>& outData, const vector<BigInt>& input)
{
    for (const auto& number : input)
    {
        auto serialized = bigIntToArray(number);
        outSizes.push_back(serialized.second);
        outData.insert(outData.end(), serialized.first.get(), serialized.first.get() + serialized.second);
    }
}

SmoothSquareList unpackBigintVector(const vector<size_t>& sizes, const vector<uint32_t>& data)
{
    SmoothSquareList result;
    auto dataIter = data.begin();
    for (const auto size : sizes)
    {
        SerializedBigInt serialized;
        serialized.second = size;
        serialized.first.reset(reinterpret_cast<uint32_t*>(malloc(sizeof(uint32_t)*size)));
        std::copy(dataIter, dataIter+size, serialized.first.get());
        dataIter += size;
        result.push_back(arrayToBigInt(serialized));
    }

    return result;
}

void QuadraticSieveScheduler::doDispatch()
{
    if (communicator.isMaster())
    {
        tie(p, q) = QuadraticSieveHelper::factor(
            number,
            bind(&QuadraticSieveScheduler::sieveDistributed, this, _1, _2, _3, _4)
        );
    }
    else
    {
        BigInt number = receiveBigInt(communicator);
        BigInt start = receiveBigIntFromMaster(communicator);
        BigInt end = receiveBigIntFromMaster(communicator);
        size_t factorBaseSize;
        communicator->Bcast(&factorBaseSize, 1, MPI::UNSIGNED_LONG, Communicator::MASTER_RANK);
        vector<smallPrime_t> factorBase(factorBaseSize);
        communicator->Bcast(factorBase.data(), factorBaseSize, MPI::INT, Communicator::MASTER_RANK);

        auto result = elf().sieveSmoothSquares(start, end, number, factorBase);
        int resultSize = result.size();
        communicator->Gather(&resultSize, 1, MPI::INT, nullptr, 0, MPI::INT, Communicator::MASTER_RANK);

        vector<size_t> resultsSizes;
        vector<uint32_t> resultsData;
        packBigintVector(resultsSizes, resultsData, result);

        communicator->Gatherv(resultsSizes.data(), resultSize, MPI::UNSIGNED_LONG, nullptr, nullptr, nullptr, MPI::UNSIGNED_LONG, Communicator::MASTER_RANK);
        communicator->Gatherv(resultsData.data(), resultsData.size(), MPI::INT, nullptr, nullptr, nullptr, MPI::INT, Communicator::MASTER_RANK);
    }
}

void sendBigInt(const Communicator& communicator, const BigInt& number)
{
    auto serialized = bigIntToArray(number);
    communicator->Bcast(&serialized.second, 1, MPI::UNSIGNED_LONG, Communicator::MASTER_RANK);
    communicator->Bcast(serialized.first.get(), serialized.second, MPI::INT, Communicator::MASTER_RANK);
}

BigInt receiveBigInt(const Communicator& communicator)
{
    SerializedBigInt result;
    communicator->Bcast(&result.second, 1, MPI::UNSIGNED_LONG, Communicator::MASTER_RANK);
    result.first.reset(reinterpret_cast<uint32_t*>(malloc(result.second * sizeof(uint32_t))));
    communicator->Bcast(result.first.get(), result.second, MPI::INT, Communicator::MASTER_RANK);
    return arrayToBigInt(result);
}

void sendBigIntTo(const Communicator& communicator, const BigInt& number, int nodeId)
{
    auto serialized = bigIntToArray(number);
    communicator->Send(&serialized.second, 1, MPI::UNSIGNED_LONG, nodeId, 0);
    communicator->Send(serialized.first.get(), serialized.second, MPI::INT, nodeId, 0);
}

BigInt receiveBigIntFromMaster(const Communicator& communicator)
{
    SerializedBigInt result;
    communicator->Recv(&result.second, 1, MPI::UNSIGNED_LONG, Communicator::MASTER_RANK, 0);
    result.first.reset(reinterpret_cast<uint32_t*>(malloc(result.second * sizeof(uint32_t))));
    communicator->Recv(result.first.get(), result.second, MPI::INT, Communicator::MASTER_RANK, 0);
    return arrayToBigInt(result);
}

vector<BigInt> QuadraticSieveScheduler::sieveDistributed(
    const BigInt& start,
    const BigInt& end,
    const BigInt& number,
    const FactorBase& factorBase
)
{
    sendBigInt(communicator, number);

    BigInt intervalLength = end - start;
    BigInt chunkSize = div_ceil(intervalLength, BigInt(communicator.size()));

    for (size_t nodeId=1; nodeId < communicator.size(); ++nodeId)
    {
        BigInt partialStart = start + chunkSize*nodeId;
        BigInt partialEnd = min(partialStart + chunkSize, end);
        sendBigIntTo(communicator, partialStart, nodeId);
        sendBigIntTo(communicator, partialEnd, nodeId);
    }

    size_t factorBaseSize = factorBase.size();
    communicator->Bcast(&factorBaseSize, 1, MPI::UNSIGNED_LONG, Communicator::MASTER_RANK);
    communicator->Bcast(const_cast<smallPrime_t*>(factorBase.data()), factorBaseSize, MPI::INT, Communicator::MASTER_RANK);

    SmoothSquareList masterResult = elf().sieveSmoothSquares(start, min(start + chunkSize, end), number, factorBase);
    size_t resultSize = masterResult.size();

    vector<size_t> numberSizes;
    vector<uint32_t> numberData;
    packBigintVector(numberSizes, numberData, masterResult);

    vector<int> resultSizes(communicator.size());
    communicator->Gather(&resultSize, 1, MPI::INT, resultSizes.data(), 1, MPI::INT, Communicator::MASTER_RANK);

    auto totalSmoothSquares = std::accumulate(resultSizes.begin(), resultSizes.end(), 0);

    // gather sizes of smooth squares
    vector<int> displs(communicator.size());
    displs[0] = 0;
    for (size_t nodeId = 1; nodeId < communicator.size(); ++nodeId)
    {
        displs[nodeId] = displs[nodeId - 1] + resultSizes.at(nodeId - 1);
    }
    vector<size_t> allNumberSizes(totalSmoothSquares);
    communicator->Gatherv(numberSizes.data(), resultSize, MPI::UNSIGNED_LONG, allNumberSizes.data(), resultSizes.data(), displs.data(), MPI::UNSIGNED_LONG, Communicator::MASTER_RANK);

    // gather smooth squares
    auto numberSizesSum = std::accumulate(allNumberSizes.begin(), allNumberSizes.end(), 0);
    vector<uint32_t> allNumberData(numberSizesSum);
    vector<int> sizePerNode(communicator.size());
    auto accumulateStart = allNumberSizes.begin();
    //auto accumulateEnd = allNumberSizes.begin() + resultSizes[0];
    for (size_t nodeId = 0; nodeId < communicator.size(); ++nodeId)
    {
        auto accumulateEnd = accumulateStart + resultSizes[nodeId];
        sizePerNode[nodeId] = std::accumulate(accumulateStart, accumulateEnd, 0);
        accumulateStart = accumulateEnd;

    }
    vector<int> dataDispls(communicator.size());
    dataDispls[0] = 0;
    for (size_t nodeId = 1; nodeId < communicator.size(); ++nodeId)
    {
        dataDispls[nodeId] = dataDispls[nodeId - 1] + sizePerNode[nodeId - 1];
    }

    communicator->Gatherv(numberData.data(), numberData.size(), MPI::INT, allNumberData.data(), sizePerNode.data(), dataDispls.data(), MPI::INT, Communicator::MASTER_RANK);

    return unpackBigintVector(allNumberSizes, allNumberData);
}
<commit_msg>Considering node weights<commit_after>#include "QuadraticSieve.h"
#include "QuadraticSieveScheduler.h"
#include "QuadraticSieveElf.h"
#include "common/ProblemStatement.h"
#include "common/Utils.h"
#include <numeric>

template<typename ElemType>
std::ostream& operator<<(std::ostream& stream, const std::vector<ElemType>& list)
{
    stream << "[";
    bool first = true;
    for (const auto& element : list)
    {
        if (!first)
            stream << ", ";
        stream << element;
        first = false;
    }
    stream << "]";

    return stream;
}

using namespace std;
using namespace std::placeholders;

BigInt receiveBigInt(const Communicator& communicator);
BigInt receiveBigIntFromMaster(const Communicator& communicator);

struct serializedBigIntDeleter
{
    void operator()(uint32_t* memory)
    {
        free(memory);
    }
};

typedef std::pair<std::unique_ptr<uint32_t, serializedBigIntDeleter>, size_t> SerializedBigInt;

inline SerializedBigInt bigIntToArray(const BigInt& number)
{
    size_t arraySize;
    std::unique_ptr<uint32_t, serializedBigIntDeleter> pointer(reinterpret_cast<uint32_t*>(
        mpz_export(nullptr, &arraySize, -1, sizeof(uint32_t), 0, 0, number.get_mpz_t())
    ), serializedBigIntDeleter());
    return make_pair(std::move(pointer), arraySize);
}

inline BigInt arrayToBigInt(const SerializedBigInt& data)
{
    BigInt result;
    mpz_import(result.get_mpz_t(), data.second, -1, sizeof(uint32_t), 0, 0, data.first.get());
    return result;
}

QuadraticSieveScheduler::QuadraticSieveScheduler(const Communicator& communicator, const std::function<ElfPointer()>& factory) :
    SchedulerTemplate(communicator, factory)
{
}

void QuadraticSieveScheduler::provideData(istream& input)
{
    input >> number;

    if (input.fail())
        throw runtime_error("Failed to read BigInt from input stream in " __FILE__);
}

void QuadraticSieveScheduler::outputData(ostream& output)
{
    output << p << endl;
    output << q << endl;
}

void QuadraticSieveScheduler::generateData(const DataGenerationParameters&)
{
    // TODO: Use parameters and generate a random number
    number = 1089911;
}

bool QuadraticSieveScheduler::hasData() const
{
    return number != 0;
}

void QuadraticSieveScheduler::doSimpleDispatch()
{
    tie(p, q) = QuadraticSieveHelper::factor(
        number,
        bind(&QuadraticSieveElf::sieveSmoothSquares, &elf(), _1, _2, _3, _4)
    );
}

void packBigintVector(vector<size_t>& outSizes, vector<uint32_t>& outData, const vector<BigInt>& input)
{
    for (const auto& number : input)
    {
        auto serialized = bigIntToArray(number);
        outSizes.push_back(serialized.second);
        outData.insert(outData.end(), serialized.first.get(), serialized.first.get() + serialized.second);
    }
}

SmoothSquareList unpackBigintVector(const vector<size_t>& sizes, const vector<uint32_t>& data)
{
    SmoothSquareList result;
    auto dataIter = data.begin();
    for (const auto size : sizes)
    {
        SerializedBigInt serialized;
        serialized.second = size;
        serialized.first.reset(reinterpret_cast<uint32_t*>(malloc(sizeof(uint32_t)*size)));
        std::copy(dataIter, dataIter+size, serialized.first.get());
        dataIter += size;
        result.push_back(arrayToBigInt(serialized));
    }

    return result;
}

void QuadraticSieveScheduler::doDispatch()
{
    if (communicator.isMaster())
    {
        tie(p, q) = QuadraticSieveHelper::factor(
            number,
            bind(&QuadraticSieveScheduler::sieveDistributed, this, _1, _2, _3, _4)
        );
    }
    else
    {
        BigInt number = receiveBigInt(communicator);
        BigInt start = receiveBigIntFromMaster(communicator);
        BigInt end = receiveBigIntFromMaster(communicator);
        size_t factorBaseSize;
        communicator->Bcast(&factorBaseSize, 1, MPI::UNSIGNED_LONG, Communicator::MASTER_RANK);
        vector<smallPrime_t> factorBase(factorBaseSize);
        communicator->Bcast(factorBase.data(), factorBaseSize, MPI::INT, Communicator::MASTER_RANK);

        auto result = elf().sieveSmoothSquares(start, end, number, factorBase);
        int resultSize = result.size();
        communicator->Gather(&resultSize, 1, MPI::INT, nullptr, 0, MPI::INT, Communicator::MASTER_RANK);

        vector<size_t> resultsSizes;
        vector<uint32_t> resultsData;
        packBigintVector(resultsSizes, resultsData, result);

        communicator->Gatherv(resultsSizes.data(), resultSize, MPI::UNSIGNED_LONG, nullptr, nullptr, nullptr, MPI::UNSIGNED_LONG, Communicator::MASTER_RANK);
        communicator->Gatherv(resultsData.data(), resultsData.size(), MPI::INT, nullptr, nullptr, nullptr, MPI::INT, Communicator::MASTER_RANK);
    }
}

void sendBigInt(const Communicator& communicator, const BigInt& number)
{
    auto serialized = bigIntToArray(number);
    communicator->Bcast(&serialized.second, 1, MPI::UNSIGNED_LONG, Communicator::MASTER_RANK);
    communicator->Bcast(serialized.first.get(), serialized.second, MPI::INT, Communicator::MASTER_RANK);
}

BigInt receiveBigInt(const Communicator& communicator)
{
    SerializedBigInt result;
    communicator->Bcast(&result.second, 1, MPI::UNSIGNED_LONG, Communicator::MASTER_RANK);
    result.first.reset(reinterpret_cast<uint32_t*>(malloc(result.second * sizeof(uint32_t))));
    communicator->Bcast(result.first.get(), result.second, MPI::INT, Communicator::MASTER_RANK);
    return arrayToBigInt(result);
}

void sendBigIntTo(const Communicator& communicator, const BigInt& number, int nodeId)
{
    auto serialized = bigIntToArray(number);
    communicator->Send(&serialized.second, 1, MPI::UNSIGNED_LONG, nodeId, 0);
    communicator->Send(serialized.first.get(), serialized.second, MPI::INT, nodeId, 0);
}

BigInt receiveBigIntFromMaster(const Communicator& communicator)
{
    SerializedBigInt result;
    communicator->Recv(&result.second, 1, MPI::UNSIGNED_LONG, Communicator::MASTER_RANK, 0);
    result.first.reset(reinterpret_cast<uint32_t*>(malloc(result.second * sizeof(uint32_t))));
    communicator->Recv(result.first.get(), result.second, MPI::INT, Communicator::MASTER_RANK, 0);
    return arrayToBigInt(result);
}

vector<BigInt> QuadraticSieveScheduler::sieveDistributed(
    const BigInt& start,
    const BigInt& end,
    const BigInt& number,
    const FactorBase& factorBase
)
{
    sendBigInt(communicator, number);

    BigInt intervalLengthBigInt = end - start;

    if (!intervalLengthBigInt.fits_ulong_p())
        throw runtime_error("Interval is too long!");

    uint64_t intervalLength = intervalLengthBigInt.get_ui();
    cout << "IntervalLength: " << intervalLength << endl;
    double basicChunkSize = div_ceil(intervalLength, communicator.size());
    auto weights = communicator.weights();
    cout << "Weights: " << weights << endl;

    for (size_t nodeId=1; nodeId < communicator.size(); ++nodeId)
    {
        double weightedChunkSize = basicChunkSize * weights[nodeId];
        cout << "Chunksize for node " << nodeId << ": " << weightedChunkSize << endl;
        BigInt partialStart = start + weightedChunkSize*nodeId;
        BigInt partialEnd = min(partialStart + basicChunkSize, end);
        sendBigIntTo(communicator, partialStart, nodeId);
        sendBigIntTo(communicator, partialEnd, nodeId);
    }

    size_t factorBaseSize = factorBase.size();
    communicator->Bcast(&factorBaseSize, 1, MPI::UNSIGNED_LONG, Communicator::MASTER_RANK);
    communicator->Bcast(const_cast<smallPrime_t*>(factorBase.data()), factorBaseSize, MPI::INT, Communicator::MASTER_RANK);

    double masterChunkSize = basicChunkSize * weights[0];
    SmoothSquareList masterResult = elf().sieveSmoothSquares(start, min(start + masterChunkSize, end), number, factorBase);
    size_t resultSize = masterResult.size();

    vector<size_t> numberSizes;
    vector<uint32_t> numberData;
    packBigintVector(numberSizes, numberData, masterResult);

    vector<int> resultSizes(communicator.size());
    communicator->Gather(&resultSize, 1, MPI::INT, resultSizes.data(), 1, MPI::INT, Communicator::MASTER_RANK);

    auto totalSmoothSquares = std::accumulate(resultSizes.begin(), resultSizes.end(), 0);

    // gather sizes of smooth squares
    vector<int> displs(communicator.size());
    displs[0] = 0;
    for (size_t nodeId = 1; nodeId < communicator.size(); ++nodeId)
    {
        displs[nodeId] = displs[nodeId - 1] + resultSizes.at(nodeId - 1);
    }
    vector<size_t> allNumberSizes(totalSmoothSquares);
    communicator->Gatherv(numberSizes.data(), resultSize, MPI::UNSIGNED_LONG, allNumberSizes.data(), resultSizes.data(), displs.data(), MPI::UNSIGNED_LONG, Communicator::MASTER_RANK);

    // gather smooth squares
    auto numberSizesSum = std::accumulate(allNumberSizes.begin(), allNumberSizes.end(), 0);
    vector<uint32_t> allNumberData(numberSizesSum);
    vector<int> sizePerNode(communicator.size());
    auto accumulateStart = allNumberSizes.begin();
    //auto accumulateEnd = allNumberSizes.begin() + resultSizes[0];
    for (size_t nodeId = 0; nodeId < communicator.size(); ++nodeId)
    {
        auto accumulateEnd = accumulateStart + resultSizes[nodeId];
        sizePerNode[nodeId] = std::accumulate(accumulateStart, accumulateEnd, 0);
        accumulateStart = accumulateEnd;

    }
    vector<int> dataDispls(communicator.size());
    dataDispls[0] = 0;
    for (size_t nodeId = 1; nodeId < communicator.size(); ++nodeId)
    {
        dataDispls[nodeId] = dataDispls[nodeId - 1] + sizePerNode[nodeId - 1];
    }

    communicator->Gatherv(numberData.data(), numberData.size(), MPI::INT, allNumberData.data(), sizePerNode.data(), dataDispls.data(), MPI::INT, Communicator::MASTER_RANK);

    return unpackBigintVector(allNumberSizes, allNumberData);
}
<|endoftext|>


<commit_before>// The Art of C++ / Sequences
// Copyright (c) 2015 Daniel Frey

#include <tao/seq/tuple_cat.hpp>

#include <type_traits>
#include <tuple>

#define USE std
//#define USE tao::seq

int main()
{
  auto t = USE::tuple_cat( std::make_tuple( 1, true ),
			   std::make_tuple( 1.0 ),
			   std::make_tuple(),
			   std::make_tuple( 1UL, nullptr ) );

  static_assert( std::is_same< decltype( t ), std::tuple< int, bool, double, unsigned long, std::nullptr_t > >::value, "oops" );

  auto t2 = USE::tuple_cat( t, std::make_tuple( 1, true ),
			    t, std::make_tuple( 1.0 ),
			    t, std::make_tuple(),
			    t, std::make_tuple( 1UL, nullptr ) );

  auto t3 = USE::tuple_cat( t2, std::make_tuple( 1, true ),
			    t2, std::make_tuple( 1.0 ),
			    t2, std::make_tuple(),
			    t2, std::make_tuple( 1UL, nullptr ) );

  auto t4 = USE::tuple_cat( t3, std::make_tuple( 1, true ),
			    t2, std::make_tuple( 1.0 ),
			    t3, std::make_tuple(),
			    t2, std::make_tuple( 1UL, nullptr ) );

  static_assert( std::tuple_size< decltype( t4 ) >::value == 265, "oops" );
}
<commit_msg>By default, test our own version<commit_after>// The Art of C++ / Sequences
// Copyright (c) 2015 Daniel Frey

#include <tao/seq/tuple_cat.hpp>

#include <type_traits>
#include <tuple>

//#define USE std
#define USE tao::seq

int main()
{
  auto t = USE::tuple_cat( std::make_tuple( 1, true ),
			   std::make_tuple( 1.0 ),
			   std::make_tuple(),
			   std::make_tuple( 1UL, nullptr ) );

  static_assert( std::is_same< decltype( t ), std::tuple< int, bool, double, unsigned long, std::nullptr_t > >::value, "oops" );

  auto t2 = USE::tuple_cat( t, std::make_tuple( 1, true ),
			    t, std::make_tuple( 1.0 ),
			    t, std::make_tuple(),
			    t, std::make_tuple( 1UL, nullptr ) );

  auto t3 = USE::tuple_cat( t2, std::make_tuple( 1, true ),
			    t2, std::make_tuple( 1.0 ),
			    t2, std::make_tuple(),
			    t2, std::make_tuple( 1UL, nullptr ) );

  auto t4 = USE::tuple_cat( t3, std::make_tuple( 1, true ),
			    t2, std::make_tuple( 1.0 ),
			    t3, std::make_tuple(),
			    t2, std::make_tuple( 1UL, nullptr ) );

  static_assert( std::tuple_size< decltype( t4 ) >::value == 265, "oops" );
}
<|endoftext|>


<commit_before>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2011, Willow Garage, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 *
 */

#ifndef PCL_SURFACE_RECONSTRUCTION_IMPL_H_
#define PCL_SURFACE_RECONSTRUCTION_IMPL_H_
#include <pcl/search/pcl_search.h>

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT> void
pcl::SurfaceReconstruction<PointInT>::reconstruct (pcl::PolygonMesh &output)
{
  // Copy the header
  output.header = input_->header;

  if (!initCompute ())
  {
    output.cloud.width = output.cloud.height = 0;
    output.cloud.data.clear ();
    output.polygons.clear ();
    return;
  }

  // Check if a space search locator was given
  if (check_tree_)
  {
    if (!tree_)
    {
      if (input_->isOrganized ())
        tree_.reset (new pcl::search::OrganizedNeighbor<PointInT> ());
      else
        tree_.reset (new pcl::search::KdTree<PointInT> (false));
    }

    // Send the surface dataset to the spatial locator
    tree_->setInputCloud (input_, indices_);
  }

  // Set up the output dataset
  pcl::toROSMsg (*input_, output.cloud); /// NOTE: passing in boost shared pointer with * as const& should be OK here
  output.polygons.clear ();
  output.polygons.reserve (2*indices_->size ()); /// NOTE: usually the number of triangles is around twice the number of vertices
  // Perform the actual surface reconstruction
  performReconstruction (output);

  deinitCompute ();
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT> void
pcl::SurfaceReconstruction<PointInT>::reconstruct (pcl::PointCloud<PointInT> &points,
                                                   std::vector<pcl::Vertices> &polygons)
{
  // Copy the header
  points.header = input_->header;

  if (!initCompute ())
  {
    points.width = points.height = 0;
    points.data.clear ();
    polygons.clear ();
    return;
  }

  // Check if a space search locator was given
  if (check_tree_)
  {
    if (!tree_)
    {
      if (input_->isOrganized ())
        tree_.reset (new pcl::search::OrganizedNeighbor<PointInT> ());
      else
        tree_.reset (new pcl::search::KdTree<PointInT> (false));
    }

    // Send the surface dataset to the spatial locator
    tree_->setInputCloud (input_, indices_);
  }

  // Set up the output dataset
  polygons.clear ();
  polygons.reserve (2 * indices_->size ()); /// NOTE: usually the number of triangles is around twice the number of vertices
  // Perform the actual surface reconstruction
  performReconstruction (points, polygons);

  deinitCompute ();
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT> void
pcl::MeshConstruction<PointInT>::reconstruct (pcl::PolygonMesh &output)
{
  // Copy the header
  output.header = input_->header;

  if (!initCompute ())
  {
    output.cloud.width = output.cloud.height = 0;
    output.cloud.data.clear ();
    output.polygons.clear ();
    return;
  }

  // Check if a space search locator was given
  if (check_tree_)
  {
    if (!tree_)
    {
      if (input_->isOrganized ())
        tree_.reset (new pcl::search::OrganizedNeighbor<PointInT> ());
      else
        tree_.reset (new pcl::search::KdTree<PointInT> (false));
    }

    // Send the surface dataset to the spatial locator
    tree_->setInputCloud (input_, indices_);
  }

  // Set up the output dataset
  pcl::toROSMsg (*input_, output.cloud); /// NOTE: passing in boost shared pointer with * as const& should be OK here
  output.polygons.clear ();
  output.polygons.reserve (2*indices_->size ()); /// NOTE: usually the number of triangles is around twice the number of vertices
  // Perform the actual surface reconstruction
  performReconstruction (output);

  deinitCompute ();
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT> void
pcl::MeshConstruction<PointInT>::reconstruct (std::vector<pcl::Vertices> &polygons)
{
  if (!initCompute ())
  {
    polygons.clear ();
    return;
  }

  // Check if a space search locator was given
  if (check_tree_)
  {
    if (!tree_)
    {
      if (input_->isOrganized ())
        tree_.reset (new pcl::search::OrganizedNeighbor<PointInT> ());
      else
        tree_.reset (new pcl::search::KdTree<PointInT> (false));
    }

    // Send the surface dataset to the spatial locator
    tree_->setInputCloud (input_, indices_);
  }

  // Set up the output dataset
  //polygons.clear ();
  //polygons.reserve (2 * indices_->size ()); /// NOTE: usually the number of triangles is around twice the number of vertices
  // Perform the actual surface reconstruction
  performReconstruction (polygons);

  deinitCompute ();
}

#endif  // PCL_SURFACE_RECONSTRUCTION_IMPL_H_

<commit_msg>don't automatically clear the polygons for @MeshConstruction@<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2010-2011, Willow Garage, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of Willow Garage, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 * $Id$
 *
 */

#ifndef PCL_SURFACE_RECONSTRUCTION_IMPL_H_
#define PCL_SURFACE_RECONSTRUCTION_IMPL_H_
#include <pcl/search/pcl_search.h>

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT> void
pcl::SurfaceReconstruction<PointInT>::reconstruct (pcl::PolygonMesh &output)
{
  // Copy the header
  output.header = input_->header;

  if (!initCompute ())
  {
    output.cloud.width = output.cloud.height = 0;
    output.cloud.data.clear ();
    output.polygons.clear ();
    return;
  }

  // Check if a space search locator was given
  if (check_tree_)
  {
    if (!tree_)
    {
      if (input_->isOrganized ())
        tree_.reset (new pcl::search::OrganizedNeighbor<PointInT> ());
      else
        tree_.reset (new pcl::search::KdTree<PointInT> (false));
    }

    // Send the surface dataset to the spatial locator
    tree_->setInputCloud (input_, indices_);
  }

  // Set up the output dataset
  pcl::toROSMsg (*input_, output.cloud); /// NOTE: passing in boost shared pointer with * as const& should be OK here
  output.polygons.clear ();
  output.polygons.reserve (2*indices_->size ()); /// NOTE: usually the number of triangles is around twice the number of vertices
  // Perform the actual surface reconstruction
  performReconstruction (output);

  deinitCompute ();
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT> void
pcl::SurfaceReconstruction<PointInT>::reconstruct (pcl::PointCloud<PointInT> &points,
                                                   std::vector<pcl::Vertices> &polygons)
{
  // Copy the header
  points.header = input_->header;

  if (!initCompute ())
  {
    points.width = points.height = 0;
    points.data.clear ();
    polygons.clear ();
    return;
  }

  // Check if a space search locator was given
  if (check_tree_)
  {
    if (!tree_)
    {
      if (input_->isOrganized ())
        tree_.reset (new pcl::search::OrganizedNeighbor<PointInT> ());
      else
        tree_.reset (new pcl::search::KdTree<PointInT> (false));
    }

    // Send the surface dataset to the spatial locator
    tree_->setInputCloud (input_, indices_);
  }

  // Set up the output dataset
  polygons.clear ();
  polygons.reserve (2 * indices_->size ()); /// NOTE: usually the number of triangles is around twice the number of vertices
  // Perform the actual surface reconstruction
  performReconstruction (points, polygons);

  deinitCompute ();
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT> void
pcl::MeshConstruction<PointInT>::reconstruct (pcl::PolygonMesh &output)
{
  // Copy the header
  output.header = input_->header;

  if (!initCompute ())
  {
    output.cloud.width = output.cloud.height = 0;
    output.cloud.data.clear ();
    output.polygons.clear ();
    return;
  }

  // Check if a space search locator was given
  if (check_tree_)
  {
    if (!tree_)
    {
      if (input_->isOrganized ())
        tree_.reset (new pcl::search::OrganizedNeighbor<PointInT> ());
      else
        tree_.reset (new pcl::search::KdTree<PointInT> (false));
    }

    // Send the surface dataset to the spatial locator
    tree_->setInputCloud (input_, indices_);
  }

  // Set up the output dataset
  pcl::toROSMsg (*input_, output.cloud); /// NOTE: passing in boost shared pointer with * as const& should be OK here
//  output.polygons.clear ();
//  output.polygons.reserve (2*indices_->size ()); /// NOTE: usually the number of triangles is around twice the number of vertices
  // Perform the actual surface reconstruction
  performReconstruction (output);

  deinitCompute ();
}

//////////////////////////////////////////////////////////////////////////////////////////////
template <typename PointInT> void
pcl::MeshConstruction<PointInT>::reconstruct (std::vector<pcl::Vertices> &polygons)
{
  if (!initCompute ())
  {
    polygons.clear ();
    return;
  }

  // Check if a space search locator was given
  if (check_tree_)
  {
    if (!tree_)
    {
      if (input_->isOrganized ())
        tree_.reset (new pcl::search::OrganizedNeighbor<PointInT> ());
      else
        tree_.reset (new pcl::search::KdTree<PointInT> (false));
    }

    // Send the surface dataset to the spatial locator
    tree_->setInputCloud (input_, indices_);
  }

  // Set up the output dataset
  //polygons.clear ();
  //polygons.reserve (2 * indices_->size ()); /// NOTE: usually the number of triangles is around twice the number of vertices
  // Perform the actual surface reconstruction
  performReconstruction (polygons);

  deinitCompute ();
}

#endif  // PCL_SURFACE_RECONSTRUCTION_IMPL_H_

<|endoftext|>


<commit_before>#ifndef slic3r_LOG_HPP
#define slic3r_LOG_HPP

#include <string>
#include <vector>
#include <sstream>
#include <iostream>

namespace Slic3r {

class Log {
public:
    static void fatal_error(std::string topic, std::wstring message) {
        std::cerr << topic << " FERR" << ": ";
        std::wcerr << message << std::endl;
    }
    static void error(std::string topic, std::wstring message) {
        std::cerr << topic << "  ERR" << ": ";
        std::wcerr << message << std::endl;
    }

    static void error(std::string topic, std::string message) {
        std::cerr << topic << "  ERR" << ": ";
        std::cerr << message << std::endl;
    }

    static void info(std::string topic, std::wstring message) {
        std::clog << topic << " INFO" << ": ";
        std::wclog << message << std::endl;
    }
    static void info(std::string topic, std::string message) {
        std::clog << topic << " INFO" << ": ";
        std::clog << message << std::endl;
    }

    static void warn(std::string topic, std::wstring message) {
        std::cerr << topic << " WARN" << ": ";
        std::wcerr << message << std::endl;
    }
    static void warn(std::string topic, std::string message) {
        std::cerr << topic << " WARN" << ": ";
        std::cerr << message << std::endl;
    }

    static void debug(std::string topic, std::wstring message) {
        std::cerr << topic << " DEBUG" << ": ";
        std::wcerr << message << std::endl;
    }
    static void debug(std::string topic, std::string message) {
        std::cerr << topic << " DEBUG" << ": ";
        std::cerr << message << std::endl;
    }

    static std::ostream& debug(std::string topic) {
        std::cerr << topic << " DEBUG" << ": ";
        return std::cerr;
    }

};

/// Utility debug function to transform a std::vector of anything that
/// supports ostream& operator<<() into a std::string.
template <typename T>
std::string
log_string(const std::vector<T>& in)
{
    std::stringstream ss;
    bool first {true};
    ss << "[ ";
    for (auto& c : in) {
        if (!first) {
            ss << ", ";
        }
        ss << c;
        first = false;
    }

    ss << " ]";

    return ss.str();
}

}

#endif // slic3r_LOG_HPP
<commit_msg>Added ostream version of error<commit_after>#ifndef slic3r_LOG_HPP
#define slic3r_LOG_HPP

#include <string>
#include <vector>
#include <sstream>
#include <iostream>

namespace Slic3r {

class Log {
public:
    static void fatal_error(std::string topic, std::wstring message) {
        std::cerr << topic << " FERR" << ": ";
        std::wcerr << message << std::endl;
    }
    static void error(std::string topic, std::wstring message) {
        std::cerr << topic << "  ERR" << ": ";
        std::wcerr << message << std::endl;
    }

    static void error(std::string topic, std::string message) {
        std::cerr << topic << "  ERR" << ": ";
        std::cerr << message << std::endl;
    }

    static void info(std::string topic, std::wstring message) {
        std::clog << topic << " INFO" << ": ";
        std::wclog << message << std::endl;
    }
    static void info(std::string topic, std::string message) {
        std::clog << topic << " INFO" << ": ";
        std::clog << message << std::endl;
    }

    static void warn(std::string topic, std::wstring message) {
        std::cerr << topic << " WARN" << ": ";
        std::wcerr << message << std::endl;
    }
    static void warn(std::string topic, std::string message) {
        std::cerr << topic << " WARN" << ": ";
        std::cerr << message << std::endl;
    }

    static void debug(std::string topic, std::wstring message) {
        std::cerr << topic << " DEBUG" << ": ";
        std::wcerr << message << std::endl;
    }
    static void debug(std::string topic, std::string message) {
        std::cerr << topic << " DEBUG" << ": ";
        std::cerr << message << std::endl;
    }
    static std::ostream& error(std::string topic) {
        std::cerr << topic << "   ERR" << ": ";
        return std::cerr;
    }
    static std::ostream& debug(std::string topic) {
        std::cerr << topic << " DEBUG" << ": ";
        return std::cerr;
    }

};

/// Utility debug function to transform a std::vector of anything that
/// supports ostream& operator<<() into a std::string.
template <typename T>
std::string
log_string(const std::vector<T>& in)
{
    std::stringstream ss;
    bool first {true};
    ss << "[ ";
    for (auto& c : in) {
        if (!first) {
            ss << ", ";
        }
        ss << c;
        first = false;
    }

    ss << " ]";

    return ss.str();
}

}

#endif // slic3r_LOG_HPP
<|endoftext|>


<commit_before>#include <cstdlib>
#include <cstdio> // debug
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>

#include <tightdb/utilities.hpp>
#include <tightdb/array_string.hpp>
#include <tightdb/impl/destroy_guard.hpp>
#include <tightdb/column.hpp>

using namespace std;
using namespace tightdb;

namespace {

const int max_width = 64;

// Round up to nearest possible block length: {0, 1, 4, 8, 16, 32, 64, 128, ...}. We include 1 to store empty strings
// in as little space as possible, because 0 can only store nulls.
size_t round_up(size_t size)
{
    if (size == 0)
        return 0;

    if (size == 1)
        return 1;

    size |= size >> 1;
    size |= size >> 2;
    size |= size >> 4;
    ++size;
    return size;
}

} // anonymous namespace

bool ArrayString::is_null(size_t ndx) const
{
    TIGHTDB_ASSERT(ndx < m_size);
    StringData sd = get(ndx);
    return sd.data() == null_ptr;
}

void ArrayString::set_null(size_t ndx)
{
    TIGHTDB_ASSERT(ndx < m_size);
    StringData sd = StringData(null_ptr, 0);
    set(ndx, sd);
}

void ArrayString::set(size_t ndx, StringData value)
{
    TIGHTDB_ASSERT(ndx < m_size);
    TIGHTDB_ASSERT(value.size() < size_t(max_width)); // otherwise we have to use another column type

    // Check if we need to copy before modifying
    copy_on_write(); // Throws

    // Make room for the new value plus a zero-termination
    if (m_width <= value.size()) {
        // if m_width == 0 then entire array contains only null entries
        if (value.data() == null_ptr && m_width == 0) {
            return; // set null element to null
        }

//        TIGHTDB_ASSERT(0 < value.size());

        // Calc min column width
        size_t new_width;
        if (m_width == 0 && value.size() == 0)
            new_width = ::round_up(1); // Entire Array is nulls; expand to m_width > 0
        else
            new_width = ::round_up(value.size() + 1);

        //TIGHTDB_ASSERT(value.size() < new_width);

        // FIXME: Should we try to avoid double copying when realloc fails to preserve the address?
        alloc(m_size, new_width); // Throws

        char* base = m_data;
        char* new_end = base + m_size*new_width;

        // Expand the old values in reverse order
        if (0 < m_width) {
            const char* old_end = base + m_size*m_width;
            while (new_end != base) {
                *--new_end = char(*--old_end + (new_width-m_width));
                {
                    // extend 0-padding
                    char* new_begin = new_end - (new_width-m_width);
                    fill(new_begin, new_end, 0);
                    new_end = new_begin;
                }
                {
                    // copy string payload
                    const char* old_begin = old_end - (m_width-1);
                    if(static_cast<size_t>(old_end - old_begin) < m_width) // non-null string
                        new_end = copy_backward(old_begin, old_end, new_end);
                    old_end = old_begin;
                }
            }
        }
        else {
            // m_width == 0, so all elements are null. Expand that to new width.
            while (new_end != base) {
                *--new_end = new_width; //  char(new_width - 1);
                {
                    char* new_begin = new_end - (new_width-1);
                    fill(new_begin, new_end, 0); // Fill with zero bytes
                    new_end = new_begin;
                }
            }
        }

        m_width = new_width;
    }

    TIGHTDB_ASSERT(0 < m_width);

    // Set the value
    char* begin = m_data + (ndx * m_width);
    char* end   = begin + (m_width-1);
    begin = copy(value.data(), value.data()+value.size(), begin);
    fill(begin, end, 0); // Pad with zero bytes
    TIGHTDB_STATIC_ASSERT(max_width <= 128, "Padding size must fit in 7-bits");
//    TIGHTDB_ASSERT(end - begin < max_width);
    if (value.data() == null_ptr) {
        *end = m_width;
    }
    else {
        int pad_size = int(end - begin);
        *end = char(pad_size);
    }
}

void ArrayString::insert(size_t ndx, StringData value)
{
    TIGHTDB_ASSERT(ndx <= m_size);
    TIGHTDB_ASSERT(value.size() < size_t(max_width)); // otherwise we have to use another column type

    // Check if we need to copy before modifying
    copy_on_write(); // Throws

    // Todo: Below code will perform up to 3 memcpy() operations in worst case. Todo, if we improve the
    // allocator to make a gap for the new value for us, we can have just 1. We can also have 2 by merging
    // memmove() and set(), but it's a bit complex. May be done after support of null is completed.

    // Allocate room for the new value
    alloc(m_size+1, m_width); // Throws

    // Make gap for new value
    memmove(m_data + m_width * (ndx + 1), m_data + m_width * ndx, m_width * (m_size - ndx));

    m_size++;

    // Set new value
    set(ndx, value);
    return;
}

void ArrayString::erase(size_t ndx)
{
    TIGHTDB_ASSERT(ndx < m_size);

    // Check if we need to copy before modifying
    copy_on_write(); // Throws

    // move data backwards after deletion
    if (ndx < m_size-1) {
        char* new_begin = m_data + ndx*m_width;
        char* old_begin = new_begin + m_width;
        char* old_end   = m_data + m_size*m_width;
        copy(old_begin, old_end, new_begin);
    }

    --m_size;

    // Update size in header
    set_header_size(m_size);
}

size_t ArrayString::CalcByteLen(size_t count, size_t width) const
{
    // FIXME: This arithemtic could overflow. Consider using one of
    // the functions in <tightdb/util/safe_int_ops.hpp>
    return header_size + (count * width);
}

size_t ArrayString::CalcItemCount(size_t bytes, size_t width) const TIGHTDB_NOEXCEPT
{
    if (width == 0) return size_t(-1); // zero-width gives infinite space

    size_t bytes_without_header = bytes - header_size;
    return bytes_without_header / width;
}

size_t ArrayString::count(StringData value, size_t begin, size_t end) const TIGHTDB_NOEXCEPT
{
    size_t num_matches = 0;

    size_t begin_2 = begin;
    for (;;) {
        size_t ndx = find_first(value, begin_2, end);
        if (ndx == not_found)
            break;
        ++num_matches;
        begin_2 = ndx + 1;
    }

    return num_matches;
}

size_t ArrayString::find_first(StringData value, size_t begin, size_t end) const TIGHTDB_NOEXCEPT
{
    if (end == size_t(-1))
        end = m_size;
    TIGHTDB_ASSERT(begin <= m_size && end <= m_size && begin <= end);

    if (m_width == 0)
        return value.size() == 0 && begin < end ? begin : size_t(-1);

    // A string can never be wider than the column width
    if (m_width <= value.size())
        return size_t(-1);

    if (value.size() == 0) {
        const char* data = m_data + (m_width-1);
        for (size_t i = begin; i != end; ++i) {
            size_t size = (m_width-1) - data[i * m_width];
            if (TIGHTDB_UNLIKELY(size == 0))
                return i;
        }
    }
    else {
        for (size_t i = begin; i != end; ++i) {
            const char* data = m_data + (i * m_width);
            size_t j = 0;
            for (;;) {
                if (TIGHTDB_LIKELY(data[j] != value[j]))
                    break;
                ++j;
                if (TIGHTDB_UNLIKELY(j == value.size())) {
                    size_t size = (m_width-1) - data[m_width-1];
                    if (TIGHTDB_LIKELY(size == value.size()))
                        return i;
                    break;
                }
            }
        }
    }

    return not_found;
}

void ArrayString::find_all(Column& result, StringData value, size_t add_offset,
                           size_t begin, size_t end)
{
    size_t begin_2 = begin;
    for (;;) {
        size_t ndx = find_first(value, begin_2, end);
        if (ndx == not_found)
            break;
        result.add(add_offset + ndx); // Throws
        begin_2 = ndx + 1;
    }
}

bool ArrayString::compare_string(const ArrayString& c) const TIGHTDB_NOEXCEPT
{
    if (c.size() != size())
        return false;

    for (size_t i = 0; i < size(); ++i) {
        if (get(i) != c.get(i))
            return false;
    }

    return true;
}

ref_type ArrayString::bptree_leaf_insert(size_t ndx, StringData value, TreeInsertBase& state)
{
    size_t leaf_size = size();
    TIGHTDB_ASSERT(leaf_size <= TIGHTDB_MAX_BPNODE_SIZE);
    if (leaf_size < ndx) ndx = leaf_size;
    if (TIGHTDB_LIKELY(leaf_size < TIGHTDB_MAX_BPNODE_SIZE)) {
        insert(ndx, value); // Throws
        return 0; // Leaf was not split
    }

    // Split leaf node
    ArrayString new_leaf(m_alloc);
    new_leaf.create(); // Throws
    if (ndx == leaf_size) {
        new_leaf.add(value); // Throws
        state.m_split_offset = ndx;
    }
    else {
        for (size_t i = ndx; i != leaf_size; ++i)
            new_leaf.add(get(i)); // Throws
        truncate(ndx); // Throws
        add(value); // Throws
        state.m_split_offset = ndx + 1;
    }
    state.m_split_size = leaf_size + 1;
    return new_leaf.get_ref();
}

MemRef ArrayString::slice(size_t offset, size_t size, Allocator& target_alloc) const
{
    TIGHTDB_ASSERT(is_attached());

    // FIXME: This can be optimized as a single contiguous copy
    // operation.
    ArrayString slice(target_alloc);
    _impl::ShallowArrayDestroyGuard dg(&slice);
    slice.create(); // Throws
    size_t begin = offset;
    size_t end   = offset + size;
    for (size_t i = begin; i != end; ++i) {
        StringData value = get(i);
        slice.add(value); // Throws
    }
    dg.release();
    return slice.get_mem();
}

#ifdef TIGHTDB_DEBUG

void ArrayString::string_stats() const
{
    size_t total = 0;
    size_t longest = 0;

    for (size_t i = 0; i < m_size; ++i) {
        StringData str = get(i);
        size_t size = str.size() + 1;
        total += size;
        if (size > longest) longest = size;
    }

    size_t size = m_size * m_width;
    size_t zeroes = size - total;
    size_t zavg = zeroes / (m_size ? m_size : 1); // avoid possible div by zero

    cout << "Size: " << m_size << "\n";
    cout << "Width: " << m_width << "\n";
    cout << "Total: " << size << "\n";
    cout << "Capacity: " << m_capacity << "\n\n";
    cout << "Bytes string: " << total << "\n";
    cout << "     longest: " << longest << "\n";
    cout << "Bytes zeroes: " << zeroes << "\n";
    cout << "         avg: " << zavg << "\n";
}

void ArrayString::to_dot(ostream& out, StringData title) const
{
    ref_type ref = get_ref();

    if (title.size() != 0) {
        out << "subgraph cluster_" << ref << " {" << endl;
        out << " label = \"" << title << "\";" << endl;
        out << " color = white;" << endl;
    }

    out << "n" << hex << ref << dec << "[shape=none,label=<";
    out << "

" << endl;

    // Header
    out << "";
    out << "0x" << hex << ref << dec << "	" << endl;

    for (size_t i = 0; i < m_size; ++i)
        out << "\"" << get(i) << "\"	" << endl;

    out << "

>];" << endl;

    if (title.size() != 0)
        out << "}" << endl;

    to_dot_parent_edge(out);
}

#endif // TIGHTDB_DEBUG
<commit_msg>Update array_string.cpp<commit_after>#include <cstdlib>
#include <cstdio> // debug
#include <algorithm>
#include <iostream>
#include <iomanip>
#include <cstring>

#include <tightdb/utilities.hpp>
#include <tightdb/array_string.hpp>
#include <tightdb/impl/destroy_guard.hpp>
#include <tightdb/column.hpp>

using namespace std;
using namespace tightdb;

namespace {

const int max_width = 64;

// Round up to nearest possible block length: {0, 1, 4, 8, 16, 32, 64, 128, ...}. We include 1 to store empty
// strings in as little space as possible, because 0 can only store nulls.
size_t round_up(size_t size)
{
    if (size == 0)
        return 0;

    if (size == 1)
        return 1;

    size |= size >> 1;
    size |= size >> 2;
    size |= size >> 4;
    ++size;
    return size;
}

} // anonymous namespace

bool ArrayString::is_null(size_t ndx) const
{
    TIGHTDB_ASSERT(ndx < m_size);
    StringData sd = get(ndx);
    return sd.data() == null_ptr;
}

void ArrayString::set_null(size_t ndx)
{
    TIGHTDB_ASSERT(ndx < m_size);
    StringData sd = StringData(null_ptr, 0);
    set(ndx, sd);
}

void ArrayString::set(size_t ndx, StringData value)
{
    TIGHTDB_ASSERT(ndx < m_size);
    TIGHTDB_ASSERT(value.size() < size_t(max_width)); // otherwise we have to use another column type

    // Check if we need to copy before modifying
    copy_on_write(); // Throws

    // Make room for the new value plus a zero-termination
    if (m_width <= value.size()) {
        // if m_width == 0 then entire array contains only null entries
        if (value.data() == null_ptr && m_width == 0) {
            return; // set null element to null
        }

//        TIGHTDB_ASSERT(0 < value.size());

        // Calc min column width
        size_t new_width;
        if (m_width == 0 && value.size() == 0)
            new_width = ::round_up(1); // Entire Array is nulls; expand to m_width > 0
        else
            new_width = ::round_up(value.size() + 1);

        //TIGHTDB_ASSERT(value.size() < new_width);

        // FIXME: Should we try to avoid double copying when realloc fails to preserve the address?
        alloc(m_size, new_width); // Throws

        char* base = m_data;
        char* new_end = base + m_size*new_width;

        // Expand the old values in reverse order
        if (0 < m_width) {
            const char* old_end = base + m_size*m_width;
            while (new_end != base) {
                *--new_end = char(*--old_end + (new_width-m_width));
                {
                    // extend 0-padding
                    char* new_begin = new_end - (new_width-m_width);
                    fill(new_begin, new_end, 0);
                    new_end = new_begin;
                }
                {
                    // copy string payload
                    const char* old_begin = old_end - (m_width-1);
                    if(static_cast<size_t>(old_end - old_begin) < m_width) // non-null string
                        new_end = copy_backward(old_begin, old_end, new_end);
                    old_end = old_begin;
                }
            }
        }
        else {
            // m_width == 0, so all elements are null. Expand that to new width.
            while (new_end != base) {
                *--new_end = new_width; //  char(new_width - 1);
                {
                    char* new_begin = new_end - (new_width-1);
                    fill(new_begin, new_end, 0); // Fill with zero bytes
                    new_end = new_begin;
                }
            }
        }

        m_width = new_width;
    }

    TIGHTDB_ASSERT(0 < m_width);

    // Set the value
    char* begin = m_data + (ndx * m_width);
    char* end   = begin + (m_width-1);
    begin = copy(value.data(), value.data()+value.size(), begin);
    fill(begin, end, 0); // Pad with zero bytes
    TIGHTDB_STATIC_ASSERT(max_width <= 128, "Padding size must fit in 7-bits");
//    TIGHTDB_ASSERT(end - begin < max_width);
    if (value.data() == null_ptr) {
        *end = m_width;
    }
    else {
        int pad_size = int(end - begin);
        *end = char(pad_size);
    }
}

void ArrayString::insert(size_t ndx, StringData value)
{
    TIGHTDB_ASSERT(ndx <= m_size);
    TIGHTDB_ASSERT(value.size() < size_t(max_width)); // otherwise we have to use another column type

    // Check if we need to copy before modifying
    copy_on_write(); // Throws

    // Todo: Below code will perform up to 3 memcpy() operations in worst case. Todo, if we improve the
    // allocator to make a gap for the new value for us, we can have just 1. We can also have 2 by merging
    // memmove() and set(), but it's a bit complex. May be done after support of null is completed.

    // Allocate room for the new value
    alloc(m_size+1, m_width); // Throws

    // Make gap for new value
    memmove(m_data + m_width * (ndx + 1), m_data + m_width * ndx, m_width * (m_size - ndx));

    m_size++;

    // Set new value
    set(ndx, value);
    return;
}

void ArrayString::erase(size_t ndx)
{
    TIGHTDB_ASSERT(ndx < m_size);

    // Check if we need to copy before modifying
    copy_on_write(); // Throws

    // move data backwards after deletion
    if (ndx < m_size-1) {
        char* new_begin = m_data + ndx*m_width;
        char* old_begin = new_begin + m_width;
        char* old_end   = m_data + m_size*m_width;
        copy(old_begin, old_end, new_begin);
    }

    --m_size;

    // Update size in header
    set_header_size(m_size);
}

size_t ArrayString::CalcByteLen(size_t count, size_t width) const
{
    // FIXME: This arithemtic could overflow. Consider using one of
    // the functions in <tightdb/util/safe_int_ops.hpp>
    return header_size + (count * width);
}

size_t ArrayString::CalcItemCount(size_t bytes, size_t width) const TIGHTDB_NOEXCEPT
{
    if (width == 0) return size_t(-1); // zero-width gives infinite space

    size_t bytes_without_header = bytes - header_size;
    return bytes_without_header / width;
}

size_t ArrayString::count(StringData value, size_t begin, size_t end) const TIGHTDB_NOEXCEPT
{
    size_t num_matches = 0;

    size_t begin_2 = begin;
    for (;;) {
        size_t ndx = find_first(value, begin_2, end);
        if (ndx == not_found)
            break;
        ++num_matches;
        begin_2 = ndx + 1;
    }

    return num_matches;
}

size_t ArrayString::find_first(StringData value, size_t begin, size_t end) const TIGHTDB_NOEXCEPT
{
    if (end == size_t(-1))
        end = m_size;
    TIGHTDB_ASSERT(begin <= m_size && end <= m_size && begin <= end);

    if (m_width == 0)
        return value.size() == 0 && begin < end ? begin : size_t(-1);

    // A string can never be wider than the column width
    if (m_width <= value.size())
        return size_t(-1);

    if (value.size() == 0) {
        const char* data = m_data + (m_width-1);
        for (size_t i = begin; i != end; ++i) {
            size_t size = (m_width-1) - data[i * m_width];
            if (TIGHTDB_UNLIKELY(size == 0))
                return i;
        }
    }
    else {
        for (size_t i = begin; i != end; ++i) {
            const char* data = m_data + (i * m_width);
            size_t j = 0;
            for (;;) {
                if (TIGHTDB_LIKELY(data[j] != value[j]))
                    break;
                ++j;
                if (TIGHTDB_UNLIKELY(j == value.size())) {
                    size_t size = (m_width-1) - data[m_width-1];
                    if (TIGHTDB_LIKELY(size == value.size()))
                        return i;
                    break;
                }
            }
        }
    }

    return not_found;
}

void ArrayString::find_all(Column& result, StringData value, size_t add_offset,
                           size_t begin, size_t end)
{
    size_t begin_2 = begin;
    for (;;) {
        size_t ndx = find_first(value, begin_2, end);
        if (ndx == not_found)
            break;
        result.add(add_offset + ndx); // Throws
        begin_2 = ndx + 1;
    }
}

bool ArrayString::compare_string(const ArrayString& c) const TIGHTDB_NOEXCEPT
{
    if (c.size() != size())
        return false;

    for (size_t i = 0; i < size(); ++i) {
        if (get(i) != c.get(i))
            return false;
    }

    return true;
}

ref_type ArrayString::bptree_leaf_insert(size_t ndx, StringData value, TreeInsertBase& state)
{
    size_t leaf_size = size();
    TIGHTDB_ASSERT(leaf_size <= TIGHTDB_MAX_BPNODE_SIZE);
    if (leaf_size < ndx) ndx = leaf_size;
    if (TIGHTDB_LIKELY(leaf_size < TIGHTDB_MAX_BPNODE_SIZE)) {
        insert(ndx, value); // Throws
        return 0; // Leaf was not split
    }

    // Split leaf node
    ArrayString new_leaf(m_alloc);
    new_leaf.create(); // Throws
    if (ndx == leaf_size) {
        new_leaf.add(value); // Throws
        state.m_split_offset = ndx;
    }
    else {
        for (size_t i = ndx; i != leaf_size; ++i)
            new_leaf.add(get(i)); // Throws
        truncate(ndx); // Throws
        add(value); // Throws
        state.m_split_offset = ndx + 1;
    }
    state.m_split_size = leaf_size + 1;
    return new_leaf.get_ref();
}

MemRef ArrayString::slice(size_t offset, size_t size, Allocator& target_alloc) const
{
    TIGHTDB_ASSERT(is_attached());

    // FIXME: This can be optimized as a single contiguous copy
    // operation.
    ArrayString slice(target_alloc);
    _impl::ShallowArrayDestroyGuard dg(&slice);
    slice.create(); // Throws
    size_t begin = offset;
    size_t end   = offset + size;
    for (size_t i = begin; i != end; ++i) {
        StringData value = get(i);
        slice.add(value); // Throws
    }
    dg.release();
    return slice.get_mem();
}

#ifdef TIGHTDB_DEBUG

void ArrayString::string_stats() const
{
    size_t total = 0;
    size_t longest = 0;

    for (size_t i = 0; i < m_size; ++i) {
        StringData str = get(i);
        size_t size = str.size() + 1;
        total += size;
        if (size > longest) longest = size;
    }

    size_t size = m_size * m_width;
    size_t zeroes = size - total;
    size_t zavg = zeroes / (m_size ? m_size : 1); // avoid possible div by zero

    cout << "Size: " << m_size << "\n";
    cout << "Width: " << m_width << "\n";
    cout << "Total: " << size << "\n";
    cout << "Capacity: " << m_capacity << "\n\n";
    cout << "Bytes string: " << total << "\n";
    cout << "     longest: " << longest << "\n";
    cout << "Bytes zeroes: " << zeroes << "\n";
    cout << "         avg: " << zavg << "\n";
}

void ArrayString::to_dot(ostream& out, StringData title) const
{
    ref_type ref = get_ref();

    if (title.size() != 0) {
        out << "subgraph cluster_" << ref << " {" << endl;
        out << " label = \"" << title << "\";" << endl;
        out << " color = white;" << endl;
    }

    out << "n" << hex << ref << dec << "[shape=none,label=<";
    out << "

" << endl;

    // Header
    out << "";
    out << "0x" << hex << ref << dec << "	" << endl;

    for (size_t i = 0; i < m_size; ++i)
        out << "\"" << get(i) << "\"	" << endl;

    out << "

>];" << endl;

    if (title.size() != 0)
        out << "}" << endl;

    to_dot_parent_edge(out);
}

#endif // TIGHTDB_DEBUG
<|endoftext|>


<commit_before>/*
 *
 * Copyright 2017 gRPC authors.
 *
 * 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 <stdint.h>
#include <string.h>

#include <memory>

#include <grpc/grpc.h>
#include <grpc/impl/codegen/propagation_bits.h>
#include <grpc/slice.h>
#include <grpc/status.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>

#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/useful.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/end2end_tests.h"
#include "test/core/util/test_config.h"

#define MAX_CONNECTION_IDLE_MS 2000
#define MAX_CONNECTION_AGE_MS 9999

static void* tag(intptr_t t) { return reinterpret_cast<void*>(t); }

static void drain_cq(grpc_completion_queue* cq) {
  grpc_event ev;
  do {
    ev = grpc_completion_queue_next(cq, grpc_timeout_seconds_to_deadline(5),
                                    nullptr);
  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
}

static void simple_request_body(grpc_end2end_test_config /*config*/,
                                grpc_end2end_test_fixture* f) {
  grpc_call* c;
  grpc_call* s;
  grpc_core::CqVerifier cqv(f->cq);
  grpc_op ops[6];
  grpc_op* op;
  grpc_metadata_array initial_metadata_recv;
  grpc_metadata_array trailing_metadata_recv;
  grpc_metadata_array request_metadata_recv;
  grpc_call_details call_details;
  grpc_status_code status;
  grpc_call_error error;
  grpc_slice details;
  int was_cancelled = 2;
  char* peer;

  gpr_timespec deadline = grpc_timeout_seconds_to_deadline(30);
  c = grpc_channel_create_call(f->client, nullptr, GRPC_PROPAGATE_DEFAULTS,
                               f->cq, grpc_slice_from_static_string("/foo"),
                               nullptr, deadline, nullptr);
  GPR_ASSERT(c);

  peer = grpc_call_get_peer(c);
  GPR_ASSERT(peer != nullptr);
  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
  gpr_free(peer);

  grpc_metadata_array_init(&initial_metadata_recv);
  grpc_metadata_array_init(&trailing_metadata_recv);
  grpc_metadata_array_init(&request_metadata_recv);
  grpc_call_details_init(&call_details);

  memset(ops, 0, sizeof(ops));
  op = ops;
  op->op = GRPC_OP_SEND_INITIAL_METADATA;
  op->data.send_initial_metadata.count = 0;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  op->op = GRPC_OP_RECV_INITIAL_METADATA;
  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
  op->data.recv_status_on_client.status = &status;
  op->data.recv_status_on_client.status_details = &details;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
                                nullptr);
  GPR_ASSERT(GRPC_CALL_OK == error);

  error =
      grpc_server_request_call(f->server, &s, &call_details,
                               &request_metadata_recv, f->cq, f->cq, tag(101));
  GPR_ASSERT(GRPC_CALL_OK == error);
  cqv.Expect(tag(101), true);
  cqv.Verify();

  peer = grpc_call_get_peer(s);
  GPR_ASSERT(peer != nullptr);
  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
  gpr_free(peer);
  peer = grpc_call_get_peer(c);
  GPR_ASSERT(peer != nullptr);
  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
  gpr_free(peer);

  memset(ops, 0, sizeof(ops));
  op = ops;
  op->op = GRPC_OP_SEND_INITIAL_METADATA;
  op->data.send_initial_metadata.count = 0;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
  op->data.send_status_from_server.trailing_metadata_count = 0;
  op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
  grpc_slice status_details = grpc_slice_from_static_string("xyz");
  op->data.send_status_from_server.status_details = &status_details;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
  op->data.recv_close_on_server.cancelled = &was_cancelled;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
                                nullptr);
  GPR_ASSERT(GRPC_CALL_OK == error);

  cqv.Expect(tag(102), true);
  cqv.Expect(tag(1), true);
  cqv.Verify();

  GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
  GPR_ASSERT(was_cancelled == 0);

  grpc_slice_unref(details);
  grpc_metadata_array_destroy(&initial_metadata_recv);
  grpc_metadata_array_destroy(&trailing_metadata_recv);
  grpc_metadata_array_destroy(&request_metadata_recv);
  grpc_call_details_destroy(&call_details);

  grpc_call_unref(c);
  grpc_call_unref(s);
}

static void test_max_connection_idle(grpc_end2end_test_config config) {
  grpc_end2end_test_fixture f = config.create_fixture(nullptr, nullptr);
  grpc_connectivity_state state = GRPC_CHANNEL_IDLE;
  grpc_core::CqVerifier cqv(f.cq);

  auto client_args = grpc_core::ChannelArgs()
                         .Set(GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS, 1000)
                         .Set(GRPC_ARG_MAX_RECONNECT_BACKOFF_MS, 1000)
                         .Set(GRPC_ARG_MIN_RECONNECT_BACKOFF_MS, 5000)
                         .ToC();
  grpc_arg server_a[2];
  server_a[0].type = GRPC_ARG_INTEGER;
  server_a[0].key = const_cast<char*>(GRPC_ARG_MAX_CONNECTION_IDLE_MS);
  server_a[0].value.integer = MAX_CONNECTION_IDLE_MS;
  server_a[1].type = GRPC_ARG_INTEGER;
  server_a[1].key = const_cast<char*>(GRPC_ARG_MAX_CONNECTION_AGE_MS);
  server_a[1].value.integer = MAX_CONNECTION_AGE_MS;
  grpc_channel_args server_args = {GPR_ARRAY_SIZE(server_a), server_a};

  config.init_client(&f, client_args.get());
  config.init_server(&f, &server_args);

  /* check that we're still in idle, and start connecting */
  GPR_ASSERT(grpc_channel_check_connectivity_state(f.client, 1) ==
             GRPC_CHANNEL_IDLE);
  /* we'll go through some set of transitions (some might be missed), until
     READY is reached */
  while (state != GRPC_CHANNEL_READY) {
    grpc_channel_watch_connectivity_state(
        f.client, state, grpc_timeout_seconds_to_deadline(10), f.cq, tag(99));
    cqv.Expect(tag(99), true);
    cqv.Verify();
    state = grpc_channel_check_connectivity_state(f.client, 0);
    GPR_ASSERT(state == GRPC_CHANNEL_READY ||
               state == GRPC_CHANNEL_CONNECTING ||
               state == GRPC_CHANNEL_TRANSIENT_FAILURE);
  }

  /* Use a simple request to cancel and reset the max idle timer */
  simple_request_body(config, &f);

  /* wait for the channel to reach its maximum idle time */
  grpc_channel_watch_connectivity_state(
      f.client, GRPC_CHANNEL_READY,
      grpc_timeout_milliseconds_to_deadline(MAX_CONNECTION_IDLE_MS + 3000),
      f.cq, tag(99));
  cqv.Expect(tag(99), true);
  cqv.Verify();
  state = grpc_channel_check_connectivity_state(f.client, 0);
  GPR_ASSERT(state == GRPC_CHANNEL_TRANSIENT_FAILURE ||
             state == GRPC_CHANNEL_CONNECTING || state == GRPC_CHANNEL_IDLE);

  grpc_server_shutdown_and_notify(f.server, f.cq, tag(0xdead));
  cqv.Expect(tag(0xdead), true);
  cqv.Verify();

  grpc_server_destroy(f.server);
  grpc_channel_destroy(f.client);
  grpc_completion_queue_shutdown(f.cq);
  drain_cq(f.cq);
  grpc_completion_queue_destroy(f.cq);
  config.tear_down_data(&f);
}

void max_connection_idle(grpc_end2end_test_config config) {
  test_max_connection_idle(config);
}

void max_connection_idle_pre_init(void) {}
<commit_msg>[fixit] More max_connection_idle fixes (#30639)<commit_after>/*
 *
 * Copyright 2017 gRPC authors.
 *
 * 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 <stdint.h>
#include <string.h>

#include <memory>

#include <grpc/grpc.h>
#include <grpc/impl/codegen/propagation_bits.h>
#include <grpc/slice.h>
#include <grpc/status.h>
#include <grpc/support/alloc.h>
#include <grpc/support/log.h>
#include <grpc/support/time.h>

#include "src/core/lib/channel/channel_args.h"
#include "src/core/lib/gpr/useful.h"
#include "test/core/end2end/cq_verifier.h"
#include "test/core/end2end/end2end_tests.h"
#include "test/core/util/test_config.h"

#define MAX_CONNECTION_IDLE_MS 2000
#define MAX_CONNECTION_AGE_MS 9999

static void* tag(intptr_t t) { return reinterpret_cast<void*>(t); }

static void drain_cq(grpc_completion_queue* cq) {
  grpc_event ev;
  do {
    ev = grpc_completion_queue_next(cq, grpc_timeout_seconds_to_deadline(5),
                                    nullptr);
  } while (ev.type != GRPC_QUEUE_SHUTDOWN);
}

static void simple_request_body(grpc_end2end_test_config /*config*/,
                                grpc_end2end_test_fixture* f) {
  grpc_call* c;
  grpc_call* s;
  grpc_core::CqVerifier cqv(f->cq);
  grpc_op ops[6];
  grpc_op* op;
  grpc_metadata_array initial_metadata_recv;
  grpc_metadata_array trailing_metadata_recv;
  grpc_metadata_array request_metadata_recv;
  grpc_call_details call_details;
  grpc_status_code status;
  grpc_call_error error;
  grpc_slice details;
  int was_cancelled = 2;
  char* peer;

  gpr_timespec deadline = grpc_timeout_seconds_to_deadline(30);
  c = grpc_channel_create_call(f->client, nullptr, GRPC_PROPAGATE_DEFAULTS,
                               f->cq, grpc_slice_from_static_string("/foo"),
                               nullptr, deadline, nullptr);
  GPR_ASSERT(c);

  peer = grpc_call_get_peer(c);
  GPR_ASSERT(peer != nullptr);
  gpr_log(GPR_DEBUG, "client_peer_before_call=%s", peer);
  gpr_free(peer);

  grpc_metadata_array_init(&initial_metadata_recv);
  grpc_metadata_array_init(&trailing_metadata_recv);
  grpc_metadata_array_init(&request_metadata_recv);
  grpc_call_details_init(&call_details);

  memset(ops, 0, sizeof(ops));
  op = ops;
  op->op = GRPC_OP_SEND_INITIAL_METADATA;
  op->data.send_initial_metadata.count = 0;
  op->flags = GRPC_INITIAL_METADATA_WAIT_FOR_READY |
              GRPC_INITIAL_METADATA_WAIT_FOR_READY_EXPLICITLY_SET;
  op->reserved = nullptr;
  op++;
  op->op = GRPC_OP_SEND_CLOSE_FROM_CLIENT;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  op->op = GRPC_OP_RECV_INITIAL_METADATA;
  op->data.recv_initial_metadata.recv_initial_metadata = &initial_metadata_recv;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  op->op = GRPC_OP_RECV_STATUS_ON_CLIENT;
  op->data.recv_status_on_client.trailing_metadata = &trailing_metadata_recv;
  op->data.recv_status_on_client.status = &status;
  op->data.recv_status_on_client.status_details = &details;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  error = grpc_call_start_batch(c, ops, static_cast<size_t>(op - ops), tag(1),
                                nullptr);
  GPR_ASSERT(GRPC_CALL_OK == error);

  error =
      grpc_server_request_call(f->server, &s, &call_details,
                               &request_metadata_recv, f->cq, f->cq, tag(101));
  GPR_ASSERT(GRPC_CALL_OK == error);
  cqv.Expect(tag(101), true);
  cqv.Verify();

  peer = grpc_call_get_peer(s);
  GPR_ASSERT(peer != nullptr);
  gpr_log(GPR_DEBUG, "server_peer=%s", peer);
  gpr_free(peer);
  peer = grpc_call_get_peer(c);
  GPR_ASSERT(peer != nullptr);
  gpr_log(GPR_DEBUG, "client_peer=%s", peer);
  gpr_free(peer);

  memset(ops, 0, sizeof(ops));
  op = ops;
  op->op = GRPC_OP_SEND_INITIAL_METADATA;
  op->data.send_initial_metadata.count = 0;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  op->op = GRPC_OP_SEND_STATUS_FROM_SERVER;
  op->data.send_status_from_server.trailing_metadata_count = 0;
  op->data.send_status_from_server.status = GRPC_STATUS_UNIMPLEMENTED;
  grpc_slice status_details = grpc_slice_from_static_string("xyz");
  op->data.send_status_from_server.status_details = &status_details;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  op->op = GRPC_OP_RECV_CLOSE_ON_SERVER;
  op->data.recv_close_on_server.cancelled = &was_cancelled;
  op->flags = 0;
  op->reserved = nullptr;
  op++;
  error = grpc_call_start_batch(s, ops, static_cast<size_t>(op - ops), tag(102),
                                nullptr);
  GPR_ASSERT(GRPC_CALL_OK == error);

  cqv.Expect(tag(102), true);
  cqv.Expect(tag(1), true);
  cqv.Verify();

  GPR_ASSERT(status == GRPC_STATUS_UNIMPLEMENTED);
  GPR_ASSERT(0 == grpc_slice_str_cmp(details, "xyz"));
  GPR_ASSERT(0 == grpc_slice_str_cmp(call_details.method, "/foo"));
  GPR_ASSERT(was_cancelled == 0);

  grpc_slice_unref(details);
  grpc_metadata_array_destroy(&initial_metadata_recv);
  grpc_metadata_array_destroy(&trailing_metadata_recv);
  grpc_metadata_array_destroy(&request_metadata_recv);
  grpc_call_details_destroy(&call_details);

  grpc_call_unref(c);
  grpc_call_unref(s);
}

static void test_max_connection_idle(grpc_end2end_test_config config) {
  grpc_end2end_test_fixture f = config.create_fixture(nullptr, nullptr);
  grpc_connectivity_state state = GRPC_CHANNEL_IDLE;
  grpc_core::CqVerifier cqv(f.cq);

  auto client_args = grpc_core::ChannelArgs()
                         .Set(GRPC_ARG_INITIAL_RECONNECT_BACKOFF_MS, 1000)
                         .Set(GRPC_ARG_MAX_RECONNECT_BACKOFF_MS, 1000)
                         .Set(GRPC_ARG_MIN_RECONNECT_BACKOFF_MS, 5000)
                         .ToC();
  grpc_arg server_a[2];
  server_a[0].type = GRPC_ARG_INTEGER;
  server_a[0].key = const_cast<char*>(GRPC_ARG_MAX_CONNECTION_IDLE_MS);
  server_a[0].value.integer = MAX_CONNECTION_IDLE_MS;
  server_a[1].type = GRPC_ARG_INTEGER;
  server_a[1].key = const_cast<char*>(GRPC_ARG_MAX_CONNECTION_AGE_MS);
  server_a[1].value.integer = MAX_CONNECTION_AGE_MS;
  grpc_channel_args server_args = {GPR_ARRAY_SIZE(server_a), server_a};

  config.init_client(&f, client_args.get());
  config.init_server(&f, &server_args);

  /* check that we're still in idle, and start connecting */
  GPR_ASSERT(grpc_channel_check_connectivity_state(f.client, 1) ==
             GRPC_CHANNEL_IDLE);
  /* we'll go through some set of transitions (some might be missed), until
     READY is reached */
  while (state != GRPC_CHANNEL_READY) {
    grpc_channel_watch_connectivity_state(
        f.client, state, grpc_timeout_seconds_to_deadline(10), f.cq, tag(99));
    cqv.Expect(tag(99), true);
    cqv.Verify();
    state = grpc_channel_check_connectivity_state(f.client, 0);
    GPR_ASSERT(state == GRPC_CHANNEL_READY ||
               state == GRPC_CHANNEL_CONNECTING ||
               state == GRPC_CHANNEL_TRANSIENT_FAILURE);
  }

  /* Use a simple request to cancel and reset the max idle timer */
  simple_request_body(config, &f);

  /* wait for the channel to reach its maximum idle time */
  grpc_channel_watch_connectivity_state(
      f.client, GRPC_CHANNEL_READY,
      gpr_time_add(grpc_timeout_milliseconds_to_deadline(3000),
                   gpr_time_from_millis(MAX_CONNECTION_IDLE_MS, GPR_TIMESPAN)),
      f.cq, tag(99));
  cqv.Expect(tag(99), true);
  cqv.Verify();
  state = grpc_channel_check_connectivity_state(f.client, 0);
  GPR_ASSERT(state == GRPC_CHANNEL_TRANSIENT_FAILURE ||
             state == GRPC_CHANNEL_CONNECTING || state == GRPC_CHANNEL_IDLE);

  grpc_server_shutdown_and_notify(f.server, f.cq, tag(0xdead));
  cqv.Expect(tag(0xdead), true);
  cqv.Verify();

  grpc_server_destroy(f.server);
  grpc_channel_destroy(f.client);
  grpc_completion_queue_shutdown(f.cq);
  drain_cq(f.cq);
  grpc_completion_queue_destroy(f.cq);
  config.tear_down_data(&f);
}

void max_connection_idle(grpc_end2end_test_config config) {
  test_max_connection_idle(config);
}

void max_connection_idle_pre_init(void) {}
<|endoftext|>


<commit_before>void draw() {
  for (int i = 0; i < 6; i++) {
    for (int j = 0; j < 6; j++) {
      for(int k = 0; k < numShapes; k++) {
        int centerX = 150 + i * 110;
        int centerY = 150 + j * 110;

        // Add some randomness!
        scale([[size]]);
        rotate(random() * (1.0 - [[smoothing]]));
        translate(random() * (1.0 - [[smoothing]]),
                  random() * (1.0 - [[smoothing]]));

        drawRect(centerX, centerY, k);
      }
    }
  }
}
<commit_msg>add opacity parameter<commit_after>void draw() {
  for (int i = 0; i < 6; i++) {
    for (int j = 0; j < 6; j++) {
      for(int k = 0; k < numShapes; k++) {
        int centerX = 150 + i * 110;
        int centerY = 150 + j * 110;

        // Add some randomness!
        scale([[size]]);
        rotate(random() * (1.0 - [[smoothing]]));
        translate(random() * (1.0 - [[smoothing]]),
                  random() * (1.0 - [[smoothing]]));
        color(255, [[opacity]]);
        drawRect(centerX, centerY, k);
      }
    }
  }
}
<|endoftext|>


<commit_before>/*
  Copyright (c) 2013 Matthew Stump

  This file is part of libmutton.

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

  libmutton 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 Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <boost/test/unit_test.hpp>
#include <boost/filesystem.hpp>

#include <leveldb/db.h>

#include "fixtures.hpp"
#include "context.hpp"
#include "index_reader_writer_leveldb.hpp"

BOOST_AUTO_TEST_SUITE(_index_reader_writer_leveldb)

struct auto_path_t {

    auto_path_t() :
        path("tmp/testdb")
    {
        boost::filesystem::create_directories(path);
    }

    ~auto_path_t()
    {
        boost::filesystem::remove_all(path);
    }

    std::string path;
};

BOOST_AUTO_TEST_CASE(index_partition)
{
    auto_path_t path;
    mtn::context_t context(new mtn::index_reader_writer_leveldb_t());

    context.opt(MTN_OPT_DB_PATH, static_cast<const void*>(path.path.c_str()), path.path.size());
    context.init();

    mtn::byte_t bucket_name_array[] = "bizbang";
    mtn::byte_t field_name_array[] = "foobar";

    std::vector<mtn::byte_t> bucket(bucket_name_array, bucket_name_array + 7);
    std::vector<mtn::byte_t> field(field_name_array, field_name_array + 6);

    mtn::index_t* index = NULL;
    context.index_reader_writer().read_index(1, bucket, field, &index);
    BOOST_CHECK(NULL != index);
    BOOST_CHECK_EQUAL(1, index->partition());
}

BOOST_AUTO_TEST_CASE(index_bucket)
{
    auto_path_t path;
    mtn::context_t context(new mtn::index_reader_writer_leveldb_t());

    context.opt(MTN_OPT_DB_PATH, static_cast<const void*>(path.path.c_str()), path.path.size());
    BOOST_CHECK(context.init());

    mtn::byte_t bucket_name_array[] = "bizbang";
    mtn::byte_t field_name_array[] = "foobar";

    std::vector<mtn::byte_t> bucket(bucket_name_array, bucket_name_array + 7);
    std::vector<mtn::byte_t> field(field_name_array, field_name_array + 6);

    mtn::index_t* index = NULL;
    context.index_reader_writer().read_index(1, bucket, field, &index);
    BOOST_CHECK(NULL != index);
    BOOST_CHECK_EQUAL(index->bucket().size(), bucket.size());
    BOOST_CHECK(std::equal(index->bucket().begin(), index->bucket().end(), bucket.begin()));
}

BOOST_AUTO_TEST_CASE(index_field)
{
    auto_path_t path;
    mtn::context_t context(new mtn::index_reader_writer_leveldb_t());

    context.opt(MTN_OPT_DB_PATH, static_cast<const void*>(path.path.c_str()), path.path.size());
    BOOST_CHECK(context.init());

    mtn::byte_t bucket_name_array[] = "bizbang";
    mtn::byte_t field_name_array[] = "foobar";

    std::vector<mtn::byte_t> bucket(bucket_name_array, bucket_name_array + 7);
    std::vector<mtn::byte_t> field(field_name_array, field_name_array + 6);

    mtn::index_t* index = NULL;
    context.index_reader_writer().read_index(1, bucket, field, &index);
    BOOST_CHECK(NULL != index);
    BOOST_CHECK_EQUAL(index->field().size(), field.size());
    BOOST_CHECK(std::equal(index->field().begin(), index->field().end(), field.begin()));
}

BOOST_AUTO_TEST_CASE(read_write_segment)
{
    auto_path_t path;
    mtn::context_t context(new mtn::index_reader_writer_leveldb_t());

    context.opt(MTN_OPT_DB_PATH, static_cast<const void*>(path.path.c_str()), path.path.size());
    context.init();

    mtn::byte_t bucket_name_array[] = "bizbang";
    mtn::byte_t field_name_array[] = "foobar";

    std::vector<mtn::byte_t> bucket(bucket_name_array, bucket_name_array + 7);
    std::vector<mtn::byte_t> field(field_name_array, field_name_array + 6);

    mtn::index_segment_t segment_one;
    mtn::index_segment_t segment_two;
    memset(segment_one, 0xFFFFFFFF, MTN_INDEX_SEGMENT_SIZE);
    memset(segment_two, 0, MTN_INDEX_SEGMENT_SIZE);

    mtn::status_t status;
    status = context.index_reader_writer().write_segment(1, bucket, field, 2, 3, segment_one);
    BOOST_CHECK(status);

    status = context.index_reader_writer().read_segment(1, bucket, field, 2, 3, segment_two);
    BOOST_CHECK(status);

    BOOST_CHECK_EQUAL(0, memcmp(segment_one, segment_two, MTN_INDEX_SEGMENT_SIZE));
}

BOOST_AUTO_TEST_CASE(slice_set_bit_simple)
{
    auto_path_t path;
    mtn::context_t context(new mtn::index_reader_writer_leveldb_t());

    context.opt(MTN_OPT_DB_PATH, static_cast<const void*>(path.path.c_str()), path.path.size());
    context.init();

    mtn::byte_t bucket_name_array[] = "bizbang";
    mtn::byte_t field_name_array[] = "foobar";

    std::vector<mtn::byte_t> bucket(bucket_name_array, bucket_name_array + 7);
    std::vector<mtn::byte_t> field(field_name_array, field_name_array + 6);

    mtn::index_t* index_one = NULL;
    context.index_reader_writer().read_index(1, bucket, field, &index_one);
    BOOST_CHECK(NULL != index_one);
    BOOST_CHECK(index_one->index_value(context.index_reader_writer(), 1, 1, true));
    BOOST_CHECK_EQUAL(1, index_one->size());

    mtn::index_slice_t slice_one;
    BOOST_CHECK(!slice_one.bit(1));
    BOOST_CHECK(index_one->slice(slice_one));
    BOOST_CHECK_EQUAL(1, slice_one.size());
    BOOST_CHECK(slice_one.bit(1));

    mtn::index_t* index_two = NULL;
    context.index_reader_writer().read_index(1, bucket, field, &index_two);
    BOOST_CHECK(NULL != index_two);

    mtn::index_slice_t slice_two;
    BOOST_CHECK(!slice_two.bit(1));
    BOOST_CHECK(index_two->slice(slice_two));
    BOOST_CHECK_EQUAL(1, slice_two.size());
    BOOST_CHECK(slice_two.bit(1));
}

BOOST_AUTO_TEST_CASE(slice_set_bit_larger_offset)
{
    auto_path_t path;
    mtn::context_t context(new mtn::index_reader_writer_leveldb_t());

    context.opt(MTN_OPT_DB_PATH, static_cast<const void*>(path.path.c_str()), path.path.size());
    context.init();

    mtn::byte_t bucket_name_array[] = "bizbang";
    mtn::byte_t field_name_array[] = "foobar";

    std::vector<mtn::byte_t> bucket(bucket_name_array, bucket_name_array + 7);
    std::vector<mtn::byte_t> field(field_name_array, field_name_array + 6);

    mtn::index_t* index_one = NULL;
    context.index_reader_writer().read_index(1, bucket, field, &index_one);
    BOOST_CHECK(NULL != index_one);
    BOOST_CHECK(index_one->index_value(context.index_reader_writer(), 2048, 1, true));

    mtn::index_slice_t slice_one;
    BOOST_CHECK(!slice_one.bit(1));
    BOOST_CHECK(index_one->slice(slice_one));
    BOOST_CHECK(slice_one.bit(1));

    mtn::index_t* index_two = NULL;
    context.index_reader_writer().read_index(1, bucket, field, &index_two);
    BOOST_CHECK(NULL != index_two);

    mtn::index_slice_t slice_two;
    BOOST_CHECK(!slice_two.bit(1));
    BOOST_CHECK(index_two->slice(slice_two));
    BOOST_CHECK(slice_two.bit(1));
}

BOOST_AUTO_TEST_CASE(slice_set_bit_larger_user)
{
    auto_path_t path;
    mtn::context_t context(new mtn::index_reader_writer_leveldb_t());

    context.opt(MTN_OPT_DB_PATH, static_cast<const void*>(path.path.c_str()), path.path.size());
    context.init();

    mtn::byte_t bucket_name_array[] = "bizbang";
    mtn::byte_t field_name_array[] = "foobar";

    std::vector<mtn::byte_t> bucket(bucket_name_array, bucket_name_array + 7);
    std::vector<mtn::byte_t> field(field_name_array, field_name_array + 6);

    mtn::index_t* index_one = NULL;
    context.index_reader_writer().read_index(1, bucket, field, &index_one);
    BOOST_CHECK(NULL != index_one);
    BOOST_CHECK(index_one->index_value(context.index_reader_writer(), 2048, 4096, true));

    mtn::index_slice_t slice_one;
    BOOST_CHECK(!slice_one.bit(4096));
    BOOST_CHECK(index_one->slice(slice_one));
    BOOST_CHECK(slice_one.bit(4096));

    mtn::index_t* index_two = NULL;
    context.index_reader_writer().read_index(1, bucket, field, &index_two);
    BOOST_CHECK(NULL != index_two);

    mtn::index_slice_t slice_two;
    BOOST_CHECK(!slice_two.bit(4096));
    BOOST_CHECK(index_two->slice(slice_two));
    BOOST_CHECK(slice_two.bit(4096));
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>fix unit test broken to context.opt interface change<commit_after>/*
  Copyright (c) 2013 Matthew Stump

  This file is part of libmutton.

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

  libmutton 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 Affero General Public License for more details.

  You should have received a copy of the GNU Affero General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <boost/test/unit_test.hpp>
#include <boost/filesystem.hpp>

#include <leveldb/db.h>

#include "fixtures.hpp"
#include "context.hpp"
#include "index_reader_writer_leveldb.hpp"

BOOST_AUTO_TEST_SUITE(_index_reader_writer_leveldb)

struct auto_path_t {

    auto_path_t() :
        path("tmp/testdb")
    {
        boost::filesystem::create_directories(path);
    }

    ~auto_path_t()
    {
        boost::filesystem::remove_all(path);
    }

    std::string path;
};

BOOST_AUTO_TEST_CASE(index_partition)
{
    auto_path_t path;
    mtn::context_t context(new mtn::index_reader_writer_leveldb_t());

    context.set_opt(MTN_OPT_DB_PATH, static_cast<const void*>(path.path.c_str()), path.path.size());
    context.init();

    mtn::byte_t bucket_name_array[] = "bizbang";
    mtn::byte_t field_name_array[] = "foobar";

    std::vector<mtn::byte_t> bucket(bucket_name_array, bucket_name_array + 7);
    std::vector<mtn::byte_t> field(field_name_array, field_name_array + 6);

    mtn::index_t* index = NULL;
    context.index_reader_writer().read_index(1, bucket, field, &index);
    BOOST_CHECK(NULL != index);
    BOOST_CHECK_EQUAL(1, index->partition());
}

BOOST_AUTO_TEST_CASE(index_bucket)
{
    auto_path_t path;
    mtn::context_t context(new mtn::index_reader_writer_leveldb_t());

    context.set_opt(MTN_OPT_DB_PATH, static_cast<const void*>(path.path.c_str()), path.path.size());
    BOOST_CHECK(context.init());

    mtn::byte_t bucket_name_array[] = "bizbang";
    mtn::byte_t field_name_array[] = "foobar";

    std::vector<mtn::byte_t> bucket(bucket_name_array, bucket_name_array + 7);
    std::vector<mtn::byte_t> field(field_name_array, field_name_array + 6);

    mtn::index_t* index = NULL;
    context.index_reader_writer().read_index(1, bucket, field, &index);
    BOOST_CHECK(NULL != index);
    BOOST_CHECK_EQUAL(index->bucket().size(), bucket.size());
    BOOST_CHECK(std::equal(index->bucket().begin(), index->bucket().end(), bucket.begin()));
}

BOOST_AUTO_TEST_CASE(index_field)
{
    auto_path_t path;
    mtn::context_t context(new mtn::index_reader_writer_leveldb_t());

    context.set_opt(MTN_OPT_DB_PATH, static_cast<const void*>(path.path.c_str()), path.path.size());
    BOOST_CHECK(context.init());

    mtn::byte_t bucket_name_array[] = "bizbang";
    mtn::byte_t field_name_array[] = "foobar";

    std::vector<mtn::byte_t> bucket(bucket_name_array, bucket_name_array + 7);
    std::vector<mtn::byte_t> field(field_name_array, field_name_array + 6);

    mtn::index_t* index = NULL;
    context.index_reader_writer().read_index(1, bucket, field, &index);
    BOOST_CHECK(NULL != index);
    BOOST_CHECK_EQUAL(index->field().size(), field.size());
    BOOST_CHECK(std::equal(index->field().begin(), index->field().end(), field.begin()));
}

BOOST_AUTO_TEST_CASE(read_write_segment)
{
    auto_path_t path;
    mtn::context_t context(new mtn::index_reader_writer_leveldb_t());

    context.set_opt(MTN_OPT_DB_PATH, static_cast<const void*>(path.path.c_str()), path.path.size());
    context.init();

    mtn::byte_t bucket_name_array[] = "bizbang";
    mtn::byte_t field_name_array[] = "foobar";

    std::vector<mtn::byte_t> bucket(bucket_name_array, bucket_name_array + 7);
    std::vector<mtn::byte_t> field(field_name_array, field_name_array + 6);

    mtn::index_segment_t segment_one;
    mtn::index_segment_t segment_two;
    memset(segment_one, 0xFFFFFFFF, MTN_INDEX_SEGMENT_SIZE);
    memset(segment_two, 0, MTN_INDEX_SEGMENT_SIZE);

    mtn::status_t status;
    status = context.index_reader_writer().write_segment(1, bucket, field, 2, 3, segment_one);
    BOOST_CHECK(status);

    status = context.index_reader_writer().read_segment(1, bucket, field, 2, 3, segment_two);
    BOOST_CHECK(status);

    BOOST_CHECK_EQUAL(0, memcmp(segment_one, segment_two, MTN_INDEX_SEGMENT_SIZE));
}

BOOST_AUTO_TEST_CASE(slice_set_bit_simple)
{
    auto_path_t path;
    mtn::context_t context(new mtn::index_reader_writer_leveldb_t());

    context.set_opt(MTN_OPT_DB_PATH, static_cast<const void*>(path.path.c_str()), path.path.size());
    context.init();

    mtn::byte_t bucket_name_array[] = "bizbang";
    mtn::byte_t field_name_array[] = "foobar";

    std::vector<mtn::byte_t> bucket(bucket_name_array, bucket_name_array + 7);
    std::vector<mtn::byte_t> field(field_name_array, field_name_array + 6);

    mtn::index_t* index_one = NULL;
    context.index_reader_writer().read_index(1, bucket, field, &index_one);
    BOOST_CHECK(NULL != index_one);
    BOOST_CHECK(index_one->index_value(context.index_reader_writer(), 1, 1, true));
    BOOST_CHECK_EQUAL(1, index_one->size());

    mtn::index_slice_t slice_one;
    BOOST_CHECK(!slice_one.bit(1));
    BOOST_CHECK(index_one->slice(slice_one));
    BOOST_CHECK_EQUAL(1, slice_one.size());
    BOOST_CHECK(slice_one.bit(1));

    mtn::index_t* index_two = NULL;
    context.index_reader_writer().read_index(1, bucket, field, &index_two);
    BOOST_CHECK(NULL != index_two);

    mtn::index_slice_t slice_two;
    BOOST_CHECK(!slice_two.bit(1));
    BOOST_CHECK(index_two->slice(slice_two));
    BOOST_CHECK_EQUAL(1, slice_two.size());
    BOOST_CHECK(slice_two.bit(1));
}

BOOST_AUTO_TEST_CASE(slice_set_bit_larger_offset)
{
    auto_path_t path;
    mtn::context_t context(new mtn::index_reader_writer_leveldb_t());

    context.set_opt(MTN_OPT_DB_PATH, static_cast<const void*>(path.path.c_str()), path.path.size());
    context.init();

    mtn::byte_t bucket_name_array[] = "bizbang";
    mtn::byte_t field_name_array[] = "foobar";

    std::vector<mtn::byte_t> bucket(bucket_name_array, bucket_name_array + 7);
    std::vector<mtn::byte_t> field(field_name_array, field_name_array + 6);

    mtn::index_t* index_one = NULL;
    context.index_reader_writer().read_index(1, bucket, field, &index_one);
    BOOST_CHECK(NULL != index_one);
    BOOST_CHECK(index_one->index_value(context.index_reader_writer(), 2048, 1, true));

    mtn::index_slice_t slice_one;
    BOOST_CHECK(!slice_one.bit(1));
    BOOST_CHECK(index_one->slice(slice_one));
    BOOST_CHECK(slice_one.bit(1));

    mtn::index_t* index_two = NULL;
    context.index_reader_writer().read_index(1, bucket, field, &index_two);
    BOOST_CHECK(NULL != index_two);

    mtn::index_slice_t slice_two;
    BOOST_CHECK(!slice_two.bit(1));
    BOOST_CHECK(index_two->slice(slice_two));
    BOOST_CHECK(slice_two.bit(1));
}

BOOST_AUTO_TEST_CASE(slice_set_bit_larger_user)
{
    auto_path_t path;
    mtn::context_t context(new mtn::index_reader_writer_leveldb_t());

    context.set_opt(MTN_OPT_DB_PATH, static_cast<const void*>(path.path.c_str()), path.path.size());
    context.init();

    mtn::byte_t bucket_name_array[] = "bizbang";
    mtn::byte_t field_name_array[] = "foobar";

    std::vector<mtn::byte_t> bucket(bucket_name_array, bucket_name_array + 7);
    std::vector<mtn::byte_t> field(field_name_array, field_name_array + 6);

    mtn::index_t* index_one = NULL;
    context.index_reader_writer().read_index(1, bucket, field, &index_one);
    BOOST_CHECK(NULL != index_one);
    BOOST_CHECK(index_one->index_value(context.index_reader_writer(), 2048, 4096, true));

    mtn::index_slice_t slice_one;
    BOOST_CHECK(!slice_one.bit(4096));
    BOOST_CHECK(index_one->slice(slice_one));
    BOOST_CHECK(slice_one.bit(4096));

    mtn::index_t* index_two = NULL;
    context.index_reader_writer().read_index(1, bucket, field, &index_two);
    BOOST_CHECK(NULL != index_two);

    mtn::index_slice_t slice_two;
    BOOST_CHECK(!slice_two.bit(4096));
    BOOST_CHECK(index_two->slice(slice_two));
    BOOST_CHECK(slice_two.bit(4096));
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>