<commit_before>/**
 * @file  main.cpp
 * @brief A few short examples in a row.
 *
 *  Demonstrate how-to use the SQLite++ wrapper
 *
 * Copyright (c) 2012-2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
 *
 * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
 * or copy at http://opensource.org/licenses/MIT)
 */

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

#include "../../src/SQLiteC++.h"

static const char* filename_example_db3 = "examples/example1/example.db3";
static const char* filename_logo_png    = "examples/example1/logo.png";

/// Object Oriented Basic example
class Example
{
public:
    // Constructor
    Example(void) :
        mDb(filename_example_db3),                                  // Open a database file in readonly mode
        mQuery(mDb, "SELECT * FROM test WHERE weight > :min_weight")// Compile a SQL query, containing one parameter (index 1)
    {
    }
    virtual ~Example(void)
    {
    }

    /// List the rows where the "weight" column is greater than the provided aParamValue
    void ListGreaterThan (const int aParamValue)
    {
        std::cout << "ListGreaterThan (" << aParamValue << ")\n";

        // Bind the integer value provided to the first parameter of the SQL query
        mQuery.bind(":min_weight", aParamValue); // same as mQuery.bind(1, aParamValue);

        // Loop to execute the query step by step, to get one a row of results at a time
        while (mQuery.executeStep())
        {
            std::cout << "row : (" << mQuery.getColumn(0) << ", " << mQuery.getColumn(1) << ", " << mQuery.getColumn(2) << ")\n";
        }

        // Reset the query to be able to use it again later
        mQuery.reset();
    }

private:
    SQLite::Database    mDb;    ///< Database connection
    SQLite::Statement   mQuery; ///< Database prepared SQL query
};

int main (void)
{
    // Basic example (1/6) :
    try
    {
        // Open a database file in readonly mode
        SQLite::Database    db(filename_example_db3);  // SQLITE_OPEN_READONLY
        std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n";

        // Test if the 'test' table exists
        bool bExists = db.tableExists("test");
        std::cout << "SQLite table 'test' exists=" << bExists << "\n";

        // Get a single value result with an easy to use shortcut
        std::string value = db.execAndGet("SELECT value FROM test WHERE id=2");
        std::cout << "execAndGet=" << value.c_str() << std::endl;

        // Compile a SQL query, containing one parameter (index 1)
        SQLite::Statement   query(db, "SELECT * FROM test WHERE weight > ?");
        std::cout << "SQLite statement '" << query.getQuery().c_str() << "' compiled (" << query.getColumnCount () << " columns in the result)\n";
        // Bind the integer value 2 to the first parameter of the SQL query
        query.bind(1, 2);
        std::cout << "binded with integer value 2 :\n";

        // Loop to execute the query step by step, to get one a row of results at a time
        while (query.executeStep())
        {
            // Demonstrate how to get some typed column value (and the equivalent explicit call)
            int         id      = query.getColumn(0); // = query.getColumn(0).getInt()
          //const char* pvalue  = query.getColumn(1); // = query.getColumn(1).getText()
            std::string value2  = query.getColumn(1); // = query.getColumn(1).getText()
            int         bytes   = query.getColumn(1).getBytes();
            double      weight  = query.getColumn(2); // = query.getColumn(2).getInt()

			std::string name(query.getColumn(0).getName());

            std::cout << "row : (" << id << " [" << name.c_str() << "], \"" << value2.c_str() << "\" "  << bytes << "B, " << weight << ")\n";
        }

        // Reset the query to use it again
        query.reset();
        std::cout << "SQLite statement '" << query.getQuery().c_str() << "' reseted (" << query.getColumnCount () << " columns in the result)\n";
        // Bind the string value "6" to the first parameter of the SQL query
        query.bind(1, "6");
        std::cout << "binded with string value \"6\" :\n";

        while (query.executeStep())
        {
            // Demonstrate that inserting column value in a std:ostream is natural
            std::cout << "row : (" << query.getColumn(0) << ", " << query.getColumn(1) << ", " << query.getColumn(2) << ")\n";
        }
    }
    catch (std::exception& e)
    {
        std::cout << "SQLite exception: " << e.what() << std::endl;
        abort(); // unexpected error : abort the example program
    }

    ////////////////////////////////////////////////////////////////////////////
    // Object Oriented Basic example (2/6) :
    try
    {
        // Open the database and compile the query
        Example example;

        // Demonstrate the way to use the same query with different parameter values
        example.ListGreaterThan(8);
        example.ListGreaterThan(6);
        example.ListGreaterThan(2);
    }
    catch (std::exception& e)
    {
        std::cout << "SQLite exception: " << e.what() << std::endl;
        abort(); // unexpected error : abort the example program
    }

    // The execAndGet wrapper example (3/6) :
    try
    {
        // Open a database file in readonly mode
        SQLite::Database    db(filename_example_db3);  // SQLITE_OPEN_READONLY
        std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n";

        // WARNING: Be very careful with this dangerous method: you have to
        // make a COPY OF THE result, else it will be destroy before the next line
        // (when the underlying temporary Statement and Column objects are destroyed)
        std::string value = db.execAndGet("SELECT value FROM test WHERE id=2");
        std::cout << "execAndGet=" << value.c_str() << std::endl;
    }
    catch (std::exception& e)
    {
        std::cout << "SQLite exception: " << e.what() << std::endl;
        abort(); // unexpected error : abort the example program
    }

    ////////////////////////////////////////////////////////////////////////////
    // Simple batch queries example (4/6) :
    try
    {
        // Open a database file in create/write mode
        SQLite::Database    db("test.db3", SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
        std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n";

        db.exec("DROP TABLE IF EXISTS test");

        db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)");

        // first row
        int nb = db.exec("INSERT INTO test VALUES (NULL, \"test\")");
        std::cout << "INSERT INTO test VALUES (NULL, \"test\")\", returned " << nb << std::endl;

        // second row
        nb = db.exec("INSERT INTO test VALUES (NULL, \"second\")");
        std::cout << "INSERT INTO test VALUES (NULL, \"second\")\", returned " << nb << std::endl;

        // update the second row
        nb = db.exec("UPDATE test SET value=\"second-updated\" WHERE id='2'");
        std::cout << "UPDATE test SET value=\"second-updated\" WHERE id='2', returned " << nb << std::endl;

        // Check the results : expect two row of result
        SQLite::Statement   query(db, "SELECT * FROM test");
        std::cout << "SELECT * FROM test :\n";
        while (query.executeStep())
        {
            std::cout << "row : (" << query.getColumn(0) << ", " << query.getColumn(1) << ")\n";
        }

        db.exec("DROP TABLE test");
    }
    catch (std::exception& e)
    {
        std::cout << "SQLite exception: " << e.what() << std::endl;
        abort(); // unexpected error : abort the example program
    }
    remove("test.db3");

    ////////////////////////////////////////////////////////////////////////////
    // RAII transaction example (5/6) :
    try
    {
        // Open a database file in create/write mode
        SQLite::Database    db("transaction.db3", SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
        std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n";

        db.exec("DROP TABLE IF EXISTS test");

        // Exemple of a successful transaction :
        try
        {
            // Begin transaction
            SQLite::Transaction transaction(db);

            db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)");

            int nb = db.exec("INSERT INTO test VALUES (NULL, \"test\")");
            std::cout << "INSERT INTO test VALUES (NULL, \"test\")\", returned " << nb << std::endl;

            // Commit transaction
            transaction.commit();
        }
        catch (std::exception& e)
        {
            std::cout << "SQLite exception: " << e.what() << std::endl;
            abort(); // unexpected error : abort the example program
        }

        // Exemple of a rollbacked transaction :
        try
        {
            // Begin transaction
            SQLite::Transaction transaction(db);

            int nb = db.exec("INSERT INTO test VALUES (NULL, \"second\")");
            std::cout << "INSERT INTO test VALUES (NULL, \"second\")\", returned " << nb << std::endl;

            nb = db.exec("INSERT INTO test ObviousError");
            std::cout << "INSERT INTO test \"error\", returned " << nb << std::endl;

            abort(); // unexpected success : abort the example program

            // Commit transaction
            transaction.commit();
        }
        catch (std::exception& e)
        {
            std::cout << "SQLite exception: " << e.what() << std::endl;
            // expected error, see above
        }

        // Check the results (expect only one row of result, as the second one has been rollbacked by the error)
        SQLite::Statement   query(db, "SELECT * FROM test");
        std::cout << "SELECT * FROM test :\n";
        while (query.executeStep())
        {
            std::cout << "row : (" << query.getColumn(0) << ", " << query.getColumn(1) << ")\n";
        }
    }
    catch (std::exception& e)
    {
        std::cout << "SQLite exception: " << e.what() << std::endl;
        abort(); // unexpected error : abort the example program
    }
    remove("transaction.db3");

    ////////////////////////////////////////////////////////////////////////////
    // Binary blob and in-memory database example (6/6) :
    try
    {
        // Open a database file in create/write mode
        SQLite::Database    db(":memory:", SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
        std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n";

        db.exec("DROP TABLE IF EXISTS test");
        db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value BLOB)");

        FILE* fp = fopen(filename_logo_png, "rb");
        if (NULL != fp)
        {
            char  buffer[16*1024];
            void* blob = &buffer;
            size_t size = fread(blob, 1, 16*1024, fp);
            buffer[size] = '\0';
            fclose (fp);
            std::cout << "blob size=" << size << " :\n";

            // Insert query
            SQLite::Statement   query(db, "INSERT INTO test VALUES (NULL, ?)");
            // Bind the blob value to the first parameter of the SQL query
            query.bind(1, blob, size);
            std::cout << "blob binded successfully\n";

            // Execute the one-step query to insert the blob
            int nb = query.exec ();
            std::cout << "INSERT INTO test VALUES (NULL, ?)\", returned " << nb << std::endl;
        }
        else
        {
            std::cout << "file " << filename_logo_png << " not found !\n";
            abort(); // unexpected error : abort the example program
        }

        fp = fopen("out.png", "wb");
        if (NULL != fp)
        {
            const void* blob = NULL;
            size_t size;

            SQLite::Statement   query(db, "SELECT * FROM test");
            std::cout << "SELECT * FROM test :\n";
            if (query.executeStep())
            {
                SQLite::Column colBlob = query.getColumn(1);
                blob = colBlob.getBlob ();
                size = colBlob.getBytes ();
                std::cout << "row : (" << query.getColumn(0) << ", size=" << size << ")\n";
                size_t sizew = fwrite(blob, 1, size, fp);
                assert(sizew == size);
                fclose (fp);
            }
        }
        else
        {
            std::cout << "file out.png not created !\n";
            abort(); // unexpected error : abort the example program
        }
    }
    catch (std::exception& e)
    {
        std::cout << "SQLite exception: " << e.what() << std::endl;
        abort(); // unexpected error : abort the example program
    }
    remove("out.png");

    std::cout << "everything ok, quitting\n";

    return 0;
}
<commit_msg>Improving the example, showing the column names<commit_after>/**
 * @file  main.cpp
 * @brief A few short examples in a row.
 *
 *  Demonstrate how-to use the SQLite++ wrapper
 *
 * Copyright (c) 2012-2013 Sebastien Rombauts (sebastien.rombauts@gmail.com)
 *
 * Distributed under the MIT License (MIT) (See accompanying file LICENSE.txt
 * or copy at http://opensource.org/licenses/MIT)
 */

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

#include "../../src/SQLiteC++.h"

static const char* filename_example_db3 = "examples/example1/example.db3";
static const char* filename_logo_png    = "examples/example1/logo.png";

