text:
/****************************************************************************
**
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the examples of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
**   * Redistributions of source code must retain the above copyright
**     notice, this list of conditions and the following disclaimer.
**   * Redistributions in binary form must reproduce the above copyright
**     notice, this list of conditions and the following disclaimer in
**     the documentation and/or other materials provided with the
**     distribution.
**   * Neither the name of The Qt Company Ltd nor the names of its
**     contributors may be used to endorse or promote products derived
**     from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtWidgets/QApplication>
#include <QtQml/QQmlApplicationEngine>
#include <QtQml/QQmlContext>
#include <qdebug.h>

#define BOOST_DATE_TIME_NO_LIB
//#include "C:/Programming/boost_1_59_0/boost/interprocess/shared_memory_object.hpp"
//#include "boost/interprocess/shared_memory_object.hpp"
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <iostream>

//#include "MyModel.h"
#include "../EOSAI/SharedMemory.h"
#include "GameData.h"
#include "InterprocLoop.h"
#include "PoiListModel.h"

#include < stdio.h >
#include < stdlib.h >

#include <boost/interprocess/sync/interprocess_semaphore.hpp>
using namespace boost::interprocess;

/*
#define MAX_NUMBER_OF_PLAYERS 10+1
struct shared_memory_buffer {
    //writer initialized with one to start
    //reader have to wait
    //shared_memory_buffer() : writer(1), reader(0), value(0){}
    shared_memory_buffer() : lock(1), value(0){}
    //interprocess_semaphore writer, reader;
    interprocess_semaphore lock;

    // Update flags
    int     m_iPlayerNamesUpdate = 0;

    int     m_iGameState = 0; // 0 = no game, 1 = game happening AI processing, 2 = game happening AI not processing
    int     m_iTurn = 0;
    char    m_strPlayerNames[MAX_NUMBER_OF_PLAYERS][20]; // store upto 20 characters

    int     value;
    char    str[100];
    //wchar_t str2[100];
};
*/
/*
#define min(a, b) (((a) < (b)) ? (a) : (b))

//memcpy(data->m_strPlayerNames[1], "Rommel-Rommel-Rommel-Rommel", 20);
//strncpy_s(data->m_strPlayerNames[1], "Rommel-Rommel-Rommel-Rommel", 20);
//strncpy(data->m_strPlayerNames[1], "Rommel-Rommel", 20);
void string_copy(char* dest, const char* src, int iSize)
{
    int iStringLength = strlen(src);
    int iCharactersToCopy = min(iStringLength, iSize - 1);

    memcpy(dest, src, iCharactersToCopy);
    dest[iCharactersToCopy] = 0;
}

class EOSAIAIPlayer
{
    public:
        EOSAIAIPlayer(){ m_strPlayerName[0] = 0; }
        void SetPlayerName( std::string str ){ string_copy(m_strPlayerName, str.c_str(), 20); }
    //private:
        bool  m_bIsActive = false;
        char  m_strPlayerName[20];
        float m_fIntelligence01 = 0.5f;
};

#define MAX_NUMBER_OF_PLAYERS 10+1
class shared_memory_buffer
{
public:
    //writer initialized with one to start
    //reader have to wait
    //shared_memory_buffer() : writer(1), reader(0), value(0){}
    shared_memory_buffer() : lock(1), m_iValue(0){}
    //interprocess_semaphore writer, reader;
    interprocess_semaphore lock;

    //void SetPlayerName(int iPlayer, std::string str){ m_iPlayerNamesUpdate++; string_copy(m_strPlayerNames[iPlayer], str.c_str(), 20); }
    char    m_strEOSAIVersion[20];// = "0.1.333";

    // Update flags
    int     m_iPlayerNamesUpdate = 0;

    int     m_iGameState = 1; // 0 = no game, 1 = game happening AI processing, 2 = game happening AI not processing
    int     m_iTurn = 2;
    EOSAIAIPlayer  m_Players[MAX_NUMBER_OF_PLAYERS];
    //char    m_strPlayerNames[MAX_NUMBER_OF_PLAYERS][20]; // store upto 20 characters

    int     m_iValue;
    char    str[100];
};
*/
bool m_bEOSAISharedMemoryFileExists = false;
QQmlApplicationEngine* g_pQmlApplicationEngine = NULL;
#include "GameMapImage.h"
#include "StatusLine.h"

int main(int argc, char *argv[])
{
    using namespace boost::interprocess;
    GameData gameData;

    //QtQuickControlsApplication app(argc, argv);
    QApplication app(argc, argv);

    //InterprocLoop loop;

    //qmlRegisterType<TextBalloon>(uri, 1, 0, "TextBalloon");
    qmlRegisterType<GameMapImage>("GameMapLib", 1, 0, "GameMapImage");

    //QQmlApplicationEngine* engine = new QQmlApplicationEngine(this);
    //QQmlApplicationEngine engine(QUrl("qrc:/main.qml"));
    //QQmlApplicationEngine engine;
    g_pQmlApplicationEngine = new QQmlApplicationEngine();

    //MyModel model;
    //g_pQmlApplicationEngine->rootContext()->setContextProperty("theModel", &model);
    //
    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_strApplicationHeader", "EOSAI User Interface");
    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_bEOSAISharedMemoryFileExists", false );
    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_strEOSAIVersion", "" );
    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_strEOSAIBuildDate", "" );

    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_strCurrentTurn", "-" );
    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_strOverallProcessingStateColor", "#CCC" );
    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_strOverallProcessingStateText", "Idle" );
    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_strConnectionState", "No AI is currently running." );
    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_strConnectionStatusColor", "#FAA" ); //  "#FF6" : "#FAA"

    //
    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_iNumberOfPlayers", 0 );
    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_iNumberOfPoi", 0 );

    //g_pQmlApplicationEngine->rootContext()->setContextProperty("m_bDisplayCommonData", true );

    //g_pQmlApplicationEngine->rootContext()->setContextProperty("m_strCommonWarningsAndErrorsCount", "(0)" );
    //g_pQmlApplicationEngine->rootContext()->setContextProperty("m_strCommonStatus", "" );
    //g_pQmlApplicationEngine->rootContext()->setContextProperty("m_strCommonWarningsAndErrors", "" );
    //g_pQmlApplicationEngine->rootContext()->setContextProperty("m_strCommonUnitTemplates", "" );
    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_iCommonData_NumberOfUnitTemplates", 0 );
    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_szCommonData_UnitTemplates", "" );
    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_iCommonData_NumberOfTechnologies", 0 );
    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_szCommonData_Technologies", "" );

    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_iCommonData_MapWidth", 0 );
    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_iCommonData_MapHeight", 0 );

    //PoiListModel poiListModel;
    //g_pQmlApplicationEngine->rootContext()->setContextProperty( "poiListModel", &poiListModel );
    g_pQmlApplicationEngine->rootContext()->setContextProperty( "poiListModel", &g_pGameData->m_PoiListModel );

    //
    //StatusLineModel model2;
    //model.m_StatusLineList.append(StatusLine("i-Turn"));
    //model.m_StatusLineList.append(StatusLine("Polar bear", "Large"));
    //model.m_StatusLineList.append(StatusLine("Quoll", "Small"));
    //g_pQmlApplicationEngine->rootContext()->setContextProperty( "statusLineModel", &model2 );
    g_pQmlApplicationEngine->rootContext()->setContextProperty( "statusListModel", &g_pGameData->m_StatusListModel );

    QStringList playerDropdownList;
    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_PlayerDropdownList", QVariant::fromValue(playerDropdownList));

    for( int iPlayer=1; iPlayer<MAX_NUMBER_OF_PLAYERS; iPlayer++ )
    {
        QString str = QString("m_strPlayer%1Type").arg(iPlayer);
        g_pQmlApplicationEngine->rootContext()->setContextProperty(str, "" );
        str = QString("m_strPlayer%1ProcessingColor").arg(iPlayer);
        g_pQmlApplicationEngine->rootContext()->setContextProperty(str, "" );
    }

    QString strStatus;
    //g_pQmlApplicationEngine->rootContext()->setContextProperty("m_szCommonData_Status", "" );
    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_szCommonData_Poi", "" );

    //strStatus  = "Infantry (Class 1)\n";
    //strStatus += "Tank (Class 1)";
    //g_pQmlApplicationEngine->rootContext()->setContextProperty("m_strCommonUnitTemplates", strStatus );

    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_strPlayer1Details", "" );
    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_strPlayer2Details", "" );

    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_bPlayerXIsAI", false );
    g_pQmlApplicationEngine->rootContext()->setContextProperty("m_strPlayerXProcessingStateColor", "" );

    g_pQmlApplicationEngine->load(QUrl(QStringLiteral("qrc:/main.qml")));

    InterprocLoop loop;
    loop.BeginListening();
/*
    //qDebug() << "Test";
    try
    {
        //create a shared memory object.
        //shared_memory_object shm(open_only, "shared_memory",read_write);
        g_pSharedMemoryObject = new shared_memory_object(open_only, "shared_memory",read_write);

        //Map the whole shared memory in this process
        //mapped_region region(shm,read_write);
        //mapped_region region( *g_pSharedMemoryObject, read_write );
        g_pMappedRegion = new mapped_region( *g_pSharedMemoryObject, read_write );

        //get the region address
        //void* addr = region.get_address();
        void* pAddr = g_pMappedRegion->get_address();

        //Obtain the shared structure
        SharedMemoryBuffer* data = static_cast<SharedMemoryBuffer*>(pAddr);

        engine.rootContext()->setContextProperty("m_bEOSAISharedMemoryFileExists", true );
        engine.rootContext()->setContextProperty("m_strEOSAIVersion", data->m_strEOSAIVersion );

        int iPass=0;

        //while(true)
        {
            // If "reader" is 0, wait. If "reader" is 1, then continue (and decrement the number).
            //wait until a number gets available
            //data->reader.wait();
            // If "lock" is 0, wait. If "lock" is 1, then continue (and decrement the number).
            data->lock.wait();

           std::wstring testStr2 = L"testStr2❤☀☆☂☻♞☯☭☢";
           //std::wstring testStr2 = L"testStr2";
           //std::wstring str2 = data->str2;

           //std::string strPlayer1Name = data->m_strPlayerNames[1];

           //print the original value
           //qDebug() << i << " Original Value: " << data->value << " " << data->str << " " << data->str2[0] << "," << data->str2[1] << " " << *(data->str2);
           //qDebug() << i << " Original Value: " << data->value << " " << data->str << " " << " " << str2.c_str() << "/" << testStr2;

           // Output: "286  Original Value:  63   Brit3     0x564c8a8 / 0x34c0278"
           //qDebug() << i << " Original Value: " << data->value << " " << data->str << " " << " " << str2.c_str() << "/" << testStr2.c_str();

           qDebug() << iPass
                    << " data->m_strEOSAIVersion: " << data->m_strEOSAIVersion
                    << " data->m_iPlayerNamesUpdate: " << data->m_iPlayerNamesUpdate
                    << " data->m_iGameState: " << data->m_iGameState
                    << " data->m_iTurn: " << data->m_iTurn;
                    //<< " Player1Name:" << strPlayer1Name.c_str()
                    //<< " Player2Name:" << data->m_strPlayerNames[2]
                    //<< " data->m_iValue: " << data->m_iValue
                    //<< " data->str: " << data->str;

           for( int iPlayer=0; iPlayer<MAX_NUMBER_OF_PLAYERS; iPlayer++ )
           {
               if( data->m_Players[iPlayer].m_ePlayerType == AIPlayer )
               {
                   qDebug() << "   Player" << iPlayer << ": " << data->m_Players[iPlayer].m_strPlayerName;
                   qDebug() << "     Intelligence: " << data->m_Players[iPlayer].m_fIntelligence01;
                   qDebug() << "     ProcessingState: " << data->m_Players[iPlayer].GetProcessingStateText();
               }
               if( data->m_Players[iPlayer].m_ePlayerType == HumanPlayer )
               {
                   qDebug() << "   Player" << iPlayer << ": " << data->m_Players[iPlayer].m_strPlayerName;
                   qDebug() << "     Intelligence" << ": Human";
               }
           }

           //std::cout << i << " Original Value: " << data->value << " " << data->str << "\n";
           //std::cout << "..a  " << str2.c_str() << "\n";
           std::wcout << "..b  " << testStr2 << "\n"; //  L"testStr2❤☀☆☂☻♞☯☭☢"; -> testStr2â¤â..a
           //std::cout << "  str: " << data->str << "\n";
           iPass++;

           //create the sqrt of the original value
           //data->value = sqrt(data->value);
           //data->value = data->str;

           //writer can print sqrt
           // Increment the "writer" value. The other process will handle the data if "writer" is set to 1.
           //data->writer.post();
           // Increment the "lock" value. The other process will handle the data if "lock" is set to 1.
           data->lock.post();
        }
    }
    catch (interprocess_exception e)
    {
        qDebug() << "Exception";
        //std::cout << "Exception";
        const char* pWhat = e.what();
        //int g = 0;
        qDebug() << "Exception pWhat=" << pWhat;

        m_bEOSAISharedMemoryFileExists = false;
        engine.rootContext()->setContextProperty("m_bEOSAISharedMemoryFileExists", false );
    }
*/
/*
#ifdef DO_NOT_COMPILE
    try
    {
        //engine.rootContext()->setContextProperty("m_strApplicationHeader", "childContext");
        shared_memory_object shm (open_only, "EOSAISharedMemory", read_only); // "The system cannot find the file specified."

        //qDebug() << "ChildProcess-2";

        //engine.rootContext()->setContextProperty("m_strApplicationHeader", "childContext-2");
        //qDebug() << "ChildProcess-3";

        //Map the whole shared memory in this process
        mapped_region region(shm, read_only);
        //qDebug() << "ChildProcess-EverythingGood";

        //Check that memory was initialized to 1
        char *mem = static_cast<char*>(region.get_address());
        int iValue = mem[0];

        QString str = QString("x%1y").arg( iValue );
        engine.rootContext()->setContextProperty("m_strApplicationHeader", "EOSAI User Interface-"+str );

        m_bEOSAISharedMemoryFileExists = true;
        engine.rootContext()->setContextProperty("m_bEOSAISharedMemoryFileExists", true );
    }
    catch (interprocess_exception e)
    {
        qDebug() << "Exception";
        //std::cout << "Exception";
        const char* pWhat = e.what();
        int g = 0;
        qDebug() << "Exception pWhat=" << pWhat;

        m_bEOSAISharedMemoryFileExists = false;
        engine.rootContext()->setContextProperty("m_bEOSAISharedMemoryFileExists", false );
    }
#endif

#ifdef DO_NOT_COMPILE
    if(argc == 1){  //Parent process
        qDebug() << "ParentProcess";
        engine.rootContext()->setContextProperty("m_strApplicationHeader", "parentContext");
       //Remove shared memory on construction and destruction
       struct shm_remove
       {
          shm_remove() { shared_memory_object::remove("EOSAISharedMemory"); }
          ~shm_remove(){ shared_memory_object::remove("EOSAISharedMemory"); }
       } remover;

       //Create a shared memory object.
       shared_memory_object shm (create_only, "EOSAISharedMemory", read_write);

       //Set size
       shm.truncate(1000);

       //Map the whole shared memory in this process
       mapped_region region(shm, read_write);

       //Write all the memory to 1
       std::memset(region.get_address(), 3, region.get_size());

       //Launch child process
       std::string s(argv[0]); s += " child ";
       if(0 != std::system(s.c_str()))
       {
          return 1;
       }
    }
    else{
        qDebug() << "ChildProcess-1";
        engine.rootContext()->setContextProperty("m_strApplicationHeader", "childContext");
       //Open already created shared memory object.
       shared_memory_object shm (open_only, "EOSAISharedMemory", read_only);

       engine.rootContext()->setContextProperty("m_strApplicationHeader", "childContext-2");

       //Map the whole shared memory in this process
       mapped_region region(shm, read_only);
       qDebug() << "ChildProcess-EverythingGood";

       //Check that memory was initialized to 1
       char *mem = static_cast<char*>(region.get_address());
       int iValue = mem[0];

       QString str = QString("x%1y").arg( iValue );
       engine.rootContext()->setContextProperty("m_strApplicationHeader", "childContext-EverythingGood-"+str );

       //for(std::size_t i = 0; i < region.get_size(); ++i)
       //{
       //    QString str = QString("x%1y").arg( *mem );
       //    engine.rootContext()->setContextProperty("m_strApplicationHeader", "childContext-EverythingGood-"+str );
       //   if(*mem++ != 1)
       //   {
       //      return 1;   //Error checking memory
       //   }
       //}

       //engine.rootContext()->setContextProperty("m_strApplicationHeader", "childContext-EverythingGood");
    }
#endif
*/

    /*
    // Shared Memory
    try
    {
        qDebug() << "Getting shared memory";
        //std::cout << "Getting shared memory";

        //Open already created shared memory object.
        shared_memory_object shm(open_only, "Global\MySharedMemory", read_only);
        //shared_memory_object shm(open_only, "EOSAISharedMemory", read_only);
        qDebug() << "Getting shared memory-2";

        //Map the whole shared memory in this process
        mapped_region region(shm, read_only);
        qDebug() << "Getting shared memory-3";

        //Check that memory was initialized to 1
        char *mem = static_cast<char*>(region.get_address());
        for (std::size_t i = 0; i < region.get_size(); ++i)
        {
            if (*mem++ != 1)
            {
                return 1;   //Error checking memory
            }
        }
    }
    catch (interprocess_exception e)
    {
        qDebug() << "Exception";
        //std::cout << "Exception";
        const char* pWhat = e.what();
        int g = 0;
        qDebug() << "Exception pWhat=" << pWhat;
    }
    */

    return app.exec();
}

