<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ControlOOoTContext.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: rt $ $Date: 2008-03-12 11:13:15 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmloff.hxx"

#ifndef _XMLOFF_CONTROLOOOTCONTEXT_HXX
#include "ControlOOoTContext.hxx"
#endif
#ifndef _XMLOFF_IGNORETCONTEXT_HXX
#include "IgnoreTContext.hxx"
#endif
#ifndef _XMLOFF_MUTABLEATTRLIST_HXX
#include "MutableAttrList.hxx"
#endif
#ifndef _XMLOFF_XMLNMSPE_HXX
#include "xmlnmspe.hxx"
#endif
#ifndef _XMLOFF_ACTIONMAPTYPESOOO_HXX
#include "ActionMapTypesOOo.hxx"
#endif
#ifndef _XMLOFF_ELEMTRANSFORMERACTION_HXX
#include "ElemTransformerAction.hxx"
#endif
#ifndef _XMLOFF_TRANSFORMERACTIONS_HXX
#include "TransformerActions.hxx"
#endif
#ifndef _XMLOFF_TRANSFORMERBASE_HXX
#include "TransformerBase.hxx"
#endif

using ::rtl::OUString;

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::xml::sax;
using namespace ::xmloff::token;

TYPEINIT1( XMLControlOOoTransformerContext, XMLTransformerContext );

XMLControlOOoTransformerContext::XMLControlOOoTransformerContext(
        XMLTransformerBase& rImp,
        const OUString& rQName ) :
    XMLTransformerContext( rImp, rQName )
{
}

XMLControlOOoTransformerContext::~XMLControlOOoTransformerContext()
{
}

void XMLControlOOoTransformerContext::StartElement(
    const Reference< XAttributeList >& rAttrList )
{
    m_xAttrList = new XMLMutableAttributeList( rAttrList, sal_True );
}

XMLTransformerContext *XMLControlOOoTransformerContext::CreateChildContext(
        sal_uInt16 /*nPrefix*/,
        const OUString& /*rLocalName*/,
        const OUString& rQName,
        const Reference< XAttributeList >& rAttrList )
{
    XMLTransformerContext *pContext = 0;

    if( !m_aElemQName.getLength() )
    {
        pContext = new XMLIgnoreTransformerContext( GetTransformer(),
                                                    rQName,
                                                    sal_False, sal_False );
        m_aElemQName = rQName;
        static_cast< XMLMutableAttributeList * >( m_xAttrList.get() )
                ->AppendAttributeList( rAttrList );
        GetTransformer().ProcessAttrList( m_xAttrList,
                                          OOO_FORM_CONTROL_ACTIONS,
                                          sal_False );
        GetTransformer().GetDocHandler()->startElement( m_aElemQName,
                                                        m_xAttrList );
    }
    else
    {
        pContext = new XMLIgnoreTransformerContext( GetTransformer(),
                                                    rQName,
                                                    sal_True, sal_True );
    }
    return pContext;
}

void XMLControlOOoTransformerContext::EndElement()
{
    GetTransformer().GetDocHandler()->endElement( m_aElemQName );
}

void XMLControlOOoTransformerContext::Characters( const OUString& rChars )
{
    // ignore
    if( m_aElemQName.getLength() )
        XMLTransformerContext::Characters( rChars );
}
<commit_msg>INTEGRATION: CWS changefileheader (1.6.18); FILE MERGED 2008/04/01 13:05:44 thb 1.6.18.2: #i85898# Stripping all external header guards 2008/03/31 16:28:49 rt 1.6.18.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: ControlOOoTContext.cxx,v $
 * $Revision: 1.7 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmloff.hxx"
#include "ControlOOoTContext.hxx"
#include "IgnoreTContext.hxx"
#include "MutableAttrList.hxx"
#include "xmlnmspe.hxx"
#include "ActionMapTypesOOo.hxx"
#include "ElemTransformerAction.hxx"
#include "TransformerActions.hxx"
#ifndef _XMLOFF_TRANSFORMERBASE_HXX
#include "TransformerBase.hxx"
#endif

using ::rtl::OUString;

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::xml::sax;
using namespace ::xmloff::token;

TYPEINIT1( XMLControlOOoTransformerContext, XMLTransformerContext );

XMLControlOOoTransformerContext::XMLControlOOoTransformerContext(
        XMLTransformerBase& rImp,
        const OUString& rQName ) :
    XMLTransformerContext( rImp, rQName )
{
}

XMLControlOOoTransformerContext::~XMLControlOOoTransformerContext()
{
}

void XMLControlOOoTransformerContext::StartElement(
    const Reference< XAttributeList >& rAttrList )
{
    m_xAttrList = new XMLMutableAttributeList( rAttrList, sal_True );
}

XMLTransformerContext *XMLControlOOoTransformerContext::CreateChildContext(
        sal_uInt16 /*nPrefix*/,
        const OUString& /*rLocalName*/,
        const OUString& rQName,
        const Reference< XAttributeList >& rAttrList )
{
    XMLTransformerContext *pContext = 0;

    if( !m_aElemQName.getLength() )
    {
        pContext = new XMLIgnoreTransformerContext( GetTransformer(),
                                                    rQName,
                                                    sal_False, sal_False );
        m_aElemQName = rQName;
        static_cast< XMLMutableAttributeList * >( m_xAttrList.get() )
                ->AppendAttributeList( rAttrList );
        GetTransformer().ProcessAttrList( m_xAttrList,
                                          OOO_FORM_CONTROL_ACTIONS,
                                          sal_False );
        GetTransformer().GetDocHandler()->startElement( m_aElemQName,
                                                        m_xAttrList );
    }
    else
    {
        pContext = new XMLIgnoreTransformerContext( GetTransformer(),
                                                    rQName,
                                                    sal_True, sal_True );
    }
    return pContext;
}

void XMLControlOOoTransformerContext::EndElement()
{
    GetTransformer().GetDocHandler()->endElement( m_aElemQName );
}

void XMLControlOOoTransformerContext::Characters( const OUString& rChars )
{
    // ignore
    if( m_aElemQName.getLength() )
        XMLTransformerContext::Characters( rChars );
}
<|endoftext|>


<commit_before>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2006 Mikio L. Braun
 * Written (W) 1999-2009 Soeren Sonnenburg
 * Copyright (C) 1999-2009 Fraunhofer Institute FIRST and Max-Planck-Society
 */

#include <shogun/lib/config.h>

#ifdef HAVE_LAPACK
#include <shogun/regression/KernelRidgeRegression.h>
#include <shogun/mathematics/lapack.h>
#include <shogun/mathematics/Math.h>

using namespace shogun;

CKernelRidgeRegression::CKernelRidgeRegression()
: CKernelMachine()
{
	init();
}

CKernelRidgeRegression::CKernelRidgeRegression(float64_t tau, CKernel* k, CLabels* lab, ETrainingType m)
: CKernelMachine()
{
	init();

	m_tau=tau;
	set_labels(lab);
	set_kernel(k);
	set_epsilon(0.0001);
	m_train_func=m;
}

void CKernelRidgeRegression::init()
{
	m_tau=1e-6;

	SG_ADD(&m_tau, "tau", "Regularization parameter", MS_AVAILABLE);
}

bool CKernelRidgeRegression::train_machine_pinv(CFeatures* data)
{
	if (!m_labels)
		SG_ERROR("No labels set\n");

	if (data)
	{
		if (m_labels->get_num_labels() != data->get_num_vectors())
			SG_ERROR("Number of training vectors does not match number of labels\n");
		kernel->init(data, data);
	}
	ASSERT(kernel && kernel->has_features());

	// Get kernel matrix
	SGMatrix<float64_t> kernel_matrix=kernel->get_kernel_matrix<float64_t>();
	int32_t n = kernel_matrix.num_cols;
	int32_t m = kernel_matrix.num_rows;
	ASSERT(kernel_matrix.matrix && m>0 && n>0);

	for(int32_t i=0; i < n; i++)
		kernel_matrix.matrix[i+i*n]+=m_tau;

	/* re-set alphas of kernel machine */
	m_alpha=m_labels->get_labels_copy();

	/* tell kernel machine that all alphas are needed as'support vectors' */
	m_svs=SGVector<index_t>(m_alpha.vlen);
	m_svs.range_fill();

	if (get_alphas().vlen!=n)
	{
		SG_ERROR("Number of labels does not match number of kernel"
				" columns (num_labels=%d cols=%d\n", m_alpha.vlen, n);
	}

	clapack_dposv(CblasRowMajor,CblasUpper, n, 1, kernel_matrix.matrix, n,
			m_alpha.vector, n);

	SG_FREE(kernel_matrix.matrix);

	return true;
}

bool CKernelRidgeRegression::train_machine_gs(CFeatures* data)
{
	if (!m_labels)
		SG_ERROR("No labels set\n");

	if (data)
	{
		if (m_labels->get_num_labels() != data->get_num_vectors())
			SG_ERROR("Number of training vectors does not match number of labels\n");
		kernel->init(data, data);
	}
	ASSERT(kernel && kernel->has_features());

	int32_t n = kernel->get_num_vec_rhs();
	int32_t m = kernel->get_num_vec_lhs();
	ASSERT(m>0 && n>0);

	// re-set alphas of kernel machine
	SGVector<float64_t> b;
	float64_t alpha_old;

	b=m_labels->get_labels_copy();
	m_alpha=m_labels->get_labels_copy();
	m_alpha.zero();

	// tell kernel machine that all alphas are needed as 'support vectors'
	m_svs=SGVector<index_t>(m_alpha.vlen);
	m_svs.range_fill();

	if (get_alphas().vlen!=n)
	{
		SG_ERROR("Number of labels does not match number of kernel"
				" columns (num_labels=%d cols=%d\n", m_alpha.vlen, n);
	}

	// Gauss-Seidel iterative method
	float64_t sigma, err, d;
	bool flag=true;
	while(flag)
	{
		err=0.0;
		for(int32_t i=0; i<n; i++)
		{
			sigma=b[i];
			for(int32_t j=0; j<n; j++)
				if (i!=j)
					sigma-=kernel->kernel(j, i)*m_alpha[j];
			alpha_old=m_alpha[i];
			m_alpha[i]=sigma/(kernel->kernel(i, i)+m_tau);
			d=fabs(alpha_old-m_alpha[i]);
			if(d>err)
				err=d;
		}
		if (err<=m_epsilon)
			flag=false;
	}

	return true;
}

bool CKernelRidgeRegression::train_machine(CFeatures *data)
{
	switch (m_train_func)
	{
		case PINV:
			return train_machine_pinv(data);
			break;
		case GS:
			return train_machine_gs(data);
			break;
		default:
			return train_machine_pinv(data);
			break;
	}
}

bool CKernelRidgeRegression::load(FILE* srcfile)
{
	SG_SET_LOCALE_C;
	SG_RESET_LOCALE;
	return false;
}

bool CKernelRidgeRegression::save(FILE* dstfile)
{
	SG_SET_LOCALE_C;
	SG_RESET_LOCALE;
	return false;
}
#endif
<commit_msg>Fixed KRR crasher<commit_after>/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Written (W) 2006 Mikio L. Braun
 * Written (W) 1999-2009 Soeren Sonnenburg
 * Copyright (C) 1999-2009 Fraunhofer Institute FIRST and Max-Planck-Society
 */

#include <shogun/lib/config.h>

#ifdef HAVE_LAPACK
#include <shogun/regression/KernelRidgeRegression.h>
#include <shogun/mathematics/lapack.h>
#include <shogun/mathematics/Math.h>

using namespace shogun;

CKernelRidgeRegression::CKernelRidgeRegression()
: CKernelMachine()
{
	init();
}

CKernelRidgeRegression::CKernelRidgeRegression(float64_t tau, CKernel* k, CLabels* lab, ETrainingType m)
: CKernelMachine()
{
	init();

	m_tau=tau;
	set_labels(lab);
	set_kernel(k);
	set_epsilon(0.0001);
	m_train_func=m;
}

void CKernelRidgeRegression::init()
{
	m_tau=1e-6;

	SG_ADD(&m_tau, "tau", "Regularization parameter", MS_AVAILABLE);
}