/// Object Oriented Basic example
class Example
{
public:
    // Constructor
    Example(void) :
        mDb(filename_example_db3),                                  // Open a database file in readonly mode
        mQuery(mDb, "SELECT * FROM test WHERE weight > :min_weight")// Compile a SQL query, containing one parameter (index 1)
    {
    }
    virtual ~Example(void)
    {
    }

    /// List the rows where the "weight" column is greater than the provided aParamValue
    void ListGreaterThan (const int aParamValue)
    {
        std::cout << "ListGreaterThan (" << aParamValue << ")\n";

        // Bind the integer value provided to the first parameter of the SQL query
        mQuery.bind(":min_weight", aParamValue); // same as mQuery.bind(1, aParamValue);

        // Loop to execute the query step by step, to get one a row of results at a time
        while (mQuery.executeStep())
        {
            std::cout << "row (" << mQuery.getColumn(0) << ", \"" << mQuery.getColumn(1) << "\", " << mQuery.getColumn(2) << ")\n";
        }

        // Reset the query to be able to use it again later
        mQuery.reset();
    }

private:
    SQLite::Database    mDb;    ///< Database connection
    SQLite::Statement   mQuery; ///< Database prepared SQL query
};

int main (void)
{
    // Basic example (1/6) :
    try
    {
        // Open a database file in readonly mode
        SQLite::Database    db(filename_example_db3);  // SQLITE_OPEN_READONLY
        std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n";

        // Test if the 'test' table exists
        bool bExists = db.tableExists("test");
        std::cout << "SQLite table 'test' exists=" << bExists << "\n";

        // Get a single value result with an easy to use shortcut
        std::string value = db.execAndGet("SELECT value FROM test WHERE id=2");
        std::cout << "execAndGet=" << value.c_str() << std::endl;

        // Compile a SQL query, containing one parameter (index 1)
        SQLite::Statement   query(db, "SELECT * FROM test WHERE weight > ?");
        std::cout << "SQLite statement '" << query.getQuery().c_str() << "' compiled (" << query.getColumnCount () << " columns in the result)\n";
        // Bind the integer value 2 to the first parameter of the SQL query
        query.bind(1, 2);
        std::cout << "binded with integer value '2' :\n";

        // Loop to execute the query step by step, to get one a row of results at a time
        while (query.executeStep())
        {
            // Demonstrate how to get some typed column value (and the equivalent explicit call)
            int         id      = query.getColumn(0); // = query.getColumn(0).getInt()
          //const char* pvalue  = query.getColumn(1); // = query.getColumn(1).getText()
            std::string value2  = query.getColumn(1); // = query.getColumn(1).getText()
            int         bytes   = query.getColumn(1).getBytes();
            double      weight  = query.getColumn(2); // = query.getColumn(2).getInt()

#ifdef SQLITE_ENABLE_COLUMN_METADATA
            static bool bFirst = true;
            if (bFirst)
            {
                // Show how to get the name of a column.
                // Requires the SQLITE_ENABLE_COLUMN_METADATA preprocessor macro to be also defined at compile times of the SQLite library.
                std::string name0 = query.getColumn(0).getName();
                std::string name1 = query.getColumn(1).getName();
                std::string name2 = query.getColumn(2).getName();
                std::cout << "table 'test' [\"" << name0.c_str() << "\", \"" << name1.c_str() << "\", \"" << name2.c_str() << "\"]\n";
                bFirst = false;
            }
#endif
            std::cout << "row (" << id << ", \"" << value2.c_str() << "\" "  << bytes << " bytes, " << weight << ")\n";

        }

        // Reset the query to use it again
        query.reset();
        std::cout << "SQLite statement '" << query.getQuery().c_str() << "' reseted (" << query.getColumnCount () << " columns in the result)\n";
        // Bind the string value "6" to the first parameter of the SQL query
        query.bind(1, "6");
        std::cout << "binded with string value \"6\" :\n";

        while (query.executeStep())
        {
            // Demonstrate that inserting column value in a std:ostream is natural
            std::cout << "row (" << query.getColumn(0) << ", \"" << query.getColumn(1) << "\", " << query.getColumn(2) << ")\n";
        }
    }
    catch (std::exception& e)
    {
        std::cout << "SQLite exception: " << e.what() << std::endl;
        abort(); // unexpected error : abort the example program
    }

    ////////////////////////////////////////////////////////////////////////////
    // Object Oriented Basic example (2/6) :
    try
    {
        // Open the database and compile the query
        Example example;

        // Demonstrate the way to use the same query with different parameter values
        example.ListGreaterThan(8);
        example.ListGreaterThan(6);
        example.ListGreaterThan(2);
    }
    catch (std::exception& e)
    {
        std::cout << "SQLite exception: " << e.what() << std::endl;
        abort(); // unexpected error : abort the example program
    }

    // The execAndGet wrapper example (3/6) :
    try
    {
        // Open a database file in readonly mode
        SQLite::Database    db(filename_example_db3);  // SQLITE_OPEN_READONLY
        std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n";

        // WARNING: Be very careful with this dangerous method: you have to
        // make a COPY OF THE result, else it will be destroy before the next line
        // (when the underlying temporary Statement and Column objects are destroyed)
        std::string value = db.execAndGet("SELECT value FROM test WHERE id=2");
        std::cout << "execAndGet=" << value.c_str() << std::endl;
    }
    catch (std::exception& e)
    {
        std::cout << "SQLite exception: " << e.what() << std::endl;
        abort(); // unexpected error : abort the example program
    }

    ////////////////////////////////////////////////////////////////////////////
    // Simple batch queries example (4/6) :
    try
    {
        // Open a database file in create/write mode
        SQLite::Database    db("test.db3", SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
        std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n";

        db.exec("DROP TABLE IF EXISTS test");

        db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)");

        // first row
        int nb = db.exec("INSERT INTO test VALUES (NULL, \"test\")");
        std::cout << "INSERT INTO test VALUES (NULL, \"test\")\", returned " << nb << std::endl;

        // second row
        nb = db.exec("INSERT INTO test VALUES (NULL, \"second\")");
        std::cout << "INSERT INTO test VALUES (NULL, \"second\")\", returned " << nb << std::endl;

        // update the second row
        nb = db.exec("UPDATE test SET value=\"second-updated\" WHERE id='2'");
        std::cout << "UPDATE test SET value=\"second-updated\" WHERE id='2', returned " << nb << std::endl;

        // Check the results : expect two row of result
        SQLite::Statement   query(db, "SELECT * FROM test");
        std::cout << "SELECT * FROM test :\n";
        while (query.executeStep())
        {
            std::cout << "row (" << query.getColumn(0) << ", \"" << query.getColumn(1) << "\")\n";
        }

        db.exec("DROP TABLE test");
    }
    catch (std::exception& e)
    {
        std::cout << "SQLite exception: " << e.what() << std::endl;
        abort(); // unexpected error : abort the example program
    }
    remove("test.db3");

    ////////////////////////////////////////////////////////////////////////////
    // RAII transaction example (5/6) :
    try
    {
        // Open a database file in create/write mode
        SQLite::Database    db("transaction.db3", SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
        std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n";

        db.exec("DROP TABLE IF EXISTS test");

        // Exemple of a successful transaction :
        try
        {
            // Begin transaction
            SQLite::Transaction transaction(db);

            db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)");

            int nb = db.exec("INSERT INTO test VALUES (NULL, \"test\")");
            std::cout << "INSERT INTO test VALUES (NULL, \"test\")\", returned " << nb << std::endl;

            // Commit transaction
            transaction.commit();
        }
        catch (std::exception& e)
        {
            std::cout << "SQLite exception: " << e.what() << std::endl;
            abort(); // unexpected error : abort the example program
        }

        // Exemple of a rollbacked transaction :
        try
        {
            // Begin transaction
            SQLite::Transaction transaction(db);

            int nb = db.exec("INSERT INTO test VALUES (NULL, \"second\")");
            std::cout << "INSERT INTO test VALUES (NULL, \"second\")\", returned " << nb << std::endl;

            nb = db.exec("INSERT INTO test ObviousError");
            std::cout << "INSERT INTO test \"error\", returned " << nb << std::endl;

            abort(); // unexpected success : abort the example program

            // Commit transaction
            transaction.commit();
        }
        catch (std::exception& e)
        {
            std::cout << "SQLite exception: " << e.what() << std::endl;
            // expected error, see above
        }

        // Check the results (expect only one row of result, as the second one has been rollbacked by the error)
        SQLite::Statement   query(db, "SELECT * FROM test");
        std::cout << "SELECT * FROM test :\n";
        while (query.executeStep())
        {
            std::cout << "row (" << query.getColumn(0) << ", \"" << query.getColumn(1) << "\")\n";
        }
    }
    catch (std::exception& e)
    {
        std::cout << "SQLite exception: " << e.what() << std::endl;
        abort(); // unexpected error : abort the example program
    }
    remove("transaction.db3");

    ////////////////////////////////////////////////////////////////////////////
    // Binary blob and in-memory database example (6/6) :
    try
    {
        // Open a database file in create/write mode
        SQLite::Database    db(":memory:", SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE);
        std::cout << "SQLite database file '" << db.getFilename().c_str() << "' opened successfully\n";

        db.exec("DROP TABLE IF EXISTS test");
        db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value BLOB)");

        FILE* fp = fopen(filename_logo_png, "rb");
        if (NULL != fp)
        {
            char  buffer[16*1024];
            void* blob = &buffer;
            size_t size = fread(blob, 1, 16*1024, fp);
            buffer[size] = '\0';
            fclose (fp);
            std::cout << "blob size=" << size << " :\n";

            // Insert query
            SQLite::Statement   query(db, "INSERT INTO test VALUES (NULL, ?)");
            // Bind the blob value to the first parameter of the SQL query
            query.bind(1, blob, size);
            std::cout << "blob binded successfully\n";

            // Execute the one-step query to insert the blob
            int nb = query.exec ();
            std::cout << "INSERT INTO test VALUES (NULL, ?)\", returned " << nb << std::endl;
        }
        else
        {
            std::cout << "file " << filename_logo_png << " not found !\n";
            abort(); // unexpected error : abort the example program
        }

        fp = fopen("out.png", "wb");
        if (NULL != fp)
        {
            const void* blob = NULL;
            size_t size;

            SQLite::Statement   query(db, "SELECT * FROM test");
            std::cout << "SELECT * FROM test :\n";
            if (query.executeStep())
            {
                SQLite::Column colBlob = query.getColumn(1);
                blob = colBlob.getBlob ();
                size = colBlob.getBytes ();
                std::cout << "row (" << query.getColumn(0) << ", size=" << size << ")\n";
                size_t sizew = fwrite(blob, 1, size, fp);
                assert(sizew == size);
                fclose (fp);
            }
        }
        else
        {
            std::cout << "file out.png not created !\n";
            abort(); // unexpected error : abort the example program
        }
    }
    catch (std::exception& e)
    {
        std::cout << "SQLite exception: " << e.what() << std::endl;
        abort(); // unexpected error : abort the example program
    }
    remove("out.png");

    std::cout << "everything ok, quitting\n";

    return 0;
}
<|endoftext|>


<commit_before>/***********************************************************************
Moses - factored phrase-based language decoder
Copyright (C) 2010 University of Edinburgh

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

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
***********************************************************************/
#define BOOST_TEST_MODULE BackwardTest
#include <boost/test/unit_test.hpp>

#include "lm/config.hh"
#include "lm/left.hh"
#include "lm/model.hh"
#include "lm/state.hh"

#include "moses/Sentence.h"
#include "moses/TypeDef.h"

#include "moses/StaticData.h"