max_stars_repo_name: BritClousing/EOSAI

max_issues_repo_name: BritClousing/EOSAI

max_forks_repo_name: BritClousing/EOSAI


text:
/*
 * ============================================================================
 *
 *       Filename:  test_graphcontainer.cc
 *
 *         Author:  Prashant Pandey (), ppandey2@cs.cmu.edu
 *   Organization:  Carnegie Mellon University
 *
 * ============================================================================
 */

#include <stdlib.h>
#include <assert.h>

#include <iostream>
#include <string>
#include <openssl/rand.h>

#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>

#include "graph.h"

using namespace variantstore;
std::shared_ptr<spdlog::logger> console;

int test_correctness(const Graph& graph, std::unordered_map<uint32_t,
											std::unordered_set<uint32_t>>& adj_list,
											std::set<std::pair<uint32_t, uint32_t>>& edge_list) {
	// check graph correctness by iterating over @adj_list
	for (auto it = adj_list.begin(); it != adj_list.end(); ++it) {
		Graph::vertex_set neighbors = graph.out_neighbors(it->first);

		if (it->second != neighbors) {
			std::cout << it->first << " - ";
			std::cout << '\n';
			for (auto const n : neighbors) {
				std::cout << n << " ";
			}

			std::cout << '\n';
			for (auto const n : it->second) {
				std::cout << n << " ";
			}
			std::cout << '\n';
			ERROR("correctness test failed!");
			return EXIT_FAILURE;
		}
	}
	PRINT("Correctness check passed: by iterating over @adj_list!");

	// check graph correctness by iterating over Graph::VertexIterator
	Graph::VertexIterator vitr = graph.begin_vertices();
	while (!vitr.done()) {
		Graph::vertex v = *vitr;
		Graph::vertex_set neighbors = graph.out_neighbors(v);

		if (adj_list[v] != neighbors) {
			std::cout << v << " - ";
			std::cout << '\n';
			for (auto const n : neighbors) {
				std::cout << n << " ";
			}

			std::cout << '\n';
			for (auto const n : adj_list[v]) {
				std::cout << n << " ";
			}
			std::cout << '\n';
			ERROR("correctness test failed!");
			return EXIT_FAILURE;
		}
		//assert(adj_list[v] == neighbors);
		++vitr;
	}
	PRINT("Correctness check passed: by iterating over Graph::VertexIterator!");

	// check graph correctness by iterating over @edge_list
	for (auto it = edge_list.begin(); it != edge_list.end(); ++it) {
		if (!graph.is_edge(*it)) {
			PRINT("Graph edge: " << (*it).first << " - " << (*it).second);
			ERROR("correctness test failed!");
			return EXIT_FAILURE;
		}
	}
	PRINT("Correctness check passed: by iterating over @edge_list!");

	// check graph correctness by iterating over Graph::EdgeIterator
	Graph::EdgeIterator eitr = graph.begin_edges();
	while(!eitr.done()) {
		Graph::edge e = *eitr;
		if (edge_list.find(e) == edge_list.end()) {
			PRINT("Graph edge: " << e.first << " - " << e.second);
			ERROR("correctness test failed!");
			return EXIT_FAILURE;
		}
		++eitr;
	}
	PRINT("Correctness check passed: by iterating over Graph::EdgeIterator!");

	return EXIT_SUCCESS;
}

/*
 * ===  FUNCTION  =============================================================
 *         Name:  main
 *  Description:
 * ============================================================================
 */
	int
main ( int argc, char *argv[] )
{
	if (argc < 2) {
		fprintf(stderr, "Please specify the log of the number of slots in the CQF.\n");
		exit(1);
	}
	uint64_t qbits = atoi(argv[1]);
	uint64_t nslots = (1ULL << qbits);
	uint64_t nvals = 95*nslots/100;
	//nslots *= 16;

	// create a typedef for the Graph type
	//typedef boost::adjacency_list<boost::setS, boost::vecS, boost::directedS>
		//BoostGraph;

	console = spdlog::default_logger();
	Graph graph(nslots);
	//BoostGraph bg(nslots);

	/* Generate random values */
	uint32_t *vals = (uint32_t*)malloc(nvals*sizeof(vals[0]));
	RAND_bytes((unsigned char *)vals, sizeof(*vals) * nvals);
	for (uint32_t i = 0; i < nvals; i++) {
		vals[i] = (1 * vals[i]) % nvals + 1;
	}

	srand(time(NULL));
	// to check the correctness of our graph implementation.
	std::unordered_map<uint32_t, std::unordered_set<uint32_t>> adj_list;
	std::set<std::pair<uint32_t, uint32_t>> edge_list;
	for (uint32_t i = 0; i < nvals; i++) {
		uint32_t key = vals[i];
		uint32_t nedges = rand() % 4 + 1;		// up to 4 outgoing edges from a node

		//if (nedges > 1)
			//PRINT("Higher degree node: " << key << " " << nedges);
		//else if (nedges == 1)
			//PRINT("Single degree node: " << key);

		std::unordered_set<uint32_t> vec;
		for (uint32_t j = 0; j < nedges; j++) {
			uint32_t tonode = vals[rand() % nvals];
			graph.add_edge(key, tonode);
			//boost::add_edge(key, tonode, bg);
			vec.insert(tonode);
			edge_list.insert(std::make_pair(key, tonode));
		}
		adj_list[key].merge(vec);
	}

	PRINT("Num vertices: " << graph.get_num_vertices());
	PRINT("Num edges: " << graph.get_num_edges());

	if (test_correctness(graph, adj_list, edge_list) == EXIT_FAILURE)
		return EXIT_FAILURE;

	PRINT("Serializing graph");
	graph.serialize("./ser");

	PRINT("Loading graph from disk");
	Graph file_graph("./ser");

	PRINT("Testing correctness for file graph");
	if (test_correctness(file_graph, adj_list, edge_list) == EXIT_FAILURE)
		return EXIT_FAILURE;

	return EXIT_SUCCESS;
}				/* ----------  end of function main  ---------- */

ext: cc

max_stars_repo_name: Kingsford-Group/variantstore

max_issues_repo_name: Kingsford-Group/variantstore

max_forks_repo_name: Kingsford-Group/variantstore


text:
// system
#include <sstream>

// library headers
#include <gtest/gtest.h>
#include <boost/filesystem.hpp>
#include <XdgUtils/DesktopEntry/DesktopEntry.h>

// local
#include <appimage/utils/ResourcesExtractor.h>

using namespace appimage::utils;
using namespace XdgUtils::DesktopEntry;
namespace bf = boost::filesystem;

TEST(TestResourcesExtractor, getDesktopEntryPath) {
    appimage::core::AppImage appImage(TEST_DATA_DIR "appimagetool-x86_64.AppImage");
    ResourcesExtractor extractor(appImage);

    auto desktopEntryPath = extractor.getDesktopEntryPath();

    ASSERT_EQ(desktopEntryPath, "appimagetool.desktop");
}

TEST(TestResourcesExtractor, getIconPaths) {
    /* We need to edit the echo AppImage to properly tests this feature */

//    appimage::core::AppImage appImage(TEST_DATA_DIR "Echo-x86_64.AppImage");
//    ResourcesExtractor extractor(appImage);
//
//    auto iconFilePaths = extractor.getIconFilePaths("utilities-terminal");
//
//    const std::vector<std::string> expected = {"usr/share/icons/hicolor/scalable/utilities-terminal.svg"};
//    ASSERT_EQ(iconFilePaths,  expected);
}

