<commit_before>
#include "geometry/identity.hpp"

#include <vector>

#include "geometry/frame.hpp"
#include "geometry/orthogonal_map.hpp"
#include "geometry/r3_element.hpp"
#include "glog/logging.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "quantities/si.hpp"
#include "serialization/geometry.pb.h"
#include "testing_utilities/almost_equals.hpp"

namespace principia {

using quantities::Length;
using quantities::si::Metre;
using ::testing::Eq;

namespace geometry {

class IdentityTest : public testing::Test {
 protected:
  using World1 = Frame<serialization::Frame::TestTag,
                       serialization::Frame::TEST1, true>;
  using World2 = Frame<serialization::Frame::TestTag,
                       serialization::Frame::TEST2, true>;
  using Orth = OrthogonalMap<World1, World2>;
  using Id = Identity<World1, World2>;
  using R3 = R3Element<quantities::Length>;

  void SetUp() override {
    vector_ = Vector<quantities::Length, World1>(
        R3(1.0 * Metre, 2.0 * Metre, 3.0 * Metre));
    bivector_ = Bivector<quantities::Length, World1>(
        R3(1.0 * Metre, 2.0 * Metre, 3.0 * Metre));
    trivector_ = Trivector<quantities::Length, World1>(4.0 * Metre);
  }

  Vector<quantities::Length, World1> vector_;
  Bivector<quantities::Length, World1> bivector_;
  Trivector<quantities::Length, World1> trivector_;
};

using IdentityDeathTest = IdentityTest;

TEST_F(IdentityTest, Determinant) {
  Id identity;
  EXPECT_TRUE(identity.Determinant().Positive());
}

TEST_F(IdentityTest, AppliedToVector) {
  EXPECT_THAT(Id::Identity()(vector_).coordinates(),
              Eq<R3>({1.0 * Metre, 2.0 * Metre, 3.0 * Metre}));
}

TEST_F(IdentityTest, AppliedToBivector) {
  EXPECT_THAT(Id::Identity()(bivector_).coordinates(),
              Eq<R3>({1.0 * Metre, 2.0 * Metre, 3.0 * Metre}));
}

TEST_F(IdentityTest, AppliedToTrivector) {
  EXPECT_THAT(Id::Identity()(trivector_).coordinates(),
              Eq(4.0 * Metre));
}

TEST_F(IdentityTest, Inverse) {
  Vector<quantities::Length, World1> const vector1 = vector_;
  Vector<quantities::Length, World2> const vector2 =
      Vector<quantities::Length, World2>(
          R3(1.0 * Metre, 2.0 * Metre, 3.0 * Metre));
  EXPECT_THAT(Id::Identity().Inverse()(vector2).coordinates(),
              Eq<R3>({1.0 * Metre, 2.0 * Metre, 3.0 * Metre}));
  Id id;
  Identity<World1, World1> const identity1 = id.Inverse() * id;
  EXPECT_THAT(identity1(vector1), Eq(vector1));
  Identity<World2, World2> const identity2 = id * id.Inverse();
  EXPECT_THAT(identity2(vector2), Eq(vector2));
}

TEST_F(IdentityTest, Forget) {
  EXPECT_THAT(Id::Identity().Forget()(vector_).coordinates(),
              Eq<R3>({1.0 * Metre, 2.0 * Metre, 3.0 * Metre}));
}

TEST_F(IdentityTest, Compose) {
  struct World3;
  using Orth12 = OrthogonalMap<World1, World2>;
  using Orth13 = OrthogonalMap<World1, World3>;
  using Orth23 = OrthogonalMap<World2, World3>;
  using Id12 = Identity<World1, World2>;
  using Id13 = Identity<World1, World3>;
  using Id23 = Identity<World2, World3>;
  Id12 id12;
  Orth12 const o12 = id12.Forget();
  Id23 id23;
  Orth23 const o23 = id23.Forget();
  Id13 const id13 = id23 * id12;
  Orth13 const o13 = o23 * o12;
  for (Length l = 1 * Metre; l < 4 * Metre; l += 1 * Metre) {
    Vector<quantities::Length, World1> modified_vector(
        {l, vector_.coordinates().y, vector_.coordinates().z});
    EXPECT_THAT(id13(modified_vector), Eq(o13(modified_vector)));
  }
}

TEST_F(IdentityDeathTest, SerializationError) {
  using Id12 = Identity<World1, World2>;
  EXPECT_DEATH({
    serialization::LinearMap message;
    Id12 const id = Id12::ReadFromMessage(message);
  }, "Fingerprint");
}

TEST_F(IdentityTest, SerializationSuccess) {
  serialization::LinearMap message;
  Identity<World1, World2> id12a;
  id12a.WriteToMessage(&message);
  EXPECT_TRUE(message.has_from_frame());
  EXPECT_TRUE(message.has_to_frame());
  EXPECT_EQ(message.from_frame().tag_type_fingerprint(),
            message.to_frame().tag_type_fingerprint());
  EXPECT_NE(message.from_frame().tag(),
            message.to_frame().tag());
  EXPECT_EQ(message.from_frame().is_inertial(),
            message.to_frame().is_inertial());
  Identity<World1, World2> const id12b =
      Identity<World1, World2>::ReadFromMessage(message);
  EXPECT_THAT(id12a(vector_), id12b(vector_));
}

}  // namespace geometry
}  // namespace principia
<commit_msg>Fix compilation errors emitted by Clang 5.0<commit_after>
#include "geometry/identity.hpp"

#include <vector>

#include "geometry/frame.hpp"
#include "geometry/orthogonal_map.hpp"
#include "geometry/r3_element.hpp"
#include "glog/logging.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "quantities/si.hpp"
#include "serialization/geometry.pb.h"
#include "testing_utilities/almost_equals.hpp"

namespace principia {

using quantities::Length;
using quantities::si::Metre;
using ::testing::Eq;

namespace geometry {

class IdentityTest : public testing::Test {
 protected:
  using World1 = Frame<serialization::Frame::TestTag,
                       serialization::Frame::TEST1, true>;
  using World2 = Frame<serialization::Frame::TestTag,
                       serialization::Frame::TEST2, true>;
  using Orth = OrthogonalMap<World1, World2>;
  using Id = Identity<World1, World2>;
  using R3 = R3Element<quantities::Length>;

  void SetUp() override {
    vector_ = Vector<quantities::Length, World1>(
        R3(1.0 * Metre, 2.0 * Metre, 3.0 * Metre));
    bivector_ = Bivector<quantities::Length, World1>(
        R3(1.0 * Metre, 2.0 * Metre, 3.0 * Metre));
    trivector_ = Trivector<quantities::Length, World1>(4.0 * Metre);
  }

  Vector<quantities::Length, World1> vector_;
  Bivector<quantities::Length, World1> bivector_;
  Trivector<quantities::Length, World1> trivector_;
};

using IdentityDeathTest = IdentityTest;

TEST_F(IdentityTest, Determinant) {
  Id identity;
  EXPECT_TRUE(identity.Determinant().Positive());
}

TEST_F(IdentityTest, AppliedToVector) {
  Id identity;
  EXPECT_THAT(identity(vector_).coordinates(),
              Eq<R3>({1.0 * Metre, 2.0 * Metre, 3.0 * Metre}));
}

TEST_F(IdentityTest, AppliedToBivector) {
  Id identity;
  EXPECT_THAT(identity(bivector_).coordinates(),
              Eq<R3>({1.0 * Metre, 2.0 * Metre, 3.0 * Metre}));
}

TEST_F(IdentityTest, AppliedToTrivector) {
  Id identity;
  EXPECT_THAT(identity(trivector_).coordinates(),
              Eq(4.0 * Metre));
}

TEST_F(IdentityTest, Inverse) {
  Vector<quantities::Length, World1> const vector1 = vector_;
  Vector<quantities::Length, World2> const vector2 =
      Vector<quantities::Length, World2>(
          R3(1.0 * Metre, 2.0 * Metre, 3.0 * Metre));
  Id identity;
  EXPECT_THAT(identity.Inverse()(vector2).coordinates(),
              Eq<R3>({1.0 * Metre, 2.0 * Metre, 3.0 * Metre}));
  Id id;
  Identity<World1, World1> const identity1 = id.Inverse() * id;
  EXPECT_THAT(identity1(vector1), Eq(vector1));
  Identity<World2, World2> const identity2 = id * id.Inverse();
  EXPECT_THAT(identity2(vector2), Eq(vector2));
}

TEST_F(IdentityTest, Forget) {
  Id identity;
  EXPECT_THAT(identity.Forget()(vector_).coordinates(),
              Eq<R3>({1.0 * Metre, 2.0 * Metre, 3.0 * Metre}));
}

TEST_F(IdentityTest, Compose) {
  struct World3;
  using Orth12 = OrthogonalMap<World1, World2>;
  using Orth13 = OrthogonalMap<World1, World3>;
  using Orth23 = OrthogonalMap<World2, World3>;
  using Id12 = Identity<World1, World2>;
  using Id13 = Identity<World1, World3>;
  using Id23 = Identity<World2, World3>;
  Id12 id12;
  Orth12 const o12 = id12.Forget();
  Id23 id23;
  Orth23 const o23 = id23.Forget();
  Id13 const id13 = id23 * id12;
  Orth13 const o13 = o23 * o12;
  for (Length l = 1 * Metre; l < 4 * Metre; l += 1 * Metre) {
    Vector<quantities::Length, World1> modified_vector(
        {l, vector_.coordinates().y, vector_.coordinates().z});
    EXPECT_THAT(id13(modified_vector), Eq(o13(modified_vector)));
  }
}

TEST_F(IdentityDeathTest, SerializationError) {
  using Id12 = Identity<World1, World2>;
  EXPECT_DEATH({
    serialization::LinearMap message;
    Id12 const id = Id12::ReadFromMessage(message);
  }, "Fingerprint");
}

TEST_F(IdentityTest, SerializationSuccess) {
  serialization::LinearMap message;
  Identity<World1, World2> id12a;
  id12a.WriteToMessage(&message);
  EXPECT_TRUE(message.has_from_frame());
  EXPECT_TRUE(message.has_to_frame());
  EXPECT_EQ(message.from_frame().tag_type_fingerprint(),
            message.to_frame().tag_type_fingerprint());
  EXPECT_NE(message.from_frame().tag(),
            message.to_frame().tag());
  EXPECT_EQ(message.from_frame().is_inertial(),
            message.to_frame().is_inertial());
  Identity<World1, World2> const id12b =
      Identity<World1, World2>::ReadFromMessage(message);
  EXPECT_THAT(id12a(vector_), id12b(vector_));
}

}  // namespace geometry
}  // namespace principia
<|endoftext|>