bool CKernelRidgeRegression::train_machine_pinv(CFeatures* data)
{
	if (!m_labels)
		SG_ERROR("No labels set\n");

	if (data)
	{
		if (m_labels->get_num_labels() != data->get_num_vectors())
			SG_ERROR("Number of training vectors does not match number of labels\n");
		kernel->init(data, data);
	}
	ASSERT(kernel && kernel->has_features());

	// Get kernel matrix
	SGMatrix<float64_t> kernel_matrix=kernel->get_kernel_matrix<float64_t>();
	int32_t n = kernel_matrix.num_cols;
	int32_t m = kernel_matrix.num_rows;
	ASSERT(kernel_matrix.matrix && m>0 && n>0);

	for(int32_t i=0; i < n; i++)
		kernel_matrix.matrix[i+i*n]+=m_tau;

	/* re-set alphas of kernel machine */
	m_alpha=m_labels->get_labels_copy();

	/* tell kernel machine that all alphas are needed as'support vectors' */
	m_svs=SGVector<index_t>(m_alpha.vlen);
	m_svs.range_fill();

	if (get_alphas().vlen!=n)
	{
		SG_ERROR("Number of labels does not match number of kernel"
				" columns (num_labels=%d cols=%d\n", m_alpha.vlen, n);
	}

	clapack_dposv(CblasRowMajor,CblasUpper, n, 1, kernel_matrix.matrix, n,
			m_alpha.vector, n);

	return true;
}

bool CKernelRidgeRegression::train_machine_gs(CFeatures* data)
{
	if (!m_labels)
		SG_ERROR("No labels set\n");

	if (data)
	{
		if (m_labels->get_num_labels() != data->get_num_vectors())
			SG_ERROR("Number of training vectors does not match number of labels\n");
		kernel->init(data, data);
	}
	ASSERT(kernel && kernel->has_features());

	int32_t n = kernel->get_num_vec_rhs();
	int32_t m = kernel->get_num_vec_lhs();
	ASSERT(m>0 && n>0);

	// re-set alphas of kernel machine
	SGVector<float64_t> b;
	float64_t alpha_old;

	b=m_labels->get_labels_copy();
	m_alpha=m_labels->get_labels_copy();
	m_alpha.zero();

	// tell kernel machine that all alphas are needed as 'support vectors'
	m_svs=SGVector<index_t>(m_alpha.vlen);
	m_svs.range_fill();

	if (get_alphas().vlen!=n)
	{
		SG_ERROR("Number of labels does not match number of kernel"
				" columns (num_labels=%d cols=%d\n", m_alpha.vlen, n);
	}

	// Gauss-Seidel iterative method
	float64_t sigma, err, d;
	bool flag=true;
	while(flag)
	{
		err=0.0;
		for(int32_t i=0; i<n; i++)
		{
			sigma=b[i];
			for(int32_t j=0; j<n; j++)
				if (i!=j)
					sigma-=kernel->kernel(j, i)*m_alpha[j];
			alpha_old=m_alpha[i];
			m_alpha[i]=sigma/(kernel->kernel(i, i)+m_tau);
			d=fabs(alpha_old-m_alpha[i]);
			if(d>err)
				err=d;
		}
		if (err<=m_epsilon)
			flag=false;
	}

	return true;
}

bool CKernelRidgeRegression::train_machine(CFeatures *data)
{
	switch (m_train_func)
	{
		case PINV:
			return train_machine_pinv(data);
			break;
		case GS:
			return train_machine_gs(data);
			break;
		default:
			return train_machine_pinv(data);
			break;
	}
}

bool CKernelRidgeRegression::load(FILE* srcfile)
{
	SG_SET_LOCALE_C;
	SG_RESET_LOCALE;
	return false;
}

bool CKernelRidgeRegression::save(FILE* dstfile)
{
	SG_SET_LOCALE_C;
	SG_RESET_LOCALE;
	return false;
}
#endif
<|endoftext|>


<commit_before>/*
 * Distributed under the OSI-approved Apache License, Version 2.0.  See
 * accompanying file Copyright.txt for details.
 */
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <ctime>

#include <chrono>
#include <iostream>
#include <signal.h>
#include <sstream>
#include <stdexcept>
#include <thread>

#include <adios2.h>

#include <gtest/gtest.h>

#include "TestData.h"

class CommonServerTest : public ::testing::Test
{
public:
    CommonServerTest() = default;
};

adios2::Params engineParams = {};         // parsed from command line
int DurationSeconds = 60 * 60 * 24 * 365; // one year default
int DelayMS = 1000;                       // one step per sec default
static int MyCloseNow = 0;
static int GlobalCloseNow = 0;
std::string fname = "ADIOS2CommonServer";
std::string engine = "SST";

static std::string Trim(std::string &str)
{
    size_t first = str.find_first_not_of(' ');
    size_t last = str.find_last_not_of(' ');
    return str.substr(first, (last - first + 1));
}

/*
 * Engine parameters spec is a poor-man's JSON.  name:value pairs are separated
 * by commas.  White space is trimmed off front and back.  No quotes or anything
 * fancy allowed.
 */
static adios2::Params ParseEngineParams(std::string Input)
{
    std::istringstream ss(Input);
    std::string Param;
    adios2::Params Ret = {};

    while (std::getline(ss, Param, ','))
    {
        std::istringstream ss2(Param);
        std::string ParamName;
        std::string ParamValue;
        std::getline(ss2, ParamName, ':');
        if (!std::getline(ss2, ParamValue, ':'))
        {
            throw std::invalid_argument("Engine parameter \"" + Param +
                                        "\" missing value");
        }
        Ret[Trim(ParamName)] = Trim(ParamValue);
    }
    return Ret;
}

std::string shutdown_name = "DieTest";

inline bool file_exists(const std::string &name)
{
    struct stat buffer;
    return (stat(name.c_str(), &buffer) == 0);
}

// ADIOS2 COMMON write
TEST_F(CommonServerTest, ADIOS2CommonServer)
{
    int mpiRank = 0, mpiSize = 1;

    // Number of steps

    std::remove(shutdown_name.c_str());
#ifdef ADIOS2_HAVE_MPI
    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
#endif

// Server test data using ADIOS2

#ifdef ADIOS2_HAVE_MPI
    adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON);
#else
    adios2::ADIOS adios(true);
#endif
    adios2::IO io = adios.DeclareIO("TestIO");

    // Declare 1D variables (NumOfProcesses * Nx)
    // The local process' part (start, count) can be defined now or later
    // before Write().
    {
        adios2::Dims shape{static_cast<unsigned int>(Nx * mpiSize)};
        adios2::Dims start{static_cast<unsigned int>(Nx * mpiRank)};
        adios2::Dims count{static_cast<unsigned int>(Nx)};
        adios2::Dims shape2{static_cast<unsigned int>(Nx * mpiSize), 2};
        adios2::Dims start2{static_cast<unsigned int>(Nx * mpiRank), 0};
        adios2::Dims count2{static_cast<unsigned int>(Nx), 2};
        adios2::Dims shape3{2, static_cast<unsigned int>(Nx * mpiSize)};
        adios2::Dims start3{0, static_cast<unsigned int>(Nx * mpiRank)};
        adios2::Dims count3{2, static_cast<unsigned int>(Nx)};
        adios2::Dims time_shape{static_cast<unsigned int>(mpiSize)};
        adios2::Dims time_start{static_cast<unsigned int>(mpiRank)};
        adios2::Dims time_count{1};
        io.DefineVariable<double>("scalar_r64");
        io.DefineVariable<int8_t>("i8", shape, start, count);
        io.DefineVariable<int16_t>("i16", shape, start, count);
        io.DefineVariable<int32_t>("i32", shape, start, count);
        io.DefineVariable<int64_t>("i64", shape, start, count);
        io.DefineVariable<float>("r32", shape, start, count);
        io.DefineVariable<double>("r64", shape, start, count);
        io.DefineVariable<std::complex<float>>("c32", shape, start, count);
        io.DefineVariable<std::complex<double>>("c64", shape, start, count);
        io.DefineVariable<double>("r64_2d", shape2, start2, count2);
        io.DefineVariable<double>("r64_2d_rev", shape3, start3, count3);
        io.DefineVariable<int64_t>("time", time_shape, time_start, time_count);
    }

    // Create the Engine
    io.SetEngine(engine);
    io.SetParameters(engineParams);

    adios2::Engine engine = io.Open(fname, adios2::Mode::Write);

    // Advance to the next time step
    std::time_t EndTime = std::time(NULL) + DurationSeconds;
    size_t step = 0;

    while ((std::time(NULL) < EndTime) && !GlobalCloseNow)
    {
        // Generate test data for each process uniquely
        generateCommonTestData(step, mpiRank, mpiSize);

        engine.BeginStep();
        // Retrieve the variables that previously went out of scope
        auto scalar_r64 = io.InquireVariable<double>("scalar_r64");
        auto var_i8 = io.InquireVariable<int8_t>("i8");
        auto var_i16 = io.InquireVariable<int16_t>("i16");
        auto var_i32 = io.InquireVariable<int32_t>("i32");
        auto var_i64 = io.InquireVariable<int64_t>("i64");
        auto var_u8 = io.InquireVariable<uint8_t>("u8");
        auto var_r32 = io.InquireVariable<float>("r32");
        auto var_r64 = io.InquireVariable<double>("r64");
        auto var_c32 = io.InquireVariable<std::complex<float>>("c32");
        auto var_c64 = io.InquireVariable<std::complex<double>>("c64");
        auto var_r64_2d = io.InquireVariable<double>("r64_2d");
        auto var_r64_2d_rev = io.InquireVariable<double>("r64_2d_rev");
        auto var_time = io.InquireVariable<int64_t>("time");

        // Make a 1D selection to describe the local dimensions of the
        // variable we write and its offsets in the global spaces
        adios2::Box<adios2::Dims> sel({mpiRank * Nx}, {Nx});
        adios2::Box<adios2::Dims> sel2({mpiRank * Nx, 0}, {Nx, 2});
        adios2::Box<adios2::Dims> sel3({0, mpiRank * Nx}, {2, Nx});
        adios2::Box<adios2::Dims> sel_time(
            {static_cast<unsigned long>(mpiRank)}, {1});
        var_i8.SetSelection(sel);
        var_i16.SetSelection(sel);
        var_i32.SetSelection(sel);
        var_i64.SetSelection(sel);
        var_r32.SetSelection(sel);
        var_r64.SetSelection(sel);
        var_c32.SetSelection(sel);
        var_c64.SetSelection(sel);
        var_r64_2d.SetSelection(sel2);
        var_r64_2d_rev.SetSelection(sel3);
        var_time.SetSelection(sel_time);

        // Write each one
        // fill in the variable with values from starting index to
        // starting index + count
        const adios2::Mode sync = adios2::Mode::Sync;

        engine.Put(scalar_r64, data_scalar_R64, sync);
        engine.Put(var_i8, data_I8.data(), sync);
        engine.Put(var_i16, data_I16.data(), sync);
        engine.Put(var_i32, data_I32.data(), sync);
        engine.Put(var_i64, data_I64.data(), sync);
        engine.Put(var_r32, data_R32.data(), sync);
        engine.Put(var_r64, data_R64.data(), sync);
        engine.Put(var_c32, data_C32.data(), sync);
        engine.Put(var_c64, data_C64.data(), sync);
        engine.Put(var_r64_2d, &data_R64_2d[0][0], sync);
        engine.Put(var_r64_2d_rev, &data_R64_2d_rev[0][0], sync);
        // Advance to the next time step
        std::time_t localtime = std::time(NULL);
        engine.Put(var_time, (int64_t *)&localtime);
        engine.EndStep();
        std::this_thread::sleep_for(std::chrono::milliseconds(
            DelayMS)); /* sleep for DelayMS milliseconds */
        step++;
#ifdef ADIOS2_HAVE_MPI
        MPI_Allreduce(&MyCloseNow, &GlobalCloseNow, 1, MPI_INT, MPI_LOR,
                      MPI_COMM_WORLD);
        if (file_exists(shutdown_name))
        {
            MyCloseNow = GlobalCloseNow = 1;
        }
#else
        GlobalCloseNow = MyCloseNow;
        if (file_exists(shutdown_name))
        {
            MyCloseNow = GlobalCloseNow = 1;
        }
#endif
    }
    // Close the file
    engine.Close();
}