TEST(TestResourcesExtractor, extractEntriesTo) {
    appimage::core::AppImage appImage(TEST_DATA_DIR "Echo-x86_64.AppImage");
    ResourcesExtractor extractor(appImage);

    auto tempFile = bf::temp_directory_path() / boost::filesystem::unique_path("libappimage-%%%%-%%%%-%%%%-%%%%");;
    std::map<std::string, std::string> map = {{".DirIcon", tempFile.string()}};
    extractor.extractTo(map);

    ASSERT_TRUE(bf::exists(tempFile));
    ASSERT_TRUE(bf::file_size(tempFile) > 0);

    bf::remove(tempFile);
}

TEST(TestResourcesExtractor, extractOne) {
    appimage::core::AppImage appImage(TEST_DATA_DIR "Echo-x86_64.AppImage");
    ResourcesExtractor extractor(appImage);

    auto fileData = extractor.extract("echo.desktop");

    ASSERT_FALSE(fileData.empty());
    ASSERT_THROW(extractor.extract("missing_file"), appimage::core::PayloadIteratorError);
}

TEST(TestResourcesExtractor, extractMany) {
    appimage::core::AppImage appImage(TEST_DATA_DIR "Echo-x86_64.AppImage");
    ResourcesExtractor extractor(appImage);

    auto filesData = extractor.extract(std::vector<std::string>{"echo.desktop", ".DirIcon"});

    ASSERT_FALSE(filesData.empty());
    for (const auto& itr: filesData)
        ASSERT_FALSE(itr.second.empty());

    ASSERT_THROW(extractor.extract(std::vector<std::string>{"missing_file"}), appimage::core::PayloadIteratorError);
}

ext: cpp

max_stars_repo_name: srevinsaju/libappimage


text:
#include "CEGO/concurrentqueue.h"
#include "CEGO/CEGO.hpp"
#include <Eigen/Dense>
#if defined(PYBIND11)
#include <pybind11/embed.h>
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
#include <pybind11/stl.h>
#include <pybind11/eigen.h>
namespace py = pybind11;
#include <atomic>
#include <fstream>

std::atomic_size_t Ncalls(0);

inline bool ValidNumber(double x)
{
    // Idea from http://www.johndcook.com/IEEE_exceptions_in_cpp.html
    return (x <= DBL_MAX && x >= -DBL_MAX);
};

class Antoine {
public:
    double m_Tt, m_Tc, m_pc, m_Dc;
    Eigen::ArrayXd m_LHS, m_T;
    std::string m_name;
    Antoine(const std::string &name) :  m_name(name)
    {
        py::module ct = py::module::import("ctREFPROP.ctREFPROP"); // Import cytpes wrapper of REFPROP dll
        std::string RPPREFIX(getenv("RPPREFIX"));
        auto R = ct.attr("REFPROPFunctionLibrary")(RPPREFIX + "/REFPRP64.DLL");
        auto version = R.attr("RPVersion")().cast<std::string>();
        auto setup_info = R.attr("SETUPdll")(1, name+".FLD", "HMX.BNC","DEF");
        if (setup_info.attr("ierr").cast<int>() != 0) {
            throw std::invalid_argument( setup_info.attr("herr").cast<std::string>() );
        }
        auto info = R.attr("INFOdll")(1);
        m_pc = info.attr("Pc").cast<double>();
        m_Tc = info.attr("Tc").cast<double>();
        m_Tt = info.attr("Ttrp").cast<double>();
        m_Dc = info.attr("Dc").cast<double>();

        std::size_t N = 300;
        m_LHS.resize(N);
        m_T.resize(N);
        std::vector<double> z(1,1);
        Eigen::ArrayXd Tvec = Eigen::ArrayXd::LinSpaced(N, m_Tc*0.999, 0.99*m_Tt);
        Eigen::Index j = 0;

        for (auto i = 0; i < Tvec.size(); ++i){
            auto o = R.attr("TQFLSHdll")(Tvec[i], 1, &z, 0);
            int ierr = o.attr("ierr").cast<int>();

            if (ierr <= 100){
                double p = o.attr("P").cast<double>();
                if (!ValidNumber(p)){ continue; }
                m_LHS(j) = p;
            }
            m_T(j) = Tvec(i);
            j++;
        }
        m_LHS.conservativeResize(j);
        m_T.conservativeResize(j);
    }
    void plot_curve(){
        #if defined(PYBIND11)
        py::module plt = py::module::import("matplotlib.pyplot"); // Import matplotlib
        plt.attr("plot")(1/m_T, m_LHS);
        plt.attr("show")();
        #else
        std::cout << "No pybind11 support, so no plots\n";
        #endif
    }
    Eigen::ArrayXd eval_RHS(const Eigen::ArrayXd& T, const Eigen::ArrayXd &c) {
        return c[3]*pow(10,c[0]-c[1]/(c[2]+T));
    }
    double objective(const CEGO::AbstractIndividual *pind) {
        const std::vector<double> &c = static_cast<const CEGO::NumericalIndividual<double>*>(pind)->get_coefficients();
        return objective(Eigen::Map<const Eigen::ArrayXd>(&(c[0]), c.size()) );
    }
    double objective(const Eigen::ArrayXd &c) {
        Ncalls++;
        double ssq = ((eval_RHS(m_T, c) - m_LHS)/m_LHS).square().sum();
        return ssq;
    }
    void plot_trace(const std::vector<double> &best_costs) {
        #if defined(PYBIND11)
        py::module plt = py::module::import("matplotlib.pyplot"); // Import matplotlib
        plt.attr("plot")(best_costs);
        plt.attr("show")();
        #else
        std::cout << "No pybind11 support, so no plots\n";
        #endif
    }
    const Eigen::ArrayXd &get_T(){ return m_T; }
};

int main()
{
    py::scoped_interpreter interp{};
    std::srand((unsigned int)time(0));

    // Construct the bounds
    std::vector<CEGO::Bound> bounds;
    for (auto i = 0; i < 3; ++i) {
        bounds.push_back(CEGO::Bound(std::pair<double, double>(-10000, 10000)));
    }
    for (auto i = 0; i < 1; ++i) {
        bounds.push_back(CEGO::Bound(std::pair<double, double>(0.1,100)));
    }
    Antoine rp("PROPANE");
    //rp.plot_curve();

    CEGO::CostFunction cost_wrapper = std::bind((double (Antoine::*)(const CEGO::AbstractIndividual *)) &Antoine::objective, &rp, std::placeholders::_1);
    auto Nlayers = 5;
    auto layers = CEGO::Layers<double>(cost_wrapper, bounds.size(), 2000, Nlayers, 3);
    layers.parallel = false;
    layers.set_bounds(bounds);

    auto flags = layers.get_evolver_flags();
    flags["Nelite"] = 2;
    flags["Fmin"] = 0.5;
    flags["Fmax"] = 1.0;
    flags["CR"] = 0.7;
    layers.set_evolver_flags(flags);

    std::vector<double> best_costs;
    std::vector<std::vector<double> > objs;
    double VTR = 1e-6, best_cost = 999999.0;
    auto startTime = std::chrono::system_clock::now();
    for (auto counter = 0; counter < 3000; ++counter) {
        layers.do_generation();

        // Store the best objective function in each layer
        std::vector<double> oo;
        for (auto &&cost_coefficients : layers.get_best_per_layer()) {
            oo.push_back(std::get<0>(cost_coefficients));
        }
        objs.push_back(oo);

        // For the overall best result, print it, and write JSON to file
        auto best_layer = layers.get_best();
        best_cost = std::get<0>(best_layer); best_costs.push_back(best_cost);
        if (counter % 50 == 0) {
            std::cout << counter << ": best: " << best_cost << "\n ";// << CEGO::vec2string(best_coeffs) << "\n";
        }
        if (best_cost < VTR){ break; }
    }
    auto best_layer = layers.get_best();
    auto c = std::get<1>(best_layer);
    auto endTime = std::chrono::system_clock::now();
    double elap = std::chrono::duration<double>(endTime - startTime).count();

    // Get the results stored in the thread-safe queue
    std::vector<CEGO::Result> results; Eigen::MatrixXd mat;
    results = layers.get_results();

    std::cout << "cbest" << Eigen::Map<Eigen::ArrayXd>(&(c[0]), c.size()) << std::endl;

    std::cout << "run:" << elap << " s\n";
    std::cout << "NFE:" << Ncalls << std::endl;
}

#else

int main(){
    std::cout << "Due to lack of pybind11 support, this file cannot be run\n";
}

#endif

ext: cxx

max_stars_repo_name: jedbrown/CEGO

max_issues_repo_name: jedbrown/CEGO

max_forks_repo_name: jedbrown/CEGO


text:
#pragma once
#include <type_traits>
#include <iterator>
#include <utility>  // for std::pair
#include <tuple>    // for std::tie

#include <ext/range/range_traits.hpp>
#include <boost/range/as_literal.hpp>

/// функции интерполяции строк подобно unix shell оболочкам,
/// но допустимые символы обрабатываются несколько упрощенно
/// ${var} для имени допустимы любые символы
/// $var допустимы только 0-9a-zA-Z_
///  $, $0, $_, $var
/// поддерживается escape'инг \$var, $var\ cont, ${var\}}
///
/// пример использование:
///     std::map<string, string> dict = {{"name", "bond"}, {"date", "friday"}};
///     string res = ext::interpolate("my name is %name and this is test on %date val%", dict);
///
/// Dictionary - класс словаря:
///   * должен иметь как минимум key_type typedef - тип ключа,
///     некоторый строковый stl-like container совместимый с входной строкой
///   * должна быть глобальная функция dictionary_find:
///     auto res = dictionary_find(dict, key);
///     результат - некоторый тип:
///       - конвертируемый в bool, если данные по ключу найдены - true, иначе false
///       - при разыменование - возвращает некий string range того же типа что и входной текст
///         например, это может быть указатель(как простой так и smart), boost::optional
///
/// входной range любой boost::range совместимый range символов.
/// Поддерживаемые типы символов: char/char16_t/char32_t/wchar_t.
/// выходной параметр итератор или контейнер.
/// для контейнера должны быть специализированна функция ext::append.

namespace ext
{
	template <class StdMapType, class Key>
	const typename StdMapType::mapped_type * dictionary_find(const StdMapType & map, const Key & key);

	namespace interpolate_internal
	{
		/// карта допустимых символов для переменных в не расширенном формате.
		/// это 0-9 a-z A-Z _
		extern const bool key_allowed_ascii_chars[128];

		struct key_start
		{
			template <class Char>
			inline bool operator()(Char ch) const { return ch == '$'; }
		};

		struct extended_key_stop
		{
			template <class Char>
			inline bool operator()(Char ch) const { return ch == '}'; }
		};

		struct key_stop
		{
			template <class Char,
				typename std::enable_if<std::is_signed<Char>::value, int>::type = 0
			>
			inline bool operator()(Char ch) const
			{
				return operator()(typename std::make_unsigned<Char>::type(ch));
			}

			template <class Char,
				typename std::enable_if< ! std::is_signed<Char>::value, int>::type = 0
			>
			inline bool operator()(Char ch) const
			{
				return ch > 127 || !key_allowed_ascii_chars[ch];
			}
		};

		template <class Iterator, class OutputIterator, class StopFunc>
		std::pair<Iterator, OutputIterator> copy_escaped_until(Iterator first, Iterator last, OutputIterator out, StopFunc stop)
		{
			for (; first != last; ++first, ++out)
			{
				auto ch = *first;
				switch (ch)
				{
				// экранирующий символ, пока просто копируем следующий как есть.
				// при желании, обработку можно будет расширить
				case '\\':
					if (first == last) goto exit;
					*out = *++first;
					continue;

				default:
					if (stop(ch)) goto exit;
					*out = ch;
				}
			}

		exit: return {first, out};
		}

		template <class Iterator, class OutIterator, class Dictionary>
		OutIterator interpolate_into_iterator(Iterator first, Iterator last, OutIterator out, const Dictionary & dict)
		{
			typedef typename std::iterator_traits<Iterator>::value_type char_type;
			typedef typename Dictionary::key_type key_type;

			key_type key;
			for (;;)
			{
				// ищем ключ, копируем строку
				std::tie(first, out) = copy_escaped_until(first, last, out, key_start());
				// не нашли символ ключа -> скопировали весь шаблон
				if (first == last)
					return out;

				++first;
				// после символа ключа - конец строки. копируем символ и выходим
				if (first == last) {
					*out++ = '$';
					return out;
				}

				bool extended;
				ext::clear(key);
				auto keyIt = std::back_inserter(key);
				// расширенный ключ
				if (*first == '{')
				{
					extended = true;
					std::tie(first, std::ignore) = copy_escaped_until(++first, last, keyIt, extended_key_stop());
					// ключ не закрыт
					if (first == last)
					{
						*out++ = '$'; *out++ = '{';
						out = std::copy(std::begin(key), std::end(key), out);
						return out;
					}

					++first; // съедаем '}'
				} // обычный ключ
				else
				{
					extended = false;
					std::tie(first, std::ignore) = copy_escaped_until(first, last, keyIt, key_stop());

					// $<space> - копируем символ и идем в начало алгоритма
					if (boost::empty(key)) {
						*out++ = '$';
						continue;
					}
				}

				/// выполняем подстановку
				using ext::dictionary_find;
				auto val = dictionary_find(dict, key);
				if (val)
					out = std::copy(boost::const_begin(*val), boost::const_end(*val), out);
				else
				{   // ключ 'отклонено' - копируем имя ключа как есть из шаблона
					*out++ = '$';
					if (extended) *out++ = '{';
					out = std::copy(boost::const_begin(key), boost::const_end(key), out);
					if (extended) *out++ = '}';
				}
			}
		}