<commit_before>/// @file
/// @brief Sqlite library wrapper

// Copyright 2015 Matthew Chandler

// 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.

#ifndef SQLITE_HPP
#define SQLITE_HPP

#include <string>

#include <sqlitepp/sqlite3.h>

/// Sqlite C++ wrapper and associated types

/// @ingroup sqlite
/// @sa [C API](https://www.sqlite.org/c3ref/intro.html)
namespace sqlite
{
    /// Sqlite database connection

    /// Holds a connection to a database. SQL may be run with either the exec() method,
    /// or by using create_statement() to build a Connection::Stmt object
    /// @sa [C API](https://www.sqlite.org/c3ref/sqlite3.html)
    class Connection final
    {
    public:
        class Stmt;

        /// Open / create new DB

        /// @param[in] filename Path to sqlite database file
        /// @exception Runtime_error on error connecting to DB
        /// @sa [C API](https://www.sqlite.org/c3ref/open.html)
        Connection(const std::string & filename);
        ~Connection();

        // non-copyable
        Connection(const Connection &) = delete;
        Connection & operator=(const Connection &) = delete;

        // need to explicitly say we want default move ctors
        Connection(Connection &&) = default;
        Connection & operator=(Connection &&) = default;

        /// Create a new prepared statement

        /// @param[in] sql SQL code to prepare
        /// @return Prepared statement for the SQL code input
        /// @exception Logic_error on error parsing SQL
        /// @sa [C API](https://www.sqlite.org/c3ref/prepare.html)
        Stmt create_statement(const std::string & sql);

        /// Execute SQL statement(s)

        /// Will execute the SQL in-place, without needing to create a Connection::Stmt object.
        /// @param[in] sql SQL code to execute
        /// @param[in] callback Function to call for every row. May be NULL. Parameters are:
        /// - arg: The arg parameter from the exec call
        /// - column_data: Array of column data (as strings) for the current row
        /// - column_names: Array of column names
        /// @param[in,out] arg Data to pass as 1st arg of callback. May be NULL.
        /// @exception Logic_error on error evaluating SQL
        /// @sa [C API](https://www.sqlite.org/c3ref/exec.html)
        void exec(const std::string & sql, int (*callback)(void *, int, char **, char **) = nullptr,
            void * arg = nullptr);

        /// Start a transaction

        /// @sa [C API](https://www.sqlite.org/lang_transaction.html)
        void begin_transaction();

        /// End a transaction & commit

        /// @sa [C API](https://www.sqlite.org/lang_transaction.html)
        void commit();

        /// End a transaction & rollback

        /// @sa [C API](https://www.sqlite.org/lang_transaction.html)
        void rollback();

        /// Interrupt a long-running query

        /// @sa [C API](https://www.sqlite.org/c3ref/interrupt.html)
        void interrupt();

        /// Get last INSERTed Row ID

        /// @ returns Row ID for last INSERTed row
        /// @sa [C API](https://www.sqlite.org/c3ref/last_insert_rowid.html)
        sqlite3_int64 last_insert_rowid();

        /// Get total number of rows modified

        /// @returns Total number of rows inserted, modified or deleted by all
        /// INSERT, UPDATE or DELETE statements completed since the database
        /// connection was opened, including those executed as part of trigger
        /// programs.
        /// @sa [C API](https://www.sqlite.org/c3ref/total_changes.html)
        int total_changes();

        /// Column metadata info

        /// This is the return type for table_column_metadata()
        struct Column_metadata
        {
            std::string type; ///< Column's declared data type
            std::string collation; ///< Name of default collation sequence
            bool not_null = false; ///< \c true if the column has a NOT NULL constraint
            bool primary_key = false; ///< \c true if column is part of the PRIMARY KEY
            bool auto_inc = false; ///< \c true True if column is AUTOINCREMENT
        };

        /// Get column metadata

        /// @param[in] table_name Table name
        /// @param[in] column_name Column name
        /// @param[in] db_name DB name, or \c "main" if omitted
        /// @returns The chosen column's metadata
        /// @exception Runtime_error on error looking up info
        /// @sa [C API](https://www.sqlite.org/c3ref/table_column_metadata.html)
        Column_metadata table_column_metadata(const std::string & table_name, const std::string & column_name,
            const std::string & db_name = "main");

        /// Get wrapped C sqlite3 object (for use with the sqlite [C API](https://www.sqlite.org/c3ref/intro.html))

        /// @returns C sqlite3 object
        const sqlite3 * get_c_obj() const;

        /// Get wrapped C sqlite3 object (for use with the sqlite [C API](https://www.sqlite.org/c3ref/intro.html))

        /// @returns C sqlite3 object
        sqlite3 * get_c_obj();

    private:
        /// sqlite C API's DB connection obj
        sqlite3 * _db = nullptr;
    };

    /// Prepared statement obj - usually created by Connection::create_statement

    /// Data is bound to the statement with the bind() overloads, step() is called
    /// to execute the statement, and then get_col() can be used to retrieve rows
    /// from a SELECT statement.
    ///
    /// When INSERTing or UPDATing multiple rows, call reset() to reuse the statement obj.
    /// @sa [C API](https://www.sqlite.org/c3ref/stmt.html)
    class Connection::Stmt final
    {
    public:
        /// Prepare a new statement for the given SQL

        /// It is usually easier to use Connection::create_statement instead of this
        /// @param[in] sql SQL code to prepare
        /// @param[in] db Database Connection to prepare statement for
        /// @exception Logic_error on error parsing SQL
        /// @sa [C API](https://www.sqlite.org/c3ref/prepare.html)
        Stmt(const std::string & sql, Connection & db);
        ~Stmt();

        // non-copyable
        Stmt(const Stmt &) = delete;
        Stmt & operator=(const Stmt &) = delete;

        // need to explicit say we want default move ctors
        Stmt(Stmt &&) = default;
        Stmt & operator=(Stmt &&) = default;

        /// @name Bind functions
        /// Functions for binding data to SQL statements
        /// @{

        /// Bind var by index

        /// @note As in the sqlite C API, bind var indexes start at 1
        /// @param[in] index Bind variable index
        /// @param[in] val Bind variable value
        /// @exception Logic_error on error binding
        /// @sa [C API](https://www.sqlite.org/c3ref/bind_blob.html)
        void bind(const int index, const double val);

        /// @overload bind(const int, const int)
        void bind(const int index, const int val);

        /// @overload bind(const int, const int)
        void bind(const int index, const sqlite3_int64 val);

        /// @overload bind(const int, const int)
        void bind(const int index, const std::string & val);

        /// @overload bind(const int, const int)
        void bind(const int index, const char * val);

        /// Bind null by index

        /// @note As in the sqlite C API, bind var indexes start at 1
        /// @param[in] index Bind variable index
        /// @exception Logic_error on error binding
        /// @sa [C API](https://www.sqlite.org/c3ref/bind_blob.html)
        void bind_null(const int index);

        /// @copydoc bind_null(const int)
        void bind(const int index);

        /// Bind var by name

        /// @param[in] name Bind variable name
        /// @param[in] val Bind variable value
        /// @exception Logic_error on error binding
        /// @sa [C API](https://www.sqlite.org/c3ref/bind_blob.html)
        void bind(const std::string & name, const double val);

        /// @overload bind(const std::string &, const int)
        void bind(const std::string & name, const int val);

        /// @overload bind(const std::string &, const int)
        void bind(const std::string & name, const sqlite3_int64 val);

        /// @overload bind(const std::string &, const int)
        void bind(const std::string & name, const std::string & val);

        /// @overload bind(const std::string &, const int)
        void bind(const std::string & name, const char * val);