int main(int argc, char **argv)
{
#ifdef ADIOS2_HAVE_MPI
    MPI_Init(nullptr, nullptr);
#endif

    int result, bare_args = 0;
    ::testing::InitGoogleTest(&argc, argv);

    while (argc > 1)
    {
        if (std::string(argv[1]) == "--duration")
        {
            std::istringstream ss(argv[2]);
            if (!(ss >> DurationSeconds))
                std::cerr << "Invalid number for duration " << argv[1] << '\n';
            argv++;
            argc--;
        }
        else if (std::string(argv[1]) == "--shutdown_filename")
        {
            shutdown_name = std::string(argv[2]);
            argv++;
            argc--;
        }
        else if (std::string(argv[1]) == "--ms_delay")
        {
            std::istringstream ss(argv[2]);
            if (!(ss >> DelayMS))
                std::cerr << "Invalid number for ms_delay " << argv[1] << '\n';
            argv++;
            argc--;
        }
        else if (std::string(argv[1]) == "--filename")
        {
            fname = std::string(argv[2]);
            argv++;
            argc--;
        }
        else if (std::string(argv[1]) == "--engine")
        {
            engine = std::string(argv[2]);
            argv++;
            argc--;
        }
        else if (std::string(argv[1]) == "--engine_params")
        {
            std::cout << "PArsing engineparams in -- " << argv[2] << std::endl;

            engineParams = ParseEngineParams(argv[2]);
            argv++;
            argc--;
        }
        else
        {
            if (bare_args == 0)
            {
                /* first arg without -- is engine */
                engine = std::string(argv[1]);
            }
            if (bare_args == 1)
            {
                /* second arg without -- is filename */
                fname = std::string(argv[1]);
            }
            if (bare_args == 2)
            {
                /* third arg without -- is engine params */
                engineParams = ParseEngineParams(argv[1]);
            }
            if (bare_args > 2)
            {
                throw std::invalid_argument("Unknown argument \"" +
                                            std::string(argv[1]) + "\"");
            }
            bare_args++;
        }
        argv++;
        argc--;
    }

    result = RUN_ALL_TESTS();

#ifdef ADIOS2_HAVE_MPI
    MPI_Finalize();
#endif

    return result;
}
<commit_msg>add cast<commit_after>/*
 * Distributed under the OSI-approved Apache License, Version 2.0.  See
 * accompanying file Copyright.txt for details.
 */
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <ctime>

#include <chrono>
#include <iostream>
#include <signal.h>
#include <sstream>
#include <stdexcept>
#include <thread>

#include <adios2.h>

#include <gtest/gtest.h>

#include "TestData.h"

class CommonServerTest : public ::testing::Test
{
public:
    CommonServerTest() = default;
};

adios2::Params engineParams = {};         // parsed from command line
int DurationSeconds = 60 * 60 * 24 * 365; // one year default
int DelayMS = 1000;                       // one step per sec default
static int MyCloseNow = 0;
static int GlobalCloseNow = 0;
std::string fname = "ADIOS2CommonServer";
std::string engine = "SST";

static std::string Trim(std::string &str)
{
    size_t first = str.find_first_not_of(' ');
    size_t last = str.find_last_not_of(' ');
    return str.substr(first, (last - first + 1));
}

/*
 * Engine parameters spec is a poor-man's JSON.  name:value pairs are separated
 * by commas.  White space is trimmed off front and back.  No quotes or anything
 * fancy allowed.
 */
static adios2::Params ParseEngineParams(std::string Input)
{
    std::istringstream ss(Input);
    std::string Param;
    adios2::Params Ret = {};

    while (std::getline(ss, Param, ','))
    {
        std::istringstream ss2(Param);
        std::string ParamName;
        std::string ParamValue;
        std::getline(ss2, ParamName, ':');
        if (!std::getline(ss2, ParamValue, ':'))
        {
            throw std::invalid_argument("Engine parameter \"" + Param +
                                        "\" missing value");
        }
        Ret[Trim(ParamName)] = Trim(ParamValue);
    }
    return Ret;
}

std::string shutdown_name = "DieTest";

inline bool file_exists(const std::string &name)
{
    struct stat buffer;
    return (stat(name.c_str(), &buffer) == 0);
}

// ADIOS2 COMMON write
TEST_F(CommonServerTest, ADIOS2CommonServer)
{
    int mpiRank = 0, mpiSize = 1;

    // Number of steps

    std::remove(shutdown_name.c_str());
#ifdef ADIOS2_HAVE_MPI
    MPI_Comm_rank(MPI_COMM_WORLD, &mpiRank);
    MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
#endif

// Server test data using ADIOS2

#ifdef ADIOS2_HAVE_MPI
    adios2::ADIOS adios(MPI_COMM_WORLD, adios2::DebugON);
#else
    adios2::ADIOS adios(true);
#endif
    adios2::IO io = adios.DeclareIO("TestIO");

    // Declare 1D variables (NumOfProcesses * Nx)
    // The local process' part (start, count) can be defined now or later
    // before Write().
    {
        adios2::Dims shape{static_cast<unsigned int>(Nx * mpiSize)};
        adios2::Dims start{static_cast<unsigned int>(Nx * mpiRank)};
        adios2::Dims count{static_cast<unsigned int>(Nx)};
        adios2::Dims shape2{static_cast<unsigned int>(Nx * mpiSize), 2};
        adios2::Dims start2{static_cast<unsigned int>(Nx * mpiRank), 0};
        adios2::Dims count2{static_cast<unsigned int>(Nx), 2};
        adios2::Dims shape3{2, static_cast<unsigned int>(Nx * mpiSize)};
        adios2::Dims start3{0, static_cast<unsigned int>(Nx * mpiRank)};
        adios2::Dims count3{2, static_cast<unsigned int>(Nx)};
        adios2::Dims time_shape{static_cast<unsigned int>(mpiSize)};
        adios2::Dims time_start{static_cast<unsigned int>(mpiRank)};
        adios2::Dims time_count{1};
        io.DefineVariable<double>("scalar_r64");
        io.DefineVariable<int8_t>("i8", shape, start, count);
        io.DefineVariable<int16_t>("i16", shape, start, count);
        io.DefineVariable<int32_t>("i32", shape, start, count);
        io.DefineVariable<int64_t>("i64", shape, start, count);
        io.DefineVariable<float>("r32", shape, start, count);
        io.DefineVariable<double>("r64", shape, start, count);
        io.DefineVariable<std::complex<float>>("c32", shape, start, count);
        io.DefineVariable<std::complex<double>>("c64", shape, start, count);
        io.DefineVariable<double>("r64_2d", shape2, start2, count2);
        io.DefineVariable<double>("r64_2d_rev", shape3, start3, count3);
        io.DefineVariable<int64_t>("time", time_shape, time_start, time_count);
    }

    // Create the Engine
    io.SetEngine(engine);
    io.SetParameters(engineParams);

    adios2::Engine engine = io.Open(fname, adios2::Mode::Write);

    // Advance to the next time step
    std::time_t EndTime = std::time(NULL) + DurationSeconds;
    size_t step = 0;

    while ((std::time(NULL) < EndTime) && !GlobalCloseNow)
    {
        // Generate test data for each process uniquely
        generateCommonTestData((int)step, mpiRank, mpiSize);

        engine.BeginStep();
        // Retrieve the variables that previously went out of scope
        auto scalar_r64 = io.InquireVariable<double>("scalar_r64");
        auto var_i8 = io.InquireVariable<int8_t>("i8");
        auto var_i16 = io.InquireVariable<int16_t>("i16");
        auto var_i32 = io.InquireVariable<int32_t>("i32");
        auto var_i64 = io.InquireVariable<int64_t>("i64");
        auto var_u8 = io.InquireVariable<uint8_t>("u8");
        auto var_r32 = io.InquireVariable<float>("r32");
        auto var_r64 = io.InquireVariable<double>("r64");
        auto var_c32 = io.InquireVariable<std::complex<float>>("c32");
        auto var_c64 = io.InquireVariable<std::complex<double>>("c64");
        auto var_r64_2d = io.InquireVariable<double>("r64_2d");
        auto var_r64_2d_rev = io.InquireVariable<double>("r64_2d_rev");
        auto var_time = io.InquireVariable<int64_t>("time");

        // Make a 1D selection to describe the local dimensions of the
        // variable we write and its offsets in the global spaces
        adios2::Box<adios2::Dims> sel({mpiRank * Nx}, {Nx});
        adios2::Box<adios2::Dims> sel2({mpiRank * Nx, 0}, {Nx, 2});
        adios2::Box<adios2::Dims> sel3({0, mpiRank * Nx}, {2, Nx});
        adios2::Box<adios2::Dims> sel_time(
            {static_cast<unsigned long>(mpiRank)}, {1});
        var_i8.SetSelection(sel);
        var_i16.SetSelection(sel);
        var_i32.SetSelection(sel);
        var_i64.SetSelection(sel);
        var_r32.SetSelection(sel);
        var_r64.SetSelection(sel);
        var_c32.SetSelection(sel);
        var_c64.SetSelection(sel);
        var_r64_2d.SetSelection(sel2);
        var_r64_2d_rev.SetSelection(sel3);
        var_time.SetSelection(sel_time);

        // Write each one
        // fill in the variable with values from starting index to
        // starting index + count
        const adios2::Mode sync = adios2::Mode::Sync;

        engine.Put(scalar_r64, data_scalar_R64, sync);
        engine.Put(var_i8, data_I8.data(), sync);
        engine.Put(var_i16, data_I16.data(), sync);
        engine.Put(var_i32, data_I32.data(), sync);
        engine.Put(var_i64, data_I64.data(), sync);
        engine.Put(var_r32, data_R32.data(), sync);
        engine.Put(var_r64, data_R64.data(), sync);
        engine.Put(var_c32, data_C32.data(), sync);
        engine.Put(var_c64, data_C64.data(), sync);
        engine.Put(var_r64_2d, &data_R64_2d[0][0], sync);
        engine.Put(var_r64_2d_rev, &data_R64_2d_rev[0][0], sync);
        // Advance to the next time step
        std::time_t localtime = std::time(NULL);
        engine.Put(var_time, (int64_t *)&localtime);
        engine.EndStep();
        std::this_thread::sleep_for(std::chrono::milliseconds(
            DelayMS)); /* sleep for DelayMS milliseconds */
        step++;
#ifdef ADIOS2_HAVE_MPI
        MPI_Allreduce(&MyCloseNow, &GlobalCloseNow, 1, MPI_INT, MPI_LOR,
                      MPI_COMM_WORLD);
        if (file_exists(shutdown_name))
        {
            MyCloseNow = GlobalCloseNow = 1;
        }
#else
        GlobalCloseNow = MyCloseNow;
        if (file_exists(shutdown_name))
        {
            MyCloseNow = GlobalCloseNow = 1;
        }
#endif
    }
    // Close the file
    engine.Close();
}

int main(int argc, char **argv)
{
#ifdef ADIOS2_HAVE_MPI
    MPI_Init(nullptr, nullptr);
#endif

    int result, bare_args = 0;
    ::testing::InitGoogleTest(&argc, argv);

    while (argc > 1)
    {
        if (std::string(argv[1]) == "--duration")
        {
            std::istringstream ss(argv[2]);
            if (!(ss >> DurationSeconds))
                std::cerr << "Invalid number for duration " << argv[1] << '\n';
            argv++;
            argc--;
        }
        else if (std::string(argv[1]) == "--shutdown_filename")
        {
            shutdown_name = std::string(argv[2]);
            argv++;
            argc--;
        }
        else if (std::string(argv[1]) == "--ms_delay")
        {
            std::istringstream ss(argv[2]);
            if (!(ss >> DelayMS))
                std::cerr << "Invalid number for ms_delay " << argv[1] << '\n';
            argv++;
            argc--;
        }
        else if (std::string(argv[1]) == "--filename")
        {
            fname = std::string(argv[2]);
            argv++;
            argc--;
        }
        else if (std::string(argv[1]) == "--engine")
        {
            engine = std::string(argv[2]);
            argv++;
            argc--;
        }
        else if (std::string(argv[1]) == "--engine_params")
        {
            std::cout << "PArsing engineparams in -- " << argv[2] << std::endl;

            engineParams = ParseEngineParams(argv[2]);
            argv++;
            argc--;
        }
        else
        {
            if (bare_args == 0)
            {
                /* first arg without -- is engine */
                engine = std::string(argv[1]);
            }
            if (bare_args == 1)
            {
                /* second arg without -- is filename */
                fname = std::string(argv[1]);
            }
            if (bare_args == 2)
            {
                /* third arg without -- is engine params */
                engineParams = ParseEngineParams(argv[1]);
            }
            if (bare_args > 2)
            {
                throw std::invalid_argument("Unknown argument \"" +
                                            std::string(argv[1]) + "\"");
            }
            bare_args++;
        }
        argv++;
        argc--;
    }

    result = RUN_ALL_TESTS();

#ifdef ADIOS2_HAVE_MPI
    MPI_Finalize();
#endif

    return result;
}
<|endoftext|>