//#include "BackwardLMState.h"
#include "moses/LM/Backward.h"
#include "moses/LM/BackwardLMState.h"
#include "moses/Util.h"

#include "lm/state.hh"
#include "lm/left.hh"

#include <vector>

using namespace Moses;
//using namespace std;
/*
template <class M> void Foo() {

  Moses::BackwardLanguageModel<M> *backwardLM;
  // = new Moses::BackwardLanguageModel<M>( filename, factorType, lazy );

}
template <class M> void Everything() {
  //  Foo<M>();
}
*/

namespace Moses {

// Apparently some Boost versions use templates and are pretty strict about types matching.
#define SLOPPY_CHECK_CLOSE(ref, value, tol) BOOST_CHECK_CLOSE(static_cast<double>(ref), static_cast<double>(value), static_cast<double>(tol));

class BackwardLanguageModelTest {

  public:
    BackwardLanguageModelTest() :
      dummyInput(new Sentence()),
      backwardLM(
	       //           BackwardLanguageModel
		 //		 new Moses::BackwardLanguageModel<Model>(
	      ConstructBackwardLM(
		  		     boost::unit_test::framework::master_test_suite().argv[1],
		 		     0,
		 		     false)
		 )
    {
      // This space intentionally left blank
    }

    ~BackwardLanguageModelTest() {
      delete dummyInput;
      delete backwardLM;
    }

    void testEmptyHypothesis() {
      FFState *ffState = const_cast< FFState * >(backwardLM->EmptyHypothesisState( *dummyInput ));

      BOOST_CHECK( ffState != NULL );
      /*
      //      lm::ngram::ChartState &state = static_cast< const BackwardLMState >(*ffState).state;
      BackwardLMState *lmState = static_cast< BackwardLMState* >(ffState);
      //const lm::ngram::ChartState &state = static_cast< const BackwardLMState* >(ffState)->state;
      //lm::ngram::ChartState &state = lmState->state;

      //      BOOST_CHECK( state.left.length == 1 );
      //      BOOST_CHECK( state.right.Length() == 0 );

      BackwardLanguageModel<lm::ngram::ProbingModel> *lm = static_cast< BackwardLanguageModel<lm::ngram::ProbingModel> *>(backwardLM);
    lm::ngram::ChartState &state = lmState->state;
    lm::ngram::RuleScore<lm::ngram::ProbingModel> ruleScore(*(lm->m_ngram), state);
    double score = ruleScore.Finish();
    SLOPPY_CHECK_CLOSE(-1.457693, score, 0.001);
      */
      delete ffState;
    }

    void testCalcScore() {
      //std::vector<WordIndex> words

      Phrase phrase;
      BOOST_CHECK( phrase.GetSize() == 0 );

      std::vector<FactorType> outputFactorOrder;
      outputFactorOrder.push_back(0);

      phrase.CreateFromString(
			      //StaticData::Instance().GetOutputFactorOrder(),
			      outputFactorOrder,
			      "the",
			      StaticData::Instance().GetFactorDelimiter());

      BOOST_CHECK( phrase.GetSize() == 1 );

      // BackwardLanguageModel<lm::ngram::ProbingModel> *lm = static_cast< BackwardLanguageModel<lm::ngram::ProbingModel> *>(backwardLM);

      //Word &word = phrase.GetWord(0);
      //Word
      //      BOOST_CHECK( word == lm->m_ngram->GetVocabulary().Index("the") );

      float fullScore;
      float ngramScore;
      size_t oovCount;
      backwardLM->CalcScore(phrase, fullScore, ngramScore, oovCount);

      BOOST_CHECK( oovCount == 0 );
      SLOPPY_CHECK_CLOSE( TransformLMScore(-1.383059), fullScore, 0.01);
      SLOPPY_CHECK_CLOSE( TransformLMScore( 0.0 ), ngramScore, 0.01);

    }

  private:
    const Sentence *dummyInput;
  //    BackwardLanguageModel<Model> *backwardLM;
    LanguageModel *backwardLM;
  /*
    void LookupVocab(const StringPiece &str, std::vector<WordIndex *> &out) {

      out.clear();
      for (util::TokenIter<util::SingleCharacter, true> i(str, ' '); i; ++i) {
	out.push_back(lm->m_ngram.GetVocabulary().Index(*i));
      }
    }
  */
};

}

const char *FileLocation() {
  if (boost::unit_test::framework::master_test_suite().argc < 2) {
    BOOST_FAIL("Jamfile must specify arpa file for this test, but did not");
  }
  return boost::unit_test::framework::master_test_suite().argv[1];
}

BOOST_AUTO_TEST_CASE(ProbingAll) {
  //  Everything<lm::ngram::Model>();
  /*
  const std::string filename( boost::unit_test::framework::master_test_suite().argv[1] );
  size_t factorType = 0;
  bool lazy = false;

  LanguageModel *backwardLM = ConstructBackwardLM( filename, factorType, lazy );
  const Sentence *dummyInput = new Sentence();

  const FFState *ffState = backwardLM->EmptyHypothesisState( *dummyInput );

  //new BackwardLanguageModel<lm::ngram::Model>( filename, factorType, lazy );

  delete dummyInput;
  delete backwardLM;
  */
  //BackwardLanguageModelTest<lm::ngram::TrieModel> test;
BackwardLanguageModelTest test;
  test.testEmptyHypothesis();
  test.testCalcScore();
  //  test->testEmptyHypothesis();
}
<commit_msg>Work on BackwardLM unit testing<commit_after>/***********************************************************************
Moses - factored phrase-based language decoder
Copyright (C) 2010 University of Edinburgh

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

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
***********************************************************************/
#define BOOST_TEST_MODULE BackwardTest
#include <boost/test/unit_test.hpp>

#include "lm/config.hh"
#include "lm/left.hh"
#include "lm/model.hh"
#include "lm/state.hh"

#include "moses/Sentence.h"
#include "moses/TypeDef.h"

#include "moses/StaticData.h"

//#include "BackwardLMState.h"
#include "moses/LM/Backward.h"
#include "moses/LM/BackwardLMState.h"
#include "moses/Util.h"

#include "lm/state.hh"
#include "lm/left.hh"

#include <vector>

using namespace Moses;
//using namespace std;
/*
template <class M> void Foo() {

  Moses::BackwardLanguageModel<M> *backwardLM;
  // = new Moses::BackwardLanguageModel<M>( filename, factorType, lazy );

}
template <class M> void Everything() {
  //  Foo<M>();
}
*/

namespace Moses {

// Apparently some Boost versions use templates and are pretty strict about types matching.
#define SLOPPY_CHECK_CLOSE(ref, value, tol) BOOST_CHECK_CLOSE(static_cast<double>(ref), static_cast<double>(value), static_cast<double>(tol));

class BackwardLanguageModelTest {

  public:
    BackwardLanguageModelTest() :
      dummyInput(new Sentence()),
      backwardLM(
	       //           BackwardLanguageModel
		 //		 new Moses::BackwardLanguageModel<Model>(
	      ConstructBackwardLM(
		  		     boost::unit_test::framework::master_test_suite().argv[1],
		 		     0,
		 		     false)
		 )
    {
      // This space intentionally left blank
    }

    ~BackwardLanguageModelTest() {
      delete dummyInput;
      delete backwardLM;
    }

    void testEmptyHypothesis() {
      FFState *ffState = const_cast< FFState * >(backwardLM->EmptyHypothesisState( *dummyInput ));

      BOOST_CHECK( ffState != NULL );

      delete ffState;
    }

    void testCalcScore() {

      double p_the      = -1.383059;
      double p_licenses = -2.360783;
      double p_for      = -1.661813;
      double p_most     = -2.360783;
      double p_software = -1.62042;

      double p_the_licenses  = -0.9625873;
      double p_licenses_for  = -1.661557;
      double p_for_most      = -0.4526253;
      double p_most_software = -1.70295;

      double p_the_licenses_for  = p_the_licenses + p_licenses_for;
      double p_licenses_for_most = p_licenses_for + p_for_most;

      // the
      {
	Phrase phrase;
	BOOST_CHECK( phrase.GetSize() == 0 );

	std::vector<FactorType> outputFactorOrder;
	outputFactorOrder.push_back(0);

	phrase.CreateFromString(
				outputFactorOrder,
				"the",
				StaticData::Instance().GetFactorDelimiter());

	BOOST_CHECK( phrase.GetSize() == 1 );

	float fullScore;
	float ngramScore;
	size_t oovCount;
	backwardLM->CalcScore(phrase, fullScore, ngramScore, oovCount);

	BOOST_CHECK( oovCount == 0 );
	SLOPPY_CHECK_CLOSE( TransformLMScore(p_the), fullScore, 0.01);
	SLOPPY_CHECK_CLOSE( TransformLMScore( 0.0 ), ngramScore, 0.01);
      }

      // the licenses
      {
	Phrase phrase;
	BOOST_CHECK( phrase.GetSize() == 0 );

	std::vector<FactorType> outputFactorOrder;
	outputFactorOrder.push_back(0);

	phrase.CreateFromString(
				outputFactorOrder,
				"the licenses",
				StaticData::Instance().GetFactorDelimiter());

	BOOST_CHECK( phrase.GetSize() == 2 );

	float fullScore;
	float ngramScore;
	size_t oovCount;
	backwardLM->CalcScore(phrase, fullScore, ngramScore, oovCount);

	BOOST_CHECK( oovCount == 0 );
	SLOPPY_CHECK_CLOSE( TransformLMScore(p_licenses + p_the_licenses), fullScore, 0.01);
	SLOPPY_CHECK_CLOSE( TransformLMScore( 0.0 ), ngramScore, 0.01);
      }

      // the licenses for
      {
	Phrase phrase;
	BOOST_CHECK( phrase.GetSize() == 0 );

	std::vector<FactorType> outputFactorOrder;
	outputFactorOrder.push_back(0);

	phrase.CreateFromString(
				outputFactorOrder,
				"the licenses for",
				StaticData::Instance().GetFactorDelimiter());

	BOOST_CHECK( phrase.GetSize() == 3 );

	float fullScore;
	float ngramScore;
	size_t oovCount;
	backwardLM->CalcScore(phrase, fullScore, ngramScore, oovCount);

	BOOST_CHECK( oovCount == 0 );
	SLOPPY_CHECK_CLOSE( TransformLMScore( p_the_licenses_for ), ngramScore, 0.01);
	SLOPPY_CHECK_CLOSE( TransformLMScore(p_for + p_licenses_for + p_the_licenses), fullScore, 0.01);
      }

      // the licenses for most
      {
	Phrase phrase;
	BOOST_CHECK( phrase.GetSize() == 0 );

	std::vector<FactorType> outputFactorOrder;
	outputFactorOrder.push_back(0);

	phrase.CreateFromString(
				outputFactorOrder,
				"the licenses for most",
				StaticData::Instance().GetFactorDelimiter());

	BOOST_CHECK( phrase.GetSize() == 4 );

	float fullScore;
	float ngramScore;
	size_t oovCount;
	backwardLM->CalcScore(phrase, fullScore, ngramScore, oovCount);

	BOOST_CHECK( oovCount == 0 );
	SLOPPY_CHECK_CLOSE( TransformLMScore( p_the_licenses + p_licenses_for ), ngramScore, 0.01);
	SLOPPY_CHECK_CLOSE( TransformLMScore(p_most + p_for_most + p_licenses_for + p_the_licenses), fullScore, 0.01);
      }

    }

  private:
    const Sentence *dummyInput;
    LanguageModel *backwardLM;

};

}

const char *FileLocation() {
  if (boost::unit_test::framework::master_test_suite().argc < 2) {
    BOOST_FAIL("Jamfile must specify arpa file for this test, but did not");
  }
  return boost::unit_test::framework::master_test_suite().argv[1];
}