        /// Bind null by name

        /// @param[in] name Bind variable name
        /// @exception Logic_error on error binding
        /// @sa [C API](https://www.sqlite.org/c3ref/bind_blob.html)
        void bind_null(const std::string & name);

        /// @copydoc bind_null(const std::string &)
        void bind(const std::string & name);

        /// @}

        /// Get bind var name from index

        /// @param[in] index Bind variable index
        /// @returns Bind variable name
        /// @exception Logic_error on error finding name
        /// @sa [C API](https://www.sqlite.org/c3ref/bind_parameter_name.html)
        std::string bind_parameter_name(const int index);

        /// Get bind var index by name

        /// @param[in] name Bind variable name
        /// @returns Bind variable index
        /// @exception Logic_error on error finding index
        /// @sa [C API](https://www.sqlite.org/c3ref/bind_parameter_index.html)
        int bind_parameter_index(const std::string & name);

        /// Get number of bind parameters

        /// @returns Number of bind parameters
        /// @sa [C API](https://www.sqlite.org/c3ref/bind_parameter_count.html)
        int bind_parameter_count();

        /// Run the statement.

        /// @returns
        /// - \c true on SELECT statements when more rows remain to be fetched
        /// - \c false for UPDATE, DELETE, or database commands, or when no more rows can be SELECTED
        /// @exception Logic_error on error evaluating SQL
        /// @sa [C API](https://www.sqlite.org/c3ref/step.html)
        bool step();

        /// Get SELECTed column

        /// @param[in] column Column number
        /// - Unlike bind() indexes, column indexes start at 0
        /// @returns Column data for the current row
        /// @note Only specific template types are allowed
        /// See documentation for template specializations.
        /// @sa [C API](https://www.sqlite.org/c3ref/column_blob.html)
        template<typename T>
        T get_col(const int column);

        /// Reset the statement

        /// Useful for inserting or updating multiple rows
        /// @exception Logic_error on error resetting
        /// @sa [C API](https://www.sqlite.org/c3ref/reset.html)
        void reset();

        /// Clear all bind vars to NULL

        /// @sa [C API](https://www.sqlite.org/c3ref/clear_bindings.html)
        void clear_bindings();

        /// Determine if the statment has been reset

        /// @returns \c true if the statement is busy (step has been called, but is not complete, nor reset)
        /// @sa [C API](https://www.sqlite.org/c3ref/stmt_busy.html)
        bool busy();

        /// Determine if the statment is read-only

        /// @returns \c true if the statement does not directly write to the DB
        /// @sa [C API](https://www.sqlite.org/c3ref/stmt_readonly.html)
        bool readonly();

        /// Get wrapped C sqlite3_stmt object (for use with the sqlite [C API](https://www.sqlite.org/c3ref/intro.html))

        /// @returns C sqlite3_stmt object
        const sqlite3_stmt * get_c_obj() const;

        /// Get wrapped C sqlite3_stmt object (for use with the sqlite [C API](https://www.sqlite.org/c3ref/intro.html))

        /// @returns C sqlite3_stmt object
        sqlite3_stmt * get_c_obj();

    private:
        /// Sqlite C API's prepared statement obj
        sqlite3_stmt * _stmt = nullptr;
        /// Copy of sqlite DB connection obj
        sqlite3 * _db = nullptr;
    };
};

# endif // SQLITE_HPP
<commit_msg>fix non-explicit constructor<commit_after>/// @file
/// @brief Sqlite library wrapper

// Copyright 2015 Matthew Chandler

// 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.

#ifndef SQLITE_HPP
#define SQLITE_HPP

#include <string>

#include <sqlitepp/sqlite3.h>

/// Sqlite C++ wrapper and associated types

/// @ingroup sqlite
/// @sa [C API](https://www.sqlite.org/c3ref/intro.html)
namespace sqlite
{
    /// Sqlite database connection

    /// Holds a connection to a database. SQL may be run with either the exec() method,
    /// or by using create_statement() to build a Connection::Stmt object
    /// @sa [C API](https://www.sqlite.org/c3ref/sqlite3.html)
    class Connection final
    {
    public:
        class Stmt;

        /// Open / create new DB

        /// @param[in] filename Path to sqlite database file
        /// @exception Runtime_error on error connecting to DB
        /// @sa [C API](https://www.sqlite.org/c3ref/open.html)
        explicit Connection(const std::string & filename);
        ~Connection();

        // non-copyable
        Connection(const Connection &) = delete;
        Connection & operator=(const Connection &) = delete;

        // need to explicitly say we want default move ctors
        Connection(Connection &&) = default;
        Connection & operator=(Connection &&) = default;

        /// Create a new prepared statement

        /// @param[in] sql SQL code to prepare
        /// @return Prepared statement for the SQL code input
        /// @exception Logic_error on error parsing SQL
        /// @sa [C API](https://www.sqlite.org/c3ref/prepare.html)
        Stmt create_statement(const std::string & sql);

        /// Execute SQL statement(s)

        /// Will execute the SQL in-place, without needing to create a Connection::Stmt object.
        /// @param[in] sql SQL code to execute
        /// @param[in] callback Function to call for every row. May be NULL. Parameters are:
        /// - arg: The arg parameter from the exec call
        /// - column_data: Array of column data (as strings) for the current row
        /// - column_names: Array of column names
        /// @param[in,out] arg Data to pass as 1st arg of callback. May be NULL.
        /// @exception Logic_error on error evaluating SQL
        /// @sa [C API](https://www.sqlite.org/c3ref/exec.html)
        void exec(const std::string & sql, int (*callback)(void *, int, char **, char **) = nullptr,
            void * arg = nullptr);

        /// Start a transaction

        /// @sa [C API](https://www.sqlite.org/lang_transaction.html)
        void begin_transaction();

        /// End a transaction & commit

        /// @sa [C API](https://www.sqlite.org/lang_transaction.html)
        void commit();

        /// End a transaction & rollback

        /// @sa [C API](https://www.sqlite.org/lang_transaction.html)
        void rollback();

        /// Interrupt a long-running query

        /// @sa [C API](https://www.sqlite.org/c3ref/interrupt.html)
        void interrupt();

        /// Get last INSERTed Row ID

        /// @ returns Row ID for last INSERTed row
        /// @sa [C API](https://www.sqlite.org/c3ref/last_insert_rowid.html)
        sqlite3_int64 last_insert_rowid();

        /// Get total number of rows modified

        /// @returns Total number of rows inserted, modified or deleted by all
        /// INSERT, UPDATE or DELETE statements completed since the database
        /// connection was opened, including those executed as part of trigger
        /// programs.
        /// @sa [C API](https://www.sqlite.org/c3ref/total_changes.html)
        int total_changes();

        /// Column metadata info

        /// This is the return type for table_column_metadata()
        struct Column_metadata
        {
            std::string type; ///< Column's declared data type
            std::string collation; ///< Name of default collation sequence
            bool not_null = false; ///< \c true if the column has a NOT NULL constraint
            bool primary_key = false; ///< \c true if column is part of the PRIMARY KEY
            bool auto_inc = false; ///< \c true True if column is AUTOINCREMENT
        };

        /// Get column metadata

        /// @param[in] table_name Table name
        /// @param[in] column_name Column name
        /// @param[in] db_name DB name, or \c "main" if omitted
        /// @returns The chosen column's metadata
        /// @exception Runtime_error on error looking up info
        /// @sa [C API](https://www.sqlite.org/c3ref/table_column_metadata.html)
        Column_metadata table_column_metadata(const std::string & table_name, const std::string & column_name,
            const std::string & db_name = "main");

        /// Get wrapped C sqlite3 object (for use with the sqlite [C API](https://www.sqlite.org/c3ref/intro.html))

        /// @returns C sqlite3 object
        const sqlite3 * get_c_obj() const;

        /// Get wrapped C sqlite3 object (for use with the sqlite [C API](https://www.sqlite.org/c3ref/intro.html))

        /// @returns C sqlite3 object
        sqlite3 * get_c_obj();

    private:
        /// sqlite C API's DB connection obj
        sqlite3 * _db = nullptr;
    };

    /// Prepared statement obj - usually created by Connection::create_statement

    /// Data is bound to the statement with the bind() overloads, step() is called
    /// to execute the statement, and then get_col() can be used to retrieve rows
    /// from a SELECT statement.
    ///
    /// When INSERTing or UPDATing multiple rows, call reset() to reuse the statement obj.
    /// @sa [C API](https://www.sqlite.org/c3ref/stmt.html)
    class Connection::Stmt final
    {
    public:
        /// Prepare a new statement for the given SQL

        /// It is usually easier to use Connection::create_statement instead of this
        /// @param[in] sql SQL code to prepare
        /// @param[in] db Database Connection to prepare statement for
        /// @exception Logic_error on error parsing SQL
        /// @sa [C API](https://www.sqlite.org/c3ref/prepare.html)
        Stmt(const std::string & sql, Connection & db);
        ~Stmt();

        // non-copyable
        Stmt(const Stmt &) = delete;
        Stmt & operator=(const Stmt &) = delete;

        // need to explicit say we want default move ctors
        Stmt(Stmt &&) = default;
        Stmt & operator=(Stmt &&) = default;