		template <class Iterator, class Containter, class Dictionary>
		void interpolate_into_container(Iterator first, Iterator last, Containter & cont, const Dictionary & dict)
		{
			typedef typename std::iterator_traits<Iterator>::value_type char_type;
			typedef typename Dictionary::key_type key_type;

			key_type key;
			auto outit = std::back_inserter(cont);
			for (;;)
			{
				// ищем ключ, копируем строку
				std::tie(first, outit) = copy_escaped_until(first, last, outit, key_start());
				// не нашли символ ключа -> скопировали весь шаблон
				if (first == last)
					return;

				++first;
				// после символа ключа - конец строки. копируем символ и выходим
				if (first == last) {
					*outit++ = '$';
					return;
				}

				bool extended;
				ext::clear(key);
				auto keyIt = std::back_inserter(key);
				// расширенный ключ
				if (*first == '{')
				{
					extended = true;
					std::tie(first, std::ignore) = copy_escaped_until(++first, last, keyIt, extended_key_stop());
					// ключ не закрыт
					if (first == last)
					{
						*outit++ = '$'; *outit++ = '{';
						outit = std::copy(std::begin(key), std::end(key), outit);
						return;
					}

					++first; // съедаем '}'
				} // обычный ключ
				else
				{
					extended = false;
					std::tie(first, std::ignore) = copy_escaped_until(first, last, keyIt, key_stop());

					// $<space> - копируем символ и идем в начало алгоритма
					if (boost::empty(key)) {
						*outit++ = '$';
						continue;
					}
				}

				/// выполняем подстановку
				using ext::dictionary_find;
				auto val = dictionary_find(dict, key);
				if (val)
					ext::append(cont, boost::const_begin(*val), boost::const_end(*val));
				else
				{   // ключ 'отклонен' - копируем имя ключа как есть из шаблона
					*outit++ = '$';
					if (extended) *outit++ = '{';
					ext::append(cont, boost::const_begin(key), boost::const_end(key));
					if (extended) *outit++ = '}';
				}
			}
		}
	} // namespace InterpolateInternal

	/// поиск в карте словаре по умолчанию,
	/// может быть специализированно/перегружено, в том числе в родном namespace'е класса -
	/// тем самым предоставляя поиск в словаре для interpolate функций
	template <class StdMapType, class Key>
	const typename StdMapType::mapped_type * dictionary_find(const StdMapType & map, const Key & key)
	{
		auto it = map.find(key);
		return it != map.end() ? &it->second : nullptr;
	}

	template <
		class Range, class Dictionary, class OutIter,
		typename std::enable_if<!ext::is_range<OutIter>::value, int>::type = 0
	>
	inline OutIter interpolate(const Range & text, const Dictionary & dict, OutIter dest)
	{
		static_assert(std::is_same<char, typename boost::range_value<Range>::type>::value, "only char currently supported");
		auto textlit = boost::as_literal(text);
		return interpolate_internal::interpolate_into_iterator
			(boost::const_begin(textlit), boost::const_end(textlit), dest, dict);
	}

	template <
		class Range, class Dictionary, class Container,
		typename std::enable_if<ext::is_range<Container>::value, int>::type = 0
	>
	inline void interpolate(const Range & text, const Dictionary & dict, Container & outc)
	{
		static_assert(std::is_same<char, typename boost::range_value<Range>::type>::value, "only char currently supported");
		auto textlit = boost::as_literal(text);
		interpolate_internal::interpolate_into_container
			(boost::const_begin(textlit), boost::const_end(textlit), outc, dict);
	}

	template <class Range, class Dictionary>
	auto interpolate(const Range & text, const Dictionary & dict) ->
	                 std::basic_string<typename boost::range_value<Range>::type>
	{
		std::basic_string<typename boost::range_value<Range>::type> res;
		interpolate(text, dict, res);
		return res;
	}

	template <
		class CharT, class CharTraits, class Allocator,
		class Dictionary
	>
	auto interpolate(const std::basic_string<CharT, CharTraits, Allocator> & text,
	                 const Dictionary & dict) -> std::basic_string<CharT, CharTraits, Allocator>
	{
		std::basic_string<CharT, CharTraits, Allocator> res;
		interpolate(text, dict, res);
		return res;
	}
}

ext: hpp

max_stars_repo_name: dmlys/extlib

max_issues_repo_name: dmlys/extlib

max_forks_repo_name: dmlys/extlib


text:
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------

#include "stdafx.h"

#include <boost/test/unit_test.hpp>
#include "Common/boost-taef.h"
#include "Store/test/Common.Test.h"

using namespace Api;
using namespace Common;
using namespace ServiceModel;
using namespace Reliability::ReplicationComponent;
using namespace std;

#define VERIFY( condition, fmt, ...) \
    { \
    wstring tmp; \
    StringWriter writer(tmp); \
    writer.Write(fmt, __VA_ARGS__); \
    VERIFY_IS_TRUE( condition, tmp.c_str() ); \
} \

namespace Store
{
    StringLiteral const TraceComponent("HealthTrackerTest");

    class ComMockPartition
        : public IFabricStatefulServicePartition3
        , private Common::ComUnknownBase
    {
        BEGIN_COM_INTERFACE_LIST(ComMockPartition)
            COM_INTERFACE_ITEM(IID_IUnknown,IFabricStatefulServicePartition3)
            COM_INTERFACE_ITEM(IID_IFabricStatefulServicePartition,IFabricStatefulServicePartition)
            COM_INTERFACE_ITEM(IID_IFabricStatefulServicePartition1,IFabricStatefulServicePartition1)
            COM_INTERFACE_ITEM(IID_IFabricStatefulServicePartition2,IFabricStatefulServicePartition2)
            COM_INTERFACE_ITEM(IID_IFabricStatefulServicePartition3, IFabricStatefulServicePartition3)
        END_COM_INTERFACE_LIST()

    public:

        virtual ~ComMockPartition() {};

    public: // Test

        void ValidateReportCount(long expectedCount)
        {
            auto count = healthReportCount_.load();
            bool success = (count == expectedCount);

            if (!success)
            {
                auto msg = wformatString("expected={0} actual={1}", expectedCount, count);
                Trace.WriteError(TraceComponent, "{0}", msg);
                VERIFY(success, "{0}", msg);
            }
        }

    public:

        // IFabricStatefulServicePartition3

        virtual HRESULT ReportReplicaHealth2(const FABRIC_HEALTH_INFORMATION * publicInfo, const FABRIC_HEALTH_REPORT_SEND_OPTIONS *) override
        {
            HealthInformation internalInfo;
            auto error = internalInfo.FromCommonPublicApi(*publicInfo);
            VERIFY(error.IsSuccess(), "FromCommonPublicApi: error={0}", error);

            auto count = ++healthReportCount_;
            Trace.WriteInfo(TraceComponent, "ComMockPartition::ReportReplicaHealth({0}) total={1}", internalInfo, count);
            return S_OK;
        };

        HRESULT ReportPartitionHealth2(const FABRIC_HEALTH_INFORMATION *, const FABRIC_HEALTH_REPORT_SEND_OPTIONS *) override { return E_NOTIMPL; }

        // IFabricStatefulServicePartition2

        virtual HRESULT ReportReplicaHealth(const FABRIC_HEALTH_INFORMATION * publicInfo) override
        {
            return ReportReplicaHealth2(publicInfo, nullptr);
        };

        HRESULT ReportPartitionHealth(const FABRIC_HEALTH_INFORMATION *) override { return E_NOTIMPL; }

        // IFabricStatefulServicePartition1

        HRESULT ReportMoveCost(FABRIC_MOVE_COST) override { return E_NOTIMPL; }

        // IFabricStatefulServicePartition

        HRESULT GetPartitionInfo(const FABRIC_SERVICE_PARTITION_INFORMATION **) override { return E_NOTIMPL; }

        HRESULT GetReadStatus(FABRIC_SERVICE_PARTITION_ACCESS_STATUS *) override { return E_NOTIMPL; }

        HRESULT GetWriteStatus(FABRIC_SERVICE_PARTITION_ACCESS_STATUS *) override { return E_NOTIMPL; }

        HRESULT CreateReplicator(
            IFabricStateProvider *,
            FABRIC_REPLICATOR_SETTINGS const *,
            IFabricReplicator **,
            IFabricStateReplicator **) override { return E_NOTIMPL; }

        HRESULT ReportLoad(
            ULONG,
            const FABRIC_LOAD_METRIC *) override { return E_NOTIMPL; }

        HRESULT ReportFault(FABRIC_FAULT_TYPE) override { return E_NOTIMPL; }

    private:
        Common::atomic_long healthReportCount_;

    }; // ComMockPartition

    class HealthTrackerTest
    {
    public:
        HealthTrackerTest() { BOOST_REQUIRE(MethodSetup()); }
        TEST_METHOD_SETUP(MethodSetup);
        ~HealthTrackerTest() { BOOST_REQUIRE(MethodCleanup()); }
        TEST_METHOD_CLEANUP(MethodCleanup);
    };

#if !defined(PLATFORM_UNIX)
    void WaitWithBuffer(TimeSpan const delay)
    {
        Sleep(static_cast<DWORD>(delay.TotalPositiveMilliseconds() + 50));
    }