BOOST_AUTO_TEST_CASE(ProbingAll) {

  BackwardLanguageModelTest test;
  test.testEmptyHypothesis();
  test.testCalcScore();

}
<|endoftext|>


<commit_before>/***************************************************************************
 *  @file       binary_search_tree.hpp
 *  @author     Alan.W
 *  @date       24  June 2014
 *  @remark     Implementations for algorithims from CLRS using C++ templates.
 ***************************************************************************/
//!     page 294
//!     tree-insert(T,z)
/* 1    y = nil
 * 2    x = T.root
 * 3    whie x != nil
 * 4        y = x
 * 5        if z.key < x.key
 * 6            x = x.left
 * 7        else
 *              x = x.right
 * 8    z.parent = y
 * 9    if y == nil
 * 10       T.root = z  //i.e. was empty
 * 11   elseif z.key <y.key
 * 12       y.left = z
 * 13   else    y.right = z
 */

//!     page 288
//!     INORDER-TREE-WALK(x)    O(h)    =   O(lg n)
//1     if x != NIL
//2         INORDER-TREE-WALK(x.left)
//3         print x.key
//4         INORDER-TREE-WALK(x.right)

//!     page 291
//!     TREE-SEARCH(x,k)        O(h)    =   O(lg n)
//1     if x == NIL or k == x.key
//2         return x
//3     if k < x.key
//4         return TREE-SEARCH(x.left,  k)
//5     else
//6         return TREE-SEARCH(x.right, k)

//!     page 291
//!     ITERATIVE-TREE-SEARCH(x, k)     O(h)    =   O(lg n)
//1 	while x != NIL and k != x.key
//2		if k < x.key
//3			x = x.left
//4		else x = x.right
//5 	return x

//!     page 291
//!     TREE-MAXIMUM(x)                 O(h)    =   O(lg n)
//1     while x.right != NIL
//2         x = x.right
//3 	return x
//!     page 291
//!     TREE-MINIMUM(x)                  O(h)    =   O(lg n)
//1 	while x.left != NIL
//2         x = x.left
//3 	return x

//!
//! ex 12.1-3
//! Give a nonrecursive algorithm that performs an inorder tree walk. (Hint: An easy
//! solution uses a stack as an auxiliary data structure. A more complicated, but ele-
//! gant, solution uses no stack but assumes that we can test two pointers for equality.)
//!
//!     inorder_walk_nonrecur_with_stack(node)
/*      if(node)
 *          def stack
 *          while(node || !stack.empty())
 *              while(node)
 *                  stack.push(node)
 *                  node = node->left
 *              if(!stack.empty())
 *                  node = stack.pop()
 *                  node.print()
 *                  node = node->right
 */

//!
//! based on ch10::tree::binary_tree::checking _prev_print
//! can be found here:
//! https://github.com/Mooophy/CLRS/blob/master/ch10/tree.hpp
//!
//!     inorder_walk_by_checking_prev(node)
/*      def prev = null
 *      def curr = node
 *      while(curr)
 *
 *          if(!curr->left  ||  prev == curr->left)     //  for printing
 *              curr->print
 *
 *          if(prev == curr->parent)
 *              prev    =   curr
 *              curr    =   curr->left? left    :
 *                          curr->right?    curr->right :   curr->parent
 *          else if (prev == left && curr->right)
 *              prev    =   curr
 *              curr    =   curr->right
 *          else
 *              prev    =   curr
 *              curr    =   curr->parent
 */

//!
//! ex12.1-4
//! Give recursive algorithms that perform preorder and postorder tree walks in
//! O(n) time on a tree of n nodes.
//!
//! ex12.2-2
//! Write recursive versions of TREE-MINIMUM and TREE-MAXIMUM .
//!

#ifndef BINARY_SEARCH_TREE_H
#define BINARY_SEARCH_TREE_H

#include "node.hpp"
#include <stack>
#include <functional>

namespace ch12 {

/**
 * @brief binary search tree
 */
template<typename K, typename D>
class binary_search_tree
{
public:
    using KeyType   =   K;
    using DataType  =   D;
    using Node      =   node<K,D>;
    using sPointer  =   std::shared_ptr<Node>;
    using wPointer  =   std::weak_ptr<Node>;

    /**
     * @brief insert
     * @param key
     * @param data
     *
     * @complexity  O(lg n)
     */
    void insert(const KeyType& key, const DataType& data)
    {
        sPointer inserted = std::make_shared<Node>(key, data);
        insert(inserted);
    }

    /**
     * @brief insert
     * @param inserted  i.e. the new node
     *
     * @complexity  O(lg n)
     */
    void insert(sPointer inserted)
    {
        sPointer last = nullptr;
        sPointer curr = root;

        //! find the appropiate position
        while(curr)
        {
            last = curr;
            curr = (inserted->key < curr->key)?  curr->left  :  curr->right;
        }

        //! graft on the inserted.
        inserted->parent    =   last;
        if(!last)
            root = inserted;
        else if(inserted->key   <   last->key)
            last->left      =   inserted;
        else
            last->right     =   inserted;
    }

    /**
     * @brief inorder_print
     *
     * i.e. the interface for inorder_print.
     */
    void inorder_print()const
    {
        inorder_tree_walk(root);
    }

    /**
     * @brief inorder_print_nonrecur
     *
     * for ex12.1-3
     */
    void inorder_print_nonrecur()const
    {
        sPointer prev = nullptr;
        sPointer curr = root;
        while(curr)
        {
            //! print
            if(!curr->left  ||  prev==curr->left)
                curr->print();

            //! move curr to next node.
            if(prev == curr->parent.lock())
            {
                prev    =   curr;
                curr    =   curr->left?    curr->left   :
                            curr->right?   curr->right  :   curr->parent.lock();
            }
            else if(prev == curr->left && curr->right)
            {
                prev    =   curr;
                curr    =   curr->right;
            }
            else
            {
                prev    =   curr;
                curr    =   curr->parent.lock();
            }
        }
    }

    /**
     * @brief inoder_print_nonrecur_with_stack
     *
     * i.e. the interface for inorder_tree_walk_nonrecur_with_stack
     */
    void inoder_print_nonrecur_with_stack()const
    {
        inorder_tree_walk_nonrecur_with_stack(root);
    }

    /**
     * @brief preorder_print
     */
    void preorder_print()const
    {
        preorder_tree_walk(root);
    }

    /**
     * @brief postorder_print
     */
    void postorder_print()const
    {
        postorder_tree_walk(root);
    }

    /**
     * @brief search_iterative
     * @param key
     *
     * interface
     */
    sPointer search_recur(const KeyType& key) const
    {
        return search_recur(root, key);
    }

    /**
     * @brief search_itera
     * @param key
     *
     * interface
     */
    sPointer search_itera(const KeyType& key) const
    {
        return search_itera(root, key);
    }

    /**
     * @brief maximum_itera
     * @param node
     *
     * @complexity  O(h)=O(lg n)
     */
    sPointer maximum_itera(sPointer node) const
    {
        while(node->right)
            node    =   node->right;
        return node;
    }

    /**
     * @brief maximum_recur
     * @param node
     *
     * @complexity  O(h)=O(lg n)
     *
     * for ex12.2-2
     */
    sPointer maximum_recur(sPointer node) const
    {
        std::function<sPointer(sPointer)> maximum =

                [&maximum](sPointer node)->sPointer
        {
            if(node->right)
                return  maximum(node->right);
            else
                return  node;
        };

        return maximum(node);
    }

    /**
     * @brief mimimum_itera
     * @param node
     *
     * @complexity  O(h)=O(lg n)
     */
    sPointer minimum_itera(sPointer node) const
    {
        while(node->left)
            node    =   node->left;
        return node;
    }

    /**
     * @brief minimum_recur
     * @param node
     *
     * @complexity  O(h)=O(lg n)
     *
     * for ex12.2-2
     */
    sPointer minimum_recur(sPointer node) const
    {
        std::function<sPointer(sPointer)> minimum =
                [&minimum](sPointer node)->sPointer
        {
            if(node->left)
                return minimum(node->left);
            else
                return node;
        };

        return minimum(node);
    }

private:
    sPointer root;

    /**
     * @brief inorder_tree_walk
     * @param node
     *
     * @complexity  O(n)
     */
    void inorder_tree_walk(sPointer node)const
    {
        if(node)
        {
            inorder_tree_walk(node->left);
            node->print();
            inorder_tree_walk(node->right);
        }
    }

    /**
     * @brief inorder_tree_walk_nonrecur_with_stack
     * @param node
     *
     * for ex 12-1.2
     */
    void inorder_tree_walk_nonrecur_with_stack(sPointer node)const
    {
        if(node)
        {
            std::stack<sPointer> stk;
            while(node  ||  !stk.empty())
            {
                while(node)
                {
                    stk.push(node);
                    node    =   node->left;
                }
                if(!stk.empty())
                {
                    node    =   stk.top();
                    stk.pop();
                    node->print();
                    node    =   node->right;
                }
            }
        }
    }

    /**
     * @brief preorder_tree_walk
     */
    void preorder_tree_walk(sPointer node) const
    {
        if(node)
        {
            node->print();
            inorder_tree_walk(node->left);
            inorder_tree_walk(node->right);
        }
    }

    /**
     * @brief postorder_tree_walk
     */
    void postorder_tree_walk(sPointer node)const
    {
        if(node)
        {
            inorder_tree_walk(node->left);
            inorder_tree_walk(node->right);
            node->print();
        }
    }

    /**
     * @brief search_iterative
     * @param node
     * @param key
     *
     * @complexity  O(h)    =   O(lg n)
     */
    sPointer search_recur(sPointer node, const KeyType key) const
    {
        if(!node  ||  key == node->key)
            return  node;

        sPointer next   =   (key < node->key)?  node->left  :   node->right;
        return  search_recur(next, key);
    }

    /**
     * @brief search_itera
     * @param node
     * @param key
     *
     * @complexity  O(h)    =   O(lg n)
     */
    sPointer search_itera(sPointer node, const KeyType& key) const
    {
        while(node  &&  key != node->key)
            node    =   key < node->key?    node->left  :   node->right;
        return node;
    }

};//class binary_search_tree

}//namespace ch12

#endif // BINARY_SEARCH_TREE_H

//! test code
//! for inorder tree walk, ex12.1-3, ex12.1-4
//! search,
//#include <iostream>
//#include <string>
//#include "node.hpp"
//#include "binary_search_tree.hpp"

//int main()
//{
//    ch12::binary_search_tree<int, std::string> tree;

//    tree.insert(1,"001");
//    tree.insert(2,"002");
//    tree.insert(5,"005");
//    tree.insert(199,"199");
//    tree.insert(6,"006");
//    tree.insert(123,"123");
//    tree.insert(127,"127");
//    tree.insert(666,"666");
//    tree.insert(999,"99");
//    tree.insert(23,"23");

//    tree.search_recur(5)->print();
//    tree.search_itera(5)->print();

//    tree.inorder_print();
//    tree.inoder_print_nonrecur_with_stack();
//    tree.inorder_print_nonrecur();

//    tree.preorder_print();
//    tree.postorder_print();

//    tree.maximum_recur(tree.search_itera(5))->print();
//    tree.maximum_itera(tree.search_itera(5))->print();

//    tree.minimum_itera(tree.search_itera(123))->print();
//    tree.minimum_recur(tree.search_itera(123))->print();