        /// @name Bind functions
        /// Functions for binding data to SQL statements
        /// @{

        /// Bind var by index

        /// @note As in the sqlite C API, bind var indexes start at 1
        /// @param[in] index Bind variable index
        /// @param[in] val Bind variable value
        /// @exception Logic_error on error binding
        /// @sa [C API](https://www.sqlite.org/c3ref/bind_blob.html)
        void bind(const int index, const double val);

        /// @overload bind(const int, const int)
        void bind(const int index, const int val);

        /// @overload bind(const int, const int)
        void bind(const int index, const sqlite3_int64 val);

        /// @overload bind(const int, const int)
        void bind(const int index, const std::string & val);

        /// @overload bind(const int, const int)
        void bind(const int index, const char * val);

        /// Bind null by index

        /// @note As in the sqlite C API, bind var indexes start at 1
        /// @param[in] index Bind variable index
        /// @exception Logic_error on error binding
        /// @sa [C API](https://www.sqlite.org/c3ref/bind_blob.html)
        void bind_null(const int index);

        /// @copydoc bind_null(const int)
        void bind(const int index);

        /// Bind var by name

        /// @param[in] name Bind variable name
        /// @param[in] val Bind variable value
        /// @exception Logic_error on error binding
        /// @sa [C API](https://www.sqlite.org/c3ref/bind_blob.html)
        void bind(const std::string & name, const double val);

        /// @overload bind(const std::string &, const int)
        void bind(const std::string & name, const int val);

        /// @overload bind(const std::string &, const int)
        void bind(const std::string & name, const sqlite3_int64 val);

        /// @overload bind(const std::string &, const int)
        void bind(const std::string & name, const std::string & val);

        /// @overload bind(const std::string &, const int)
        void bind(const std::string & name, const char * val);

        /// Bind null by name

        /// @param[in] name Bind variable name
        /// @exception Logic_error on error binding
        /// @sa [C API](https://www.sqlite.org/c3ref/bind_blob.html)
        void bind_null(const std::string & name);

        /// @copydoc bind_null(const std::string &)
        void bind(const std::string & name);

        /// @}

        /// Get bind var name from index

        /// @param[in] index Bind variable index
        /// @returns Bind variable name
        /// @exception Logic_error on error finding name
        /// @sa [C API](https://www.sqlite.org/c3ref/bind_parameter_name.html)
        std::string bind_parameter_name(const int index);

        /// Get bind var index by name

        /// @param[in] name Bind variable name
        /// @returns Bind variable index
        /// @exception Logic_error on error finding index
        /// @sa [C API](https://www.sqlite.org/c3ref/bind_parameter_index.html)
        int bind_parameter_index(const std::string & name);

        /// Get number of bind parameters

        /// @returns Number of bind parameters
        /// @sa [C API](https://www.sqlite.org/c3ref/bind_parameter_count.html)
        int bind_parameter_count();

        /// Run the statement.

        /// @returns
        /// - \c true on SELECT statements when more rows remain to be fetched
        /// - \c false for UPDATE, DELETE, or database commands, or when no more rows can be SELECTED
        /// @exception Logic_error on error evaluating SQL
        /// @sa [C API](https://www.sqlite.org/c3ref/step.html)
        bool step();

        /// Get SELECTed column

        /// @param[in] column Column number
        /// - Unlike bind() indexes, column indexes start at 0
        /// @returns Column data for the current row
        /// @note Only specific template types are allowed
        /// See documentation for template specializations.
        /// @sa [C API](https://www.sqlite.org/c3ref/column_blob.html)
        template<typename T>
        T get_col(const int column);

        /// Reset the statement

        /// Useful for inserting or updating multiple rows
        /// @exception Logic_error on error resetting
        /// @sa [C API](https://www.sqlite.org/c3ref/reset.html)
        void reset();

        /// Clear all bind vars to NULL

        /// @sa [C API](https://www.sqlite.org/c3ref/clear_bindings.html)
        void clear_bindings();

        /// Determine if the statment has been reset

        /// @returns \c true if the statement is busy (step has been called, but is not complete, nor reset)
        /// @sa [C API](https://www.sqlite.org/c3ref/stmt_busy.html)
        bool busy();

        /// Determine if the statment is read-only

        /// @returns \c true if the statement does not directly write to the DB
        /// @sa [C API](https://www.sqlite.org/c3ref/stmt_readonly.html)
        bool readonly();

        /// Get wrapped C sqlite3_stmt object (for use with the sqlite [C API](https://www.sqlite.org/c3ref/intro.html))

        /// @returns C sqlite3_stmt object
        const sqlite3_stmt * get_c_obj() const;

        /// Get wrapped C sqlite3_stmt object (for use with the sqlite [C API](https://www.sqlite.org/c3ref/intro.html))

        /// @returns C sqlite3_stmt object
        sqlite3_stmt * get_c_obj();

    private:
        /// Sqlite C API's prepared statement obj
        sqlite3_stmt * _stmt = nullptr;
        /// Copy of sqlite DB connection obj
        sqlite3 * _db = nullptr;
    };
};

# endif // SQLITE_HPP
<|endoftext|>


<commit_before>// @(#)root/tree:$Name:  $:$Id: TTreeCache.cxx,v 1.10 2006/08/31 11:09:10 brun Exp $
// Author: Rene Brun   04/06/2006

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TTreeCache                                                           //
//                                                                      //
//  A specialized TFileCacheRead object for a TTree                     //
//  This class acts as a file cache, registering automatically the      //
//  baskets from the branches being processed (TTree::Draw or           //
//  TTree::Process and TSelectors) when in the learning phase.          //
//  The learning phase is by default 100 entries.                       //
//  It can be changed via TTreeCache::SetLearnEntries.                  //
//                                                                      //
//  This cache speeds-up considerably the performance, in particular    //
//  when the Tree is accessed remotely via a high latency network.      //
//                                                                      //
//  The default cache size (10 Mbytes) may be changed via the function  //
//      TTreeCache::SetCacheSize                                        //
//                                                                      //
//  Only the baskets for the requested entry range are put in the cache //
//                                                                      //
//  For each Tree being processed a TTreeCache object is created.       //
//  This object is automatically deleted when the Tree is deleted or    //
//  when the file is deleted.                                           //
//                                                                      //
//  -Special case of a TChain                                           //
//   Once the training is done on the first Tree, the list of branches  //
//   in the cache is kept for the following files.                      //
//                                                                      //
//  -Special case of a TEventlist                                       //
//   if the Tree or TChain has a TEventlist, only the buffers           //
//   referenced by the list are put in the cache.                       //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TTreeCache.h"
#include "TChain.h"
#include "TBranch.h"
#include "TEventList.h"
#include "TObjString.h"

Int_t TTreeCache::fgLearnEntries = 100;

ClassImp(TTreeCache)

//______________________________________________________________________________
TTreeCache::TTreeCache() : TFileCacheRead(),
   fEntryMin(0),
   fEntryMax(1),
   fEntryNext(1),
   fZipBytes(0),
   fNbranches(0),
   fNReadOk(0),
   fNReadMiss(0),
   fNReadPref(0),
   fBranches(0),
   fBrNames(0),
   fOwner(0),
   fTree(0),
   fIsLearning(kTRUE)
{
   // Default Constructor.
}

//______________________________________________________________________________
TTreeCache::TTreeCache(TTree *tree, Int_t buffersize) : TFileCacheRead(tree->GetCurrentFile(),buffersize),
   fEntryMin(0),
   fEntryMax(tree->GetEntriesFast()),
   fEntryNext(0),
   fZipBytes(0),
   fNbranches(0),
   fNReadOk(0),
   fNReadMiss(0),
   fNReadPref(0),
   fBranches(0),
   fBrNames(new TList),
   fOwner(tree),
   fTree(0),
   fIsLearning(kTRUE)
{
   // Constructor.

   fEntryNext = fEntryMin + fgLearnEntries;
   Int_t nleaves = tree->GetListOfLeaves()->GetEntries();
   fBranches = new TBranch*[nleaves+10]; //add a margin just in case in a TChain?
}

//______________________________________________________________________________
TTreeCache::~TTreeCache()
{
   // destructor. (in general called by the TFile destructor

   delete [] fBranches;
   if (fBrNames) {fBrNames->Delete(); delete fBrNames; fBrNames=0;}
}

//_____________________________________________________________________________
void TTreeCache::AddBranch(TBranch *b)
{
   //add a branch to the list of branches to be stored in the cache
   //this function is called by TBranch::GetBasket

   if (!fIsLearning) return;

   //Is branch already in the cache?
   Bool_t isNew = kTRUE;
   for (int i=0;i<fNbranches;i++) {
      if (fBranches[i] == b) {isNew = kFALSE; break;}
   }
   if (isNew) {
      fTree = b->GetTree();
      fBranches[fNbranches] = b;
      fBrNames->Add(new TObjString(b->GetName()));
      fZipBytes += b->GetZipBytes();
      fNbranches++;
      if (gDebug > 0) printf("Entry: %lld, registering branch: %s\n",b->GetTree()->GetReadEntry(),b->GetName());
   }
}