    BOOST_AUTO_TEST_CASE(SlowCommitTest)
    {
        StoreConfig::GetConfig().SlowCommitCountThreshold = 10;
        StoreConfig::GetConfig().SlowCommitTimeThreshold = TimeSpan::FromSeconds(10);

        auto thresholdCount = StoreConfig::GetConfig().SlowCommitCountThreshold;
        auto thresholdTime = StoreConfig::GetConfig().SlowCommitTimeThreshold;

        FABRIC_REPLICATOR_SETTINGS replicatorSettings = {0};
        ReplicatorSettingsUPtr replicatorSettingsUPtr;
        auto error = ReplicatorSettings::FromPublicApi(replicatorSettings, replicatorSettingsUPtr);
        VERIFY(error.IsSuccess(), "ReplicatorSettings::FromPublicApi error={0}", error);

        ComponentRoot root;
        auto store = EseReplicatedStore::Create(
            Guid::NewGuid(),
            DateTime::Now().Ticks,
            move(replicatorSettingsUPtr),
            ReplicatedStoreSettings(),
            EseLocalStoreSettings(
                L"HealthTrackerTest.edb",
                L".\\"),
            Api::IStoreEventHandlerPtr(),
            Api::ISecondaryEventHandlerPtr(),
            root);

        auto castedStore = reinterpret_cast<ReplicatedStore*>(store.get());

        auto mockPartition = make_com<ComMockPartition>();

        ComPointer<IFabricStatefulServicePartition> comPartition;
        auto hr = mockPartition->QueryInterface(IID_IFabricStatefulServicePartition, comPartition.VoidInitializationAddress());
        VERIFY(SUCCEEDED(hr), "QueryInterface(IID_IFabricStatefulServicePartition): hr={0}", hr);

        shared_ptr<ReplicatedStore::HealthTracker> healthTracker;
        error = ReplicatedStore::HealthTracker::Create(*castedStore, comPartition, healthTracker);
        VERIFY(error.IsSuccess(), "HealthTracker::Create(): error={0}", error);

        auto refreshTime = healthTracker->ComputeRefreshTime(thresholdTime);

        // Testcase: under count threshold
        //
        Trace.WriteInfo(TraceComponent, "*** Expect no reports");

        Trace.WriteInfo(TraceComponent, "tracker={0}", *healthTracker);

        for (auto ix=0; ix<thresholdCount-1; ++ix)
        {
            healthTracker->OnSlowCommit();
        }

        Trace.WriteInfo(TraceComponent, "tracker={0}", *healthTracker);
        mockPartition->ValidateReportCount(0);

        // Testcase: meet time threshold
        //
        Trace.WriteInfo(TraceComponent, "*** Expect no reports");

        WaitWithBuffer(thresholdTime);

        healthTracker->OnSlowCommit(); // Put index at last element to test circular buffer

        Trace.WriteInfo(TraceComponent, "tracker={0}", *healthTracker);
        mockPartition->ValidateReportCount(0);

        // Testcase: meet count threshold
        //
        Trace.WriteInfo(TraceComponent, "*** Expect report");

        WaitWithBuffer(thresholdTime);

        for (auto ix=0; ix<thresholdCount; ++ix)
        {
            healthTracker->OnSlowCommit();
        }

        Trace.WriteInfo(TraceComponent, "tracker={0}", *healthTracker);
        mockPartition->ValidateReportCount(1);

        // Testcase: meet refresh threshold (burst)
        //
        Trace.WriteInfo(TraceComponent, "*** Expect refresh (burst)");

        WaitWithBuffer(refreshTime);

        for (auto ix=0; ix<thresholdCount / 2 - 1; ++ix)
        {
            healthTracker->OnSlowCommit();
        }

        Trace.WriteInfo(TraceComponent, "tracker={0}", *healthTracker);
        mockPartition->ValidateReportCount(2);

        // Testcase: continue to meet refresh threshold (trickle)
        //
        Trace.WriteInfo(TraceComponent, "*** Expect refresh (trickle)");

        for (auto ix=0; ix<thresholdCount / 2 + 1; ++ix)
        {
            healthTracker->OnSlowCommit();
            Sleep(1000);
        }

        Trace.WriteInfo(TraceComponent, "tracker={0}", *healthTracker);
        mockPartition->ValidateReportCount(3);

        // Testcase: increase config threshold
        //
        WaitWithBuffer(refreshTime);

        Trace.WriteInfo(TraceComponent, "*** Increase config threshold");

        StoreConfig::GetConfig().SlowCommitCountThreshold = thresholdCount * 2;

        for (auto ix=0; ix<thresholdCount; ++ix)
        {
            healthTracker->OnSlowCommit();
        }

        Trace.WriteInfo(TraceComponent, "tracker={0}", *healthTracker);
        mockPartition->ValidateReportCount(3);

        for (auto ix=0; ix<thresholdCount; ++ix)
        {
            healthTracker->OnSlowCommit();
        }

        Trace.WriteInfo(TraceComponent, "tracker={0}", *healthTracker);
        mockPartition->ValidateReportCount(4);

        // Testcase: decrease config threshold
        //
        WaitWithBuffer(refreshTime);

        Trace.WriteInfo(TraceComponent, "*** Decrease config threshold");

        StoreConfig::GetConfig().SlowCommitCountThreshold = thresholdCount / 2;

        for (auto ix=0; ix<thresholdCount / 2; ++ix)
        {
            healthTracker->OnSlowCommit();
        }

        Trace.WriteInfo(TraceComponent, "tracker={0}", *healthTracker);
        mockPartition->ValidateReportCount(5);

        // Testcase: suppress multiple reports within refresh time
        //
        WaitWithBuffer(refreshTime);

        Trace.WriteInfo(TraceComponent, "*** Suppress multiple reports");

        for (auto ix=0; ix<thresholdCount * 2; ++ix)
        {
            healthTracker->OnSlowCommit();
        }

        Trace.WriteInfo(TraceComponent, "tracker={0}", *healthTracker);
        mockPartition->ValidateReportCount(6);

        // Testcase: disable reports
        //
        WaitWithBuffer(refreshTime);

        Trace.WriteInfo(TraceComponent, "*** Disable reports");

        StoreConfig::GetConfig().SlowCommitCountThreshold = 0;

        for (auto ix=0; ix<thresholdCount; ++ix)
        {
            healthTracker->OnSlowCommit();
        }

        Trace.WriteInfo(TraceComponent, "tracker={0}", *healthTracker);
        mockPartition->ValidateReportCount(6);

        // Testcase: re-enable reports
        //
        WaitWithBuffer(refreshTime);

        Trace.WriteInfo(TraceComponent, "*** Re-enable reports");

        StoreConfig::GetConfig().SlowCommitCountThreshold = thresholdCount;

        for (auto ix=0; ix<thresholdCount; ++ix)
        {
            healthTracker->OnSlowCommit();
        }

        Trace.WriteInfo(TraceComponent, "tracker={0}", *healthTracker);
        mockPartition->ValidateReportCount(7);
    }
#endif

    bool HealthTrackerTest::MethodSetup()
    {
        StoreConfig::GetConfig().Test_Reset();
        return true;
    }

    bool HealthTrackerTest::MethodCleanup()
    {
        return true;
    }
}

max_stars_repo_name: gridgentoo/ServiceFabricAzure

max_issues_repo_name: gridgentoo/ServiceFabricAzure

max_forks_repo_name: gridgentoo/ServiceFabricAzure


text:
/*
  Copyright 2008 Larry Gritz and the other authors and contributors.
  All Rights Reserved.

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

  (This is the Modified BSD License)
*/

/// \file
/// Implementation of ImageBuf class.

#include <iostream>

#include <OpenEXR/ImathFun.h>
#include <OpenEXR/half.h>
#include <boost/scoped_ptr.hpp>

#include "imageio.h"
#include "imagebuf.h"
#include "imagebufalgo.h"
#include "imagecache.h"
#include "dassert.h"
#include "strutil.h"
#include "fmath.h"