<commit_before>#include "CurlImpl.h"
#include "CurlInitializer.h"
#include "Exception.h"
#include "MockCurlApi.h"

#include <functional>
#include <gmock/gmock.h>

using namespace Instagram;
using namespace testing;

TEST(CurlInitializerTest, InitializesLibcurl)
{
    std::shared_ptr<MockCurlApi> curlApi(new MockCurlApi);

    InSequence dummy;
    EXPECT_CALL(*curlApi, curl_global_init(_)).WillOnce(Return(CURLE_OK));
    EXPECT_CALL(*curlApi, curl_global_cleanup());

    CurlInitializer curlInit(curlApi);
}

TEST(CurlInitializerTest, ThrowsIfInitFails)
{
    std::shared_ptr<MockCurlApi> curlApi(new MockCurlApi);

    EXPECT_CALL(*curlApi, curl_global_init(_)).WillOnce(Return(CURLE_BAD_FUNCTION_ARGUMENT));

    std::auto_ptr<CurlInitializer> curlInitializer;
    ASSERT_THROW(curlInitializer.reset(new CurlInitializer(curlApi)), Instagram::Exception);
}

TEST(CurlConstructTest, ThrowsIfEasyInitFails)
{
    std::shared_ptr<MockCurlApi> curlApi(new MockCurlApi);

    EXPECT_CALL(*curlApi, curl_easy_init()).WillOnce(Return(static_cast<CURL*>(0)));

    CurlPtr curl;
    ASSERT_THROW(curl.reset(new CurlImpl(curlApi)), Instagram::Exception);
}

class CurlTest : public Test
{
protected:
    virtual void SetUp()
    {
        DefaultValue<CURLcode>::Set(CURLE_OK);

        curlApi.reset(new MockCurlApi);

        EXPECT_CALL(*curlApi, curl_easy_init()).WillOnce(Return(handle));

        curl.reset(new CurlImpl(curlApi));
    }

    virtual void TearDown()
    {
        EXPECT_CALL(*curlApi, curl_easy_cleanup(handle));

        curl.reset();

        DefaultValue<CURLcode>::Clear();
    }

    CURL* handle = reinterpret_cast<CURL*>(123);

    std::shared_ptr<MockCurlApi> curlApi;
    CurlPtr curl;
};

ACTION_P4(InvokeWriteCallback, callback, response, data, result)
{
    *result = callback(response, strlen(response), 1, data);
    return CURLE_OK;
}

TEST_F(CurlTest, PerformsGetRequest)
{
    std::string url = "http://example.com";
    EXPECT_CALL(*curlApi, curl_easy_setopt_string(handle, CURLOPT_URL, StrEq(url)));
    EXPECT_CALL(*curlApi, curl_easy_setopt_long(handle, CURLOPT_HTTPGET, 1));

    WriteCallback callback = 0;
    EXPECT_CALL(*curlApi, curl_easy_setopt_func(handle, CURLOPT_WRITEFUNCTION, _))
        .WillOnce(DoAll(SaveArg<2>(&callback), Return(CURLE_OK)));

    void* data = 0;
    EXPECT_CALL(*curlApi, curl_easy_setopt_ptr(handle, CURLOPT_WRITEDATA, _))
        .WillOnce(DoAll(SaveArg<2>(&data), Return(CURLE_OK)));

    char response[] = "response";
    size_t callbackResult = 0;
    EXPECT_CALL(*curlApi, curl_easy_perform(handle))
        // we need std::refs because these values will be set only inside curl_easy_perform, now values are empty
        .WillOnce(InvokeWriteCallback(std::ref(callback), response, std::ref(data), &callbackResult));

    std::string res = curl->get(url);

    ASSERT_THAT(res, StrEq(response));
    ASSERT_THAT(callbackResult, Eq(strlen(response)));
}

class CurlErrorsTest : public Test
{
protected:
    virtual void SetUp()
    {
        DefaultValue<CURLcode>::Set(CURLE_OK);

        curlApi.reset(new NiceMock<MockCurlApi>);

        EXPECT_CALL(*curlApi, curl_easy_init()).WillOnce(Return(reinterpret_cast<CURL*>(1)));
        curl.reset(new CurlImpl(curlApi));
    }

    virtual void TearDown()
    {
        DefaultValue<CURLcode>::Clear();
    }

    std::shared_ptr<MockCurlApi> curlApi;
    CurlPtr curl;
};

TEST_F(CurlErrorsTest, ThrowsIfSetUrlFails)
{
    EXPECT_CALL(*curlApi, curl_easy_setopt_string(_, CURLOPT_URL, _)).WillOnce(Return(CURLE_OUT_OF_MEMORY));

    ASSERT_THROW(curl->get(""), Instagram::Exception);
}

TEST_F(CurlErrorsTest, ThrowsIfSetGetMethodFails)
{
    EXPECT_CALL(*curlApi, curl_easy_setopt_long(_, CURLOPT_HTTPGET, _)).WillOnce(Return(CURLE_OUT_OF_MEMORY));

    ASSERT_THROW(curl->get(""), Instagram::Exception);
}

TEST_F(CurlErrorsTest, ThrowsIfSetWriteFunctionFails)
{
    EXPECT_CALL(*curlApi, curl_easy_setopt_func(_, CURLOPT_WRITEFUNCTION, _)).WillOnce(Return(CURLE_OUT_OF_MEMORY));

    ASSERT_THROW(curl->get(""), Instagram::Exception);
}

TEST_F(CurlErrorsTest, ThrowsIfSetWriteDataFails)
{
    EXPECT_CALL(*curlApi, curl_easy_setopt_ptr(_, CURLOPT_WRITEDATA, _)).WillOnce(Return(CURLE_OUT_OF_MEMORY));

    ASSERT_THROW(curl->get(""), Instagram::Exception);
}

TEST_F(CurlErrorsTest, ThrowsIfPerformFails)
{
    EXPECT_CALL(*curlApi, curl_easy_perform(_)).WillOnce(Return(CURLE_OUT_OF_MEMORY));

    ASSERT_THROW(curl->get(""), Instagram::Exception);
}
<commit_msg>Don't use deprecated std::auto_ptr<commit_after>#include "CurlImpl.h"
#include "CurlInitializer.h"
#include "Exception.h"
#include "MockCurlApi.h"

#include <functional>
#include <gmock/gmock.h>

using namespace Instagram;
using namespace testing;

TEST(CurlInitializerTest, InitializesLibcurl)
{
    std::shared_ptr<MockCurlApi> curlApi(new MockCurlApi);

    InSequence dummy;
    EXPECT_CALL(*curlApi, curl_global_init(_)).WillOnce(Return(CURLE_OK));
    EXPECT_CALL(*curlApi, curl_global_cleanup());

    CurlInitializer curlInit(curlApi);
}

TEST(CurlInitializerTest, ThrowsIfInitFails)
{
    std::shared_ptr<MockCurlApi> curlApi(new MockCurlApi);

    EXPECT_CALL(*curlApi, curl_global_init(_)).WillOnce(Return(CURLE_BAD_FUNCTION_ARGUMENT));

    std::unique_ptr<CurlInitializer> curlInitializer;
    ASSERT_THROW(curlInitializer.reset(new CurlInitializer(curlApi)), Instagram::Exception);
}

TEST(CurlConstructTest, ThrowsIfEasyInitFails)
{
    std::shared_ptr<MockCurlApi> curlApi(new MockCurlApi);

    EXPECT_CALL(*curlApi, curl_easy_init()).WillOnce(Return(static_cast<CURL*>(0)));

    CurlPtr curl;
    ASSERT_THROW(curl.reset(new CurlImpl(curlApi)), Instagram::Exception);
}

class CurlTest : public Test
{
protected:
    virtual void SetUp()
    {
        DefaultValue<CURLcode>::Set(CURLE_OK);

        curlApi.reset(new MockCurlApi);

        EXPECT_CALL(*curlApi, curl_easy_init()).WillOnce(Return(handle));

        curl.reset(new CurlImpl(curlApi));
    }

    virtual void TearDown()
    {
        EXPECT_CALL(*curlApi, curl_easy_cleanup(handle));

        curl.reset();

        DefaultValue<CURLcode>::Clear();
    }

    CURL* handle = reinterpret_cast<CURL*>(123);

    std::shared_ptr<MockCurlApi> curlApi;
    CurlPtr curl;
};

ACTION_P4(InvokeWriteCallback, callback, response, data, result)
{
    *result = callback(response, strlen(response), 1, data);
    return CURLE_OK;
}

TEST_F(CurlTest, PerformsGetRequest)
{
    std::string url = "http://example.com";
    EXPECT_CALL(*curlApi, curl_easy_setopt_string(handle, CURLOPT_URL, StrEq(url)));
    EXPECT_CALL(*curlApi, curl_easy_setopt_long(handle, CURLOPT_HTTPGET, 1));

    WriteCallback callback = 0;
    EXPECT_CALL(*curlApi, curl_easy_setopt_func(handle, CURLOPT_WRITEFUNCTION, _))
        .WillOnce(DoAll(SaveArg<2>(&callback), Return(CURLE_OK)));

    void* data = 0;
    EXPECT_CALL(*curlApi, curl_easy_setopt_ptr(handle, CURLOPT_WRITEDATA, _))
        .WillOnce(DoAll(SaveArg<2>(&data), Return(CURLE_OK)));

    char response[] = "response";
    size_t callbackResult = 0;
    EXPECT_CALL(*curlApi, curl_easy_perform(handle))
        // we need std::refs because these values will be set only inside curl_easy_perform, now values are empty
        .WillOnce(InvokeWriteCallback(std::ref(callback), response, std::ref(data), &callbackResult));

    std::string res = curl->get(url);

    ASSERT_THAT(res, StrEq(response));
    ASSERT_THAT(callbackResult, Eq(strlen(response)));
}

class CurlErrorsTest : public Test
{
protected:
    virtual void SetUp()
    {
        DefaultValue<CURLcode>::Set(CURLE_OK);

        curlApi.reset(new NiceMock<MockCurlApi>);

        EXPECT_CALL(*curlApi, curl_easy_init()).WillOnce(Return(reinterpret_cast<CURL*>(1)));
        curl.reset(new CurlImpl(curlApi));
    }

    virtual void TearDown()
    {
        DefaultValue<CURLcode>::Clear();
    }

    std::shared_ptr<MockCurlApi> curlApi;
    CurlPtr curl;
};

TEST_F(CurlErrorsTest, ThrowsIfSetUrlFails)
{
    EXPECT_CALL(*curlApi, curl_easy_setopt_string(_, CURLOPT_URL, _)).WillOnce(Return(CURLE_OUT_OF_MEMORY));

    ASSERT_THROW(curl->get(""), Instagram::Exception);
}

TEST_F(CurlErrorsTest, ThrowsIfSetGetMethodFails)
{
    EXPECT_CALL(*curlApi, curl_easy_setopt_long(_, CURLOPT_HTTPGET, _)).WillOnce(Return(CURLE_OUT_OF_MEMORY));

    ASSERT_THROW(curl->get(""), Instagram::Exception);
}

TEST_F(CurlErrorsTest, ThrowsIfSetWriteFunctionFails)
{
    EXPECT_CALL(*curlApi, curl_easy_setopt_func(_, CURLOPT_WRITEFUNCTION, _)).WillOnce(Return(CURLE_OUT_OF_MEMORY));

    ASSERT_THROW(curl->get(""), Instagram::Exception);
}

TEST_F(CurlErrorsTest, ThrowsIfSetWriteDataFails)
{
    EXPECT_CALL(*curlApi, curl_easy_setopt_ptr(_, CURLOPT_WRITEDATA, _)).WillOnce(Return(CURLE_OUT_OF_MEMORY));

    ASSERT_THROW(curl->get(""), Instagram::Exception);
}

TEST_F(CurlErrorsTest, ThrowsIfPerformFails)
{
    EXPECT_CALL(*curlApi, curl_easy_perform(_)).WillOnce(Return(CURLE_OUT_OF_MEMORY));

    ASSERT_THROW(curl->get(""), Instagram::Exception);
}
<|endoftext|>