//_____________________________________________________________________________
Bool_t TTreeCache::FillBuffer()
{
   //Fill the cache buffer with the branches in the cache

   if (fNbranches <= 0) return kFALSE;
   TTree *tree = fBranches[0]->GetTree();
   Long64_t entry = tree->GetReadEntry();
   if (entry < fEntryNext) return kFALSE;

   // estimate number of entries that can fit in the cache
   // compare it to the original value of fBufferSize not
   // to the real one
   fEntryNext = entry + tree->GetEntries()*fBufferSizeMin/fZipBytes;

   if (fEntryMax <= 0) fEntryMax = tree->GetEntries();
   if (fEntryNext > fEntryMax) fEntryNext = fEntryMax+1;

   //check if owner has a TEventList set. If yes we optimize for this special case
   //reading only the baskets containing entries in the list
   TEventList *elist = fOwner->GetEventList();
   Long64_t chainOffset = 0;
   if (elist) {
      if (fOwner->IsA() ==TChain::Class()) {
         TChain *chain = (TChain*)fOwner;
         Int_t t = chain->GetTreeNumber();
         chainOffset = chain->GetTreeOffset()[t];
      }
   }

   //clear cache buffer
   TFileCacheRead::Prefetch(0,0);
   //store baskets
   Bool_t mustBreak = kFALSE;
   for (Int_t i=0;i<fNbranches;i++) {
      if (mustBreak) break;
      TBranch *b = fBranches[i];
      Int_t nb = b->GetMaxBaskets();
      Int_t *lbaskets   = b->GetBasketBytes();
      Long64_t *entries = b->GetBasketEntry();
      if (!lbaskets || !entries) continue;
      //we have found the branch. We now register all its baskets
      //from the requested offset to the basket below fEntrymax
      for (Int_t j=0;j<nb;j++) {
         Long64_t pos = b->GetBasketSeek(j);
         Int_t len = lbaskets[j];
         if (pos <= 0 || len <= 0) continue;
         if (entries[j] > fEntryNext) continue;
         if (entries[j] < entry && (j<nb-1 && entries[j+1] < entry)) continue;
         if (elist) {
            Long64_t emax = fEntryMax;
            if (j<nb-1) emax = entries[j+1]-1;
            if (!elist->ContainsRange(entries[j]+chainOffset,emax+chainOffset)) continue;
         }
         fNReadPref++;
         TFileCacheRead::Prefetch(pos,len);
         //we allow up to twice the default buffer size. When using eventlist in particular
         //it may happen that the evaluation of fEntryNext is bad, hence this protection
         if (fNtot > 2*fBufferSizeMin) {TFileCacheRead::Prefetch(0,0);mustBreak = kTRUE; break;}
      }
      if (gDebug > 0) printf("Entry: %lld, registering baskets branch %s, fEntryNext=%lld, fNseek=%d, fNtot=%d\n",entry,fBranches[i]->GetName(),fEntryNext,fNseek,fNtot);
   }
   fIsLearning = kFALSE;
   if (mustBreak) return kFALSE;
   return kTRUE;
}

//_____________________________________________________________________________
Double_t TTreeCache::GetEfficiency()
{
   // Give the total efficiency of the cache... defined as the ratio
   // of blocks found in the cache vs. the number of blocks prefetched
   // ( it could be more than 1 if we read the same block from the cache more
   //   than once )
   // Note: This should eb used at the end of the processing or we will
   //       get uncomplete stats

   if ( !fNReadPref )
      return 0;

   return ((Double_t)fNReadOk / (Double_t)fNReadPref);
}

//_____________________________________________________________________________
Double_t TTreeCache::GetEfficiencyRel()
{
   // This will indicate a sort of relative efficiency... a ratio of the
   // reads found in the cache to the number of reads so far

   if ( !fNReadOk && !fNReadMiss )
      return 0;

   return ((Double_t)fNReadOk / (Double_t)(fNReadOk + fNReadMiss));
}

//_____________________________________________________________________________
Int_t TTreeCache::GetLearnEntries()
{
   //static function returning the number of entries used to train the cache
   //see SetLearnEntries

   return fgLearnEntries;
}

//_____________________________________________________________________________
TTree *TTreeCache::GetTree() const
{
   //return Tree in the cache
   if (fNbranches <= 0) return 0;
   return fBranches[0]->GetTree();
}

//_____________________________________________________________________________
Int_t TTreeCache::ReadBuffer(char *buf, Long64_t pos, Int_t len)
{
   // Read buffer at position pos.
   // If pos is in the list of prefetched blocks read from fBuffer,
   // then try to fill the cache from the list of selected branches,
   // otherwise normal read from file. Returns -1 in case of read
   // failure, 0 in case not in cache and 1 in case read from cache.
   // This function overloads TFileCacheRead::ReadBuffer.

   //Is request already in the cache?
   if (TFileCacheRead::ReadBuffer(buf,pos,len) == 1){
      fNReadOk++;
      return 1;
   }

   //not found in cache. Do we need to fill the cache?
   Bool_t bufferFilled = FillBuffer();
   if (bufferFilled) {
      Int_t res = TFileCacheRead::ReadBuffer(buf,pos,len);

      if (res == 1)
         fNReadOk++;
      else if (res == 0)
         fNReadMiss++;

      return res;
   }
   fNReadMiss++;

   return 0;
}

//_____________________________________________________________________________
void TTreeCache::SetEntryRange(Long64_t emin, Long64_t emax)
{
   // Set the minimum and maximum entry number to be processed
   // this information helps to optimize the number of baskets to read
   // when prefetching the branch buffers.

   fEntryMin  = emin;
   fEntryMax  = emax;
   fEntryNext  = fEntryMin + fgLearnEntries;
   if (gDebug > 0) printf("SetEntryRange: fEntryMin=%lld, fEntryMax=%lld, fEntryNext=%lld\n",fEntryMin,fEntryMax,fEntryNext);
   fIsLearning = kTRUE;
   fNbranches  = 0;
   fZipBytes   = 0;
   if (fBrNames) fBrNames->Delete();

}

//_____________________________________________________________________________
void TTreeCache::SetLearnEntries(Int_t n)
{
   // Static function to set the number of entries to be used in learning mode
   // The default value for n is 10. n must be >= 1

   if (n < 1) n = 1;
   fgLearnEntries = n;
}

//_____________________________________________________________________________
void TTreeCache::UpdateBranches(TTree *tree)
{
   //update pointer to current Tree and recompute pointers to the branches in the cache

   fTree = tree;

   fEntryMin  = 0;
   fEntryMax  = fTree->GetEntries();
   fEntryNext = fEntryMin + fgLearnEntries;
   fZipBytes  = 0;
   fNbranches = 0;
   TIter next(fBrNames);
   TObjString *os;
   while ((os = (TObjString*)next())) {
      TBranch *b = fTree->GetBranch(os->GetName());
      if (!b) continue;
      fBranches[fNbranches] = b;
      fZipBytes   += b->GetZipBytes();
      fNbranches++;
   }
}
<commit_msg>avoid division by zero in entry number estimation<commit_after>// @(#)root/tree:$Name:  $:$Id: TTreeCache.cxx,v 1.11 2006/10/19 19:35:52 pcanal Exp $
// Author: Rene Brun   04/06/2006

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TTreeCache                                                           //
//                                                                      //
//  A specialized TFileCacheRead object for a TTree                     //
//  This class acts as a file cache, registering automatically the      //
//  baskets from the branches being processed (TTree::Draw or           //
//  TTree::Process and TSelectors) when in the learning phase.          //
//  The learning phase is by default 100 entries.                       //
//  It can be changed via TTreeCache::SetLearnEntries.                  //
//                                                                      //
//  This cache speeds-up considerably the performance, in particular    //
//  when the Tree is accessed remotely via a high latency network.      //
//                                                                      //
//  The default cache size (10 Mbytes) may be changed via the function  //
//      TTreeCache::SetCacheSize                                        //
//                                                                      //
//  Only the baskets for the requested entry range are put in the cache //
//                                                                      //
//  For each Tree being processed a TTreeCache object is created.       //
//  This object is automatically deleted when the Tree is deleted or    //
//  when the file is deleted.                                           //
//                                                                      //
//  -Special case of a TChain                                           //
//   Once the training is done on the first Tree, the list of branches  //
//   in the cache is kept for the following files.                      //
//                                                                      //
//  -Special case of a TEventlist                                       //
//   if the Tree or TChain has a TEventlist, only the buffers           //
//   referenced by the list are put in the cache.                       //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TTreeCache.h"
#include "TChain.h"
#include "TBranch.h"
#include "TEventList.h"
#include "TObjString.h"

Int_t TTreeCache::fgLearnEntries = 100;

ClassImp(TTreeCache)

//______________________________________________________________________________
TTreeCache::TTreeCache() : TFileCacheRead(),
   fEntryMin(0),
   fEntryMax(1),
   fEntryNext(1),
   fZipBytes(0),
   fNbranches(0),
   fNReadOk(0),
   fNReadMiss(0),
   fNReadPref(0),
   fBranches(0),
   fBrNames(0),
   fOwner(0),
   fTree(0),
   fIsLearning(kTRUE)
{
   // Default Constructor.
}