OIIO_NAMESPACE_ENTER
{

ROI
get_roi (const ImageSpec &spec)
{
    return ROI (spec.x, spec.x + spec.width,
                spec.y, spec.y + spec.height,
                spec.z, spec.z + spec.depth);
}

ROI
get_roi_full (const ImageSpec &spec)
{
    return ROI (spec.full_x, spec.full_x + spec.full_width,
                spec.full_y, spec.full_y + spec.full_height,
                spec.full_z, spec.full_z + spec.full_depth);
}

void
set_roi (ImageSpec &spec, const ROI &newroi)
{
    spec.x = newroi.xbegin;
    spec.y = newroi.ybegin;
    spec.z = newroi.zbegin;
    spec.width = newroi.width();
    spec.height = newroi.height();
    spec.depth = newroi.depth();
}

void
set_roi_full (ImageSpec &spec, const ROI &newroi)
{
    spec.full_x = newroi.xbegin;
    spec.full_y = newroi.ybegin;
    spec.full_z = newroi.zbegin;
    spec.full_width = newroi.width();
    spec.full_height = newroi.height();
    spec.full_depth = newroi.depth();
}

ROI
roi_union (const ROI &A, const ROI &B)
{
    return ROI (std::min (A.xbegin, B.xbegin), std::max (A.xend, B.xend),
                std::min (A.ybegin, B.ybegin), std::max (A.yend, B.yend),
                std::min (A.zbegin, B.zbegin), std::max (A.zend, B.zend));
}

ROI
roi_intersection (const ROI &A, const ROI &B)
{
    return ROI (std::max (A.xbegin, B.xbegin), std::min (A.xend, B.xend),
                std::max (A.ybegin, B.ybegin), std::min (A.yend, B.yend),
                std::max (A.zbegin, B.zbegin), std::min (A.zend, B.zend));
}

ImageBuf::ImageBuf (const std::string &filename,
                    ImageCache *imagecache)
    : m_name(filename), m_nsubimages(0),
      m_current_subimage(-1), m_current_miplevel(-1),
      m_localpixels(NULL), m_clientpixels(false),
      m_spec_valid(false), m_pixels_valid(false),
      m_badfile(false), m_orientation(1), m_pixelaspect(1),
      m_imagecache(imagecache)
{
}

ImageBuf::ImageBuf (const std::string &filename, const ImageSpec &spec)
    : m_name(filename), m_nsubimages(0),
      m_current_subimage(-1), m_current_miplevel(-1),
      m_localpixels(NULL), m_clientpixels(false),
      m_spec_valid(false), m_pixels_valid(false),
      m_badfile(false), m_orientation(1), m_pixelaspect(1),
      m_imagecache(NULL)
{
    alloc (spec);
}

ImageBuf::ImageBuf (const std::string &filename, const ImageSpec &spec,
                    void *buffer)
    : m_name(filename), m_nsubimages(0),
      m_current_subimage(-1), m_current_miplevel(-1),
      m_localpixels(NULL), m_clientpixels(false),
      m_spec_valid(false), m_pixels_valid(false),
      m_badfile(false), m_orientation(1), m_pixelaspect(1),
      m_imagecache(NULL)
{
    m_spec = spec;
    m_nativespec = spec;
    m_spec_valid = true;
    m_pixels_valid = true;
    m_localpixels = (char *)buffer;
    m_clientpixels = true;
}

ImageBuf::ImageBuf (const ImageBuf &src)
    : m_name(src.m_name), m_fileformat(src.m_fileformat),
      m_nsubimages(src.m_nsubimages),
      m_current_subimage(src.m_current_subimage),
      m_current_miplevel(src.m_current_miplevel),
      m_nmiplevels(src.m_nmiplevels),
      m_spec(src.m_spec), m_nativespec(src.m_nativespec),
      m_pixels(src.m_pixels),
      m_localpixels(src.m_localpixels),
      m_clientpixels(src.m_clientpixels),
      m_spec_valid(src.m_spec_valid), m_pixels_valid(src.m_pixels_valid),
      m_badfile(src.m_badfile),
      m_orientation(src.m_orientation),
      m_pixelaspect(src.m_pixelaspect),
      m_imagecache(src.m_imagecache),
      m_cachedpixeltype(src.m_cachedpixeltype)
{
    if (src.localpixels()) {
        // Source had the image fully in memory (no cache)
        if (src.m_clientpixels) {
            // Source just wrapped the client app's pixels
            ASSERT (0 && "ImageBuf wrapping client buffer not yet supported");
        } else {
            // We own our pixels
            // Make sure our localpixels points to our own owned memory.
            m_localpixels = &m_pixels[0];
        }
    } else {
        // Source was cache-based
        // nothing else to do
    }
}

ImageBuf::~ImageBuf ()
{
    // Do NOT destroy m_imagecache here -- either it was created
    // externally and passed to the ImageBuf ctr or reset() method, or
    // else init_spec requested the system-wide shared cache, which
    // does not need to be destroyed.
}

#if 0
const ImageBuf &
ImageBuf::operator= (const ImageBuf &src)
{
    if (&src != this) {
        m_name = src.m_name;
        m_fileformat = src.m_fileformat;
        m_nsubimages = src.m_nsubimages;
        m_current_subimage = src.m_current_subimage;
        m_current_miplevel = src.m_current_miplevel;
        m_nmiplevels = src.m_nmiplevels;
        m_spec = src.m_spec;
        m_nativespec = src.m_nativespec;
        m_pixels = src.m_pixels;
        m_localpixels = src.m_localpixels;
        m_clientpixels = src.m_clientpixels;
        m_spec_valid = src.m_spec_valid;
        m_pixels_valid = src.m_pixels_valid;
        m_badfile = src.m_badfile;
        m_err.clear();
        m_orientation = src.m_orientation;
        m_pixelaspect = src.m_pixelaspect;
        m_imagecache = src.m_imagecache;
        m_cachedpixeltype = src.m_cachedpixeltype;
        if (src.localpixels()) {
            // Source had the image fully in memory (no cache)
            if (src.m_clientpixels) {
                // Source just wrapped the client app's pixels
                ASSERT (0 && "ImageBuf wrapping client buffer not yet supported");
                std::vector<char> tmp;
                std::swap (m_pixels, tmp);  // delete it with prejudice
            } else {
                // We own our pixels
                // Make sure our localpixels points to our own owned memory.
                m_localpixels = &m_pixels[0];
            }
        } else {
            // Source was cache-based
            std::vector<char> tmp;
            std::swap (m_pixels, tmp);  // delete it with prejudice
        }
    }
    return *this;
}
#endif

static spin_mutex err_mutex;      ///< Protect m_err fields

bool
ImageBuf::has_error () const
{
    spin_lock lock (err_mutex);
    return ! m_err.empty();
}

std::string
ImageBuf::geterror (void) const
{
    spin_lock lock (err_mutex);
    std::string e = m_err;
    m_err.clear();
    return e;
}

void
ImageBuf::append_error (const std::string &message) const
{
    spin_lock lock (err_mutex);
    ASSERT (m_err.size() < 1024*1024*16 &&
            "Accumulated error messages > 16MB. Try checking return codes!");
    if (m_err.size() && m_err[m_err.size()-1] != '\n')
        m_err += '\n';
    m_err += message;
}

void
ImageBuf::clear ()
{
    m_name.clear ();
    m_fileformat.clear ();
    m_nsubimages = 0;
    m_current_subimage = -1;
    m_current_miplevel = -1;
    m_spec = ImageSpec ();
    m_nativespec = ImageSpec ();
    {
        std::vector<char> tmp;
        std::swap (m_pixels, tmp);  // clear it with deallocation
    }
    m_localpixels = NULL;
    m_clientpixels = false;
    m_spec_valid = false;
    m_pixels_valid = false;
    m_badfile = false;
    m_orientation = 1;
    m_pixelaspect = 1;
}

void
ImageBuf::reset (const std::string &filename, ImageCache *imagecache)
{
    clear ();
    m_name = ustring (filename);
    if (imagecache)
        m_imagecache = imagecache;
}

void
ImageBuf::reset (const std::string &filename, const ImageSpec &spec)
{
    clear ();
    m_name = ustring (filename);
    m_current_subimage = 0;
    m_current_miplevel = 0;
    alloc (spec);
}

void
ImageBuf::realloc ()
{
    size_t newsize = spec().image_bytes ();
    if (((int)m_pixels.size() - (int)newsize) > 4*1024*1024) {
        // If we are substantially shrinking, try to actually free
        // memory, which std::vector::resize does not do!
        std::vector<char> tmp;      // vector with 0 memory
        std::swap (tmp, m_pixels);  // Now tmp holds the mem, not m_pixels
        // As tmp leaves scope, it frees m_pixels's old memory
    }
    m_pixels.resize (newsize);
    m_localpixels = &m_pixels[0];
    m_clientpixels = false;
#if 0
    std::cerr << "ImageBuf " << m_name << " local allocation: " << newsize << "\n";
#endif
}

void
ImageBuf::alloc (const ImageSpec &spec)
{
    m_spec = spec;
    m_nativespec = spec;
    m_spec_valid = true;
    realloc ();
}

void
ImageBuf::copy_from (const ImageBuf &src)
{
    if (this == &src)
        return;
    ASSERT (m_spec.width == src.m_spec.width &&
            m_spec.height == src.m_spec.height &&
            m_spec.depth == src.m_spec.depth &&
            m_spec.nchannels == src.m_spec.nchannels);
    realloc ();
    src.get_pixels (src.xbegin(), src.xend(), src.ybegin(), src.yend(),
                    src.zbegin(), src.zend(), m_spec.format, m_localpixels);
}

bool
ImageBuf::init_spec (const std::string &filename, int subimage, int miplevel)
{
    if (m_current_subimage >= 0 && m_current_miplevel >= 0
            && m_name == filename && m_current_subimage == subimage
            && m_current_miplevel == miplevel)
        return true;   // Already done

    if (! m_imagecache) {
        m_imagecache = ImageCache::create (true /* shared cache */);
    }

    m_name = filename;
    m_nsubimages = 0;
    m_nmiplevels = 0;
    static ustring s_subimages("subimages"), s_miplevels("miplevels");
    m_imagecache->get_image_info (m_name, subimage, miplevel, s_subimages,
                                  TypeDesc::TypeInt, &m_nsubimages);
    m_imagecache->get_image_info (m_name, subimage, miplevel, s_miplevels,
                                  TypeDesc::TypeInt, &m_nmiplevels);
    m_imagecache->get_imagespec (m_name, m_spec, subimage, miplevel);
    m_imagecache->get_imagespec (m_name, m_nativespec, subimage, miplevel, true);
    if (m_nsubimages) {
        m_badfile = false;
        m_spec_valid = true;
        m_orientation = m_spec.get_int_attribute ("orientation", 1);
        m_pixelaspect = m_spec.get_float_attribute ("pixelaspectratio", 1.0f);
        m_current_subimage = subimage;
        m_current_miplevel = miplevel;
    } else {
        m_badfile = true;
        m_spec_valid = false;
        m_current_subimage = -1;
        m_current_miplevel = -1;
        m_err = m_imagecache->geterror ();
        // std::cerr << "ImageBuf ERROR: " << m_err << "\n";
    }

    return !m_badfile;
}

bool
ImageBuf::read (int subimage, int miplevel, bool force, TypeDesc convert,
               ProgressCallback progress_callback,
               void *progress_callback_data)
{
    if (pixels_valid() && !force &&
            subimage == this->subimage() && miplevel == this->miplevel())
        return true;

    if (! init_spec (m_name.string(), subimage, miplevel)) {
        m_badfile = true;
        m_spec_valid = false;
        return false;
    }

    // Set our current spec to the requested subimage
    if (! m_imagecache->get_imagespec (m_name, m_spec, subimage, miplevel) ||
        ! m_imagecache->get_imagespec (m_name, m_nativespec, subimage, miplevel, true)) {
        m_err = m_imagecache->geterror ();
        return false;
    }
    m_current_subimage = subimage;
    m_current_miplevel = miplevel;

#if 1
    // If we don't already have "local" pixels, and we aren't asking to
    // convert the pixels to a specific (and different) type, then take an
    // early out by relying on the cache.
    int peltype = TypeDesc::UNKNOWN;
    m_imagecache->get_image_info (m_name, subimage, miplevel,
                                  ustring("cachedpixeltype"),
                                  TypeDesc::TypeInt, &peltype);
    m_cachedpixeltype = TypeDesc ((TypeDesc::BASETYPE)peltype);
    if (! m_localpixels && ! force &&
        (convert == m_cachedpixeltype || convert == TypeDesc::UNKNOWN)) {
        m_spec.format = m_cachedpixeltype;
#ifdef DEBUG
        std::cerr << "read was not necessary -- using cache\n";
#endif
        return true;
    } else {
#ifdef DEBUG
        std::cerr << "going to have to read " << m_name << ": "
                  << m_spec.format.c_str() << " vs " << convert.c_str() << "\n";
#endif
    }
#endif

    if (convert != TypeDesc::UNKNOWN)
        m_spec.format = convert;
    m_orientation = m_spec.get_int_attribute ("orientation", 1);
    m_pixelaspect = m_spec.get_float_attribute ("pixelaspectratio", 1.0f);

    realloc ();
    if (m_imagecache->get_pixels (m_name, subimage, miplevel,
                                  m_spec.x, m_spec.x+m_spec.width,
                                  m_spec.y, m_spec.y+m_spec.height,
                                  m_spec.z, m_spec.z+m_spec.depth,
                                  m_spec.format, m_localpixels)) {
        m_pixels_valid = true;
    } else {
        m_pixels_valid = false;
        m_err = m_imagecache->geterror ();
    }

    return m_pixels_valid;
}

bool
ImageBuf::write (ImageOutput *out,
                 ProgressCallback progress_callback,
                 void *progress_callback_data) const
{
    stride_t as = AutoStride;
    bool ok = true;
    if (m_localpixels) {
        ok = out->write_image (m_spec.format, m_localpixels, as, as, as,
                               progress_callback, progress_callback_data);
    } else {
        std::vector<char> tmp (m_spec.image_bytes());
        get_pixels (xbegin(), xend(), ybegin(), yend(), zbegin(), zend(),
                    m_spec.format, &tmp[0]);
        ok = out->write_image (m_spec.format, &tmp[0], as, as, as,
                               progress_callback, progress_callback_data);
        // FIXME -- not good for huge images.  Instead, we should read
        // little bits at a time (scanline or tile blocks).
    }
    if (! ok)
        m_err = out->geterror ();
    return ok;
}

bool
ImageBuf::save (const std::string &_filename, const std::string &_fileformat,
                ProgressCallback progress_callback,
                void *progress_callback_data) const
{
    std::string filename = _filename.size() ? _filename : name();
    std::string fileformat = _fileformat.size() ? _fileformat : filename;
    boost::scoped_ptr<ImageOutput> out (ImageOutput::create (fileformat.c_str(), "" /* searchpath */));
    if (! out) {
        m_err = geterror();
        return false;
    }
    if (! out->open (filename.c_str(), m_spec)) {
        m_err = out->geterror ();
        return false;
    }
    if (! write (out.get(), progress_callback, progress_callback_data))
        return false;
    out->close ();
    if (progress_callback)
        progress_callback (progress_callback_data, 0);
    return true;
}

bool
ImageBuf::reres (const ImageBuf &src)
{
    if (localpixels() && ! m_clientpixels) {
        m_spec.width = src.m_spec.width;
        m_spec.height = src.m_spec.height;
        m_spec.depth = src.m_spec.depth;
        m_spec.nchannels = src.m_spec.nchannels;
        m_spec.format = src.m_spec.format;
        m_spec.channelformats = src.m_spec.channelformats;
        m_spec.channelnames = src.m_spec.channelnames;
        m_spec.alpha_channel = src.m_spec.alpha_channel;
        m_spec.z_channel = src.m_spec.z_channel;
        return true;
    }
    return false;  // not the kind of ImageBuf that can be resized
}

void
ImageBuf::copy_metadata (const ImageBuf &src)
{
    m_spec.full_x = src.m_spec.full_x;
    m_spec.full_y = src.m_spec.full_y;
    m_spec.full_z = src.m_spec.full_z;
    m_spec.full_width = src.m_spec.full_width;
    m_spec.full_height = src.m_spec.full_height;
    m_spec.full_depth = src.m_spec.full_depth;
    m_spec.tile_width = src.m_spec.tile_width;
    m_spec.tile_height = src.m_spec.tile_height;
    m_spec.tile_depth = src.m_spec.tile_depth;
    m_spec.extra_attribs = src.m_spec.extra_attribs;
}

namespace {

// Pixel-by-pixel copy fully templated by both data types.
template<class D, class S>
void copy_pixels_2 (ImageBuf &dst, const ImageBuf &src, int xbegin, int xend,
                    int ybegin, int yend, int zbegin, int zend, int nchannels)
{
    if (is_same<D,S>::value) {
        // If both bufs are the same type, just directly copy the values
        ImageBuf::Iterator<D,D> d (dst, xbegin, xend, ybegin, yend, zbegin, zend);
        ImageBuf::ConstIterator<D,D> s (src, xbegin, xend, ybegin, yend, zbegin, zend);
        for ( ; ! d.done();  ++d, ++s) {
            if (s.exists() && d.exists()) {
                for (int c = 0;  c < nchannels;  ++c)
                    d[c] = s[c];
            }
        }
    } else {
        // If the two bufs are different types, convert through float
        ImageBuf::Iterator<D,float> d (dst, xbegin, xend, ybegin, yend, zbegin, zend);
        ImageBuf::ConstIterator<S,float> s (dst, xbegin, xend, ybegin, yend, zbegin, zend);
        for ( ; ! d.done();  ++d, ++s) {
            if (s.exists() && d.exists()) {
                for (int c = 0;  c < nchannels;  ++c)
                    d[c] = s[c];
            }
        }
    }
}

// Call two-type template copy_pixels_2 based on src AND dst data type
template<class S>
void copy_pixels_ (ImageBuf &dst, const ImageBuf &src, int xbegin, int xend,
                   int ybegin, int yend, int zbegin, int zend, int nchannels)
{
    switch (dst.spec().format.basetype) {
    case TypeDesc::FLOAT :
        copy_pixels_2<float,S> (dst, src, xbegin, xend, ybegin, yend,
                                zbegin, zend, nchannels);
        break;
    case TypeDesc::UINT8 :
        copy_pixels_2<unsigned char,S> (dst, src, xbegin, xend, ybegin, yend,
                                        zbegin, zend, nchannels);
        break;
    case TypeDesc::INT8  :
        copy_pixels_2<char,S> (dst, src, xbegin, xend, ybegin, yend,
                               zbegin, zend, nchannels);
        break;
    case TypeDesc::UINT16:
        copy_pixels_2<unsigned short,S> (dst, src, xbegin, xend, ybegin, yend,
                                         zbegin, zend, nchannels);
        break;
    case TypeDesc::INT16 :
        copy_pixels_2<short,S> (dst, src, xbegin, xend, ybegin, yend,
                                zbegin, zend, nchannels);
        break;
    case TypeDesc::UINT  :
        copy_pixels_2<unsigned int,S> (dst, src, xbegin, xend, ybegin, yend,
                                       zbegin, zend, nchannels);
        break;
    case TypeDesc::INT   :
        copy_pixels_2<int,S> (dst, src, xbegin, xend, ybegin, yend,
                              zbegin, zend, nchannels);
        break;
    case TypeDesc::HALF  :
        copy_pixels_2<half,S> (dst, src, xbegin, xend, ybegin, yend,
                               zbegin, zend, nchannels);
        break;
    case TypeDesc::DOUBLE:
        copy_pixels_2<double,S> (dst, src, xbegin, xend, ybegin, yend,
                                 zbegin, zend, nchannels);
        break;
    case TypeDesc::UINT64:
        copy_pixels_2<unsigned long long,S> (dst, src, xbegin, xend, ybegin, yend,
                                             zbegin, zend, nchannels);
        break;
    case TypeDesc::INT64 :
        copy_pixels_2<long long,S> (dst, src, xbegin, xend, ybegin, yend,
                                    zbegin, zend, nchannels);
        break;
    default:
        ASSERT (0);
    }
}

}

bool
ImageBuf::copy_pixels (const ImageBuf &src)
{
    // compute overlap
    int xbegin = std::max (this->xbegin(), src.xbegin());
    int xend = std::min (this->xend(), src.xend());
    int ybegin = std::max (this->ybegin(), src.ybegin());
    int yend = std::min (this->yend(), src.yend());
    int zbegin = std::max (this->zbegin(), src.zbegin());
    int zend = std::min (this->zend(), src.zend());
    int nchannels = std::min (this->nchannels(), src.nchannels());

    // If we aren't copying over all our pixels, zero out the pixels
    if (xbegin != this->xbegin() || xend != this->xend() ||
        ybegin != this->ybegin() || yend != this->yend() ||
        zbegin != this->zbegin() || zend != this->zend() ||
        nchannels != this->nchannels())
        ImageBufAlgo::zero (*this);

    // Call template copy_pixels_ based on src data type
    switch (src.spec().format.basetype) {
    case TypeDesc::FLOAT :
        copy_pixels_<float> (*this, src, xbegin, xend, ybegin, yend,
                             zbegin, zend, nchannels);
        break;
    case TypeDesc::UINT8 :
        copy_pixels_<unsigned char> (*this, src, xbegin, xend, ybegin, yend,
                                     zbegin, zend, nchannels);
        break;
    case TypeDesc::INT8  :
        copy_pixels_<char> (*this, src, xbegin, xend, ybegin, yend,
                            zbegin, zend, nchannels);
        break;
    case TypeDesc::UINT16:
        copy_pixels_<unsigned short> (*this, src, xbegin, xend, ybegin, yend,
                                      zbegin, zend, nchannels);
        break;
    case TypeDesc::INT16 :
        copy_pixels_<short> (*this, src, xbegin, xend, ybegin, yend,
                             zbegin, zend, nchannels);
        break;
    case TypeDesc::UINT  :
        copy_pixels_<unsigned int> (*this, src, xbegin, xend, ybegin, yend,
                                    zbegin, zend, nchannels);
        break;
    case TypeDesc::INT   :
        copy_pixels_<int> (*this, src, xbegin, xend, ybegin, yend,
                           zbegin, zend, nchannels);
        break;
    case TypeDesc::HALF  :
        copy_pixels_<half> (*this, src, xbegin, xend, ybegin, yend,
                            zbegin, zend, nchannels);
        break;
    case TypeDesc::DOUBLE:
        copy_pixels_<double> (*this, src, xbegin, xend, ybegin, yend,
                              zbegin, zend, nchannels);
        break;
    case TypeDesc::UINT64:
        copy_pixels_<unsigned long long> (*this, src, xbegin, xend, ybegin, yend,
                                          zbegin, zend, nchannels);
        break;
    case TypeDesc::INT64 :
        copy_pixels_<long long> (*this, src, xbegin, xend, ybegin, yend,
                                 zbegin, zend, nchannels);
        break;
    default:
        ASSERT (0);
    }
    return true;
}

bool
ImageBuf::copy (const ImageBuf &src)
{
    if (! m_spec_valid && ! m_pixels_valid) {
        // uninitialized
        if (! src.m_spec_valid && ! src.m_pixels_valid)
            return true;   // uninitialized=uninitialized is a nop
        // uninitialized = initialized : set up *this with local storage
        reset (src.name(), src.spec());
    }

    bool selfcopy = (&src == this);

    if (cachedpixels()) {
        if (selfcopy) {  // special case: self copy of ImageCache loads locally
            return read (subimage(), miplevel(), true /*force*/);
        }
        reset (src.name(), src.spec());
        // Now it has local pixels
    }

    if (selfcopy)
        return true;

    if (localpixels()) {
        if (m_clientpixels) {
            // app-owned memory
            if (spec().width != src.spec().width ||
                spec().height != src.spec().height ||
                spec().depth != src.spec().depth ||
                spec().nchannels != src.spec().nchannels) {
                // size doesn't match, fail
                return false;
            }
            this->copy_metadata (src);
        } else {
            // locally owned memory -- we can fully resize it
            reset (src.name(), src.spec());
        }
        return this->copy_pixels (src);
    }

    return false;   // all other cases fail
}

template<typename T>
static inline float getchannel_ (const ImageBuf &buf, int x, int y, int c)
{
    ImageBuf::ConstIterator<T> pixel (buf, x, y);
    return pixel[c];
}

float
ImageBuf::getchannel (int x, int y, int c) const
{
    if (c < 0 || c >= spec().nchannels)
        return 0.0f;
    switch (spec().format.basetype) {
    case TypeDesc::FLOAT : return getchannel_<float> (*this, x, y, c);
    case TypeDesc::UINT8 : return getchannel_<unsigned char> (*this, x, y, c);
    case TypeDesc::INT8  : return getchannel_<char> (*this, x, y, c);
    case TypeDesc::UINT16: return getchannel_<unsigned short> (*this, x, y, c);
    case TypeDesc::INT16 : return getchannel_<short> (*this, x, y, c);
    case TypeDesc::UINT  : return getchannel_<unsigned int> (*this, x, y, c);
    case TypeDesc::INT   : return getchannel_<int> (*this, x, y, c);
    case TypeDesc::HALF  : return getchannel_<half> (*this, x, y, c);
    case TypeDesc::DOUBLE: return getchannel_<double> (*this, x, y, c);
    case TypeDesc::UINT64: return getchannel_<unsigned long long> (*this, x, y, c);
    case TypeDesc::INT64 : return getchannel_<long long> (*this, x, y, c);
    default:
        ASSERT (0);
        return 0.0f;
    }
}

template<typename T>
static inline void
getpixel_ (const ImageBuf &buf, int x, int y, int z, float *result, int chans)
{
    ImageBuf::ConstIterator<T> pixel (buf, x, y, z);
    if (pixel.valid()) {
        for (int i = 0;  i < chans;  ++i)
            result[i] = pixel[i];
    } else {
        for (int i = 0;  i < chans;  ++i)
            result[i] = 0.0f;
    }
}

void
ImageBuf::getpixel (int x, int y, int z, float *pixel, int maxchannels) const
{
    int n = std::min (spec().nchannels, maxchannels);
    switch (spec().format.basetype) {
    case TypeDesc::FLOAT : getpixel_<float> (*this, x, y, z, pixel, n); break;
    case TypeDesc::UINT8 : getpixel_<unsigned char> (*this, x, y, z, pixel, n); break;
    case TypeDesc::INT8  : getpixel_<char> (*this, x, y, z, pixel, n); break;
    case TypeDesc::UINT16: getpixel_<unsigned short> (*this, x, y, z, pixel, n); break;
    case TypeDesc::INT16 : getpixel_<short> (*this, x, y, z, pixel, n); break;
    case TypeDesc::UINT  : getpixel_<unsigned int> (*this, x, y, z, pixel, n); break;
    case TypeDesc::INT   : getpixel_<int> (*this, x, y, z, pixel, n); break;
    case TypeDesc::HALF  : getpixel_<half> (*this, x, y, z, pixel, n); break;
    case TypeDesc::DOUBLE: getpixel_<double> (*this, x, y, z, pixel, n); break;
    case TypeDesc::UINT64: getpixel_<unsigned long long> (*this, x, y, z, pixel, n); break;
    case TypeDesc::INT64 : getpixel_<long long> (*this, x, y, z, pixel, n); break;
    default:
        ASSERT (0);
    }
}

void
ImageBuf::interppixel (float x, float y, float *pixel) const
{
    const int maxchannels = 64;  // Reasonable guess
    float p[4][maxchannels];
    DASSERT (spec().nchannels <= maxchannels &&
             "You need to increase maxchannels in ImageBuf::interppixel");
    int n = std::min (spec().nchannels, maxchannels);
    x -= 0.5f;
    y -= 0.5f;
    int xtexel, ytexel;
    float xfrac, yfrac;
    xfrac = floorfrac (x, &xtexel);
    yfrac = floorfrac (y, &ytexel);
    getpixel (xtexel, ytexel, p[0], n);
    getpixel (xtexel+1, ytexel, p[1], n);
    getpixel (xtexel, ytexel+1, p[2], n);
    getpixel (xtexel+1, ytexel+1, p[3], n);
    bilerp (p[0], p[1], p[2], p[3], xfrac, yfrac, n, pixel);
}

template<typename T>
static inline void
setpixel_ (ImageBuf &buf, int x, int y, int z, const float *data, int chans)
{
    ImageBuf::Iterator<T> pixel (buf, x, y, z);
    if (pixel.valid()) {
        for (int i = 0;  i < chans;  ++i)
            pixel[i] = data[i];
    }
}

void
ImageBuf::setpixel (int x, int y, int z, const float *pixel, int maxchannels)
{
    int n = std::min (spec().nchannels, maxchannels);
    switch (spec().format.basetype) {
    case TypeDesc::FLOAT : setpixel_<float> (*this, x, y, z, pixel, n); break;
    case TypeDesc::UINT8 : setpixel_<unsigned char> (*this, x, y, z, pixel, n); break;
    case TypeDesc::INT8  : setpixel_<char> (*this, x, y, z, pixel, n); break;
    case TypeDesc::UINT16: setpixel_<unsigned short> (*this, x, y, z, pixel, n); break;
    case TypeDesc::INT16 : setpixel_<short> (*this, x, y, z, pixel, n); break;
    case TypeDesc::UINT  : setpixel_<unsigned int> (*this, x, y, z, pixel, n); break;
    case TypeDesc::INT   : setpixel_<int> (*this, x, y, z, pixel, n); break;
    case TypeDesc::HALF  : setpixel_<half> (*this, x, y, z, pixel, n); break;
    case TypeDesc::DOUBLE: setpixel_<double> (*this, x, y, z, pixel, n); break;
    case TypeDesc::UINT64: setpixel_<unsigned long long> (*this, x, y, z, pixel, n); break;
    case TypeDesc::INT64 : setpixel_<long long> (*this, x, y, z, pixel, n); break;
    default:
        ASSERT (0);
    }
}

void
ImageBuf::setpixel (int i, const float *pixel, int maxchannels)
{
    setpixel (spec().x + (i % spec().width), spec().y + (i / spec().width),
              pixel, maxchannels);
}

template<typename S, typename D>
static inline void
get_pixel_channels_ (const ImageBuf &buf, int xbegin, int xend,
                     int ybegin, int yend, int zbegin, int zend,
                     int chbegin, int chend, D *r)
{
    int w = (xend-xbegin), h = (yend-ybegin);
    imagesize_t wh = imagesize_t(w) * imagesize_t(h);
    int nchans = chend - chbegin;
    for (ImageBuf::ConstIterator<S,D> p (buf, xbegin, xend, ybegin, yend, zbegin, zend);
         p.valid(); ++p) {
        imagesize_t offset = ((p.z()-zbegin)*wh + (p.y()-ybegin)*w + (p.x()-xbegin)) * buf.nchannels();
        for (int c = 0;  c < nchans;  ++c)
            r[offset+c] = p[c+chbegin];
    }
}

template<typename D>
bool
ImageBuf::get_pixel_channels (int xbegin, int xend, int ybegin, int yend,
                              int zbegin, int zend,
                              int chbegin, int chend, D *r) const
{
    // Caveat: serious hack here.  To avoid duplicating code, use a
    // #define.  Furthermore, exploit the CType<> template to construct
    // the right C data type for the given BASETYPE.
#define TYPECASE(B)                                                     \
    case B : get_pixel_channels_<CType<B>::type,D>(*this,               \
                       xbegin, xend, ybegin, yend, zbegin, zend,        \
                       chbegin, chend, (D *)r); return true

    switch (spec().format.basetype) {
        TYPECASE (TypeDesc::UINT8);
        TYPECASE (TypeDesc::INT8);
        TYPECASE (TypeDesc::UINT16);
        TYPECASE (TypeDesc::INT16);
        TYPECASE (TypeDesc::UINT);
        TYPECASE (TypeDesc::INT);
        TYPECASE (TypeDesc::HALF);
        TYPECASE (TypeDesc::FLOAT);
        TYPECASE (TypeDesc::DOUBLE);
        TYPECASE (TypeDesc::UINT64);
        TYPECASE (TypeDesc::INT64);
    }
    return false;
#undef TYPECASE
}

bool
ImageBuf::get_pixel_channels (int xbegin, int xend, int ybegin, int yend,
                              int zbegin, int zend, int chbegin, int chend,
                              TypeDesc format, void *result) const
{
    // For each possible base type that the user wants for a destination
    // type, call a template specialization.
#define TYPECASE(B)                                                     \
    case B : return get_pixel_channels<CType<B>::type> (                \
                             xbegin, xend, ybegin, yend, zbegin, zend,  \
                             chbegin, chend, (CType<B>::type *)result);

    switch (format.basetype) {
        TYPECASE (TypeDesc::UINT8);
        TYPECASE (TypeDesc::INT8);
        TYPECASE (TypeDesc::UINT16);
        TYPECASE (TypeDesc::INT16);
        TYPECASE (TypeDesc::UINT);
        TYPECASE (TypeDesc::INT);
        TYPECASE (TypeDesc::HALF);
        TYPECASE (TypeDesc::FLOAT);
        TYPECASE (TypeDesc::DOUBLE);
        TYPECASE (TypeDesc::UINT64);
        TYPECASE (TypeDesc::INT64);
    }
    return false;
#undef TYPECASE
}

bool
ImageBuf::get_pixels (int xbegin, int xend, int ybegin, int yend,
                       int zbegin, int zend,
                       TypeDesc format, void *result) const
{
    return get_pixel_channels (xbegin, xend, ybegin, yend, zbegin, zend,
                               0, nchannels(), format, result);
}

int
ImageBuf::oriented_width () const
{
    return m_orientation <= 4 ? m_spec.width : m_spec.height;
}

int
ImageBuf::oriented_height () const
{
    return m_orientation <= 4 ? m_spec.height : m_spec.width;
}

int
ImageBuf::oriented_x () const
{
    return m_orientation <= 4 ? m_spec.x : m_spec.y;
}

int
ImageBuf::oriented_y () const
{
    return m_orientation <= 4 ? m_spec.y : m_spec.x;
}

int
ImageBuf::oriented_full_width () const
{
    return m_orientation <= 4 ? m_spec.full_width : m_spec.full_height;
}

int
ImageBuf::oriented_full_height () const
{
    return m_orientation <= 4 ? m_spec.full_height : m_spec.full_width;
}

int
ImageBuf::oriented_full_x () const
{
    return m_orientation <= 4 ? m_spec.full_x : m_spec.full_y;
}

int
ImageBuf::oriented_full_y () const
{
    return m_orientation <= 4 ? m_spec.full_y : m_spec.full_x;
}

void
ImageBuf::set_full (int xbegin, int xend, int ybegin, int yend,
                    int zbegin, int zend, const float *bordercolor)
{
    m_spec.full_x = xbegin;
    m_spec.full_y = ybegin;
    m_spec.full_z = zbegin;
    m_spec.full_width  = xend - xbegin;
    m_spec.full_height = yend - ybegin;
    m_spec.full_depth  = zend - zbegin;
    if (bordercolor)
        m_spec.attribute ("oiio:bordercolor",
                          TypeDesc(TypeDesc::FLOAT,m_spec.nchannels),
                          bordercolor);
}

const void *
ImageBuf::pixeladdr (int x, int y, int z) const
{
    if (cachedpixels())
        return NULL;
    x -= spec().x;
    y -= spec().y;
    z -= spec().z;
    size_t p = y * m_spec.scanline_bytes() + x * m_spec.pixel_bytes();
    if (z)
        p += z * clamped_mult64 (m_spec.scanline_bytes(), (imagesize_t)spec().height);
    return &(m_localpixels[p]);
}

void *
ImageBuf::pixeladdr (int x, int y, int z)
{
    if (cachedpixels())
        return NULL;
    x -= spec().x;
    y -= spec().y;
    z -= spec().z;
    size_t p = y * m_spec.scanline_bytes() + x * m_spec.pixel_bytes();
    if (z)
        p += z * m_spec.scanline_bytes() * spec().height;
    return &(m_localpixels[p]);
}

const void *
ImageBuf::retile (int x, int y, int z, ImageCache::Tile* &tile,
                  int &tilexbegin, int &tileybegin, int &tilezbegin) const
{
    int tw = spec().tile_width, th = spec().tile_height;
    int td = std::max (1, spec().tile_depth);
    if (tile == NULL || x < tilexbegin || x >= (tilexbegin+tw) ||
                        y < tileybegin || y >= (tileybegin+th) ||
                        z < tilezbegin || z >= (tilezbegin+td)) {
        // not the same tile as before
        if (tile)
            m_imagecache->release_tile (tile);
        int xtile = (x-spec().x) / tw;
        int ytile = (y-spec().y) / th;
        int ztile = (z-spec().z) / td;
        tilexbegin = spec().x + xtile*tw;
        tileybegin = spec().y + ytile*th;
        tilezbegin = spec().z + ztile*td;
        tile = m_imagecache->get_tile (m_name, subimage(), miplevel(), x, y, z);
    }

    size_t offset = ((y - tileybegin) * tw) + (x - tilexbegin);
    offset += ((z - tilezbegin) * tw * th);
    offset *= spec().pixel_bytes();
    TypeDesc format;
    return (const char *)m_imagecache->tile_pixels (tile, format) + offset;
}

}
OIIO_NAMESPACE_EXIT