<commit_before>#include "tsdata_tables.h"
#include "encdec.h"
#include <memory>
#include <vector>
#include <monsoon/group_name.h>
#include <monsoon/metric_name.h>
#include <monsoon/time_series_value.h>
#include <monsoon/time_series.h>
#include <monsoon/time_point.h>
#include <tuple>
#include <functional>
#include <utility>
#include <iterator>
#include <type_traits>
#include <algorithm>
#include <queue>
#include <monsoon/objpipe/callback.h>
#include <monsoon/objpipe/merge.h>

namespace monsoon {
namespace history {
namespace v2 {

tsdata_v2_tables::tsdata_v2_tables(file_segment<file_data_tables>&& data,
    const tsdata_v2::carg& constructor_arg)
: tsdata_v2(constructor_arg),
  data_(std::move(data))
{}

tsdata_v2_tables::~tsdata_v2_tables() noexcept {}

std::shared_ptr<io::fd> tsdata_v2_tables::fd() const noexcept {
  return data_.ctx().fd();
}

bool tsdata_v2_tables::is_writable() const noexcept {
  return false;
}

std::vector<time_series> tsdata_v2_tables::read_all_raw_() const {
  using namespace std::placeholders;
  using std::swap;

  std::vector<time_series> result;
  std::vector<time_series::tsv_set> tsdata;
  std::vector<time_series_value::metric_map> mmap;

  const std::shared_ptr<const file_data_tables> file_data_tables =
      data_.get();
  for (const file_data_tables_block& block : *file_data_tables) {
    const std::vector<time_point>& timestamps = std::get<0>(block);
    const std::shared_ptr<const tables> tbl = std::get<1>(block).get();

    // Create time_series maps over time.
    tsdata.resize(timestamps.size());
    std::for_each(tsdata.begin(), tsdata.end(),
        std::bind(&time_series::tsv_set::clear, _1));
    for (tables::const_reference tbl_grp : *tbl) {
      const group_name& gname = std::get<0>(tbl_grp);
      const std::shared_ptr<const group_table> grp_data =
          std::get<1>(tbl_grp).get();
      const std::vector<bool>& presence = std::get<0>(*grp_data);

      // Fill mmap with metric values over time.
      mmap.resize(presence.size());
      std::for_each(mmap.begin(), mmap.end(),
          std::bind(&time_series_value::metric_map::clear, _1));
      for (const auto& metric_entry : std::get<1>(*grp_data)) {
        const metric_name& mname = std::get<0>(metric_entry);
        const std::shared_ptr<const metric_table> mtbl =
            std::get<1>(metric_entry).get();

        // Fill mmap with a specific metric value over time.
        for (auto iter = std::make_tuple(mtbl->cbegin(), mmap.begin());
            std::get<0>(iter) != mtbl->cend() && std::get<1>(iter) != mmap.end();
            ++std::get<0>(iter), ++std::get<1>(iter)) {
          auto& out_map = *std::get<1>(iter);
          const auto& opt_mv = *std::get<0>(iter);
          if (opt_mv.has_value()) out_map.emplace(mname, opt_mv.value());
        }
      }

      // Add group over time.
      for (auto iter = std::make_tuple(
              presence.cbegin(),
              std::make_move_iterator(mmap.begin()),
              tsdata.begin());
          (std::get<0>(iter) != presence.cend()
           && std::get<1>(iter) != std::make_move_iterator(mmap.end())
           && std::get<2>(iter) != tsdata.end());
          ++std::get<0>(iter), ++std::get<1>(iter), ++std::get<2>(iter)) {
        if (*std::get<0>(iter))
          std::get<2>(iter)->emplace(time_series_value(gname, *std::get<1>(iter)));
      }
    }

    // Add a new time series to the collection.
    std::transform(std::make_move_iterator(tsdata.begin()), std::make_move_iterator(tsdata.end()), std::make_move_iterator(timestamps.begin()), std::back_inserter(result),
        [](auto&& set, auto&& ts) {
          return time_series(std::move(ts), std::move(set));
        });
  }

  return result;
}

void tsdata_v2_tables::push_back(const time_series&) {
  throw std::runtime_error("unsupported");
}

class monsoon_dirhistory_local_ metric_iteration {
 public:
  metric_iteration() = default;
  metric_iteration(const metric_iteration&) = default;
  metric_iteration& operator=(const metric_iteration&) = default;

  metric_iteration(metric_iteration&& o) noexcept
  : group(std::move(o.group)),
    metric(std::move(o.metric)),
    table(std::move(o.table)),
    b_(std::move(o.b_)),
    e_(std::move(o.e_))
  {}

  metric_iteration& operator=(metric_iteration&& o) noexcept {
    group = std::move(o.group);
    metric = std::move(o.metric);
    table = std::move(o.table);
    b_ = std::move(o.b_);
    e_ = std::move(o.e_);
    return *this;
  }

  metric_iteration(
      std::shared_ptr<const group_name> group,
      std::shared_ptr<const metric_name> metric,
      std::shared_ptr<const metric_table> table)
  : group(std::move(group)),
    metric(std::move(metric)),
    table(std::move(table))
  {
    if (table != nullptr)
      std::tie(b_, e_) = std::forward_as_tuple(table->begin(), table->end());
  }

  std::shared_ptr<const group_name> group;
  std::shared_ptr<const metric_name> metric;
  std::shared_ptr<const metric_table> table;

  explicit operator bool() const noexcept {
    return table != nullptr && b_ != e_;
  }

  auto next()
  -> std::optional<std::tuple<const group_name&, const metric_name&, const metric_value&>> {
    assert(group != nullptr && metric != nullptr && table != nullptr);
    assert(b_ != e_);
    const std::optional<metric_value> opt_mv = *b_++;
    if (!opt_mv.has_value()) return {};
    return std::tie(*group, *metric, opt_mv.value());
  }

 private:
  metric_table::const_iterator b_, e_;
};

template<typename Callback>
void monsoon_dirhistory_local_ emit_fdtblock(
    std::shared_ptr<const file_data_tables_block> block,
    Callback& cb,
    std::optional<time_point> tr_begin, std::optional<time_point> tr_end,
    const path_matcher& group_filter,
    const tag_matcher& tag_filter,
    const path_matcher& metric_filter) {
  auto timestamps = std::get<0>(*block);
  std::vector<metric_iteration> data;

  // Build parallel iterators per each selected metric.
  const std::shared_ptr<const tables> tbl_ptr = std::get<1>(*block).get();
  std::for_each(tbl_ptr->begin(), tbl_ptr->end(),
      [&data, &tbl_ptr, &group_filter, &tag_filter, &metric_filter](const auto& tbl_entry) {
        if (!group_filter(std::get<0>(tbl_entry).get_path())
            || !tag_filter(std::get<0>(tbl_entry).get_tags()))
          return; // SKIP

        const std::shared_ptr<const group_name> group_ptr =
            std::shared_ptr<const group_name>(tbl_ptr, &std::get<0>(tbl_entry));
        std::shared_ptr<const group_table> gr_tbl = std::get<1>(tbl_entry).get();
        const auto metric_map =
            std::shared_ptr<std::tuple_element_t<1, const group_table>>(
                gr_tbl,
                &std::get<1>(*gr_tbl));

        std::for_each(metric_map->begin(), metric_map->end(),
            [&data, &group_ptr, &metric_map, &metric_filter](
                const auto& metric_map_entry) {
              if (!metric_filter(metric_map_entry.first))
                return; // SKIP

              const std::shared_ptr<const metric_name> metric_ptr =
                  std::shared_ptr<const metric_name>(
                      metric_map,
                      &metric_map_entry.first);

              data.emplace_back(
                  group_ptr,
                  metric_ptr,
                  metric_map_entry.second.get());
            });
      });

  // Emit timestamps and parallel iterators.
  auto emit = tsdata_v2_tables::emit_type();
  for (const time_point& tp : timestamps) {
    std::get<0>(emit) = tp;
    std::get<1>(emit).clear();
    std::get<1>(emit).reserve(data.size());

    std::for_each(data.begin(), data.end(),
        [&emit](auto& iter) {
          if (iter) {
            auto opt_tpl = iter.next();
            if (opt_tpl.has_value()) {
              std::get<1>(emit).emplace(
                  std::piecewise_construct,
                  std::forward_as_tuple(
                      std::get<0>(std::move(opt_tpl.value())),
                      std::get<1>(std::move(opt_tpl.value()))),
                  std::forward_as_tuple(
                      std::get<2>(std::move(opt_tpl.value()))));
            }
          }
        });

    if ((!tr_begin.has_value() || tp >= tr_begin)
        && (!tr_end.has_value() || tp <= tr_end))
      cb(std::move(emit));
  }
}

auto tsdata_v2_tables::emit(
    std::optional<time_point> tr_begin, std::optional<time_point> tr_end,
    const path_matcher& group_filter,
    const tag_matcher& tag_filter,
    const path_matcher& metric_filter)
    const
-> objpipe::reader<emit_type> {
  const std::shared_ptr<const file_data_tables> file_data_tables =
      data_.get();

  if (is_sorted() && is_distinct()) { // Operate on sequential blocks.
    return objpipe::new_callback<emit_type>(
        [file_data_tables, tr_begin, tr_end, group_filter, tag_filter, metric_filter](auto cb) {
          for (const file_data_tables_block& block : *file_data_tables) {
            emit_fdtblock(
                std::shared_ptr<const file_data_tables_block>(file_data_tables, &block),
                cb,
                tr_begin, tr_end, group_filter, tag_filter, metric_filter);
          }
        });
  } else { // Parallel iteration of blocks.
    auto callback_factory =
        [&](const file_data_tables_block& block) {
          auto block_ptr = std::shared_ptr<const file_data_tables_block>(file_data_tables, &block);
          return objpipe::new_callback<emit_type>(
              [block_ptr, tr_begin, tr_end, group_filter, tag_filter, metric_filter](auto cb) {
                emit_fdtblock(
                    block_ptr,
                    cb,
                    tr_begin, tr_end, group_filter, tag_filter, metric_filter);
              });
        };
    using callback_factory_type = std::decay_t<decltype(callback_factory(std::declval<const file_data_tables_block&>()))>;

    auto less = [](const emit_type& x, const emit_type& y) noexcept {
      return std::get<0>(x) < std::get<0>(y);
    };

    std::vector<callback_factory_type> parallel;
    for (const file_data_tables_block& block : *file_data_tables)
      parallel.emplace_back(callback_factory(block));

    if (is_distinct()) { // Merge only.
      return objpipe::merge(
          std::make_move_iterator(parallel.begin()),
          std::make_move_iterator(parallel.end()),
          std::move(less));
    } else {
      auto combine = [](emit_type& x, emit_type&& y) -> emit_type& {
#if __cplusplus >= 201703
        std::get<1>(x).merge(std::get<1>(std::move(y)));
#else
        std::copy(
            std::get<1>(y).begin(),
            std::get<1>(y).end(),
            std::inserter(std::get<1>(x), std::get<1>(x).end()));
#endif
        return x;
      };

      return objpipe::merge_combine(
          std::make_move_iterator(parallel.begin()),
          std::make_move_iterator(parallel.end()),
          std::move(less),
          std::move(combine));
    }
  }
}

auto tsdata_v2_tables::emit_time(
    std::optional<time_point> tr_begin, std::optional<time_point> tr_end)
    const
-> objpipe::reader<time_point> {
  using iterator =
      typename std::tuple_element_t<0, file_data_tables_block>::const_iterator;

  const std::shared_ptr<const file_data_tables> file_data_tables =
      data_.get();

  if (is_sorted() && is_distinct()) { // Operate on sequential blocks.
    return objpipe::new_callback<time_point>(
        [file_data_tables, tr_begin, tr_end](auto cb) {
          for (const file_data_tables_block& block : *file_data_tables) {
            iterator b = std::get<0>(block).begin();
            iterator e = std::get<0>(block).end();
            if (tr_begin.has_value())
              b = std::lower_bound(b, e, tr_begin.value());
            if (tr_end.has_value())
              e = std::upper_bound(b, e, tr_end.value());

            std::for_each(b, e, cb);
          }
        });
  } else {
    auto callback_factory =
        [&](const file_data_tables_block& block) {
          auto block_ptr = std::shared_ptr<const file_data_tables_block>(file_data_tables, &block);
          return objpipe::new_callback<time_point>(
              [block_ptr, tr_begin, tr_end](auto cb) {
                iterator b = std::get<0>(*block_ptr).begin();
                iterator e = std::get<0>(*block_ptr).end();
                if (tr_begin.has_value())
                  b = std::lower_bound(b, e, tr_begin.value());
                if (tr_end.has_value())
                  e = std::upper_bound(b, e, tr_end.value());

                std::for_each(b, e, cb);
              });
        };
    using callback_factory_type = std::decay_t<decltype(callback_factory(std::declval<const file_data_tables_block&>()))>;

    std::vector<callback_factory_type> parallel;
    for (const file_data_tables_block& block : *file_data_tables)
      parallel.emplace_back(callback_factory(block));

    if (is_distinct()) { // Merge only.
      return objpipe::merge(
          std::make_move_iterator(parallel.begin()),
          std::make_move_iterator(parallel.end()));
    } else {
      return objpipe::merge_combine(
          std::make_move_iterator(parallel.begin()),
          std::make_move_iterator(parallel.end()),
          std::less<>(),
          [](const auto& x, [[maybe_unused]] const auto& y) { return x; });
    }
  }
}

}}} /* namespace monsoon::history::v2 */
<commit_msg>Fix: tsdata v2 tables file is now able to resolve metrics.<commit_after>#include "tsdata_tables.h"
#include "encdec.h"
#include <memory>
#include <vector>
#include <monsoon/group_name.h>
#include <monsoon/metric_name.h>
#include <monsoon/time_series_value.h>
#include <monsoon/time_series.h>
#include <monsoon/time_point.h>
#include <tuple>
#include <functional>
#include <utility>
#include <iterator>
#include <type_traits>
#include <algorithm>
#include <queue>
#include <monsoon/objpipe/callback.h>
#include <monsoon/objpipe/merge.h>