//    return 0;
//}
<commit_msg>added successor  On branch ch12 	modified:   ch12/binary_search_tree.hpp<commit_after>/***************************************************************************
 *  @file       binary_search_tree.hpp
 *  @author     Alan.W
 *  @date       24  June 2014
 *  @remark     Implementations for algorithims from CLRS using C++ templates.
 ***************************************************************************/
//!     page 294
//!     tree-insert(T,z)
/* 1    y = nil
 * 2    x = T.root
 * 3    whie x != nil
 * 4        y = x
 * 5        if z.key < x.key
 * 6            x = x.left
 * 7        else
 *              x = x.right
 * 8    z.parent = y
 * 9    if y == nil
 * 10       T.root = z  //i.e. was empty
 * 11   elseif z.key <y.key
 * 12       y.left = z
 * 13   else    y.right = z
 */

//!     page 288
//!     INORDER-TREE-WALK(x)    O(h)    =   O(lg n)
//1     if x != NIL
//2         INORDER-TREE-WALK(x.left)
//3         print x.key
//4         INORDER-TREE-WALK(x.right)

//!     page 291
//!     TREE-SEARCH(x,k)        O(h)    =   O(lg n)
//1     if x == NIL or k == x.key
//2         return x
//3     if k < x.key
//4         return TREE-SEARCH(x.left,  k)
//5     else
//6         return TREE-SEARCH(x.right, k)

//!     page 291
//!     ITERATIVE-TREE-SEARCH(x, k)     O(h)    =   O(lg n)
//1 	while x != NIL and k != x.key
//2		if k < x.key
//3			x = x.left
//4		else x = x.right
//5 	return x

//!     page 291
//!     TREE-MAXIMUM(x)                O(h)    =   O(lg n)
//1     while x.right != NIL
//2         x = x.right
//3 	return x
//!     page 291
//!     TREE-MINIMUM(x)                 O(h)    =   O(lg n)
//1 	while x.left != NIL
//2         x = x.left
//3 	return x

//!     page 292
//!     TREE-SUCCESSOR(x)               O(h)    =   O(lg n)
//1 	if x.right != NIL
//2         return TREE-MINIMUM(x.right)
//3 	y = x.p
//4 	while y != NIL and x == y.right
//5         x = y
//6         y = y.p
//7 	return y

//!
//! ex 12.1-3
//! Give a nonrecursive algorithm that performs an inorder tree walk. (Hint: An easy
//! solution uses a stack as an auxiliary data structure. A more complicated, but ele-
//! gant, solution uses no stack but assumes that we can test two pointers for equality.)
//!
//!     inorder_walk_nonrecur_with_stack(node)
/*      if(node)
 *          def stack
 *          while(node || !stack.empty())
 *              while(node)
 *                  stack.push(node)
 *                  node = node->left
 *              if(!stack.empty())
 *                  node = stack.pop()
 *                  node.print()
 *                  node = node->right
 */

//!
//! based on ch10::tree::binary_tree::checking _prev_print
//! can be found here:
//! https://github.com/Mooophy/CLRS/blob/master/ch10/tree.hpp
//!
//!     inorder_walk_by_checking_prev(node)
/*      def prev = null
 *      def curr = node
 *      while(curr)
 *
 *          if(!curr->left  ||  prev == curr->left)     //  for printing
 *              curr->print
 *
 *          if(prev == curr->parent)
 *              prev    =   curr
 *              curr    =   curr->left? left    :
 *                          curr->right?    curr->right :   curr->parent
 *          else if (prev == left && curr->right)
 *              prev    =   curr
 *              curr    =   curr->right
 *          else
 *              prev    =   curr
 *              curr    =   curr->parent
 */

//!
//! ex12.1-4
//! Give recursive algorithms that perform preorder and postorder tree walks in
//! O(n) time on a tree of n nodes.
//!
//! ex12.2-2
//! Write recursive versions of TREE-MINIMUM and TREE-MAXIMUM .
//!

#ifndef BINARY_SEARCH_TREE_H
#define BINARY_SEARCH_TREE_H

#include "node.hpp"
#include <stack>
#include <functional>

namespace ch12 {

/**
 * @brief binary search tree
 */
template<typename K, typename D>
class binary_search_tree
{
public:
    using KeyType   =   K;
    using DataType  =   D;
    using Node      =   node<K,D>;
    using sPointer  =   std::shared_ptr<Node>;
    using wPointer  =   std::weak_ptr<Node>;

    /**
     * @brief insert
     * @param key
     * @param data
     *
     * @complexity  O(lg n)
     */
    void insert(const KeyType& key, const DataType& data)
    {
        sPointer inserted = std::make_shared<Node>(key, data);
        insert(inserted);
    }

    /**
     * @brief insert
     * @param inserted  i.e. the new node
     *
     * @complexity  O(lg n)
     */
    void insert(sPointer inserted)
    {
        sPointer last = nullptr;
        sPointer curr = root;

        //! find the appropiate position
        while(curr)
        {
            last = curr;
            curr = (inserted->key < curr->key)?  curr->left  :  curr->right;
        }

        //! graft on the inserted.
        inserted->parent    =   last;
        if(!last)
            root = inserted;
        else if(inserted->key   <   last->key)
            last->left      =   inserted;
        else
            last->right     =   inserted;
    }

    /**
     * @brief inorder_print
     *
     * i.e. the interface for inorder_print.
     */
    void inorder_print()const
    {
        inorder_tree_walk(root);
    }

    /**
     * @brief inorder_print_nonrecur
     *
     * for ex12.1-3
     */
    void inorder_print_nonrecur()const
    {
        sPointer prev = nullptr;
        sPointer curr = root;
        while(curr)
        {
            //! print
            if(!curr->left  ||  prev==curr->left)
                curr->print();

            //! move curr to next node.
            if(prev == curr->parent.lock())
            {
                prev    =   curr;
                curr    =   curr->left?    curr->left   :
                            curr->right?   curr->right  :   curr->parent.lock();
            }
            else if(prev == curr->left && curr->right)
            {
                prev    =   curr;
                curr    =   curr->right;
            }
            else
            {
                prev    =   curr;
                curr    =   curr->parent.lock();
            }
        }
    }

    /**
     * @brief inoder_print_nonrecur_with_stack
     *
     * i.e. the interface for inorder_tree_walk_nonrecur_with_stack
     */
    void inoder_print_nonrecur_with_stack()const
    {
        inorder_tree_walk_nonrecur_with_stack(root);
    }

    /**
     * @brief preorder_print
     */
    void preorder_print()const
    {
        preorder_tree_walk(root);
    }

    /**
     * @brief postorder_print
     */
    void postorder_print()const
    {
        postorder_tree_walk(root);
    }

    /**
     * @brief search_iterative
     * @param key
     *
     * interface
     */
    sPointer search_recur(const KeyType& key) const
    {
        return search_recur(root, key);
    }

    /**
     * @brief search_itera
     * @param key
     *
     * interface
     */
    sPointer search_itera(const KeyType& key) const
    {
        return search_itera(root, key);
    }

    /**
     * @brief maximum_itera
     * @param node
     *
     * @complexity  O(h)=O(lg n)
     */
    sPointer maximum_itera(sPointer node) const
    {
        while(node->right)
            node    =   node->right;
        return node;
    }

    /**
     * @brief maximum_recur
     * @param node
     *
     * @complexity  O(h)=O(lg n)
     *
     * for ex12.2-2
     */
    sPointer maximum_recur(sPointer node) const
    {
        std::function<sPointer(sPointer)> maximum =

                [&maximum](sPointer node)->sPointer
        {
            if(node->right)
                return  maximum(node->right);
            else
                return  node;
        };

        return maximum(node);
    }

    /**
     * @brief mimimum_itera
     * @param node
     *
     * @complexity  O(h)=O(lg n)
     */
    sPointer minimum_itera(sPointer node) const
    {
        while(node->left)
            node    =   node->left;
        return node;
    }

    /**
     * @brief minimum_recur
     * @param node
     *
     * @complexity  O(h)=O(lg n)
     *
     * for ex12.2-2
     */
    sPointer minimum_recur(sPointer node) const
    {
        std::function<sPointer(sPointer)> minimum =
                [&minimum](sPointer node)->sPointer
        {
            if(node->left)
                return minimum(node->left);
            else
                return node;
        };

        return minimum(node);
    }

    /**
     * @brief successor
     * @param node
     *
     * @complexity  O(h)=O(lg n)
     */
    sPointer successor(sPointer node)
    {
        if(node->right)     // case 1 : find it by going upward.
            return minimum_itera(node->right);
        else                // case 2 : find it by going downward.
        {
            sPointer next = node->parent.lock();
            while(next  &&  node == next->right)
            {
                node    =   next;
                next    =   next->parent.lock();
            }
        }
    }

private:
    sPointer root;

    /**
     * @brief inorder_tree_walk
     * @param node
     *
     * @complexity  O(n)
     */
    void inorder_tree_walk(sPointer node)const
    {
        if(node)
        {
            inorder_tree_walk(node->left);
            node->print();
            inorder_tree_walk(node->right);
        }
    }

    /**
     * @brief inorder_tree_walk_nonrecur_with_stack
     * @param node
     *
     * for ex 12-1.2
     */
    void inorder_tree_walk_nonrecur_with_stack(sPointer node)const
    {
        if(node)
        {
            std::stack<sPointer> stk;
            while(node  ||  !stk.empty())
            {
                while(node)
                {
                    stk.push(node);
                    node    =   node->left;
                }
                if(!stk.empty())
                {
                    node    =   stk.top();
                    stk.pop();
                    node->print();
                    node    =   node->right;
                }
            }
        }
    }

    /**
     * @brief preorder_tree_walk
     */
    void preorder_tree_walk(sPointer node) const
    {
        if(node)
        {
            node->print();
            inorder_tree_walk(node->left);
            inorder_tree_walk(node->right);
        }
    }

    /**
     * @brief postorder_tree_walk
     */
    void postorder_tree_walk(sPointer node)const
    {
        if(node)
        {
            inorder_tree_walk(node->left);
            inorder_tree_walk(node->right);
            node->print();
        }
    }

    /**
     * @brief search_iterative
     * @param node
     * @param key
     *
     * @complexity  O(h)    =   O(lg n)
     */
    sPointer search_recur(sPointer node, const KeyType key) const
    {
        if(!node  ||  key == node->key)
            return  node;

        sPointer next   =   (key < node->key)?  node->left  :   node->right;
        return  search_recur(next, key);
    }

    /**
     * @brief search_itera
     * @param node
     * @param key
     *
     * @complexity  O(h)    =   O(lg n)
     */
    sPointer search_itera(sPointer node, const KeyType& key) const
    {
        while(node  &&  key != node->key)
            node    =   key < node->key?    node->left  :   node->right;
        return node;
    }

};//class binary_search_tree

}//namespace ch12

#endif // BINARY_SEARCH_TREE_H

//! test code
//! for inorder tree walk, ex12.1-3, ex12.1-4
//! search,
//#include <iostream>
//#include <string>
//#include "node.hpp"
//#include "binary_search_tree.hpp"

//int main()
//{
//    ch12::binary_search_tree<int, std::string> tree;

//    tree.insert(1,"001");
//    tree.insert(2,"002");
//    tree.insert(5,"005");
//    tree.insert(199,"199");
//    tree.insert(6,"006");
//    tree.insert(123,"123");
//    tree.insert(127,"127");
//    tree.insert(666,"666");
//    tree.insert(999,"99");
//    tree.insert(23,"23");

//    tree.search_recur(5)->print();
//    tree.search_itera(5)->print();

//    tree.inorder_print();
//    tree.inoder_print_nonrecur_with_stack();
//    tree.inorder_print_nonrecur();