//______________________________________________________________________________
TTreeCache::TTreeCache(TTree *tree, Int_t buffersize) : TFileCacheRead(tree->GetCurrentFile(),buffersize),
   fEntryMin(0),
   fEntryMax(tree->GetEntriesFast()),
   fEntryNext(0),
   fZipBytes(0),
   fNbranches(0),
   fNReadOk(0),
   fNReadMiss(0),
   fNReadPref(0),
   fBranches(0),
   fBrNames(new TList),
   fOwner(tree),
   fTree(0),
   fIsLearning(kTRUE)
{
   // Constructor.

   fEntryNext = fEntryMin + fgLearnEntries;
   Int_t nleaves = tree->GetListOfLeaves()->GetEntries();
   fBranches = new TBranch*[nleaves+10]; //add a margin just in case in a TChain?
}

//______________________________________________________________________________
TTreeCache::~TTreeCache()
{
   // destructor. (in general called by the TFile destructor

   delete [] fBranches;
   if (fBrNames) {fBrNames->Delete(); delete fBrNames; fBrNames=0;}
}

//_____________________________________________________________________________
void TTreeCache::AddBranch(TBranch *b)
{
   //add a branch to the list of branches to be stored in the cache
   //this function is called by TBranch::GetBasket

   if (!fIsLearning) return;

   //Is branch already in the cache?
   Bool_t isNew = kTRUE;
   for (int i=0;i<fNbranches;i++) {
      if (fBranches[i] == b) {isNew = kFALSE; break;}
   }
   if (isNew) {
      fTree = b->GetTree();
      fBranches[fNbranches] = b;
      fBrNames->Add(new TObjString(b->GetName()));
      fZipBytes += b->GetZipBytes();
      fNbranches++;
      if (gDebug > 0) printf("Entry: %lld, registering branch: %s\n",b->GetTree()->GetReadEntry(),b->GetName());
   }
}

//_____________________________________________________________________________
Bool_t TTreeCache::FillBuffer()
{
   // Fill the cache buffer with the branches in the cache.

   if (fNbranches <= 0) return kFALSE;
   TTree *tree = fBranches[0]->GetTree();
   Long64_t entry = tree->GetReadEntry();
   if (entry < fEntryNext) return kFALSE;

   // Estimate number of entries that can fit in the cache compare it
   // to the original value of fBufferSize not to the real one
   if (fZipBytes==0) {
      fEntryNext = entry + tree->GetEntries();;
   } else {
      fEntryNext = entry + tree->GetEntries()*fBufferSizeMin/fZipBytes;
   }
   if (fEntryMax <= 0) fEntryMax = tree->GetEntries();
   if (fEntryNext > fEntryMax) fEntryNext = fEntryMax+1;

   // Check if owner has a TEventList set. If yes we optimize for this
   // Special case reading only the baskets containing entries in the
   // list.
   TEventList *elist = fOwner->GetEventList();
   Long64_t chainOffset = 0;
   if (elist) {
      if (fOwner->IsA() ==TChain::Class()) {
         TChain *chain = (TChain*)fOwner;
         Int_t t = chain->GetTreeNumber();
         chainOffset = chain->GetTreeOffset()[t];
      }
   }

   //clear cache buffer
   TFileCacheRead::Prefetch(0,0);
   //store baskets
   Bool_t mustBreak = kFALSE;
   for (Int_t i=0;i<fNbranches;i++) {
      if (mustBreak) break;
      TBranch *b = fBranches[i];
      Int_t nb = b->GetMaxBaskets();
      Int_t *lbaskets   = b->GetBasketBytes();
      Long64_t *entries = b->GetBasketEntry();
      if (!lbaskets || !entries) continue;
      //we have found the branch. We now register all its baskets
      //from the requested offset to the basket below fEntrymax
      for (Int_t j=0;j<nb;j++) {
         Long64_t pos = b->GetBasketSeek(j);
         Int_t len = lbaskets[j];
         if (pos <= 0 || len <= 0) continue;
         if (entries[j] > fEntryNext) continue;
         if (entries[j] < entry && (j<nb-1 && entries[j+1] < entry)) continue;
         if (elist) {
            Long64_t emax = fEntryMax;
            if (j<nb-1) emax = entries[j+1]-1;
            if (!elist->ContainsRange(entries[j]+chainOffset,emax+chainOffset)) continue;
         }
         fNReadPref++;
         TFileCacheRead::Prefetch(pos,len);
         //we allow up to twice the default buffer size. When using eventlist in particular
         //it may happen that the evaluation of fEntryNext is bad, hence this protection
         if (fNtot > 2*fBufferSizeMin) {TFileCacheRead::Prefetch(0,0);mustBreak = kTRUE; break;}
      }
      if (gDebug > 0) printf("Entry: %lld, registering baskets branch %s, fEntryNext=%lld, fNseek=%d, fNtot=%d\n",entry,fBranches[i]->GetName(),fEntryNext,fNseek,fNtot);
   }
   fIsLearning = kFALSE;
   if (mustBreak) return kFALSE;
   return kTRUE;
}

//_____________________________________________________________________________
Double_t TTreeCache::GetEfficiency()
{
   // Give the total efficiency of the cache... defined as the ratio
   // of blocks found in the cache vs. the number of blocks prefetched
   // ( it could be more than 1 if we read the same block from the cache more
   //   than once )
   // Note: This should eb used at the end of the processing or we will
   //       get uncomplete stats

   if ( !fNReadPref )
      return 0;

   return ((Double_t)fNReadOk / (Double_t)fNReadPref);
}

//_____________________________________________________________________________
Double_t TTreeCache::GetEfficiencyRel()
{
   // This will indicate a sort of relative efficiency... a ratio of the
   // reads found in the cache to the number of reads so far

   if ( !fNReadOk && !fNReadMiss )
      return 0;

   return ((Double_t)fNReadOk / (Double_t)(fNReadOk + fNReadMiss));
}

//_____________________________________________________________________________
Int_t TTreeCache::GetLearnEntries()
{
   //static function returning the number of entries used to train the cache
   //see SetLearnEntries

   return fgLearnEntries;
}

//_____________________________________________________________________________
TTree *TTreeCache::GetTree() const
{
   //return Tree in the cache
   if (fNbranches <= 0) return 0;
   return fBranches[0]->GetTree();
}

//_____________________________________________________________________________
Int_t TTreeCache::ReadBuffer(char *buf, Long64_t pos, Int_t len)
{
   // Read buffer at position pos.
   // If pos is in the list of prefetched blocks read from fBuffer.
   // Otherwise try to fill the cache from the list of selected branches,
   // and recheck if pos is now in the list.
   // Returns
   //    -1 in case of read failure,
   //     0 in case not in cache,
   //     1 in case read from cache.
   // This function overloads TFileCacheRead::ReadBuffer.

   //Is request already in the cache?
   if (TFileCacheRead::ReadBuffer(buf,pos,len) == 1){
      fNReadOk++;
      return 1;
   }

   //not found in cache. Do we need to fill the cache?
   Bool_t bufferFilled = FillBuffer();
   if (bufferFilled) {
      Int_t res = TFileCacheRead::ReadBuffer(buf,pos,len);

      if (res == 1)
         fNReadOk++;
      else if (res == 0)
         fNReadMiss++;

      return res;
   }
   fNReadMiss++;

   return 0;
}

//_____________________________________________________________________________
void TTreeCache::SetEntryRange(Long64_t emin, Long64_t emax)
{
   // Set the minimum and maximum entry number to be processed
   // this information helps to optimize the number of baskets to read
   // when prefetching the branch buffers.

   fEntryMin  = emin;
   fEntryMax  = emax;
   fEntryNext  = fEntryMin + fgLearnEntries;
   if (gDebug > 0) printf("SetEntryRange: fEntryMin=%lld, fEntryMax=%lld, fEntryNext=%lld\n",fEntryMin,fEntryMax,fEntryNext);
   fIsLearning = kTRUE;
   fNbranches  = 0;
   fZipBytes   = 0;
   if (fBrNames) fBrNames->Delete();

}

//_____________________________________________________________________________
void TTreeCache::SetLearnEntries(Int_t n)
{
   // Static function to set the number of entries to be used in learning mode
   // The default value for n is 10. n must be >= 1

   if (n < 1) n = 1;
   fgLearnEntries = n;
}

//_____________________________________________________________________________
void TTreeCache::UpdateBranches(TTree *tree)
{
   //update pointer to current Tree and recompute pointers to the branches in the cache

   fTree = tree;

   fEntryMin  = 0;
   fEntryMax  = fTree->GetEntries();
   fEntryNext = fEntryMin + fgLearnEntries;
   fZipBytes  = 0;
   fNbranches = 0;
   TIter next(fBrNames);
   TObjString *os;
   while ((os = (TObjString*)next())) {
      TBranch *b = fTree->GetBranch(os->GetName());
      if (!b) continue;
      fBranches[fNbranches] = b;
      fZipBytes   += b->GetZipBytes();
      fNbranches++;
   }
}
<|endoftext|>