namespace monsoon {
namespace history {
namespace v2 {

tsdata_v2_tables::tsdata_v2_tables(file_segment<file_data_tables>&& data,
    const tsdata_v2::carg& constructor_arg)
: tsdata_v2(constructor_arg),
  data_(std::move(data))
{}

tsdata_v2_tables::~tsdata_v2_tables() noexcept {}

std::shared_ptr<io::fd> tsdata_v2_tables::fd() const noexcept {
  return data_.ctx().fd();
}

bool tsdata_v2_tables::is_writable() const noexcept {
  return false;
}

std::vector<time_series> tsdata_v2_tables::read_all_raw_() const {
  using namespace std::placeholders;
  using std::swap;

  std::vector<time_series> result;
  std::vector<time_series::tsv_set> tsdata;
  std::vector<time_series_value::metric_map> mmap;

  const std::shared_ptr<const file_data_tables> file_data_tables =
      data_.get();
  for (const file_data_tables_block& block : *file_data_tables) {
    const std::vector<time_point>& timestamps = std::get<0>(block);
    const std::shared_ptr<const tables> tbl = std::get<1>(block).get();

    // Create time_series maps over time.
    tsdata.resize(timestamps.size());
    std::for_each(tsdata.begin(), tsdata.end(),
        std::bind(&time_series::tsv_set::clear, _1));
    for (tables::const_reference tbl_grp : *tbl) {
      const group_name& gname = std::get<0>(tbl_grp);
      const std::shared_ptr<const group_table> grp_data =
          std::get<1>(tbl_grp).get();
      const std::vector<bool>& presence = std::get<0>(*grp_data);

      // Fill mmap with metric values over time.
      mmap.resize(presence.size());
      std::for_each(mmap.begin(), mmap.end(),
          std::bind(&time_series_value::metric_map::clear, _1));
      for (const auto& metric_entry : std::get<1>(*grp_data)) {
        const metric_name& mname = std::get<0>(metric_entry);
        const std::shared_ptr<const metric_table> mtbl =
            std::get<1>(metric_entry).get();

        // Fill mmap with a specific metric value over time.
        for (auto iter = std::make_tuple(mtbl->cbegin(), mmap.begin());
            std::get<0>(iter) != mtbl->cend() && std::get<1>(iter) != mmap.end();
            ++std::get<0>(iter), ++std::get<1>(iter)) {
          auto& out_map = *std::get<1>(iter);
          const auto& opt_mv = *std::get<0>(iter);
          if (opt_mv.has_value()) out_map.emplace(mname, opt_mv.value());
        }
      }

      // Add group over time.
      for (auto iter = std::make_tuple(
              presence.cbegin(),
              std::make_move_iterator(mmap.begin()),
              tsdata.begin());
          (std::get<0>(iter) != presence.cend()
           && std::get<1>(iter) != std::make_move_iterator(mmap.end())
           && std::get<2>(iter) != tsdata.end());
          ++std::get<0>(iter), ++std::get<1>(iter), ++std::get<2>(iter)) {
        if (*std::get<0>(iter))
          std::get<2>(iter)->emplace(time_series_value(gname, *std::get<1>(iter)));
      }
    }

    // Add a new time series to the collection.
    std::transform(std::make_move_iterator(tsdata.begin()), std::make_move_iterator(tsdata.end()), std::make_move_iterator(timestamps.begin()), std::back_inserter(result),
        [](auto&& set, auto&& ts) {
          return time_series(std::move(ts), std::move(set));
        });
  }

  return result;
}

void tsdata_v2_tables::push_back(const time_series&) {
  throw std::runtime_error("unsupported");
}

namespace {

auto emit_type_less = [](const tsdata_v2_tables::emit_type& x, const tsdata_v2_tables::emit_type& y) noexcept -> bool {
  return std::get<0>(x) < std::get<0>(y); // Compare time points.
};

auto emit_type_merge = [](tsdata_v2_tables::emit_type&& x, tsdata_v2_tables::emit_type&& y) -> tsdata_v2_tables::emit_type&& {
#if __cplusplus >= 201703
  std::get<1>(x).merge(std::get<1>(y));
#else
  std::copy(std::get<1>(y).begin(), std::get<1>(y).end(), std::inserter(std::get<1>(x), std::get<1>(x).end()));
#endif
  return std::move(x);
};

auto emit_fdtblock(
    std::shared_ptr<const file_data_tables_block> block,
    std::optional<time_point> tr_begin, std::optional<time_point> tr_end,
    const path_matcher& group_filter,
    const tag_matcher& tag_filter,
    const path_matcher& metric_filter)
-> objpipe::reader<tsdata_v2_tables::emit_type> {
  using emit_type = tsdata_v2_tables::emit_type;

  auto time_points_ptr = std::shared_ptr<const std::vector<time_point>>(block, &std::get<0>(*block));
  const std::shared_ptr<const tables> tbl_ptr = std::get<1>(*block).get();

  std::vector<objpipe::reader<emit_type>>
      columns;
  for (const auto& tbl_entry : *tbl_ptr) {
    if (!group_filter(std::get<0>(tbl_entry).get_path())
        || !tag_filter(std::get<0>(tbl_entry).get_tags()))
      continue; // SKIP

    auto group_name_ptr = std::shared_ptr<const group_name>(tbl_ptr, &std::get<0>(tbl_entry));
    auto group_table_ptr = std::get<1>(tbl_entry).get();

    for (const auto& mv_map_entry : std::get<1>(*group_table_ptr)) {
      if (!metric_filter(mv_map_entry.first))
        continue; // SKIP
      auto metric_name_ptr = std::shared_ptr<const metric_name>(group_table_ptr, &mv_map_entry.first);

      std::shared_ptr<const std::vector<std::optional<metric_value>>> mv_column_ptr = mv_map_entry.second.get();

      columns.emplace_back(
          objpipe::new_callback<emit_type>(
              [time_points_ptr, group_name_ptr, metric_name_ptr, mv_column_ptr](auto cb) {
                auto tp_iter = time_points_ptr->begin();
                auto mv_iter = mv_column_ptr->begin();

                for (;
                    tp_iter != time_points_ptr->end()
                    && mv_iter != mv_column_ptr->end();
                    ++tp_iter, ++mv_iter) {
                  if (mv_iter->has_value()) {
                    std::tuple_element_t<1, emit_type> map;
                    map.emplace(
                        std::piecewise_construct,
                        std::forward_as_tuple(*group_name_ptr, *metric_name_ptr),
                        std::forward_as_tuple(**mv_iter));
                    cb(std::make_tuple(*tp_iter, std::move(map)));
                  }
                }
              })
              .filter([tr_begin, tr_end](const emit_type& x) {
                const time_point tp = std::get<0>(x);
                return (!tr_begin.has_value() || tp >= tr_begin)
                    && (!tr_end.has_value() || tp <= tr_end);
              }));
    }
  }

  return objpipe::merge_combine(
      std::make_move_iterator(columns.begin()), std::make_move_iterator(columns.end()),
      emit_type_less,
      emit_type_merge);
}

} /* namespace <monsoon::history::v2::<unnamed> */

auto tsdata_v2_tables::emit(
    std::optional<time_point> tr_begin, std::optional<time_point> tr_end,
    const path_matcher& group_filter,
    const tag_matcher& tag_filter,
    const path_matcher& metric_filter)
    const
-> objpipe::reader<emit_type> {
  const std::shared_ptr<const file_data_tables> file_data_tables =
      data_.get();

  auto block_chain = objpipe::new_callback<objpipe::reader<emit_type>>(
      [file_data_tables, tr_begin, tr_end, group_filter, tag_filter, metric_filter](auto cb) {
        for (const file_data_tables_block& block : *file_data_tables) {
          cb(emit_fdtblock(
                  std::shared_ptr<const file_data_tables_block>(file_data_tables, &block),
                  tr_begin, tr_end, group_filter, tag_filter, metric_filter));
        }
      });

  if (is_sorted() && is_distinct()) { // Operate on sequential blocks.
    return block_chain.iterate();
  } else { // Parallel iteration of blocks.
    if (is_distinct()) { // Merge only.
      return objpipe::merge(
          block_chain.begin(),
          block_chain.end(),
          emit_type_less);
    } else {
      auto combine = [](emit_type& x, emit_type&& y) -> emit_type& {
#if __cplusplus >= 201703
        std::get<1>(x).merge(std::get<1>(std::move(y)));
#else
        std::copy(
            std::get<1>(y).begin(),
            std::get<1>(y).end(),
            std::inserter(std::get<1>(x), std::get<1>(x).end()));
#endif
        return x;
      };

      return objpipe::merge_combine(
          block_chain.begin(),
          block_chain.end(),
          emit_type_less,
          emit_type_merge);
    }
  }
}

auto tsdata_v2_tables::emit_time(
    std::optional<time_point> tr_begin, std::optional<time_point> tr_end)
    const
-> objpipe::reader<time_point> {
  using iterator =
      typename std::tuple_element_t<0, file_data_tables_block>::const_iterator;

  const std::shared_ptr<const file_data_tables> file_data_tables =
      data_.get();

  if (is_sorted() && is_distinct()) { // Operate on sequential blocks.
    return objpipe::new_callback<time_point>(
        [file_data_tables, tr_begin, tr_end](auto cb) {
          for (const file_data_tables_block& block : *file_data_tables) {
            iterator b = std::get<0>(block).begin();
            iterator e = std::get<0>(block).end();
            if (tr_begin.has_value())
              b = std::lower_bound(b, e, tr_begin.value());
            if (tr_end.has_value())
              e = std::upper_bound(b, e, tr_end.value());

            std::for_each(b, e, cb);
          }
        });
  } else {
    auto callback_factory =
        [&](const file_data_tables_block& block) {
          auto block_ptr = std::shared_ptr<const file_data_tables_block>(file_data_tables, &block);
          return objpipe::new_callback<time_point>(
              [block_ptr, tr_begin, tr_end](auto cb) {
                iterator b = std::get<0>(*block_ptr).begin();
                iterator e = std::get<0>(*block_ptr).end();
                if (tr_begin.has_value())
                  b = std::lower_bound(b, e, tr_begin.value());
                if (tr_end.has_value())
                  e = std::upper_bound(b, e, tr_end.value());

                std::for_each(b, e, cb);
              });
        };
    using callback_factory_type = std::decay_t<decltype(callback_factory(std::declval<const file_data_tables_block&>()))>;

    std::vector<callback_factory_type> parallel;
    for (const file_data_tables_block& block : *file_data_tables)
      parallel.emplace_back(callback_factory(block));

    if (is_distinct()) { // Merge only.
      return objpipe::merge(
          std::make_move_iterator(parallel.begin()),
          std::make_move_iterator(parallel.end()));
    } else {
      return objpipe::merge_combine(
          std::make_move_iterator(parallel.begin()),
          std::make_move_iterator(parallel.end()),
          std::less<>(),
          [](const auto& x, [[maybe_unused]] const auto& y) { return x; });
    }
  }
}

}}} /* namespace monsoon::history::v2 */
<|endoftext|>