max_stars_repo_name: fabiencastan/oiio

max_issues_repo_name: fabiencastan/oiio

max_forks_repo_name: fabiencastan/oiio


text:
// Copyright 2011 Google Inc. All Rights Reserved.
// Copyright 2015 Jin Qing.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Author: nadavs@google.com <Nadav Samet>
//         Jin Qing (http://blog.csdn.net/jq0123)

#include <stdio.h>

#include <boost/lexical_cast.hpp>
#include <boost/make_shared.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <glog/logging.h>
#include <zmq.hpp>

#include "gtest/gtest.h"
#include "rpcz/application.hpp"
#include "rpcz/application_error_code.hpp"
#include "rpcz/callback.hpp"
#include "rpcz/connection.hpp"
#include "rpcz/connection_ptr.hpp"
#include "rpcz/manager.hpp"
#include "rpcz/rpc_controller.hpp"
#include "rpcz/rpc_error.hpp"
#include "rpcz/sync_event.hpp"
#include "rpcz/zmq_utils.hpp"
#include "rpcz/service_factory_map.hpp"

namespace rpcz {

class manager_test : public ::testing::Test {
 public:
  manager_test() {
  }
  ~manager_test() {
  }

 protected:
};

// friend function of connection.
void request_connection(connection& conn,
    message_vector& data, rpc_controller* ctrl)
{
    conn.request(data, ctrl);
}

TEST_F(manager_test, TestStartsAndFinishes) {
  ASSERT_TRUE(manager::is_destroyed());
  application::set_worker_threads(4);
  manager_ptr mgr = manager::get();
}

// Sink server will not reply.
void sink_server() {
  zmq::context_t context(1);
  zmq::socket_t socket(context, ZMQ_DEALER);
  // Use tcp because inproc must under the same zmq context.
  socket.bind("tcp://*:5556");

  bool should_quit = false;
  while (!should_quit) {
    message_vector v;
    GOOGLE_CHECK(read_message_to_vector(&socket, &v));
    ASSERT_EQ(3, v.size());
    if (message_to_string(v[1]) == "hello") {
      ASSERT_EQ("there", message_to_string(v[2]).substr(0, 5));
    } else if (message_to_string(v[1]) == "QUIT") {
      should_quit = true;
    } else {
      GOOGLE_CHECK(false) << "Unknown command: " << message_to_string(v[1]);
    }
  }
}

message_vector* create_simple_request(int number=0) {
  message_vector* request = new message_vector;
  request->push_back(string_to_message("hello"));
  char str[256];
  sprintf(str, "there_%d", number);
  request->push_back(string_to_message(str));
  return request;
}

message_vector* create_quit_request() {
  message_vector* request = new message_vector;
  request->push_back(string_to_message("QUIT"));
  request->push_back(string_to_message(""));
  return request;
}

TEST_F(manager_test, TestTimeoutAsync) {
  ASSERT_TRUE(manager::is_destroyed());
  application::set_worker_threads(4);
  manager_ptr mgr = manager::get();
  zmq::context_t context(1);
  zmq::socket_t server(context, ZMQ_DEALER);
  server.bind("tcp://*:5557");
  connection_ptr conn(new connection("tcp://localhost:5557"));
  scoped_ptr<message_vector> request(create_simple_request());

  struct handler {
    rpcz::sync_event event;
    void operator()(const rpc_error* error, const void*, size_t) {
      ASSERT_TRUE(NULL != error);
      ASSERT_EQ(error_code::TIMEOUT_EXPIRED, error->get_error_code());
      event.signal();
    }
  } hdl;

  request_connection(*conn, *request,
      new rpc_controller(0, boost::ref(hdl), 0));
  hdl.event.wait();
}

class barrier_handler {
 public:
  barrier_handler() : count_(0) {}