<commit_before>//=====================================================================//
/*! @file
	@brief  BMC メイン関係
	@author 平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <iostream>
#include "bmc_main.hpp"
#include "core/glcore.hpp"
#include "widgets/widget_utils.hpp"
#include <boost/lexical_cast.hpp>

namespace app {

	//-----------------------------------------------------------------//
	/*!
		@brief  初期化
	*/
	//-----------------------------------------------------------------//
	void bmc_main::initialize()
	{
		gl::core& core = gl::core::get_instance();

		using namespace gui;
		widget_director& wd = director_.at().widget_director_;

		{ // 画像ファイル表示用フレーム
			widget::param wp(vtx::irect(30, 30, 256, 256));
			widget_frame::param wp_;
			wp_.plate_param_.set_caption(30);
			wp_.text_param_.set_text("元画像");
			src_frame_ = wd.add_widget<widget_frame>(wp, wp_);
		}
		{ // 画像ファイル表示イメージ
			widget::param wp(vtx::irect(0, 0, 256, 256), src_frame_);
			widget_image::param wp_;
			wp_.linear_ = false;
			src_image_ = wd.add_widget<widget_image>(wp, wp_);
			src_image_->set_state(widget::state::CLIP_PARENTS);
			src_image_->set_state(widget::state::RESIZE_ROOT);
			src_image_->set_state(widget::state::MOVE_ROOT, false);
		}

		{ // 画像ファイル表示用フレーム
			widget::param wp(vtx::irect(60, 60, 256, 256));
			widget_frame::param wp_;
			wp_.plate_param_.set_caption(30);
			wp_.text_param_.set_text("変換後");
			dst_frame_ = wd.add_widget<widget_frame>(wp, wp_);
		}
		{ // 画像ファイル表示イメージ
			widget::param wp(vtx::irect(0, 0, 256, 256), dst_frame_);
			widget_image::param wp_;
			wp_.linear_ = false;
			dst_image_ = wd.add_widget<widget_image>(wp, wp_);
			dst_image_->set_state(widget::state::CLIP_PARENTS);
			dst_image_->set_state(widget::state::RESIZE_ROOT);
			dst_image_->set_state(widget::state::MOVE_ROOT, false);
		}

		{ // 機能ツールパレット
			widget::param wp(vtx::irect(10, 10, 150, 300));
			widget_frame::param wp_;
			tools_ = wd.add_widget<widget_frame>(wp, wp_);
		}
		{ // スケール
			widget::param wp(vtx::irect(10, 10, 130, 40), tools_);
			widget_check::param wp_("scale");
			scale_ = wd.add_widget<widget_check>(wp, wp_);
		}
		{ // BDF page list
			widget::param wp(vtx::irect(10, 60, 100, 40), tools_);
			widget_list::param wp_("0");
			const bmc_core& bmc = *director_.at().bmc_;
			for(uint32_t i = 0; i < bmc.get_bdf_pages(); ++i) {
				std::string s = boost::lexical_cast<std::string>(i);
				wp_.text_list_.push_back(s);
			}
			bdf_page_no_ = 0;
			bdf_page_ = wd.add_widget<widget_list>(wp, wp_);
		}
		{ // ファイラー起動ボタン
//			widget::param wp(vtx::irect(5, 5, 100, 40), tools_);
//			widget_button::param wp_("file");
//			open_ = wd.add_widget<widget_button>(wp, wp_);
		}

		{ // ファイラー本体
			widget::param wp(vtx::irect(10, 30, 300, 200));
			widget_filer::param wp_(core.get_current_path());
			filer_ = wd.add_widget<widget_filer>(wp, wp_);
			filer_->enable(false);
		}
		{ // ダイアログ
			widget::param wp(vtx::irect(10, 30, 450, 200));
			widget_dialog::param wp_;
			dialog_ = wd.add_widget<widget_dialog>(wp, wp_);
			dialog_->enable(false);
		}

		mobj_.initialize();

		// プリファレンスの取得
		sys::preference& pre = director_.at().preference_;
		if(filer_) {
			filer_->load(pre);
			src_frame_->load(pre);
			dst_frame_->load(pre);
			tools_->load(pre);
		}

		// コアの画像を表示
		if(director_.at().bmc_) {
			bmc_core& bmc = *director_.at().bmc_;
			if(!bmc.get_src_image().empty()) {
				src_handle_ = mobj_.install(&bmc.get_src_image());
				src_image_->at_local_param().mobj_ = mobj_;
				src_image_->at_local_param().mobj_handle_ = src_handle_;
			}
			if(!bmc.get_dst_image().empty()) {
				dst_handle_ = mobj_.install(&bmc.get_dst_image());
				dst_image_->at_local_param().mobj_ = mobj_;
				dst_image_->at_local_param().mobj_handle_ = dst_handle_;
			}
		}
	}

	//-----------------------------------------------------------------//
	/*!
		@brief  アップデート
	*/
	//-----------------------------------------------------------------//
	void bmc_main::update()
	{
///		gl::core& core = gl::core::get_instance();
///		const vtx::spos& vsz = core.get_size();

		gui::widget_director& wd = director_.at().widget_director_;

		wd.update();

#if 0
		if(open_) {
			if(open_->get_selected()) {
				if(filer_) {
					bool f = filer_->get_state(gui::widget::state::ENABLE);
					filer_->enable(!f);
				}
			}
		}

		if(filer_) {
			if(filer_id_ != filer_->get_select_file_id()) {
				filer_id_ = filer_->get_select_file_id();
///				std::cout << "Filer: '" << filer_->get_file() << "'" << std::endl;

				img::img_files& imf = wd.at_img_files();
				if(!imf.load(filer_->get_file())) {
					dialog_->set_text("Can't decode image file:\n '"
						+ filer_->get_file() + "'");
					dialog_->enable();
				} else {
//					mobj_.destroy();
//					mobj_.initialize();
//					img_handle_ = mobj_.install(imf.get_image_if());
//					image_->at_local_param().mobj_ = mobj_;
//					image_->at_local_param().mobj_handle_ = img_handle_;
///					imf.set_image_if(imf.get_image_if());
///					imf.save("test.tga", "rle");
				}
			}
		}
#endif

		// frame 内 image のサイズを設定
		if(src_frame_ && src_image_) {
			float s = 1.0f;
			if(scale_->get_check()) {
				vtx::fpos is = mobj_.get_size(src_handle_);
				vtx::fpos ss = src_image_->at_rect().size;
				vtx::fpos sc = ss / is;
				if(sc.x < sc.y) s = sc.x; else s = sc.y;
			}
			src_image_->at_local_param().scale_ = s;

			if(wd.get_top_widget() == src_frame_ || wd.get_top_widget() == src_image_) {
				if(src_image_->get_select_in()) {
					src_image_offset_ = src_image_->get_local_param().offset_;
				}
				if(src_image_->get_select()) {
					vtx::spos d = src_image_->get_param().move_pos_ - src_image_->get_param().move_org_;
					src_image_->at_local_param().offset_ = src_image_offset_ + d / s;
				}
			}
		}

		// BDF ファイルの複数ページ対応
		bmc_core& bmc = *director_.at().bmc_;
		if(bmc.get_bdf_pages()) {
			if(bdf_page_->get_local_param().select_pos_ != bdf_page_no_) {
				bdf_page_no_ = bdf_page_->get_local_param().select_pos_;
				bmc.create_bdf_image(bdf_page_no_);
				mobj_.destroy();
				mobj_.initialize();
				dst_handle_ = mobj_.install(&bmc.get_dst_image());
				dst_image_->at_local_param().mobj_ = mobj_;
				dst_image_->at_local_param().mobj_handle_ = dst_handle_;
			}
		}

		if(dst_frame_ && dst_image_) {
			float s = 1.0f;
			if(scale_->get_check()) {
				vtx::fpos is = mobj_.get_size(dst_handle_);
				vtx::fpos ss = dst_image_->at_rect().size;
				vtx::fpos sc = ss / is;
				if(sc.x < sc.y) s = sc.x; else s = sc.y;
			}
			dst_image_->at_local_param().scale_ = s;

			if(wd.get_top_widget() == dst_frame_ || wd.get_top_widget() == dst_image_) {
				if(dst_image_->get_select_in()) {
					dst_image_offset_ = dst_image_->get_local_param().offset_;
				}
				if(dst_image_->get_select()) {
					vtx::spos d = dst_image_->get_param().move_pos_ - dst_image_->get_param().move_org_;
					dst_image_->at_local_param().offset_ = dst_image_offset_ + d / s;
				}
			}
		}

	}

	//-----------------------------------------------------------------//
	/*!
		@brief  レンダリング
	*/
	//-----------------------------------------------------------------//
	void bmc_main::render()
	{
		director_.at().widget_director_.service();
		director_.at().widget_director_.render();
	}

	//-----------------------------------------------------------------//
	/*!
		@brief  廃棄
	*/
	//-----------------------------------------------------------------//
	void bmc_main::destroy()
	{
		sys::preference& pre = director_.at().preference_;
		if(filer_) {
			filer_->save(pre);
			src_frame_->save(pre);
			dst_frame_->save(pre);
			tools_->save(pre);
		}
	}
}
<commit_msg>update: cleanup<commit_after>//=====================================================================//
/*! @file
	@brief  BMC メイン関係
	@author 平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <iostream>
#include "bmc_main.hpp"
#include "core/glcore.hpp"
#include "widgets/widget_utils.hpp"
#include <boost/lexical_cast.hpp>

namespace app {

	//-----------------------------------------------------------------//
	/*!
		@brief  初期化
	*/
	//-----------------------------------------------------------------//
	void bmc_main::initialize()
	{
		gl::core& core = gl::core::get_instance();

		using namespace gui;
		widget_director& wd = director_.at().widget_director_;

		{ // 画像ファイル表示用フレーム
			widget::param wp(vtx::irect(30, 30, 256, 256));
			widget_frame::param wp_;
			wp_.plate_param_.set_caption(30);
			wp_.text_param_.set_text("元画像");
			src_frame_ = wd.add_widget<widget_frame>(wp, wp_);
		}
		{ // 画像ファイル表示イメージ
			widget::param wp(vtx::irect(0, 0, 256, 256), src_frame_);
			widget_image::param wp_;
			wp_.linear_ = false;
			src_image_ = wd.add_widget<widget_image>(wp, wp_);
			src_image_->set_state(widget::state::CLIP_PARENTS);
			src_image_->set_state(widget::state::RESIZE_ROOT);
			src_image_->set_state(widget::state::MOVE_ROOT, false);
		}

		{ // 画像ファイル表示用フレーム
			widget::param wp(vtx::irect(60, 60, 256, 256));
			widget_frame::param wp_;
			wp_.plate_param_.set_caption(30);
			wp_.text_param_.set_text("変換後");
			dst_frame_ = wd.add_widget<widget_frame>(wp, wp_);
		}
		{ // 画像ファイル表示イメージ
			widget::param wp(vtx::irect(0, 0, 256, 256), dst_frame_);
			widget_image::param wp_;
			wp_.linear_ = false;
			dst_image_ = wd.add_widget<widget_image>(wp, wp_);
			dst_image_->set_state(widget::state::CLIP_PARENTS);
			dst_image_->set_state(widget::state::RESIZE_ROOT);
			dst_image_->set_state(widget::state::MOVE_ROOT, false);
		}

		{ // 機能ツールパレット
			widget::param wp(vtx::irect(10, 10, 150, 300));
			widget_frame::param wp_;
			tools_ = wd.add_widget<widget_frame>(wp, wp_);
		}
		{ // スケール
			widget::param wp(vtx::irect(10, 10, 130, 40), tools_);
			widget_check::param wp_("scale");
			scale_ = wd.add_widget<widget_check>(wp, wp_);
		}
		{ // BDF page list
			widget::param wp(vtx::irect(10, 60, 100, 40), tools_);
			widget_list::param wp_("0");
			const bmc_core& bmc = *director_.at().bmc_;
			for(uint32_t i = 0; i < bmc.get_bdf_pages(); ++i) {
				std::string s = boost::lexical_cast<std::string>(i);
				wp_.init_list_.push_back(s);
			}
			bdf_page_no_ = 0;
			bdf_page_ = wd.add_widget<widget_list>(wp, wp_);
		}
		{ // ファイラー起動ボタン
//			widget::param wp(vtx::irect(5, 5, 100, 40), tools_);
//			widget_button::param wp_("file");
//			open_ = wd.add_widget<widget_button>(wp, wp_);
		}

		{ // ファイラー本体
			widget::param wp(vtx::irect(10, 30, 300, 200));
			widget_filer::param wp_(core.get_current_path());
			filer_ = wd.add_widget<widget_filer>(wp, wp_);
			filer_->enable(false);
		}
		{ // ダイアログ
			widget::param wp(vtx::irect(10, 30, 450, 200));
			widget_dialog::param wp_;
			dialog_ = wd.add_widget<widget_dialog>(wp, wp_);
			dialog_->enable(false);
		}

		mobj_.initialize();

		// プリファレンスの取得
		sys::preference& pre = director_.at().preference_;
		if(filer_) {
			filer_->load(pre);
			src_frame_->load(pre);
			dst_frame_->load(pre);
			tools_->load(pre);
		}

		// コアの画像を表示
		if(director_.at().bmc_) {
			bmc_core& bmc = *director_.at().bmc_;
			if(!bmc.get_src_image().empty()) {
				src_handle_ = mobj_.install(&bmc.get_src_image());
				src_image_->at_local_param().mobj_ = mobj_;
				src_image_->at_local_param().mobj_handle_ = src_handle_;
			}
			if(!bmc.get_dst_image().empty()) {
				dst_handle_ = mobj_.install(&bmc.get_dst_image());
				dst_image_->at_local_param().mobj_ = mobj_;
				dst_image_->at_local_param().mobj_handle_ = dst_handle_;
			}
		}
	}

	//-----------------------------------------------------------------//
	/*!
		@brief  アップデート
	*/
	//-----------------------------------------------------------------//
	void bmc_main::update()
	{
///		gl::core& core = gl::core::get_instance();
///		const vtx::spos& vsz = core.get_size();

		gui::widget_director& wd = director_.at().widget_director_;

		wd.update();

#if 0
		if(open_) {
			if(open_->get_selected()) {
				if(filer_) {
					bool f = filer_->get_state(gui::widget::state::ENABLE);
					filer_->enable(!f);
				}
			}
		}

		if(filer_) {
			if(filer_id_ != filer_->get_select_file_id()) {
				filer_id_ = filer_->get_select_file_id();
///				std::cout << "Filer: '" << filer_->get_file() << "'" << std::endl;

				img::img_files& imf = wd.at_img_files();
				if(!imf.load(filer_->get_file())) {
					dialog_->set_text("Can't decode image file:\n '"
						+ filer_->get_file() + "'");
					dialog_->enable();
				} else {
//					mobj_.destroy();
//					mobj_.initialize();
//					img_handle_ = mobj_.install(imf.get_image_if());
//					image_->at_local_param().mobj_ = mobj_;
//					image_->at_local_param().mobj_handle_ = img_handle_;
///					imf.set_image_if(imf.get_image_if());
///					imf.save("test.tga", "rle");
				}
			}
		}
#endif

		// frame 内 image のサイズを設定
		if(src_frame_ && src_image_) {
			float s = 1.0f;
			if(scale_->get_check()) {
				vtx::fpos is = mobj_.get_size(src_handle_);
				vtx::fpos ss = src_image_->at_rect().size;
				vtx::fpos sc = ss / is;
				if(sc.x < sc.y) s = sc.x; else s = sc.y;
			}
			src_image_->at_local_param().scale_ = s;

			if(wd.get_top_widget() == src_frame_ || wd.get_top_widget() == src_image_) {
				if(src_image_->get_select_in()) {
					src_image_offset_ = src_image_->get_local_param().offset_;
				}
				if(src_image_->get_select()) {
					vtx::spos d = src_image_->get_param().move_pos_ - src_image_->get_param().move_org_;
					src_image_->at_local_param().offset_ = src_image_offset_ + d / s;
				}
			}
		}

		// BDF ファイルの複数ページ対応
		bmc_core& bmc = *director_.at().bmc_;
		if(bmc.get_bdf_pages()) {
//			if(bdf_page_->get_local_param().select_pos_ != bdf_page_no_) {
			if(bdf_page_->get_select_pos() != bdf_page_no_) {
				bdf_page_no_ = bdf_page_->get_select_pos();
				bmc.create_bdf_image(bdf_page_no_);
				mobj_.destroy();
				mobj_.initialize();
				dst_handle_ = mobj_.install(&bmc.get_dst_image());
				dst_image_->at_local_param().mobj_ = mobj_;
				dst_image_->at_local_param().mobj_handle_ = dst_handle_;
			}
		}

		if(dst_frame_ && dst_image_) {
			float s = 1.0f;
			if(scale_->get_check()) {
				vtx::fpos is = mobj_.get_size(dst_handle_);
				vtx::fpos ss = dst_image_->at_rect().size;
				vtx::fpos sc = ss / is;
				if(sc.x < sc.y) s = sc.x; else s = sc.y;
			}
			dst_image_->at_local_param().scale_ = s;

			if(wd.get_top_widget() == dst_frame_ || wd.get_top_widget() == dst_image_) {
				if(dst_image_->get_select_in()) {
					dst_image_offset_ = dst_image_->get_local_param().offset_;
				}
				if(dst_image_->get_select()) {
					vtx::spos d = dst_image_->get_param().move_pos_ - dst_image_->get_param().move_org_;
					dst_image_->at_local_param().offset_ = dst_image_offset_ + d / s;
				}
			}
		}

	}

	//-----------------------------------------------------------------//
	/*!
		@brief  レンダリング
	*/
	//-----------------------------------------------------------------//
	void bmc_main::render()
	{
		director_.at().widget_director_.service();
		director_.at().widget_director_.render();
	}

	//-----------------------------------------------------------------//
	/*!
		@brief  廃棄
	*/
	//-----------------------------------------------------------------//
	void bmc_main::destroy()
	{
		sys::preference& pre = director_.at().preference_;
		if(filer_) {
			filer_->save(pre);
			src_frame_->save(pre);
			dst_frame_->save(pre);
			tools_->save(pre);
		}
	}
}
<|endoftext|>