//    tree.preorder_print();
//    tree.postorder_print();

//    tree.maximum_recur(tree.search_itera(5))->print();
//    tree.maximum_itera(tree.search_itera(5))->print();

//    tree.minimum_itera(tree.search_itera(123))->print();
//    tree.minimum_recur(tree.search_itera(123))->print();

//    return 0;
//}
<|endoftext|>


<commit_before>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
// Copyright (c) 2014 Francois Beaune, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "scenepickinghandler.h"

// appleseed.studio headers.
#include "mainwindow/project/projectexplorer.h"
#include "utility/mousecoordinatestracker.h"

// appleseed.renderer headers.
#include "renderer/api/bsdf.h"
#include "renderer/api/camera.h"
#include "renderer/api/edf.h"
#include "renderer/api/entity.h"
#include "renderer/api/frame.h"
#include "renderer/api/log.h"
#include "renderer/api/material.h"
#include "renderer/api/object.h"
#include "renderer/api/project.h"
#include "renderer/api/rendering.h"
#include "renderer/api/scene.h"
#include "renderer/api/surfaceshader.h"

// appleseed.foundation headers.
#include "foundation/image/color.h"
#include "foundation/image/image.h"
#include "foundation/math/vector.h"

// Qt headers.
#include <QComboBox>
#include <QEvent>
#include <QLabel>
#include <QMouseEvent>
#include <QString>
#include <Qt>
#include <QWidget>

// Standard headers.
#include <cassert>
#include <cstddef>
#include <sstream>

using namespace foundation;
using namespace renderer;
using namespace std;

namespace appleseed {
namespace studio {

ScenePickingHandler::ScenePickingHandler(
    QWidget*                        widget,
    QComboBox*                      picking_mode_combo,
    QLabel*                         r_label,
    QLabel*                         g_label,
    QLabel*                         b_label,
    QLabel*                         a_label,
    const MouseCoordinatesTracker&  mouse_tracker,
    const ProjectExplorer&          project_explorer,
    const Project&                  project)
  : m_widget(widget)
  , m_picking_mode_combo(picking_mode_combo)
  , m_r_label(r_label)
  , m_g_label(g_label)
  , m_b_label(b_label)
  , m_a_label(a_label)
  , m_mouse_tracker(mouse_tracker)
  , m_project_explorer(project_explorer)
  , m_project(project)
  , m_enabled(true)
{
    m_widget->installEventFilter(this);

    m_picking_mode_combo->clear();
    m_picking_mode_combo->addItem("Assembly", "assembly");
    m_picking_mode_combo->addItem("Assembly Instance", "assembly_instance");
    m_picking_mode_combo->addItem("Object", "object");
    m_picking_mode_combo->addItem("Object Instance", "object_instance");
    m_picking_mode_combo->addItem("Material", "material");
    m_picking_mode_combo->addItem("Surface Shader", "surface_shader");
    m_picking_mode_combo->addItem("BSDF", "bsdf");
    m_picking_mode_combo->addItem("EDF", "edf");
    m_picking_mode_combo->setCurrentIndex(3);
}

ScenePickingHandler::~ScenePickingHandler()
{
    m_widget->removeEventFilter(this);
}

void ScenePickingHandler::set_enabled(const bool enabled)
{
    m_enabled = enabled;
}

bool ScenePickingHandler::eventFilter(QObject* object, QEvent* event)
{
    if (!m_enabled)
        return QObject::eventFilter(object, event);

    switch (event->type())
    {
      case QEvent::MouseButtonPress:
        {
            const QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
            if (mouse_event->button() == Qt::LeftButton &&
                !(mouse_event->modifiers() & (Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier)))
            {
                pick(mouse_event->pos());
                return true;
            }
        }
        break;

      case QEvent::MouseMove:
        {
            const QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
            set_rgba_label(mouse_event->pos());
        }
        break;

      case QEvent::Leave:
        m_r_label->clear();
        m_g_label->clear();
        m_b_label->clear();
        m_a_label->clear();
        break;
    }

    return QObject::eventFilter(object, event);
}

namespace
{
    void print_entity(stringstream& sstr, const char* label, const Entity* entity)
    {
        sstr << label;

        if (entity)
            sstr << "\"" << entity->get_name() << "\" (#" << entity->get_uid() << ")";
        else sstr << "n/a";

        sstr << endl;
    }

    const Entity* get_picked_entity(
        const ScenePicker::PickingResult&   picking_result,
        const QString&                      picking_mode)
    {
        if (picking_mode == "assembly")
            return picking_result.m_assembly;
        else if (picking_mode == "assembly_instance")
            return picking_result.m_assembly_instance;
        else if (picking_mode == "object")
            return picking_result.m_object;
        else if (picking_mode == "object_instance")
            return picking_result.m_object_instance;
        else if (picking_mode == "material")
            return picking_result.m_material;
        else if (picking_mode == "surface_shader")
            return picking_result.m_surface_shader;
        else if (picking_mode == "bsdf")
            return picking_result.m_bsdf;
        else if (picking_mode == "edf")
            return picking_result.m_edf;
        else
        {
            assert(!"Invalid picking mode.");
            return 0;
        }
    }
}

void ScenePickingHandler::pick(const QPoint& point)
{
    if (!m_project.has_trace_context())
    {
        RENDERER_LOG_INFO("the scene must be rendering or must have been rendered at least once for picking to be available.");
        return;
    }

    const Vector2i pix = m_mouse_tracker.widget_to_pixel(point);
    const Vector2d ndc = m_mouse_tracker.widget_to_ndc(point);

    const ScenePicker scene_picker(m_project.get_trace_context());
    const ScenePicker::PickingResult result = scene_picker.pick(ndc);

    stringstream sstr;

    sstr << "picking details:" << endl;
    sstr << "  pixel coords     " << pix.x << ", " << pix.y << endl;
    sstr << "  ndc coords       " << ndc.x << ", " << ndc.y << endl;

    print_entity(sstr, "  camera           ", result.m_camera);
    print_entity(sstr, "  assembly inst.   ", result.m_assembly_instance);
    print_entity(sstr, "  assembly         ", result.m_assembly);
    print_entity(sstr, "  object inst.     ", result.m_object_instance);
    print_entity(sstr, "  object           ", result.m_object);
    print_entity(sstr, "  material         ", result.m_material);
    print_entity(sstr, "  surface shader   ", result.m_surface_shader);
    print_entity(sstr, "  bsdf             ", result.m_bsdf);
    print_entity(sstr, "  edf              ", result.m_edf);

    RENDERER_LOG_INFO("%s", sstr.str().c_str());

    const QString picking_mode =
        m_picking_mode_combo->itemData(m_picking_mode_combo->currentIndex()).value<QString>();

    const Entity* picked_entity = get_picked_entity(result, picking_mode);

    if (picked_entity)
        m_project_explorer.highlight_entity(picked_entity->get_uid());
    else m_project_explorer.clear_highlighting();

    emit signal_entity_picked();
}

void ScenePickingHandler::set_rgba_label(const QPoint& point) const
{
    const Vector2i pix = m_mouse_tracker.widget_to_pixel(point);

    Color4f linear_rgba;
    m_project.get_frame()->image().get_pixel(
        static_cast<size_t>(pix.x),
        static_cast<size_t>(pix.y),
        linear_rgba);

    m_r_label->setText(QString().sprintf("%4.3f", linear_rgba.r));
    m_g_label->setText(QString().sprintf("%4.3f", linear_rgba.g));
    m_b_label->setText(QString().sprintf("%4.3f", linear_rgba.b));
    m_a_label->setText(QString().sprintf("%4.3f", linear_rgba.a));
}

}   // namespace studio
}   // namespace appleseed
<commit_msg>minor code tweaks.<commit_after>
//
// This source file is part of appleseed.
// Visit http://appleseedhq.net/ for additional information and resources.
//
// This software is released under the MIT license.
//
// Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
// Copyright (c) 2014 Francois Beaune, The appleseedhq Organization
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

// Interface header.
#include "scenepickinghandler.h"

// appleseed.studio headers.
#include "mainwindow/project/projectexplorer.h"
#include "utility/mousecoordinatestracker.h"

// appleseed.renderer headers.
#include "renderer/api/bsdf.h"
#include "renderer/api/camera.h"
#include "renderer/api/edf.h"
#include "renderer/api/entity.h"
#include "renderer/api/frame.h"
#include "renderer/api/log.h"
#include "renderer/api/material.h"
#include "renderer/api/object.h"
#include "renderer/api/project.h"
#include "renderer/api/rendering.h"
#include "renderer/api/scene.h"
#include "renderer/api/surfaceshader.h"

// appleseed.foundation headers.
#include "foundation/image/color.h"
#include "foundation/image/image.h"
#include "foundation/math/vector.h"

// Qt headers.
#include <QComboBox>
#include <QEvent>
#include <QLabel>
#include <QMouseEvent>
#include <QString>
#include <Qt>
#include <QWidget>

// Standard headers.
#include <cassert>
#include <cstddef>
#include <sstream>

using namespace foundation;
using namespace renderer;
using namespace std;

namespace appleseed {
namespace studio {

ScenePickingHandler::ScenePickingHandler(
    QWidget*                        widget,
    QComboBox*                      picking_mode_combo,
    QLabel*                         r_label,
    QLabel*                         g_label,
    QLabel*                         b_label,
    QLabel*                         a_label,
    const MouseCoordinatesTracker&  mouse_tracker,
    const ProjectExplorer&          project_explorer,
    const Project&                  project)
  : m_widget(widget)
  , m_picking_mode_combo(picking_mode_combo)
  , m_r_label(r_label)
  , m_g_label(g_label)
  , m_b_label(b_label)
  , m_a_label(a_label)
  , m_mouse_tracker(mouse_tracker)
  , m_project_explorer(project_explorer)
  , m_project(project)
  , m_enabled(true)
{
    m_widget->installEventFilter(this);

    m_picking_mode_combo->clear();
    m_picking_mode_combo->addItem("Assembly", "assembly");
    m_picking_mode_combo->addItem("Assembly Instance", "assembly_instance");
    m_picking_mode_combo->addItem("Object", "object");
    m_picking_mode_combo->addItem("Object Instance", "object_instance");
    m_picking_mode_combo->addItem("Material", "material");
    m_picking_mode_combo->addItem("Surface Shader", "surface_shader");
    m_picking_mode_combo->addItem("BSDF", "bsdf");
    m_picking_mode_combo->addItem("EDF", "edf");
    m_picking_mode_combo->setCurrentIndex(3);
}

ScenePickingHandler::~ScenePickingHandler()
{
    m_widget->removeEventFilter(this);
}

void ScenePickingHandler::set_enabled(const bool enabled)
{
    m_enabled = enabled;
}

bool ScenePickingHandler::eventFilter(QObject* object, QEvent* event)
{
    if (!m_enabled)
        return QObject::eventFilter(object, event);

    switch (event->type())
    {
      case QEvent::MouseButtonPress:
        {
            const QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
            if (mouse_event->button() == Qt::LeftButton &&
                !(mouse_event->modifiers() & (Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier)))
            {
                pick(mouse_event->pos());
                return true;
            }
        }
        break;

      case QEvent::MouseMove:
        {
            const QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
            set_rgba_label(mouse_event->pos());
        }
        break;

      case QEvent::Leave:
        m_r_label->clear();
        m_g_label->clear();
        m_b_label->clear();
        m_a_label->clear();
        break;
    }

    return QObject::eventFilter(object, event);
}

namespace
{
    string print_entity(const char* label, const Entity* entity)
    {
        stringstream sstr;
        sstr << label;

        if (entity)
            sstr << "\"" << entity->get_name() << "\" (#" << entity->get_uid() << ")";
        else sstr << "n/a";

        return sstr.str();
    }