  void operator()(const rpc_error*, const void*, size_t) {
    boost::unique_lock<boost::mutex> lock(mutex_);
    ++count_;
    cond_.notify_all();
  }

  virtual void wait(int n) {
    boost::unique_lock<boost::mutex> lock(mutex_);
    while (count_ < n) {
      cond_.wait(lock);
    }
  }

 private:
  boost::mutex mutex_;
  boost::condition_variable cond_;
  int count_;
};

void SendManyMessages(const connection_ptr& conn) {
  const int request_count = 1500;
  barrier_handler barrier;
  for (int i = 0; i < request_count; ++i) {
    message_vector* request = create_simple_request(i);
    request_connection(*conn, *request,
        new rpc_controller(i, boost::ref(barrier), 0/*ms*/));
  }
  barrier.wait(request_count);
}

TEST_F(manager_test, ManyClientsTest) {
  ASSERT_TRUE(manager::is_destroyed());
  application::set_worker_threads(4);
  manager_ptr mgr = manager::get();

  boost::thread thrd(sink_server);

  connection_ptr conn(new connection("tcp://localhost:5556"));
  SendManyMessages(conn);
  scoped_ptr<message_vector> request(create_quit_request());
  struct handler {
    rpcz::sync_event event;
    void operator()(const rpc_error*, const void*, size_t) {
      event.signal();
    }
  } hdl;
  request_connection(*conn, *request,
      new rpc_controller(12345678, boost::ref(hdl), 0/*ms*/));
  hdl.event.wait();
  thrd.join();
}

TEST_F(manager_test, TestUnbind) {
  ASSERT_TRUE(manager::is_destroyed());
  manager_ptr mgr = manager::get();
  const char kEndpoint[] = "inproc://server.point";
  mgr->bind(kEndpoint, boost::make_shared<service_factory_map>());
  mgr->unbind(kEndpoint);
}

const static char* kEndpoint = "inproc://test";
const static char* kReply = "gotit";

void DoThis(zmq::context_t* context) {
  BOOST_ASSERT(context);
  LOG(INFO)<<"Creating socket. Context="<<context;
  zmq::socket_t socket(*context, ZMQ_PUSH);
  socket.connect(kEndpoint);
  send_string(&socket, kReply);
  socket.close();
  LOG(INFO)<<"socket closed";
}

TEST_F(manager_test, ProcessesSingleCallback) {
  ASSERT_TRUE(manager::is_destroyed());
  application::set_worker_threads(4);
  manager_ptr mgr = manager::get();
  zmq::context_t context(1);
  zmq::socket_t socket(context, ZMQ_PULL);
  socket.bind(kEndpoint);
  mgr->add(new_callback(&DoThis, &context));
  message_vector messages;
  CHECK(read_message_to_vector(&socket, &messages));
  ASSERT_EQ(1, messages.size());
  CHECK_EQ(kReply, message_to_string(messages[0]));
}

void Increment(boost::mutex* mu,
               boost::condition_variable* cond, int* x) {
  mu->lock();
  (*x)++;
  cond->notify_one();
  mu->unlock();
}

void add_many_closures() {
  boost::mutex mu;
  boost::condition_variable cond;
  boost::unique_lock<boost::mutex> lock(mu);
  int x = 0;
  const int kMany = 137;
  manager_ptr mgr = manager::get();
  for (int i = 0; i < kMany; ++i) {
    mgr->add(new_callback(&Increment, &mu, &cond, &x));
  }
  CHECK_EQ(0, x);  // since we are holding the lock
  while (x != kMany) {
    cond.wait(lock);
  }
}

TEST_F(manager_test, ProcessesManyCallbacksFromManyThreads) {
  ASSERT_TRUE(manager::is_destroyed());
  const int thread_count = 10;
  application::set_worker_threads(thread_count);
  manager_ptr mgr = manager::get();
  boost::thread_group thread_group;
  for (int i = 0; i < thread_count; ++i) {
    thread_group.add_thread(
        new boost::thread(add_many_closures));
  }
  thread_group.join_all();
}
}  // namespace rpcz