<commit_before>#include <cstdlib>
#include "pkcs11test.h"

using namespace std;  // So sue me

namespace pkcs11 {
namespace test {

TEST_F(PKCS11Test, ParallelSessionUnsupported) {
  // No CKF_SERIAL_SESSION => not supported
  CK_SESSION_HANDLE session;
  EXPECT_CKR(CKR_SESSION_PARALLEL_NOT_SUPPORTED, g_fns->C_OpenSession(g_slot_id, 0, NULL_PTR, NULL_PTR, &session));
}

TEST_F(ReadOnlySessionTest, SessionInfo) {
  CK_SESSION_INFO session_info;
  EXPECT_CKR_OK(g_fns->C_GetSessionInfo(session_, &session_info));
  if (g_verbose) cout << session_info_description(&session_info) << endl;
}

TEST_F(ReadWriteSessionTest, SessionInfo) {
  CK_SESSION_INFO session_info;
  EXPECT_CKR_OK(g_fns->C_GetSessionInfo(session_, &session_info));
  if (g_verbose) cout << session_info_description(&session_info) << endl;
}

}  // namespace test
}  // namespace pkcs11
<commit_msg>Add minimal test for Get/SetOperationState<commit_after>#include <cstdlib>
#include "pkcs11test.h"

using namespace std;  // So sue me

namespace pkcs11 {
namespace test {

TEST_F(PKCS11Test, ParallelSessionUnsupported) {
  // No CKF_SERIAL_SESSION => not supported
  CK_SESSION_HANDLE session;
  EXPECT_CKR(CKR_SESSION_PARALLEL_NOT_SUPPORTED, g_fns->C_OpenSession(g_slot_id, 0, NULL_PTR, NULL_PTR, &session));
}

TEST_F(ReadOnlySessionTest, SessionInfo) {
  CK_SESSION_INFO session_info;
  EXPECT_CKR_OK(g_fns->C_GetSessionInfo(session_, &session_info));
  if (g_verbose) cout << session_info_description(&session_info) << endl;
}

TEST_F(ReadWriteSessionTest, SessionInfo) {
  CK_SESSION_INFO session_info;
  EXPECT_CKR_OK(g_fns->C_GetSessionInfo(session_, &session_info));
  if (g_verbose) cout << session_info_description(&session_info) << endl;
}

TEST_F(ReadWriteSessionTest, GetSetOperationState) {
  CK_ULONG len;
  CK_RV rv = g_fns->C_GetOperationState(session_, NULL_PTR, &len);
  if (rv == CKR_FUNCTION_NOT_SUPPORTED) return;

  // No state => OPERATION_NOT_INITIALIZED
  EXPECT_CKR(CKR_OPERATION_NOT_INITIALIZED, rv);

  // Create some state
  vector<CK_ATTRIBUTE_TYPE> attrs({CKA_ENCRYPT, CKA_DECRYPT});
  SecretKey key(session_, attrs);

  CK_MECHANISM mechanism = {CKM_DES_ECB, NULL_PTR, 0};
  rv = g_fns->C_EncryptInit(session_, &mechanism, key.handle());
  EXPECT_CKR_OK(rv);
  if (rv != CKR_OK) return;

  rv = g_fns->C_GetOperationState(session_, NULL_PTR, &len);
  if (rv != CKR_STATE_UNSAVEABLE) {
    EXPECT_CKR(CKR_BUFFER_TOO_SMALL, rv);
    unique_ptr<CK_BYTE, freer> state((CK_BYTE*)malloc(len));
    rv = g_fns->C_GetOperationState(session_, state.get(), &len);
    EXPECT_CKR_OK(rv);
    if (rv == CKR_OK) {
      EXPECT_CKR_OK(g_fns->C_SetOperationState(session_, state.get(), len, 0, 0));
  }
  }
}

}  // namespace test
}  // namespace pkcs11
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 koolkdev
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE file for details.
 */

#include <cstdio>
#include <vector>
#include <fstream>
#include <memory>
#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>

#include <wfslib/WfsLib.h>

int main(int argc, char *argv[]) {
	try {
		boost::program_options::options_description desc("Allowed options");
		std::string wfs_path;
		desc.add_options()
			("help", "produce help message")
			("image", boost::program_options::value<std::string>(), "wfs image file")
			("inject-file", boost::program_options::value<std::string>(), "file to inject")
			("inject-path", boost::program_options::value<std::string>(), "wfs file path to replace")
			("otp", boost::program_options::value<std::string>(), "otp file")
			("seeprom", boost::program_options::value<std::string>(), "seeprom file (required if usb)")
			("mlc", "device is mlc (default: device is usb)")
			("usb", "device is usb")
			;

		boost::program_options::variables_map vm;
		boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm);
		boost::program_options::notify(vm);

		bool bad = false;
		if (!vm.count("image")) { std::cerr << "Missing wfs image file (--image)" << std::endl; bad = true; }
		if (!vm.count("inject-file")) { std::cerr << "Missing file to inject (--inject-file)" << std::endl; bad = true; }
		if (!vm.count("inject-path")) { std::cerr << "Missing wfs file path (--inject-path)" << std::endl; bad = true; }
		if (!vm.count("otp")) { std::cerr << "Missing otp file (--otp)" << std::endl; bad = true; }
		if ((!vm.count("seeprom") && !vm.count("mlc"))) { std::cerr << "Missing seeprom file (--seeprom)" << std::endl; bad = true; }
		if (vm.count("mlc") + vm.count("usb") > 1) { std::cerr << "Can't specify both --mlc and --usb" << std::endl; bad = true; }
		if (vm.count("help") || bad) {
			std::cout << "Usage: wfs-file-injector --image <wfs image> --inject-file <file to inject> --inject-path <file path in wfs> --otp <opt path> [--seeprom <seeprom path>] [--mlc] [--usb]" << std::endl;
			std::cout << desc << "\n";
			return 1;
		}

		std::vector<uint8_t> key;
		std::unique_ptr<OTP> otp;
		// open otp
		try {
			otp.reset(OTP::LoadFromFile(vm["otp"].as<std::string>()));
		}
		catch (std::exception& e) {
			std::cerr << "Failed to open OTP: " << e.what() << std::endl;
			return 1;
		}

		if (vm.count("mlc")) {
			// mlc
			key = otp->GetMLCKey();
		}
		else {
			// usb
			std::unique_ptr<SEEPROM> seeprom;
			try {
				seeprom.reset(SEEPROM::LoadFromFile(vm["seeprom"].as<std::string>()));
			}
			catch (std::exception& e) {
				std::cerr << "Failed to open SEEPROM: " << e.what() << std::endl;
				return 1;
			}
			key = seeprom->GetUSBKey(*otp);
		}
		std::ifstream input_file(vm["inject-file"].as<std::string>(), std::ios::binary | std::ios::in);
		if (input_file.fail()) {
			std::cerr << "Failed to open file to inject" << std::endl;
			return 1;
		}
		input_file.seekg(0, std::ios::end);
		if (input_file.tellg() > static_cast<std::streampos>(SIZE_MAX)) {
			std::cerr << "Error: File to inject too big" << std::endl;
		}
		size_t file_size = static_cast<size_t>(input_file.tellg());
		input_file.seekg(0, std::ios::beg);

		auto device = std::make_shared<FileDevice>(vm["image"].as<std::string>(), 9, false);
		Wfs::DetectSectorsCount(device, key);
		Wfs::DetectSectorSize(device, key);
		auto file = Wfs(device, key).GetFile(vm["inject-path"].as<std::string>());
		if (!file) {
			std::cerr << "Error: Didn't find file " << vm["inject-path"].as<std::string>() << " in wfs" << std::endl;
			return 1;
		}
		if (file_size > file->GetSizeOnDisk()) {
			std::cerr << "Error: File to inject too big (wanted size: " << file_size << " bytes, available size: " << file->GetSizeOnDisk() << ")" << std::endl;
			return 1;
		}
		File::stream stream(file);
		std::vector<char> data(0x2000);
		size_t to_copy = file_size;
		while (to_copy > 0) {
			input_file.read((char*)&*data.begin(), std::min(data.size(), to_copy));
			auto read = input_file.gcount();
			if (read <= 0) {
				std::cerr << "Error: Failed to read file to inject" << std::endl;
				return 1;
			}
			stream.write(&*data.begin(), read);
			to_copy -= static_cast<size_t>(read);
		}
		input_file.close();
		stream.close();
		if (file_size < file->GetSize()) {
			file->Resize(file_size);
		}
		std::cout << "Done!" << std::endl;
	}
	catch (std::exception& e) {
		std::cerr << "Error: " << e.what() << std::endl;
		return 1;
	}
	return 0;
}<commit_msg>wfs-file-injector: fixed file size check<commit_after>/*
 * Copyright (C) 2017 koolkdev
 *
 * This software may be modified and distributed under the terms
 * of the MIT license.  See the LICENSE file for details.
 */

#include <cstdio>
#include <vector>
#include <fstream>
#include <memory>
#include <iostream>
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>

#include <wfslib/WfsLib.h>

int main(int argc, char *argv[]) {
	try {
		boost::program_options::options_description desc("Allowed options");
		std::string wfs_path;
		desc.add_options()
			("help", "produce help message")
			("image", boost::program_options::value<std::string>(), "wfs image file")
			("inject-file", boost::program_options::value<std::string>(), "file to inject")
			("inject-path", boost::program_options::value<std::string>(), "wfs file path to replace")
			("otp", boost::program_options::value<std::string>(), "otp file")
			("seeprom", boost::program_options::value<std::string>(), "seeprom file (required if usb)")
			("mlc", "device is mlc (default: device is usb)")
			("usb", "device is usb")
			;

		boost::program_options::variables_map vm;
		boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm);
		boost::program_options::notify(vm);

		bool bad = false;
		if (!vm.count("image")) { std::cerr << "Missing wfs image file (--image)" << std::endl; bad = true; }
		if (!vm.count("inject-file")) { std::cerr << "Missing file to inject (--inject-file)" << std::endl; bad = true; }
		if (!vm.count("inject-path")) { std::cerr << "Missing wfs file path (--inject-path)" << std::endl; bad = true; }
		if (!vm.count("otp")) { std::cerr << "Missing otp file (--otp)" << std::endl; bad = true; }
		if ((!vm.count("seeprom") && !vm.count("mlc"))) { std::cerr << "Missing seeprom file (--seeprom)" << std::endl; bad = true; }
		if (vm.count("mlc") + vm.count("usb") > 1) { std::cerr << "Can't specify both --mlc and --usb" << std::endl; bad = true; }
		if (vm.count("help") || bad) {
			std::cout << "Usage: wfs-file-injector --image <wfs image> --inject-file <file to inject> --inject-path <file path in wfs> --otp <opt path> [--seeprom <seeprom path>] [--mlc] [--usb]" << std::endl;
			std::cout << desc << "\n";
			return 1;
		}

		std::vector<uint8_t> key;
		std::unique_ptr<OTP> otp;
		// open otp
		try {
			otp.reset(OTP::LoadFromFile(vm["otp"].as<std::string>()));
		}
		catch (std::exception& e) {
			std::cerr << "Failed to open OTP: " << e.what() << std::endl;
			return 1;
		}

		if (vm.count("mlc")) {
			// mlc
			key = otp->GetMLCKey();
		}
		else {
			// usb
			std::unique_ptr<SEEPROM> seeprom;
			try {
				seeprom.reset(SEEPROM::LoadFromFile(vm["seeprom"].as<std::string>()));
			}
			catch (std::exception& e) {
				std::cerr << "Failed to open SEEPROM: " << e.what() << std::endl;
				return 1;
			}
			key = seeprom->GetUSBKey(*otp);
		}
		std::ifstream input_file(vm["inject-file"].as<std::string>(), std::ios::binary | std::ios::in);
		if (input_file.fail()) {
			std::cerr << "Failed to open file to inject" << std::endl;
			return 1;
		}
		input_file.seekg(0, std::ios::end);
		if (static_cast<uint64_t>(input_file.tellg()) > SIZE_MAX) {
			std::cerr << "Error: File to inject too big" << std::endl;
			return 1;
		}
		size_t file_size = static_cast<size_t>(input_file.tellg());
		input_file.seekg(0, std::ios::beg);

		auto device = std::make_shared<FileDevice>(vm["image"].as<std::string>(), 9, false);
		Wfs::DetectSectorsCount(device, key);
		Wfs::DetectSectorSize(device, key);
		auto file = Wfs(device, key).GetFile(vm["inject-path"].as<std::string>());
		if (!file) {
			std::cerr << "Error: Didn't find file " << vm["inject-path"].as<std::string>() << " in wfs" << std::endl;
			return 1;
		}
		if (file_size > file->GetSizeOnDisk()) {
			std::cerr << "Error: File to inject too big (wanted size: " << file_size << " bytes, available size: " << file->GetSizeOnDisk() << ")" << std::endl;
			return 1;
		}
		File::stream stream(file);
		std::vector<char> data(0x2000);
		size_t to_copy = file_size;
		while (to_copy > 0) {
			input_file.read((char*)&*data.begin(), std::min(data.size(), to_copy));
			auto read = input_file.gcount();
			if (read <= 0) {
				std::cerr << "Error: Failed to read file to inject" << std::endl;
				return 1;
			}
			stream.write(&*data.begin(), read);
			to_copy -= static_cast<size_t>(read);
		}
		input_file.close();
		stream.close();
		if (file_size < file->GetSize()) {
			file->Resize(file_size);
		}
		std::cout << "Done!" << std::endl;
	}
	catch (std::exception& e) {
		std::cerr << "Error: " << e.what() << std::endl;
		return 1;
	}
	return 0;
}<|endoftext|>