    const Entity* get_picked_entity(
        const ScenePicker::PickingResult&   picking_result,
        const QString&                      picking_mode)
    {
        if (picking_mode == "assembly")
            return picking_result.m_assembly;
        else if (picking_mode == "assembly_instance")
            return picking_result.m_assembly_instance;
        else if (picking_mode == "object")
            return picking_result.m_object;
        else if (picking_mode == "object_instance")
            return picking_result.m_object_instance;
        else if (picking_mode == "material")
            return picking_result.m_material;
        else if (picking_mode == "surface_shader")
            return picking_result.m_surface_shader;
        else if (picking_mode == "bsdf")
            return picking_result.m_bsdf;
        else if (picking_mode == "edf")
            return picking_result.m_edf;
        else
        {
            assert(!"Invalid picking mode.");
            return 0;
        }
    }
}

void ScenePickingHandler::pick(const QPoint& point)
{
    if (!m_project.has_trace_context())
    {
        RENDERER_LOG_INFO("the scene must be rendering or must have been rendered at least once for picking to be available.");
        return;
    }

    const Vector2i pix = m_mouse_tracker.widget_to_pixel(point);
    const Vector2d ndc = m_mouse_tracker.widget_to_ndc(point);

    const ScenePicker scene_picker(m_project.get_trace_context());
    const ScenePicker::PickingResult result = scene_picker.pick(ndc);

    stringstream sstr;

    sstr << "picking details:" << endl;
    sstr << "  pixel coords     " << pix.x << ", " << pix.y << endl;
    sstr << "  ndc coords       " << ndc.x << ", " << ndc.y << endl;

    sstr << print_entity("  camera           ", result.m_camera) << endl;
    sstr << print_entity("  assembly inst.   ", result.m_assembly_instance) << endl;
    sstr << print_entity("  assembly         ", result.m_assembly) << endl;
    sstr << print_entity("  object inst.     ", result.m_object_instance) << endl;
    sstr << print_entity("  object           ", result.m_object) << endl;
    sstr << print_entity("  material         ", result.m_material) << endl;
    sstr << print_entity("  surface shader   ", result.m_surface_shader) << endl;
    sstr << print_entity("  bsdf             ", result.m_bsdf) << endl;
    sstr << print_entity("  edf              ", result.m_edf);

    RENDERER_LOG_INFO("%s", sstr.str().c_str());

    const QString picking_mode =
        m_picking_mode_combo->itemData(m_picking_mode_combo->currentIndex()).value<QString>();

    const Entity* picked_entity = get_picked_entity(result, picking_mode);

    if (picked_entity)
        m_project_explorer.highlight_entity(picked_entity->get_uid());
    else m_project_explorer.clear_highlighting();

    emit signal_entity_picked();
}

void ScenePickingHandler::set_rgba_label(const QPoint& point) const
{
    const Vector2i pix = m_mouse_tracker.widget_to_pixel(point);

    Color4f linear_rgba;
    m_project.get_frame()->image().get_pixel(
        static_cast<size_t>(pix.x),
        static_cast<size_t>(pix.y),
        linear_rgba);

    m_r_label->setText(QString().sprintf("%4.3f", linear_rgba.r));
    m_g_label->setText(QString().sprintf("%4.3f", linear_rgba.g));
    m_b_label->setText(QString().sprintf("%4.3f", linear_rgba.b));
    m_a_label->setText(QString().sprintf("%4.3f", linear_rgba.a));
}

}   // namespace studio
}   // namespace appleseed
<|endoftext|>


<commit_before>#ifndef SAVE_STATE_H
# define SAVE_STATE_H
# pragma once

struct statebuf
{
  void* sp;
  void* label;
};

#if defined(__GNUC__)
inline bool __attribute__((always_inline)) savestate(statebuf& ssb) noexcept
{
	bool r;

#if defined(i386) || defined(__i386) || defined(__i386__)
	asm volatile (
		"movl %%esp, %0\n\t" // store sp
		"movl $1f, %1\n\t" // store label
		"movb $0, %2\n\t" // return false
		"jmp 2f\n\t"
		"1:movb $1, %2\n\t" // return true
		"2:"
		: "=m" (ssb.sp), "=m" (ssb.label), "=r" (r)
		:
		: "memory"
	);
#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
	asm volatile (
		"movq %%rsp, %0\n\t" // store sp
		"movq $1f, %1\n\t" // store label
		"movb $0, %2\n\t" // return false
		"jmp 2f\n\t"
		"1:movb $1, %2\n\t" // return true
		"2:"
		: "=m" (ssb.sp), "=m" (ssb.label), "=r" (r)
		:
		: "memory"
	);
#elif defined(__arm__)
  asm volatile (
    "mov %0, sp\n\t" // store sp
    "mov %1, $1f\n\t" // store label
		"mov %2, $0\n\t" // return false
    "b 2f\n\t"
    "1:mov %2, $1\n\t" // return true
    "2:"
    : "=m" (ssb.sp), "=m" (ssb.label), "=r" (r)
    :
    : "memory"
  );
#endif

	return r;
}
#elif defined(_MSC_VER)
__forceinline bool savestate(statebuf& ssb) noexcept
{
	bool r;

	__asm {
		push ebp
		mov ebx, ssb
		mov [ebx]ssb.sp, esp
		mov [ebx]ssb.label, offset _1f
		mov r, 0x0
		jmp _2f
		_1f: pop ebp
			 mov r, 0x1
		_2f:
	}

	return r;
}
#else
# error "unsupported compiler"
#endif

#if defined(__GNUC__)
#if defined(i386) || defined(__i386) || defined(__i386__)
#define restorestate(SSB)          \
  asm volatile (                   \
    "movl %0, %%esp\n\t"           \
    "jmp *%1"                      \
    :                              \
    : "m" (SSB.sp), "m" (SSB.label)\
  );
#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
#define restorestate(SSB)          \
  asm volatile (                   \
    "movq %0, %%rsp\n\t"           \
    "jmp *%1"                      \
    :                              \
    : "m" (SSB.sp), "m" (SSB.label)\
  );
#elif defined(__arm__)
#define restorestate(SSB)          \
  asm volatile (                   \
    "mov sp, %0\n\t"               \
    "b %1"                         \
    :                              \
    : "m" (SSB.sp), "m" (SSB.label)\
  );
#else
# error "unsupported architecture"
#endif
#elif defined(_MSC_VER)
#define restorestate(SSB)   \
  __asm mov ebx, this       \
  __asm add ebx, [SSB]      \
  __asm mov esp, [ebx]SSB.sp\
  __asm jmp [ebx]SSB.label
#else
# error "unsupported compiler"
#endif

#endif // SAVE_STATE_H
<commit_msg>some fixes<commit_after>#ifndef SAVE_STATE_H
# define SAVE_STATE_H
# pragma once

struct statebuf
{
  void* sp;
  void* label;
};

#if defined(__GNUC__)
inline bool __attribute__((always_inline)) savestate(statebuf& ssb) noexcept
{
	bool r;

#if defined(i386) || defined(__i386) || defined(__i386__)
	asm volatile (
		"movl %%esp, %0\n\t" // store sp
		"movl $1f, %1\n\t" // store label
		"movb $0, %2\n\t" // return false
		"jmp 2f\n\t"
		"1:movb $1, %2\n\t" // return true
		"2:"
		: "=m" (ssb.sp), "=m" (ssb.label), "=r" (r)
		:
		: "memory"
	);
#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
	asm volatile (
		"movq %%rsp, %0\n\t" // store sp
		"movq $1f, %1\n\t" // store label
		"movb $0, %2\n\t" // return false
		"jmp 2f\n\t"
		"1:movb $1, %2\n\t" // return true
		"2:"
		: "=m" (ssb.sp), "=m" (ssb.label), "=r" (r)
		:
		: "memory"
	);
#elif defined(__arm__)
  asm volatile (
    "mov %0, r13\n\t" // store sp
    "mov %1, $1f\n\t" // store label
		"mov %2, $0\n\t" // return false
    "b 2f\n\t"
    "1:mov %2, $1\n\t" // return true
    "2:"
    : "=m" (ssb.sp), "=m" (ssb.label), "=r" (r)
    :
    : "memory"
  );
#endif

	return r;
}
#elif defined(_MSC_VER)
__forceinline bool savestate(statebuf& ssb) noexcept
{
	bool r;

	__asm {
		push ebp
		mov ebx, ssb
		mov [ebx]ssb.sp, esp
		mov [ebx]ssb.label, offset _1f
		mov r, 0x0
		jmp _2f
		_1f: pop ebp
			 mov r, 0x1
		_2f:
	}

	return r;
}
#else
# error "unsupported compiler"
#endif

#if defined(__GNUC__)
#if defined(i386) || defined(__i386) || defined(__i386__)
#define restorestate(SSB)          \
  asm volatile (                   \
    "movl %0, %%esp\n\t"           \
    "jmp *%1"                      \
    :                              \
    : "m" (SSB.sp), "m" (SSB.label)\
  );
#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
#define restorestate(SSB)          \
  asm volatile (                   \
    "movq %0, %%rsp\n\t"           \
    "jmp *%1"                      \
    :                              \
    : "m" (SSB.sp), "m" (SSB.label)\
  );
#elif defined(__arm__)
#define restorestate(SSB)          \
  asm volatile (                   \
    "mov r13, %0\n\t"              \
    "b *%1"                        \
    :                              \
    : "m" (SSB.sp), "m" (SSB.label)\
  );
#else
# error "unsupported architecture"
#endif
#elif defined(_MSC_VER)
#define restorestate(SSB)   \
  __asm mov ebx, this       \
  __asm add ebx, [SSB]      \
  __asm mov esp, [ebx]SSB.sp\
  __asm jmp [ebx]SSB.label
#else
# error "unsupported compiler"
#endif

#endif // SAVE_STATE_H
<|endoftext|>


<commit_before>/*
* Copyright (c)2015 - 2019 Oasis LMF Limited
* 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 original author of this software 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.
*/
/*
Index the summarycalc output
Author: Ben Matharu  email: ben.matharu@oasislmf.org
*/
#include <stdio.h>
#include <string>
#if defined(_MSC_VER)
#include "../include/dirent.h"
#else
#include <dirent.h>
#endif

#include "../include/oasis.h"

#include <vector>
#include <string>
#include <map>

bool operator<(const summary_period &lhs, const summary_period &rhs) {

	if (lhs.summary_id != rhs.summary_id) {
		return lhs.summary_id < rhs.summary_id;
	} else if (lhs.period_no != rhs.period_no) {
		return lhs.period_no < rhs.period_no;
	} else {
		return lhs.fileindex < rhs.fileindex;
	}

}

namespace summaryindex {

	void indexevents(const std::string& fullfilename, std::vector<int> &event_ids, std::map<summary_period, std::vector<long long>> &summaryfileperiod_to_offset, int file_id, const std::map<int, std::vector<int>> &eventtoperiods) {
		FILE* fin = fopen(fullfilename.c_str(), "rb");
		if (fin == NULL) {
			fprintf(stderr, "%s: cannot open %s\n", __func__, fullfilename.c_str());
			exit(EXIT_FAILURE);
		}
		long long offset = 0;
		int summarycalcstream_type = 0;
		size_t i = fread(&summarycalcstream_type, sizeof(summarycalcstream_type), 1, fin);
		if (i != 0) offset += sizeof(summarycalcstream_type);
		int stream_type = summarycalcstream_type & summarycalc_id;

		if (stream_type != summarycalc_id) {
			fprintf(stderr, "%s: Not a summarycalc stream type %d\n", __func__, stream_type);
			exit(-1);
		}

		stream_type = streamno_mask & summarycalcstream_type;
		int samplesize;
		i = fread(&samplesize, sizeof(samplesize), 1, fin);
		if (i != 0) offset += sizeof(samplesize);
		int summary_set = 0;
		if (i != 0) i = fread(&summary_set, sizeof(summary_set), 1, fin);
		if (i != 0) offset += sizeof(summary_set);
		summarySampleslevelHeader sh;
		int last_event_id = -1;
		while (i != 0) {
			i = fread(&sh, sizeof(sh), 1, fin);
			if (i != 0) {
				summary_period k;
				k.summary_id = sh.summary_id;
				k.fileindex = file_id;
				for (auto period : eventtoperiods.at(sh.event_id)) {
					k.period_no = period;
					summaryfileperiod_to_offset[k].push_back(offset);
				}
				if (sh.event_id != last_event_id) {
					last_event_id = sh.event_id;
					event_ids.push_back(sh.event_id);
				}
				offset += sizeof(sh);
			}
			while (i != 0) {
				sampleslevelRec sr;
				i = fread(&sr, sizeof(sr), 1, fin);
				if (i != 0) offset += sizeof(sr);
				if (i == 0) break;
				if (sr.sidx == 0) break;
			}
		}

		fclose(fin);
	}
void doit(const std::string& subfolder, const std::map<int, std::vector<int>> &eventtoperiods)
{
	std::string path = "work/" + subfolder;
	if (path.substr(path.length() - 1, 1) != "/") {
		path = path + "/";
	}

	std::vector<std::string> files;
	std::map<summary_period, std::vector<long long>> summaryfileperiod_to_offset;
	std::vector<int> event_ids;
	DIR* dir;
	struct dirent* ent;
	int file_index = 0;
	if ((dir = opendir(path.c_str())) != NULL) {
		while ((ent = readdir(dir)) != NULL) {
			std::string s = ent->d_name;
			if (s.length() > 4 && s.substr(s.length() - 4, 4) == ".bin") {
				std::string s2 = path + ent->d_name;
				files.push_back(s);
				indexevents(s2, event_ids, summaryfileperiod_to_offset, file_index, eventtoperiods);
				file_index++;
			}
		}
	}
	else {
		fprintf(stderr, "Unable to open directory %s\n", path.c_str());
		exit(-1);
	}

	std::string filename =  path + "filelist.idx";
	FILE* fout = fopen(filename.c_str(), "wb");
	if (fout == NULL) {
		fprintf(stderr, "%s: cannot open %s\n", __func__, filename.c_str());
		exit(EXIT_FAILURE);
	}
	auto iter = files.begin();
	while (iter != files.end()) {
		fprintf(fout, "%s\n", iter->c_str());
		iter++;
	}

	fclose(fout);

	int max_summary_id = 0;
	filename = path + "summaries.idx";
	fout = fopen(filename.c_str(), "wb");
	if (fout == NULL) {
		fprintf(stderr, "%s: cannot open %s\n", __func__, filename.c_str());
		exit(EXIT_FAILURE);
	}

	auto s_iter = summaryfileperiod_to_offset.begin();
	while (s_iter != summaryfileperiod_to_offset.end()) {
		if (s_iter->first.summary_id > max_summary_id) max_summary_id = s_iter->first.summary_id;
		auto v_iter = s_iter->second.begin();
		while (v_iter != s_iter->second.end()) {
			fprintf(fout, "%d, %d, %d, %lld\n", s_iter->first.summary_id, s_iter->first.fileindex, s_iter->first.period_no, *v_iter);
			v_iter++;
		}
		s_iter++;
	}
	fclose(fout);

	filename = path + "max_summary_id.idx";
	fout = fopen(filename.c_str(), "wb");
	if (fout == NULL) {
		fprintf(stderr, "%s: cannot open %s\n", __func__, filename.c_str());
		exit(EXIT_FAILURE);
	}
	fprintf(fout, "%d", max_summary_id);
	fclose(fout);

}

};
<commit_msg>Use summary index files from summarycalc in aalcalc (#225)<commit_after>/*
* Copyright (c)2015 - 2019 Oasis LMF Limited
* 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 original author of this software 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.
*/
/*
Index the summarycalc output
Author: Ben Matharu  email: ben.matharu@oasislmf.org
*/
#include <stdio.h>
#include <string>
#if defined(_MSC_VER)
#include "../include/dirent.h"
#else
#include <dirent.h>
#endif

#include "../include/oasis.h"

#include <vector>
#include <string>
#include <map>

bool operator<(const summary_period &lhs, const summary_period &rhs) {

	if (lhs.summary_id != rhs.summary_id) {
		return lhs.summary_id < rhs.summary_id;
	} else if (lhs.period_no != rhs.period_no) {
		return lhs.period_no < rhs.period_no;
	} else {
		return lhs.fileindex < rhs.fileindex;
	}

}

namespace summaryindex {

	void indexevents(const std::string& fullfilename, std::map<summary_period, std::vector<long long>> &summaryfileperiod_to_offset, int file_id, const std::map<int, std::vector<int>> &eventtoperiods) {
		FILE* fin = fopen(fullfilename.c_str(), "rb");
		if (fin == NULL) {
			fprintf(stderr, "%s: cannot open %s\n", __func__, fullfilename.c_str());
			exit(EXIT_FAILURE);
		}
		long long offset = 0;
		int summarycalcstream_type = 0;
		size_t i = fread(&summarycalcstream_type, sizeof(summarycalcstream_type), 1, fin);
		if (i != 0) offset += sizeof(summarycalcstream_type);
		int stream_type = summarycalcstream_type & summarycalc_id;

		if (stream_type != summarycalc_id) {
			fprintf(stderr, "%s: Not a summarycalc stream type %d\n", __func__, stream_type);
			exit(-1);
		}

		stream_type = streamno_mask & summarycalcstream_type;
		int samplesize;
		i = fread(&samplesize, sizeof(samplesize), 1, fin);
		if (i != 0) offset += sizeof(samplesize);
		int summary_set = 0;
		if (i != 0) i = fread(&summary_set, sizeof(summary_set), 1, fin);
		if (i != 0) offset += sizeof(summary_set);
		summarySampleslevelHeader sh;
		int last_event_id = -1;
		while (i != 0) {
			i = fread(&sh, sizeof(sh), 1, fin);
			if (i != 0) {
				summary_period k;
				k.summary_id = sh.summary_id;
				k.fileindex = file_id;
				for (auto period : eventtoperiods.at(sh.event_id)) {
					k.period_no = period;
					summaryfileperiod_to_offset[k].push_back(offset);
				}
				offset += sizeof(sh);
			}
			while (i != 0) {
				sampleslevelRec sr;
				i = fread(&sr, sizeof(sr), 1, fin);
				if (i != 0) offset += sizeof(sr);
				if (i == 0) break;
				if (sr.sidx == 0) break;
			}
		}

		fclose(fin);
	}

	void indexevents(const std::string &binfilename, std::string &idxfilename, std::map<summary_period, std::vector<long long>> &summaryfileperiod_to_offset, int file_id, const std::map<int, std::vector<int>> &eventtoperiods) {

		FILE * fidx = fopen(idxfilename.c_str(), "r");
		if (fidx == nullptr) {
			fprintf(stderr, "FATAL: Cannot open %s\n", idxfilename.c_str());
			exit(EXIT_FAILURE);
		}
		FILE * fbin = fopen(binfilename.c_str(), "r");
		if (fbin == nullptr) {
			fprintf(stderr, "FATAL: Cannot open %s\n", binfilename.c_str());
			exit(EXIT_FAILURE);
		}

		char line[4096];
		summary_period k;
		k.fileindex = file_id;
		while (fgets(line, sizeof(line), fidx) != 0) {
			long long offset;
			int ret = sscanf(line, "%d,%lld", &k.summary_id, &offset);
			if (ret != 2) {
				fprintf(stderr, "FATAL: Invalid data in file %s:\n%s", idxfilename.c_str(), line);
				exit(EXIT_FAILURE);
			}
			// Get period numbers from event IDs
			flseek(fbin, offset, SEEK_SET);
			summarySampleslevelHeader sh;
			size_t i = fread(&sh, sizeof(sh), 1, fbin);
			std::map<int, std::vector<int>>::const_iterator iter = eventtoperiods.find(sh.event_id);
			if (iter == eventtoperiods.end()) continue;   // Event not found so don't process it
			for (auto period : iter->second) {
				k.period_no = period;
				summaryfileperiod_to_offset[k].push_back(offset);
			}
		}

		fclose(fidx);
		fclose(fbin);

	}

void doit(const std::string& subfolder, const std::map<int, std::vector<int>> &eventtoperiods)
{
	std::string path = "work/" + subfolder;
	if (path.substr(path.length() - 1, 1) != "/") {
		path = path + "/";
	}

	std::vector<std::string> files;
	std::map<summary_period, std::vector<long long>> summaryfileperiod_to_offset;
	DIR* dir;
	struct dirent* ent;
	int file_index = 0;
	if ((dir = opendir(path.c_str())) != NULL) {
		while ((ent = readdir(dir)) != NULL) {
			std::string s = ent->d_name;
			if (s.length() > 4 && s.substr(s.length() - 4, 4) == ".bin") {
				std::string s2 = path + ent->d_name;
				files.push_back(s);
				std::string s3 = s2;
				s3.erase(s2.length() - 4);
				s3 += ".idx";
				FILE * fidx = fopen(s3.c_str(), "r");
				if (fidx == nullptr) {
					indexevents(s2, summaryfileperiod_to_offset, file_index, eventtoperiods);
				} else {
					fclose(fidx);
					indexevents(s2, s3, summaryfileperiod_to_offset, file_index, eventtoperiods);
				}
				file_index++;
			}
		}
	}
	else {
		fprintf(stderr, "Unable to open directory %s\n", path.c_str());
		exit(-1);
	}

	std::string filename =  path + "filelist.idx";
	FILE* fout = fopen(filename.c_str(), "wb");
	if (fout == NULL) {
		fprintf(stderr, "%s: cannot open %s\n", __func__, filename.c_str());
		exit(EXIT_FAILURE);
	}
	auto iter = files.begin();
	while (iter != files.end()) {
		fprintf(fout, "%s\n", iter->c_str());
		iter++;
	}

	fclose(fout);

	int max_summary_id = 0;
	filename = path + "summaries.idx";
	fout = fopen(filename.c_str(), "wb");
	if (fout == NULL) {
		fprintf(stderr, "%s: cannot open %s\n", __func__, filename.c_str());
		exit(EXIT_FAILURE);
	}

	auto s_iter = summaryfileperiod_to_offset.begin();
	while (s_iter != summaryfileperiod_to_offset.end()) {
		if (s_iter->first.summary_id > max_summary_id) max_summary_id = s_iter->first.summary_id;
		auto v_iter = s_iter->second.begin();
		while (v_iter != s_iter->second.end()) {
			fprintf(fout, "%d, %d, %d, %lld\n", s_iter->first.summary_id, s_iter->first.fileindex, s_iter->first.period_no, *v_iter);
			v_iter++;
		}
		s_iter++;
	}
	fclose(fout);

	filename = path + "max_summary_id.idx";
	fout = fopen(filename.c_str(), "wb");
	if (fout == NULL) {
		fprintf(stderr, "%s: cannot open %s\n", __func__, filename.c_str());
		exit(EXIT_FAILURE);
	}
	fprintf(fout, "%d", max_summary_id);
	fclose(fout);

}

};
<|endoftext|>