<commit_before>#include <jni.h>

#include <EGL/egl.h>
#include <GLES/gl.h>

#include <android_native_app_glue.h>

#include <sys/resource.h>

#include "canvas.hpp"
#include "network_epoll.hpp"

#ifdef USE_FREETYPE
#include "text.hpp"
#include <sstream>
#endif

struct UserData
{
	struct android_app* app;

	EGLDisplay display;
	EGLSurface surface;
	EGLContext context;
	EGLint width;
	EGLint height;

	Canvas* canvas;
	NetworkHandler* networkHandler;
};

static const float vertices[][4] = {{-1.f,-1.f,+0.f,+1.f},
                                    {+1.f,-1.f,+1.f,+1.f},
                                    {-1.f,+1.f,+0.f,+0.f},
                                    {+1.f,+1.f,+1.f,+0.f}};

void init(UserData* userData)
{
	static const EGLint attribs[] = {
		EGL_BLUE_SIZE, 8,
		EGL_GREEN_SIZE, 8,
		EGL_RED_SIZE, 8,
		EGL_NONE
	};

	static const EGLint attribList[] = {
		EGL_CONTEXT_CLIENT_VERSION, 1,
		EGL_NONE
	};

	userData->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
	eglInitialize(userData->display, 0, 0);

	EGLConfig config;
	EGLint numConfigs;
	eglChooseConfig(userData->display, attribs, &config, 1, &numConfigs);

	EGLint format;
	eglGetConfigAttrib(userData->display, config, EGL_NATIVE_VISUAL_ID, &format);
	ANativeWindow_setBuffersGeometry(userData->app->window, 0, 0, format);

	userData->surface = eglCreateWindowSurface(userData->display, config, userData->app->window, nullptr);

	userData->context = eglCreateContext(userData->display, config, nullptr, attribList);

	eglMakeCurrent(userData->display, userData->surface, userData->surface, userData->context);

	eglQuerySurface(userData->display, userData->surface, EGL_WIDTH, &userData->width);
	eglQuerySurface(userData->display, userData->surface, EGL_HEIGHT, &userData->height);

	userData->canvas = new Canvas(userData->width, userData->height, new uint32_t[userData->width * userData->height]);
	std::fill_n(userData->canvas->data, userData->canvas->width * userData->canvas->height, 0);

#ifdef USE_FREETYPE
	writeInfoText(*(userData->canvas), 1234);
#endif

	userData->networkHandler = new NetworkHandler(*(userData->canvas), 1234, std::thread::hardware_concurrency());

	glViewport(0, 0, userData->width, userData->height);

	GLuint tex;
	glGenTextures(1, &tex);
	glBindTexture(GL_TEXTURE_2D, tex);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glEnable(GL_TEXTURE_2D);
	glVertexPointer(2, GL_FLOAT, sizeof(vertices[0]), &(vertices[0][0]));
	glTexCoordPointer(2, GL_FLOAT, sizeof(vertices[0]), &(vertices[0][2]));
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}

void draw_frame(UserData* userData)
{
	if (!userData->display) {
		return;
	}

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, userData->canvas->width, userData->canvas->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, userData->canvas->data);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, sizeof(vertices) / sizeof(vertices[0]));
	eglSwapBuffers(userData->display, userData->surface);
}

void terminate(UserData* userData)
{
	if (userData->display != EGL_NO_DISPLAY) {
		eglMakeCurrent(userData->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
		if (userData->context != EGL_NO_CONTEXT) {
			eglDestroyContext(userData->display, userData->context);
			userData->context = EGL_NO_CONTEXT;
		}
		if (userData->surface != EGL_NO_SURFACE) {
			eglDestroySurface(userData->display, userData->surface);
			userData->surface = EGL_NO_SURFACE;
		}
		eglTerminate(userData->display);
		userData->display = EGL_NO_DISPLAY;
	}

	if (userData->canvas) {
		delete userData->networkHandler;
		delete[] userData->canvas->data;
		delete userData->canvas;
		userData->canvas = nullptr;
	}
}

void handle_cmd(struct android_app* app, int32_t cmd)
{
	UserData* userData = (UserData*)app->userData;
	switch (cmd) {
		case APP_CMD_INIT_WINDOW:
			if (userData->app->window) {
				init(userData);
			}
			break;
		case APP_CMD_TERM_WINDOW:
			terminate(userData);
			break;
		case APP_CMD_LOST_FOCUS:
			draw_frame(userData);
			break;
	}
}

extern "C" void android_main(struct android_app* app)
{
	// Raise open files limit because Android makes it difficult to do for end users.
	struct rlimit rlim;
	if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
		rlim.rlim_cur = rlim.rlim_max;
		setrlimit(RLIMIT_NOFILE, &rlim);
	}

	UserData userData;

	memset(&userData, 0, sizeof(userData));
	app->userData = &userData;
	app->onAppCmd = handle_cmd;
	userData.app = app;

	// Make sure glue isn't stripped.
	app_dummy();

	while (!app->destroyRequested) {
		int events;
		struct android_poll_source* source;
		while (ALooper_pollAll(0, nullptr, &events, (void**)&source) >= 0) {
			if (source) {
				source->process(app, source);
			}
		}

		draw_frame(&userData);
	}
}
<commit_msg>Keep screen on in android<commit_after>#include <jni.h>

#include <EGL/egl.h>
#include <GLES/gl.h>

#include <android_native_app_glue.h>
#include <android/window.h>

#include <sys/resource.h>

#include "canvas.hpp"
#include "network_epoll.hpp"

#ifdef USE_FREETYPE
#include "text.hpp"
#include <sstream>
#endif

struct UserData
{
	struct android_app* app;

	EGLDisplay display;
	EGLSurface surface;
	EGLContext context;
	EGLint width;
	EGLint height;

	Canvas* canvas;
	NetworkHandler* networkHandler;
};

static const float vertices[][4] = {{-1.f,-1.f,+0.f,+1.f},
                                    {+1.f,-1.f,+1.f,+1.f},
                                    {-1.f,+1.f,+0.f,+0.f},
                                    {+1.f,+1.f,+1.f,+0.f}};

void init(UserData* userData)
{
	ANativeActivity_setWindowFlags(userData->app->activity, AWINDOW_FLAG_KEEP_SCREEN_ON, 0);

	static const EGLint attribs[] = {
		EGL_BLUE_SIZE, 8,
		EGL_GREEN_SIZE, 8,
		EGL_RED_SIZE, 8,
		EGL_NONE
	};

	static const EGLint attribList[] = {
		EGL_CONTEXT_CLIENT_VERSION, 1,
		EGL_NONE
	};

	userData->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
	eglInitialize(userData->display, 0, 0);

	EGLConfig config;
	EGLint numConfigs;
	eglChooseConfig(userData->display, attribs, &config, 1, &numConfigs);

	EGLint format;
	eglGetConfigAttrib(userData->display, config, EGL_NATIVE_VISUAL_ID, &format);
	ANativeWindow_setBuffersGeometry(userData->app->window, 0, 0, format);

	userData->surface = eglCreateWindowSurface(userData->display, config, userData->app->window, nullptr);

	userData->context = eglCreateContext(userData->display, config, nullptr, attribList);

	eglMakeCurrent(userData->display, userData->surface, userData->surface, userData->context);

	eglQuerySurface(userData->display, userData->surface, EGL_WIDTH, &userData->width);
	eglQuerySurface(userData->display, userData->surface, EGL_HEIGHT, &userData->height);

	userData->canvas = new Canvas(userData->width, userData->height, new uint32_t[userData->width * userData->height]);
	std::fill_n(userData->canvas->data, userData->canvas->width * userData->canvas->height, 0);

#ifdef USE_FREETYPE
	writeInfoText(*(userData->canvas), 1234);
#endif

	userData->networkHandler = new NetworkHandler(*(userData->canvas), 1234, std::thread::hardware_concurrency());

	glViewport(0, 0, userData->width, userData->height);

	GLuint tex;
	glGenTextures(1, &tex);
	glBindTexture(GL_TEXTURE_2D, tex);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glEnable(GL_TEXTURE_2D);
	glVertexPointer(2, GL_FLOAT, sizeof(vertices[0]), &(vertices[0][0]));
	glTexCoordPointer(2, GL_FLOAT, sizeof(vertices[0]), &(vertices[0][2]));
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
}

void draw_frame(UserData* userData)
{
	if (!userData->display) {
		return;
	}

	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, userData->canvas->width, userData->canvas->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, userData->canvas->data);
	glDrawArrays(GL_TRIANGLE_STRIP, 0, sizeof(vertices) / sizeof(vertices[0]));
	eglSwapBuffers(userData->display, userData->surface);
}

void terminate(UserData* userData)
{
	if (userData->display != EGL_NO_DISPLAY) {
		eglMakeCurrent(userData->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
		if (userData->context != EGL_NO_CONTEXT) {
			eglDestroyContext(userData->display, userData->context);
			userData->context = EGL_NO_CONTEXT;
		}
		if (userData->surface != EGL_NO_SURFACE) {
			eglDestroySurface(userData->display, userData->surface);
			userData->surface = EGL_NO_SURFACE;
		}
		eglTerminate(userData->display);
		userData->display = EGL_NO_DISPLAY;
	}

	if (userData->canvas) {
		delete userData->networkHandler;
		delete[] userData->canvas->data;
		delete userData->canvas;
		userData->canvas = nullptr;
	}
}

void handle_cmd(struct android_app* app, int32_t cmd)
{
	UserData* userData = (UserData*)app->userData;
	switch (cmd) {
		case APP_CMD_INIT_WINDOW:
			if (userData->app->window) {
				init(userData);
			}
			break;
		case APP_CMD_TERM_WINDOW:
			terminate(userData);
			break;
		case APP_CMD_LOST_FOCUS:
			draw_frame(userData);
			break;
	}
}

extern "C" void android_main(struct android_app* app)
{
	// Raise open files limit because Android makes it difficult to do for end users.
	struct rlimit rlim;
	if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
		rlim.rlim_cur = rlim.rlim_max;
		setrlimit(RLIMIT_NOFILE, &rlim);
	}

	UserData userData;

	memset(&userData, 0, sizeof(userData));
	app->userData = &userData;
	app->onAppCmd = handle_cmd;
	userData.app = app;

	// Make sure glue isn't stripped.
	app_dummy();

	while (!app->destroyRequested) {
		int events;
		struct android_poll_source* source;
		while (ALooper_pollAll(0, nullptr, &events, (void**)&source) >= 0) {
			if (source) {
				source->process(app, source);
			}
		}

		draw_frame(&userData);
	}
}
<|endoftext|>