<commit_before>#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE compile_function
#include <boost/test/unit_test.hpp>

#include "../src/compile_function.hpp"
#include "../src/core_unique_ids.hpp"
#include "../src/error/compile_exception.hpp"

#include "state_utils.hpp"
#include "function_building.hpp"

#include <llvm/IR/Function.h>
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/Value.h>

#include <unordered_map>
#include <utility>
#include <iterator>
#include <string>
#include <csetjmp>

using std::pair;
using std::unique_ptr;
using std::unordered_map;
using std::advance;
using std::string;

using llvm::Function;
using llvm::Value;
using llvm::IntegerType;
using llvm::Type;
using llvm::verifyFunction;
using llvm::raw_string_ostream;

using boost::get;

using namespace symbol_shortcuts;

BOOST_AUTO_TEST_CASE(compile_signature_test)
{
    const any_symbol params1 = list
    {
        list{a, int64_type},
        list{b, int64_type},
        list{c, int64_type},
    };
    const any_symbol return_type1 = int64_type;

    unique_ptr<Function> function1;
    unordered_map<identifier_id_t, named_value_info> parameter_table1;
    tie(function1, parameter_table1) = compile_signature(params1, return_type1, context);

    BOOST_CHECK(function1 != nullptr);
    BOOST_CHECK_EQUAL(parameter_table1.size(), 3);
    BOOST_CHECK(parameter_table1.count(a.identifier()));
    BOOST_CHECK(parameter_table1.count(b.identifier()));
    BOOST_CHECK(parameter_table1.count(c.identifier()));
    BOOST_CHECK(parameter_table1.at(b.identifier()).llvm_value == (++function1->arg_begin()));

    const any_symbol params2 = list
    {
        list{a, int64_type},
        list{b, int64_type},
        list{a, int64_type}, // duplicate parameter name
    };
    const any_symbol return_type2 = int64_type;

    BOOST_CHECK_THROW(compile_signature(params2, return_type2, context), compile_exception);
}

BOOST_AUTO_TEST_CASE(compile_instruction_test)
{
    Type* llvm_int64 = IntegerType::get(context.llvm(), 64);

    const id_symbol add_constructor{unique_ids::ADD};
    const list_symbol instruction1{add_constructor, int64_type};
    const instruction_info got1 = parse_instruction(instruction1, context.llvm());
    BOOST_CHECK(get<instruction_info::add>(got1.kind).type.llvm_type == llvm_int64);

    const id_symbol div_constructor{unique_ids::DIV};
    const list_symbol instruction2{div_constructor, int64_type};
    const instruction_info got2 = parse_instruction(instruction2, context.llvm());
    BOOST_CHECK(get<instruction_info::div>(got2.kind).type.llvm_type == llvm_int64);

    const id_symbol cmp_constructor{unique_ids::CMP};
    const ref_symbol cmp_ref{"asdfasdf"_id, &cmp_constructor};
    const id_symbol lt{unique_ids::LT};
    const list_symbol instruction3{cmp_ref, lt, int64_type};
    const instruction_info got3 = parse_instruction(instruction3, context.llvm());
    BOOST_CHECK(get<instruction_info::cmp>(got3.kind).cmp_kind == unique_ids::LT);
    BOOST_CHECK(get<instruction_info::cmp>(got3.kind).type.llvm_type == llvm_int64);
}

BOOST_AUTO_TEST_CASE(store_load_test)
{
    const list_symbol params =
    {
        list{a, int64_type}
    };
    const symbol& return_type = int64_type;
    const list_symbol body =
    {
        list{block1, list
        {
            list{let, x, alloc_int64},
            list{store_int64, a, x},
            list{let, y, load_int64, x},
            list{return_int64, y}
        }}
    };

    const list_symbol function_source =
    {
        params,
        return_type,
        body
    };

    auto function_ptr = get_compiled_function<uint64_t (uint64_t)>(function_source);
    BOOST_CHECK(function_ptr(2) == 2);
    BOOST_CHECK(function_ptr(1231) == 1231);
}

BOOST_AUTO_TEST_CASE(branch_test)
{
    const list_symbol params =
    {
        list{a, int64_type},
        list{b, int64_type},
    };

    const symbol& return_type = int64_type;

    const list_symbol body =
    {
        list{block1, list
        {
            list{let, x, cmp_eq_int64, a, b},
            list{cond_branch, x, block2, block3}
        }},
        list{block2, list
        {
            list{let, y, add_int64, a, b},
            list{return_int64, y}
        }},
        list{block3, list
        {
            list{let, z, sub_int64, a, b},
            list{return_int64, z}
        }}
    };
    const list_symbol func_source =
    {
        params,
        return_type,
        body
    };

    auto compiled_function = get_compiled_function<uint64_t (uint64_t, uint64_t)>(func_source);
    BOOST_CHECK(compiled_function);
    BOOST_CHECK_EQUAL(compiled_function(2, 2), 2 + 2);
    BOOST_CHECK_EQUAL(compiled_function(5, 3), 5 - 3);
}

BOOST_AUTO_TEST_CASE(phi_test)
{
    const list_symbol params =
    {
        list{a, int64_type},
        list{b, int64_type},
    };

    const symbol& return_type = int64_type;

    const list_symbol block1_def = {block1, list
    {
        list{let, x, cmp_eq_int64, a, b},
        list{cond_branch, x, block2, block3}
    }};
    const list_symbol block2_def = list{block2, list
    {
        list{let, y, add_int64, a, b},
        list{branch, block4}
    }};
    const list_symbol block3_def = {block3, list
    {
        list{let, z, sub_int64, a, b},
        list{branch, block4}
    }};
    const list_symbol block4_def = {block4, list
    {
        list{let, w, phi_int64, list{y, block2}, list{z, block3}},
        list{return_int64, w}
    }};

    const list_symbol func1_source =
    {
        params,
        return_type,
        list
        {
            block1_def,
            block2_def,
            block3_def,
            block4_def
        }
    };

    auto compiled_function1 = get_compiled_function<uint64_t (uint64_t, uint64_t)>(func1_source);
    BOOST_CHECK(compiled_function1);
    BOOST_CHECK_EQUAL(compiled_function1(2, 2), 2 + 2);
    BOOST_CHECK_EQUAL(compiled_function1(5, 3), 5 - 3);

    const list_symbol block4_invalid_def = {block4, list
    {
        list{let, w, phi_int64, list{z, block3}}, // missing incoming for block2
        list{return_int64, w}
    }};

    const list_symbol func2_source =
    {
        params,
        return_type,
        list
        {
            block1_def,
            block2_def,
            block3_def,
            block4_invalid_def
        }
    };
    BOOST_CHECK_THROW(compile_function(func2_source.begin(), func2_source.end(), context), compile_exception);

}

BOOST_AUTO_TEST_CASE(a_times_b_test)
{
    const ref result_loc{"result_loc"_id};
    const ref i_loc{"i_loc"_id};
    const ref init_cmp{"init_cmp"_id};
    const ref current_sum{"current_sum"_id};
    const ref next_sum{"next_sum"_id};
    const ref current_i{"current_i"_id};
    const ref next_i{"next_i"_id};
    const ref loop_cmp{"loop_cmp"_id};
    const ref result{"result"_id};

    const list params =
    {
        list{a, int64_type},
        list{b, int64_type}
    };
    const symbol& return_type = int64_type;
    const list_symbol body =
    {
        list{block1, list
        {
            list{let, result_loc, alloc_int64},
            list{store_int64, lit{"0"}, result_loc}, // v speichert die Zwischenergebnisse und schließlich das Endergebnis der Add.
            list{let, i_loc, alloc_int64},
            list{store_int64, lit{"0"}, i_loc}, // w ist ein Zähler, der zählt, wie oft die erste Eingabe addiert werden muss
            list{let, init_cmp, cmp_ne_int64, b, lit{"0"}}, // x = 1, falls b != 0, sonst: x = 0
            list{cond_branch, init_cmp, block2, block3}

        }},
        list{block2, list
        {
		    list{let, current_sum, load_int64, result_loc}, // y = die aktuelle Summe
		    list{let, next_sum, add_int64, current_sum, a}, //z ist die neue Summe, nach Addition mit a
		    list{store_int64, next_sum, result_loc},
		    list{let, current_i, load_int64, i_loc}, // der Zähler wird aus dem letzten Block geladen, current_i genannt
		    list{let, next_i, add_int64, current_i, lit{"1"}},
		    list{store_int64, next_i, i_loc},
		    list{let, loop_cmp, cmp_ne_int64, b, next_i},
		    list{cond_branch, loop_cmp, block2, block3}
        }},
        list{block3, list
        {
            list{let, result, load_int64, result_loc},
            list{return_int64, result}
        }}
    };

    const list_symbol function_source =
    {
        params,
        return_type,
        body
    };

    auto function_ptr = get_compiled_function<uint64_t (uint64_t, uint64_t)>(function_source);
    BOOST_CHECK(function_ptr(2, 3) == 6);
    BOOST_CHECK(function_ptr(0, 20) == 0);
    BOOST_CHECK(function_ptr(33, 0) == 0);
    BOOST_CHECK(function_ptr(0, 0) == 0);
}

BOOST_AUTO_TEST_CASE(test_missing_let)
{
    const list params =
    {
        list{a, int64_type},
        list{b, int64_type}
    };
    const symbol& return_type = int64_type;
    const list_symbol body =
    {
        list{block1, list
        {
            list{x, add_int64, a, b}
        }}
    };

    const list_symbol function_source =
    {
        params,
        return_type,
        body
    };
    BOOST_CHECK_THROW(get_compiled_function<void (uint64_t, uint64_t)>(function_source), compile_exception);
}

<commit_msg>fix broken test<commit_after>#define BOOST_TEST_DYN_LINK
#define BOOST_TEST_MODULE compile_function
#include <boost/test/unit_test.hpp>

#include "../src/compile_function.hpp"
#include "../src/core_unique_ids.hpp"
#include "../src/error/compile_exception.hpp"

#include "state_utils.hpp"
#include "function_building.hpp"

#include <llvm/IR/Function.h>
#include <llvm/IR/DerivedTypes.h>
#include <llvm/IR/Value.h>

#include <unordered_map>
#include <utility>
#include <iterator>
#include <string>
#include <csetjmp>

using std::pair;
using std::unique_ptr;
using std::unordered_map;
using std::advance;
using std::string;

using llvm::Function;
using llvm::Value;
using llvm::IntegerType;
using llvm::Type;
using llvm::verifyFunction;
using llvm::raw_string_ostream;

using boost::get;

using namespace symbol_shortcuts;

BOOST_AUTO_TEST_CASE(compile_signature_test)
{
    const any_symbol params1 = list
    {
        list{a, int64_type},
        list{b, int64_type},
        list{c, int64_type},
    };
    const any_symbol return_type1 = int64_type;

    unique_ptr<Function> function1;
    unordered_map<identifier_id_t, named_value_info> parameter_table1;
    tie(function1, parameter_table1) = compile_signature(params1, return_type1, context);

    BOOST_CHECK(function1 != nullptr);
    BOOST_CHECK_EQUAL(parameter_table1.size(), 3);
    BOOST_CHECK(parameter_table1.count(a.identifier()));
    BOOST_CHECK(parameter_table1.count(b.identifier()));
    BOOST_CHECK(parameter_table1.count(c.identifier()));
    BOOST_CHECK(parameter_table1.at(b.identifier()).llvm_value == (++function1->arg_begin()));

    const any_symbol params2 = list
    {
        list{a, int64_type},
        list{b, int64_type},
        list{a, int64_type}, // duplicate parameter name
    };
    const any_symbol return_type2 = int64_type;

    BOOST_CHECK_THROW(compile_signature(params2, return_type2, context), compile_exception);
}

BOOST_AUTO_TEST_CASE(compile_instruction_test)
{
    Type* llvm_int64 = IntegerType::get(context.llvm(), 64);

    const id_symbol add_constructor{unique_ids::ADD};
    const list_symbol instruction1{add_constructor, int64_type};
    const instruction_info got1 = parse_instruction(instruction1, context.llvm());
    BOOST_CHECK(get<instruction_info::add>(got1.kind).type.llvm_type == llvm_int64);

    const id_symbol div_constructor{unique_ids::DIV};
    const list_symbol instruction2{div_constructor, int64_type};
    const instruction_info got2 = parse_instruction(instruction2, context.llvm());
    BOOST_CHECK(get<instruction_info::div>(got2.kind).type.llvm_type == llvm_int64);

    const id_symbol cmp_constructor{unique_ids::CMP};
    const ref_symbol cmp_ref{"asdfasdf"_id, &cmp_constructor};
    const id_symbol lt{unique_ids::LT};
    const list_symbol instruction3{cmp_ref, lt, int64_type};
    const instruction_info got3 = parse_instruction(instruction3, context.llvm());
    BOOST_CHECK(get<instruction_info::cmp>(got3.kind).cmp_kind == unique_ids::LT);
    BOOST_CHECK(get<instruction_info::cmp>(got3.kind).type.llvm_type == llvm_int64);
}

BOOST_AUTO_TEST_CASE(store_load_test)
{
    const list_symbol params =
    {
        list{a, int64_type}
    };
    const symbol& return_type = int64_type;
    const list_symbol body =
    {
        list{block1, list
        {
            list{let, x, alloc_int64},
            list{store_int64, a, x},
            list{let, y, load_int64, x},
            list{return_int64, y}
        }}
    };

    const list_symbol function_source =
    {
        params,
        return_type,
        body
    };

    auto function_ptr = get_compiled_function<uint64_t (uint64_t)>(function_source);
    BOOST_CHECK(function_ptr(2) == 2);
    BOOST_CHECK(function_ptr(1231) == 1231);
}

BOOST_AUTO_TEST_CASE(branch_test)
{
    const list_symbol params =
    {
        list{a, int64_type},
        list{b, int64_type},
    };

    const symbol& return_type = int64_type;

    const list_symbol body =
    {
        list{block1, list
        {
            list{let, x, cmp_eq_int64, a, b},
            list{cond_branch, x, block2, block3}
        }},
        list{block2, list
        {
            list{let, y, add_int64, a, b},
            list{return_int64, y}
        }},
        list{block3, list
        {
            list{let, z, sub_int64, a, b},
            list{return_int64, z}
        }}
    };
    const list_symbol func_source =
    {
        params,
        return_type,
        body
    };

    auto compiled_function = get_compiled_function<uint64_t (uint64_t, uint64_t)>(func_source);
    BOOST_CHECK(compiled_function);
    BOOST_CHECK_EQUAL(compiled_function(2, 2), 2 + 2);
    BOOST_CHECK_EQUAL(compiled_function(5, 3), 5 - 3);
}

BOOST_AUTO_TEST_CASE(phi_test)
{
    const list_symbol params =
    {
        list{a, int64_type},
        list{b, int64_type},
    };

    const symbol& return_type = int64_type;

    const list_symbol block1_def = {block1, list
    {
        list{let, x, cmp_eq_int64, a, b},
        list{cond_branch, x, block2, block3}
    }};
    const list_symbol block2_def = list{block2, list
    {
        list{let, y, add_int64, a, b},
        list{branch, block4}
    }};
    const list_symbol block3_def = {block3, list
    {
        list{let, z, sub_int64, a, b},
        list{branch, block4}
    }};
    const list_symbol block4_def = {block4, list
    {
        list{let, w, phi_int64, list{y, block2}, list{z, block3}},
        list{return_int64, w}
    }};

    const list_symbol func1_source =
    {
        params,
        return_type,
        list
        {
            block1_def,
            block2_def,
            block3_def,
            block4_def
        }
    };

    auto compiled_function1 = get_compiled_function<uint64_t (uint64_t, uint64_t)>(func1_source);
    BOOST_CHECK(compiled_function1);
    BOOST_CHECK_EQUAL(compiled_function1(2, 2), 2 + 2);
    BOOST_CHECK_EQUAL(compiled_function1(5, 3), 5 - 3);

    const list_symbol block4_invalid_def = {block4, list
    {
        list{let, w, phi_int64, list{z, block3}}, // missing incoming for block2
        list{return_int64, w}
    }};

    const list_symbol func2_source =
    {
        params,
        return_type,
        list
        {
            block1_def,
            block2_def,
            block3_def,
            block4_invalid_def
        }
    };
    BOOST_CHECK_THROW(compile_function(func2_source.begin(), func2_source.end(), context), compile_exception);

}

BOOST_AUTO_TEST_CASE(a_times_b_test)
{
    const ref result_loc{"result_loc"_id};
    const ref i_loc{"i_loc"_id};
    const ref init_cmp{"init_cmp"_id};
    const ref current_sum{"current_sum"_id};
    const ref next_sum{"next_sum"_id};
    const ref current_i{"current_i"_id};
    const ref next_i{"next_i"_id};
    const ref loop_cmp{"loop_cmp"_id};
    const ref result{"result"_id};

    const list params =
    {
        list{a, int64_type},
        list{b, int64_type}
    };
    const symbol& return_type = int64_type;
    const list_symbol body =
    {
        list{block1, list
        {
            list{let, result_loc, alloc_int64},
            list{store_int64, lit{"0"}, result_loc}, // v speichert die Zwischenergebnisse und schließlich das Endergebnis der Add.
            list{let, i_loc, alloc_int64},
            list{store_int64, lit{"0"}, i_loc}, // w ist ein Zähler, der zählt, wie oft die erste Eingabe addiert werden muss
            list{let, init_cmp, cmp_ne_int64, b, lit{"0"}}, // x = 1, falls b != 0, sonst: x = 0
            list{cond_branch, init_cmp, block2, block3}

        }},
        list{block2, list
        {
		    list{let, current_sum, load_int64, result_loc}, // y = die aktuelle Summe
		    list{let, next_sum, add_int64, current_sum, a}, //z ist die neue Summe, nach Addition mit a
		    list{store_int64, next_sum, result_loc},
		    list{let, current_i, load_int64, i_loc}, // der Zähler wird aus dem letzten Block geladen, current_i genannt
		    list{let, next_i, add_int64, current_i, lit{"1"}},
		    list{store_int64, next_i, i_loc},
		    list{let, loop_cmp, cmp_ne_int64, b, next_i},
		    list{cond_branch, loop_cmp, block2, block3}
        }},
        list{block3, list
        {
            list{let, result, load_int64, result_loc},
            list{return_int64, result}
        }}
    };

    const list_symbol function_source =
    {
        params,
        return_type,
        body
    };

    auto function_ptr = get_compiled_function<uint64_t (uint64_t, uint64_t)>(function_source);
    BOOST_CHECK(function_ptr(2, 3) == 6);
    BOOST_CHECK(function_ptr(0, 20) == 0);
    BOOST_CHECK(function_ptr(33, 0) == 0);
    BOOST_CHECK(function_ptr(0, 0) == 0);
}

BOOST_AUTO_TEST_CASE(missing_let_test)
{
    const list params =
    {
        list{a, int64_type},
        list{b, int64_type}
    };
    const symbol& return_type = int64_type;
    const list_symbol body =
    {
        list{block1, list
        {
            list{x, add_int64, a, b}
        }}
    };

    const list_symbol function_source =
    {
        params,
        return_type,
        body
    };
    BOOST_CHECK_THROW(compile_function(function_source.begin(), function_source.end(), context), compile_exception);
}

<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include <private/qobject_p.h>
#include <qml.h>
#include <QtDeclarative/qmlcontext.h>
#include <QtDeclarative/qmlexpression.h>
#include "qmlstateoperations.h"
#include <QtCore/qdebug.h>
#include <QtDeclarative/qmlinfo.h>

QT_BEGIN_NAMESPACE

class QmlParentChangePrivate : public QObjectPrivate
{
public:
    QmlParentChangePrivate() : target(0), parent(0), origParent(0) {}

    QFxItem *target;
    QFxItem *parent;
    QFxItem *origParent;

    void doChange(QFxItem *targetParent);
};

void QmlParentChangePrivate::doChange(QFxItem *targetParent)
{
    if (targetParent && target && target->itemParent()) {
        QPointF me = target->itemParent()->mapToScene(QPointF(0,0));
        QPointF them = targetParent->mapToScene(QPointF(0,0));

        QPointF themx = targetParent->mapToScene(QPointF(1,0));
        QPointF themy = targetParent->mapToScene(QPointF(0,1));

        themx -= them;
        themy -= them;

        target->setItemParent(targetParent);

        // XXX - this is silly and will only work in a few cases

        /*
            xDiff = rx * themx_x + ry * themy_x
            yDiff = rx * themx_y + ry * themy_y
         */

        qreal rx = 0;
        qreal ry = 0;
        qreal xDiff = them.x() - me.x();
        qreal yDiff = them.y() - me.y();

        if (themx.x() == 0.) {
            ry = xDiff / themy.x();
            rx = (yDiff - ry * themy.y()) / themx.y();
        } else if (themy.x() == 0.) {
            rx = xDiff / themx.x();
            ry = (yDiff - rx * themx.y()) / themy.y();
        } else if (themx.y() == 0.) {
            ry = yDiff / themy.y();
            rx = (xDiff - ry * themy.x()) / themx.x();
        } else if (themy.y() == 0.) {
            rx = yDiff / themx.y();
            ry = (xDiff - rx * themx.x()) / themy.x();
        } else {
            qreal div = (themy.x() * themx.y() - themy.y() * themx.x());

            if (div != 0.)
                rx = (themx.y() * xDiff - themx.x() * yDiff) / div;

           if (themy.y() != 0.) ry = (yDiff - rx * themx.y()) / themy.y();
        }

        target->setX(target->x() - rx);
        target->setY(target->y() - ry);
    } else if (target) {
        target->setItemParent(targetParent);
    }
}

/*!
    \preliminary
    \qmlclass ParentChange
    \brief The ParentChange element allows you to reparent an object in a state.
*/

QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,ParentChange,QmlParentChange)
QmlParentChange::QmlParentChange(QObject *parent)
    : QmlStateOperation(*(new QmlParentChangePrivate), parent)
{
}

QmlParentChange::~QmlParentChange()
{
}

/*!
    \qmlproperty Object ParentChange::target
    This property holds the item to be reparented
*/

QFxItem *QmlParentChange::object() const
{
    Q_D(const QmlParentChange);
    return d->target;
}

void QmlParentChange::setObject(QFxItem *target)
{
    Q_D(QmlParentChange);
    d->target = target;
}

/*!
    \qmlproperty Item ParentChange::parent
    This property holds the parent for the item in this state
*/

QFxItem *QmlParentChange::parent() const
{
    Q_D(const QmlParentChange);
    return d->parent;
}

void QmlParentChange::setParent(QFxItem *parent)
{
    Q_D(QmlParentChange);
    d->parent = parent;
}

QmlStateOperation::ActionList QmlParentChange::actions()
{
    Q_D(QmlParentChange);
    if (!d->target || !d->parent)
        return ActionList();

    Action a;
    a.event = this;

    return ActionList() << a;
}

void QmlParentChange::execute()
{
    Q_D(QmlParentChange);
    if (d->target)
        d->origParent = d->target->itemParent();
    d->doChange(d->parent);
}

bool QmlParentChange::isReversable()
{
    return true;
}

void QmlParentChange::reverse()
{
    Q_D(QmlParentChange);
    d->doChange(d->origParent);
}

QString QmlParentChange::typeName() const
{
    return QLatin1String("ParentChange");
}

class QmlRunScriptPrivate : public QObjectPrivate
{
public:
    QmlRunScriptPrivate() {}

    QString script;
    QString name;
};

/*!
    \qmlclass RunScript QmlRunScript
    \brief The RunScript element allows you to run a script in a state.
*/
QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,RunScript,QmlRunScript)
QmlRunScript::QmlRunScript(QObject *parent)
: QmlStateOperation(*(new QmlRunScriptPrivate), parent)
{
}

QmlRunScript::~QmlRunScript()
{
}

/*!
    \qmlproperty string RunScript::script
    This property holds the script to run when the state is current.
*/
QString QmlRunScript::script() const
{
    Q_D(const QmlRunScript);
    return d->script;
}

void QmlRunScript::setScript(const QString &s)
{
    Q_D(QmlRunScript);
    d->script = s;
}

QString QmlRunScript::name() const
{
    Q_D(const QmlRunScript);
    return d->name;
}

void QmlRunScript::setName(const QString &n)
{
    Q_D(QmlRunScript);
    d->name = n;
}

void QmlRunScript::execute()
{
    Q_D(QmlRunScript);
    if (!d->script.isEmpty()) {
        QmlExpression expr(qmlContext(this), d->script, this);
        expr.setTrackChange(false);
        expr.value();
    }
}

QmlRunScript::ActionList QmlRunScript::actions()
{
    ActionList rv;
    Action a;
    a.event = this;
    rv << a;
    return rv;
}

/*!
    \qmlclass SetAnchors
    \brief The SetAnchors element allows you to change anchors in a state.
*/

QML_DEFINE_TYPE(QmlSetAnchors,SetAnchors)

class QmlSetAnchorsPrivate : public QObjectPrivate
{
public:
    QmlSetAnchorsPrivate() : target(0) {}

    QString name;
    QFxItem *target;
    QString resetString;
    QStringList resetList;
    QFxAnchorLine left;
    QFxAnchorLine right;
    QFxAnchorLine top;
    QFxAnchorLine bottom;
    QFxAnchorLine origLeft;
    QFxAnchorLine origRight;
    QFxAnchorLine origTop;
    QFxAnchorLine origBottom;
    qreal origX;
    qreal origY;
    qreal origWidth;
    qreal origHeight;
};

QmlSetAnchors::QmlSetAnchors(QObject *parent)
 : QmlStateOperation(*(new QmlSetAnchorsPrivate), parent)
{
}

QmlSetAnchors::~QmlSetAnchors()
{
}

QmlSetAnchors::ActionList QmlSetAnchors::actions()
{
    Action a;
    a.event = this;
    return ActionList() << a;
}

QFxItem *QmlSetAnchors::object() const
{
    Q_D(const QmlSetAnchors);
    return d->target;
}

void QmlSetAnchors::setObject(QFxItem *target)
{
    Q_D(QmlSetAnchors);
    d->target = target;
}

QString QmlSetAnchors::reset() const
{
    Q_D(const QmlSetAnchors);
    return d->resetString;
}

void QmlSetAnchors::setReset(const QString &reset)
{
    Q_D(QmlSetAnchors);
    d->resetString = reset;
    d->resetList = d->resetString.split(QLatin1Char(','));
}

QFxAnchorLine QmlSetAnchors::left() const
{
    Q_D(const QmlSetAnchors);
    return d->left;
}

void QmlSetAnchors::setLeft(const QFxAnchorLine &edge)
{
    Q_D(QmlSetAnchors);
    d->left = edge;
}

QFxAnchorLine QmlSetAnchors::right() const
{
    Q_D(const QmlSetAnchors);
    return d->right;
}

void QmlSetAnchors::setRight(const QFxAnchorLine &edge)
{
    Q_D(QmlSetAnchors);
    d->right = edge;
}

QFxAnchorLine QmlSetAnchors::top() const
{
    Q_D(const QmlSetAnchors);
    return d->top;
}

void QmlSetAnchors::setTop(const QFxAnchorLine &edge)
{
    Q_D(QmlSetAnchors);
    d->top = edge;
}

QFxAnchorLine QmlSetAnchors::bottom() const
{
    Q_D(const QmlSetAnchors);
    return d->bottom;
}

void QmlSetAnchors::setBottom(const QFxAnchorLine &edge)
{
    Q_D(QmlSetAnchors);
    d->bottom = edge;
}

void QmlSetAnchors::execute()
{
    Q_D(QmlSetAnchors);
    if (!d->target)
        return;

    //set any anchors that have been specified
    if (d->left.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->setLeft(d->left);
    if (d->right.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->setRight(d->right);
    if (d->top.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->setTop(d->top);
    if (d->bottom.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->setBottom(d->bottom);
}

bool QmlSetAnchors::isReversable()
{
    return true;
}

void QmlSetAnchors::reverse()
{
    Q_D(QmlSetAnchors);
    if (!d->target)
        return;

    //restore previous anchors
    if (d->origLeft.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->setLeft(d->origLeft);
    if (d->origRight.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->setRight(d->origRight);
    if (d->origTop.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->setTop(d->origTop);
    if (d->origBottom.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->setBottom(d->origBottom);

}

QString QmlSetAnchors::typeName() const
{
    return QLatin1String("SetAnchors");
}

QList<Action> QmlSetAnchors::extraActions()
{
    Q_D(QmlSetAnchors);
    QList<Action> extra;

    //### try to be smarter about which ones we add.
    //    or short-circuit later on if they haven't actually changed.
    //    we shouldn't set explicit width if there wasn't one before.
    if (d->target) {
        Action a;
        a.fromValue = d->origX;
        a.property = QmlMetaProperty(d->target, "x");
        extra << a;

        a.fromValue = d->origY;
        a.property = QmlMetaProperty(d->target, "y");
        extra << a;

        a.fromValue = d->origWidth;
        a.property = QmlMetaProperty(d->target, "width");
        extra << a;

        a.fromValue = d->origHeight;
        a.property = QmlMetaProperty(d->target, "height");
        extra << a;
    }

    return extra;
}

bool QmlSetAnchors::changesBindings()
{
    return true;
}

void QmlSetAnchors::clearForwardBindings()
{
    Q_D(QmlSetAnchors);
    d->origLeft = d->target->anchors()->left();
    d->origRight = d->target->anchors()->right();
    d->origTop = d->target->anchors()->top();
    d->origBottom = d->target->anchors()->bottom();
    d->origX = d->target->x();
    d->origY = d->target->y();
    d->origWidth = d->target->width();
    d->origHeight = d->target->height();

    //reset any anchors that have been specified
    if (d->resetList.contains(QLatin1String("left")))
        d->target->anchors()->resetLeft();
    if (d->resetList.contains(QLatin1String("right")))
        d->target->anchors()->resetRight();
    if (d->resetList.contains(QLatin1String("top")))
        d->target->anchors()->resetTop();
    if (d->resetList.contains(QLatin1String("bottom")))
        d->target->anchors()->resetBottom();
}

void QmlSetAnchors::clearReverseBindings()
{
    Q_D(QmlSetAnchors);
    d->origX = d->target->x();
    d->origY = d->target->y();
    d->origWidth = d->target->width();
    d->origHeight = d->target->height();

    //reset any anchors that were set in the state
    if (d->left.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->resetLeft();
    if (d->right.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->resetRight();
    if (d->top.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->resetTop();
    if (d->bottom.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->resetBottom();
}

QT_END_NAMESPACE
<commit_msg>Compile fix after merge.<commit_after>/****************************************************************************
**
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Qt Software Information (qt-info@nokia.com)
**
** This file is part of the QtDeclarative module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the either Technology Preview License Agreement or the
** Beta Release License Agreement.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at qt-sales@nokia.com.
** $QT_END_LICENSE$
**
****************************************************************************/

#include <private/qobject_p.h>
#include <qml.h>
#include <QtDeclarative/qmlcontext.h>
#include <QtDeclarative/qmlexpression.h>
#include "qmlstateoperations.h"
#include <QtCore/qdebug.h>
#include <QtDeclarative/qmlinfo.h>

QT_BEGIN_NAMESPACE

class QmlParentChangePrivate : public QObjectPrivate
{
public:
    QmlParentChangePrivate() : target(0), parent(0), origParent(0) {}

    QFxItem *target;
    QFxItem *parent;
    QFxItem *origParent;

    void doChange(QFxItem *targetParent);
};

void QmlParentChangePrivate::doChange(QFxItem *targetParent)
{
    if (targetParent && target && target->itemParent()) {
        QPointF me = target->itemParent()->mapToScene(QPointF(0,0));
        QPointF them = targetParent->mapToScene(QPointF(0,0));

        QPointF themx = targetParent->mapToScene(QPointF(1,0));
        QPointF themy = targetParent->mapToScene(QPointF(0,1));

        themx -= them;
        themy -= them;

        target->setItemParent(targetParent);

        // XXX - this is silly and will only work in a few cases

        /*
            xDiff = rx * themx_x + ry * themy_x
            yDiff = rx * themx_y + ry * themy_y
         */

        qreal rx = 0;
        qreal ry = 0;
        qreal xDiff = them.x() - me.x();
        qreal yDiff = them.y() - me.y();

        if (themx.x() == 0.) {
            ry = xDiff / themy.x();
            rx = (yDiff - ry * themy.y()) / themx.y();
        } else if (themy.x() == 0.) {
            rx = xDiff / themx.x();
            ry = (yDiff - rx * themx.y()) / themy.y();
        } else if (themx.y() == 0.) {
            ry = yDiff / themy.y();
            rx = (xDiff - ry * themy.x()) / themx.x();
        } else if (themy.y() == 0.) {
            rx = yDiff / themx.y();
            ry = (xDiff - rx * themx.x()) / themy.x();
        } else {
            qreal div = (themy.x() * themx.y() - themy.y() * themx.x());

            if (div != 0.)
                rx = (themx.y() * xDiff - themx.x() * yDiff) / div;

           if (themy.y() != 0.) ry = (yDiff - rx * themx.y()) / themy.y();
        }

        target->setX(target->x() - rx);
        target->setY(target->y() - ry);
    } else if (target) {
        target->setItemParent(targetParent);
    }
}

/*!
    \preliminary
    \qmlclass ParentChange
    \brief The ParentChange element allows you to reparent an object in a state.
*/

QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,ParentChange,QmlParentChange)
QmlParentChange::QmlParentChange(QObject *parent)
    : QmlStateOperation(*(new QmlParentChangePrivate), parent)
{
}

QmlParentChange::~QmlParentChange()
{
}

/*!
    \qmlproperty Object ParentChange::target
    This property holds the item to be reparented
*/

QFxItem *QmlParentChange::object() const
{
    Q_D(const QmlParentChange);
    return d->target;
}

void QmlParentChange::setObject(QFxItem *target)
{
    Q_D(QmlParentChange);
    d->target = target;
}

/*!
    \qmlproperty Item ParentChange::parent
    This property holds the parent for the item in this state
*/

QFxItem *QmlParentChange::parent() const
{
    Q_D(const QmlParentChange);
    return d->parent;
}

void QmlParentChange::setParent(QFxItem *parent)
{
    Q_D(QmlParentChange);
    d->parent = parent;
}

QmlStateOperation::ActionList QmlParentChange::actions()
{
    Q_D(QmlParentChange);
    if (!d->target || !d->parent)
        return ActionList();

    Action a;
    a.event = this;

    return ActionList() << a;
}

void QmlParentChange::execute()
{
    Q_D(QmlParentChange);
    if (d->target)
        d->origParent = d->target->itemParent();
    d->doChange(d->parent);
}

bool QmlParentChange::isReversable()
{
    return true;
}

void QmlParentChange::reverse()
{
    Q_D(QmlParentChange);
    d->doChange(d->origParent);
}

QString QmlParentChange::typeName() const
{
    return QLatin1String("ParentChange");
}

class QmlRunScriptPrivate : public QObjectPrivate
{
public:
    QmlRunScriptPrivate() {}

    QString script;
    QString name;
};

/*!
    \qmlclass RunScript QmlRunScript
    \brief The RunScript element allows you to run a script in a state.
*/
QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,RunScript,QmlRunScript)
QmlRunScript::QmlRunScript(QObject *parent)
: QmlStateOperation(*(new QmlRunScriptPrivate), parent)
{
}

QmlRunScript::~QmlRunScript()
{
}

/*!
    \qmlproperty string RunScript::script
    This property holds the script to run when the state is current.
*/
QString QmlRunScript::script() const
{
    Q_D(const QmlRunScript);
    return d->script;
}

void QmlRunScript::setScript(const QString &s)
{
    Q_D(QmlRunScript);
    d->script = s;
}

QString QmlRunScript::name() const
{
    Q_D(const QmlRunScript);
    return d->name;
}

void QmlRunScript::setName(const QString &n)
{
    Q_D(QmlRunScript);
    d->name = n;
}

void QmlRunScript::execute()
{
    Q_D(QmlRunScript);
    if (!d->script.isEmpty()) {
        QmlExpression expr(qmlContext(this), d->script, this);
        expr.setTrackChange(false);
        expr.value();
    }
}

QmlRunScript::ActionList QmlRunScript::actions()
{
    ActionList rv;
    Action a;
    a.event = this;
    rv << a;
    return rv;
}

/*!
    \qmlclass SetAnchors
    \brief The SetAnchors element allows you to change anchors in a state.
*/

QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,SetAnchors,QmlSetAnchors)

class QmlSetAnchorsPrivate : public QObjectPrivate
{
public:
    QmlSetAnchorsPrivate() : target(0) {}

    QString name;
    QFxItem *target;
    QString resetString;
    QStringList resetList;
    QFxAnchorLine left;
    QFxAnchorLine right;
    QFxAnchorLine top;
    QFxAnchorLine bottom;
    QFxAnchorLine origLeft;
    QFxAnchorLine origRight;
    QFxAnchorLine origTop;
    QFxAnchorLine origBottom;
    qreal origX;
    qreal origY;
    qreal origWidth;
    qreal origHeight;
};

QmlSetAnchors::QmlSetAnchors(QObject *parent)
 : QmlStateOperation(*(new QmlSetAnchorsPrivate), parent)
{
}

QmlSetAnchors::~QmlSetAnchors()
{
}

QmlSetAnchors::ActionList QmlSetAnchors::actions()
{
    Action a;
    a.event = this;
    return ActionList() << a;
}

QFxItem *QmlSetAnchors::object() const
{
    Q_D(const QmlSetAnchors);
    return d->target;
}

void QmlSetAnchors::setObject(QFxItem *target)
{
    Q_D(QmlSetAnchors);
    d->target = target;
}

QString QmlSetAnchors::reset() const
{
    Q_D(const QmlSetAnchors);
    return d->resetString;
}

void QmlSetAnchors::setReset(const QString &reset)
{
    Q_D(QmlSetAnchors);
    d->resetString = reset;
    d->resetList = d->resetString.split(QLatin1Char(','));
}

QFxAnchorLine QmlSetAnchors::left() const
{
    Q_D(const QmlSetAnchors);
    return d->left;
}

void QmlSetAnchors::setLeft(const QFxAnchorLine &edge)
{
    Q_D(QmlSetAnchors);
    d->left = edge;
}

QFxAnchorLine QmlSetAnchors::right() const
{
    Q_D(const QmlSetAnchors);
    return d->right;
}

void QmlSetAnchors::setRight(const QFxAnchorLine &edge)
{
    Q_D(QmlSetAnchors);
    d->right = edge;
}

QFxAnchorLine QmlSetAnchors::top() const
{
    Q_D(const QmlSetAnchors);
    return d->top;
}

void QmlSetAnchors::setTop(const QFxAnchorLine &edge)
{
    Q_D(QmlSetAnchors);
    d->top = edge;
}

QFxAnchorLine QmlSetAnchors::bottom() const
{
    Q_D(const QmlSetAnchors);
    return d->bottom;
}

void QmlSetAnchors::setBottom(const QFxAnchorLine &edge)
{
    Q_D(QmlSetAnchors);
    d->bottom = edge;
}

void QmlSetAnchors::execute()
{
    Q_D(QmlSetAnchors);
    if (!d->target)
        return;

    //set any anchors that have been specified
    if (d->left.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->setLeft(d->left);
    if (d->right.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->setRight(d->right);
    if (d->top.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->setTop(d->top);
    if (d->bottom.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->setBottom(d->bottom);
}

bool QmlSetAnchors::isReversable()
{
    return true;
}

void QmlSetAnchors::reverse()
{
    Q_D(QmlSetAnchors);
    if (!d->target)
        return;

    //restore previous anchors
    if (d->origLeft.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->setLeft(d->origLeft);
    if (d->origRight.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->setRight(d->origRight);
    if (d->origTop.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->setTop(d->origTop);
    if (d->origBottom.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->setBottom(d->origBottom);

}

QString QmlSetAnchors::typeName() const
{
    return QLatin1String("SetAnchors");
}

QList<Action> QmlSetAnchors::extraActions()
{
    Q_D(QmlSetAnchors);
    QList<Action> extra;

    //### try to be smarter about which ones we add.
    //    or short-circuit later on if they haven't actually changed.
    //    we shouldn't set explicit width if there wasn't one before.
    if (d->target) {
        Action a;
        a.fromValue = d->origX;
        a.property = QmlMetaProperty(d->target, "x");
        extra << a;

        a.fromValue = d->origY;
        a.property = QmlMetaProperty(d->target, "y");
        extra << a;

        a.fromValue = d->origWidth;
        a.property = QmlMetaProperty(d->target, "width");
        extra << a;

        a.fromValue = d->origHeight;
        a.property = QmlMetaProperty(d->target, "height");
        extra << a;
    }

    return extra;
}

bool QmlSetAnchors::changesBindings()
{
    return true;
}

void QmlSetAnchors::clearForwardBindings()
{
    Q_D(QmlSetAnchors);
    d->origLeft = d->target->anchors()->left();
    d->origRight = d->target->anchors()->right();
    d->origTop = d->target->anchors()->top();
    d->origBottom = d->target->anchors()->bottom();
    d->origX = d->target->x();
    d->origY = d->target->y();
    d->origWidth = d->target->width();
    d->origHeight = d->target->height();

    //reset any anchors that have been specified
    if (d->resetList.contains(QLatin1String("left")))
        d->target->anchors()->resetLeft();
    if (d->resetList.contains(QLatin1String("right")))
        d->target->anchors()->resetRight();
    if (d->resetList.contains(QLatin1String("top")))
        d->target->anchors()->resetTop();
    if (d->resetList.contains(QLatin1String("bottom")))
        d->target->anchors()->resetBottom();
}

void QmlSetAnchors::clearReverseBindings()
{
    Q_D(QmlSetAnchors);
    d->origX = d->target->x();
    d->origY = d->target->y();
    d->origWidth = d->target->width();
    d->origHeight = d->target->height();

    //reset any anchors that were set in the state
    if (d->left.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->resetLeft();
    if (d->right.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->resetRight();
    if (d->top.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->resetTop();
    if (d->bottom.anchorLine != QFxAnchorLine::Invalid)
        d->target->anchors()->resetBottom();
}

QT_END_NAMESPACE
<|endoftext|>


<commit_before>#include <cmath>
#include <cstddef>
#include <limits>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
#include <gtest/gtest.h>
#include <entt/core/memory.hpp>
#include "../common/basic_test_allocator.hpp"
#include "../common/config.h"
#include "../common/throwing_allocator.hpp"
#include "../common/throwing_type.hpp"
#include "../common/tracked_memory_resource.hpp"

TEST(ToAddress, Functionalities) {
    std::shared_ptr<int> shared = std::make_shared<int>();
    auto *plain = std::addressof(*shared);

    ASSERT_EQ(entt::to_address(shared), plain);
    ASSERT_EQ(entt::to_address(plain), plain);
}

TEST(PoccaPocmaAndPocs, Functionalities) {
    test::basic_test_allocator<int> lhs, rhs;
    // honestly, I don't even know how one is supposed to test such a thing :)
    entt::propagate_on_container_copy_assignment(lhs, rhs);
    entt::propagate_on_container_move_assignment(lhs, rhs);
    entt::propagate_on_container_swap(lhs, rhs);
}

TEST(IsPowerOfTwo, Functionalities) {
    // constexpr-ness guaranteed
    constexpr auto zero_is_power_of_two = entt::is_power_of_two(0u);

    ASSERT_FALSE(zero_is_power_of_two);
    ASSERT_TRUE(entt::is_power_of_two(1u));
    ASSERT_TRUE(entt::is_power_of_two(2u));
    ASSERT_TRUE(entt::is_power_of_two(4u));
    ASSERT_FALSE(entt::is_power_of_two(7u));
    ASSERT_TRUE(entt::is_power_of_two(128u));
    ASSERT_FALSE(entt::is_power_of_two(200u));
}

TEST(NextPowerOfTwo, Functionalities) {
    // constexpr-ness guaranteed
    constexpr auto next_power_of_two_of_zero = entt::next_power_of_two(0u);

    ASSERT_EQ(next_power_of_two_of_zero, 1u);
    ASSERT_EQ(entt::next_power_of_two(1u), 1u);
    ASSERT_EQ(entt::next_power_of_two(2u), 2u);
    ASSERT_EQ(entt::next_power_of_two(3u), 4u);
    ASSERT_EQ(entt::next_power_of_two(17u), 32u);
    ASSERT_EQ(entt::next_power_of_two(32u), 32u);
    ASSERT_EQ(entt::next_power_of_two(33u), 64u);
    ASSERT_EQ(entt::next_power_of_two(std::pow(2, 16)), std::pow(2, 16));
    ASSERT_EQ(entt::next_power_of_two(std::pow(2, 16) + 1u), std::pow(2, 17));
}

ENTT_DEBUG_TEST(NextPowerOfTwoDeathTest, Functionalities) {
    ASSERT_DEATH(static_cast<void>(entt::next_power_of_two((std::size_t{1u} << (std::numeric_limits<std::size_t>::digits - 1)) + 1)), "");
}

TEST(FastMod, Functionalities) {
    // constexpr-ness guaranteed
    constexpr auto fast_mod_of_zero = entt::fast_mod(0u, 8u);

    ASSERT_EQ(fast_mod_of_zero, 0u);
    ASSERT_EQ(entt::fast_mod(7u, 8u), 7u);
    ASSERT_EQ(entt::fast_mod(8u, 8u), 0u);
}

TEST(AllocateUnique, Functionalities) {
    test::throwing_allocator<test::throwing_type> allocator{};
    test::throwing_allocator<test::throwing_type>::trigger_on_allocate = true;
    test::throwing_type::trigger_on_value = 0;

    ASSERT_THROW((entt::allocate_unique<test::throwing_type>(allocator, 0)), test::throwing_allocator<test::throwing_type>::exception_type);
    ASSERT_THROW((entt::allocate_unique<test::throwing_type>(allocator, test::throwing_type{0})), test::throwing_type::exception_type);

    std::unique_ptr<test::throwing_type, entt::allocation_deleter<test::throwing_allocator<test::throwing_type>>> ptr = entt::allocate_unique<test::throwing_type>(allocator, 42);

    ASSERT_TRUE(ptr);
    ASSERT_EQ(*ptr, 42);

    ptr.reset();

    ASSERT_FALSE(ptr);
}

#if defined(ENTT_HAS_TRACKED_MEMORY_RESOURCE)

TEST(AllocateUnique, NoUsesAllocatorConstruction) {
    test::tracked_memory_resource memory_resource{};
    std::pmr::polymorphic_allocator<int> allocator{&memory_resource};

    using type = std::unique_ptr<int, entt::allocation_deleter<std::pmr::polymorphic_allocator<int>>>;
    type ptr = entt::allocate_unique<int>(allocator, 0);

    ASSERT_EQ(memory_resource.do_allocate_counter(), 1u);
    ASSERT_EQ(memory_resource.do_deallocate_counter(), 0u);
}

TEST(AllocateUnique, UsesAllocatorConstruction) {
    using string_type = typename test::tracked_memory_resource::string_type;

    test::tracked_memory_resource memory_resource{};
    std::pmr::polymorphic_allocator<string_type> allocator{&memory_resource};

    using type = std::unique_ptr<string_type, entt::allocation_deleter<std::pmr::polymorphic_allocator<string_type>>>;
    type ptr = entt::allocate_unique<string_type>(allocator, test::tracked_memory_resource::default_value);

    ASSERT_GT(memory_resource.do_allocate_counter(), 1u);
    ASSERT_EQ(memory_resource.do_deallocate_counter(), 0u);
}

#endif

TEST(UsesAllocatorConstructionArgs, NoUsesAllocatorConstruction) {
    const auto value = 42;
    const auto args = entt::uses_allocator_construction_args<int>(std::allocator<int>{}, value);

    static_assert(std::tuple_size_v<decltype(args)> == 1u);
    static_assert(std::is_same_v<decltype(args), const std::tuple<const int &>>);

    ASSERT_EQ(std::get<0>(args), value);
}

TEST(UsesAllocatorConstructionArgs, LeadingAllocatorConvention) {
    const auto value = 42;
    const auto args = entt::uses_allocator_construction_args<std::tuple<int, char>>(std::allocator<int>{}, value, 'c');

    static_assert(std::tuple_size_v<decltype(args)> == 4u);
    static_assert(std::is_same_v<decltype(args), const std::tuple<std::allocator_arg_t, const std::allocator<int> &, const int &, char &&>>);

    ASSERT_EQ(std::get<2>(args), value);
}

TEST(UsesAllocatorConstructionArgs, TrailingAllocatorConvention) {
    const auto size = 42u;
    const auto args = entt::uses_allocator_construction_args<std::vector<int>>(std::allocator<int>{}, size);

    static_assert(std::tuple_size_v<decltype(args)> == 2u);
    static_assert(std::is_same_v<decltype(args), const std::tuple<const unsigned int &, const std::allocator<int> &>>);

    ASSERT_EQ(std::get<0>(args), size);
}

TEST(UsesAllocatorConstructionArgs, PairPiecewiseConstruct) {
    const auto size = 42u;
    const auto tup = std::make_tuple(size);
    const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{}, std::piecewise_construct, std::make_tuple(3), tup);

    static_assert(std::tuple_size_v<decltype(args)> == 3u);
    static_assert(std::is_same_v<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<int &&>, std::tuple<const unsigned int &, const std::allocator<int> &>>>);

    ASSERT_EQ(std::get<0>(std::get<2>(args)), size);
}

TEST(UsesAllocatorConstructionArgs, PairNoArgs) {
    [[maybe_unused]] const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{});

    static_assert(std::tuple_size_v<decltype(args)> == 3u);
    static_assert(std::is_same_v<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<>, std::tuple<const std::allocator<int> &>>>);
}

TEST(UsesAllocatorConstructionArgs, PairValues) {
    const auto size = 42u;
    const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{}, 3, size);

    static_assert(std::tuple_size_v<decltype(args)> == 3u);
    static_assert(std::is_same_v<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<int &&>, std::tuple<const unsigned int &, const std::allocator<int> &>>>);

    ASSERT_EQ(std::get<0>(std::get<2>(args)), size);
}

TEST(UsesAllocatorConstructionArgs, PairConstLValueReference) {
    const auto value = std::make_pair(3, 42u);
    const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{}, value);

    static_assert(std::tuple_size_v<decltype(args)> == 3u);
    static_assert(std::is_same_v<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<const int &>, std::tuple<const unsigned int &, const std::allocator<int> &>>>);

    ASSERT_EQ(std::get<0>(std::get<1>(args)), 3);
    ASSERT_EQ(std::get<0>(std::get<2>(args)), 42u);
}

TEST(UsesAllocatorConstructionArgs, PairRValueReference) {
    [[maybe_unused]] const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{}, std::make_pair(3, 42u));

    static_assert(std::tuple_size_v<decltype(args)> == 3u);
    static_assert(std::is_same_v<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<int &&>, std::tuple<unsigned int &&, const std::allocator<int> &>>>);
}

TEST(MakeObjUsingAllocator, Functionalities) {
    const auto size = 42u;
    test::throwing_allocator<int>::trigger_on_allocate = true;

    ASSERT_THROW((entt::make_obj_using_allocator<std::vector<int, test::throwing_allocator<int>>>(test::throwing_allocator<int>{}, size)), test::throwing_allocator<int>::exception_type);

    const auto vec = entt::make_obj_using_allocator<std::vector<int>>(std::allocator<int>{}, size);

    ASSERT_FALSE(vec.empty());
    ASSERT_EQ(vec.size(), size);
}

TEST(UninitializedConstructUsingAllocator, NoUsesAllocatorConstruction) {
    std::aligned_storage_t<sizeof(int)> storage;
    std::allocator<int> allocator{};

    int *value = entt::uninitialized_construct_using_allocator(reinterpret_cast<int *>(&storage), allocator, 42);

    ASSERT_EQ(*value, 42);
}

#if defined(ENTT_HAS_TRACKED_MEMORY_RESOURCE)

TEST(UninitializedConstructUsingAllocator, UsesAllocatorConstruction) {
    using string_type = typename test::tracked_memory_resource::string_type;

    test::tracked_memory_resource memory_resource{};
    std::pmr::polymorphic_allocator<string_type> allocator{&memory_resource};
    std::aligned_storage_t<sizeof(string_type)> storage;

    string_type *value = entt::uninitialized_construct_using_allocator(reinterpret_cast<string_type *>(&storage), allocator, test::tracked_memory_resource::default_value);

    ASSERT_GT(memory_resource.do_allocate_counter(), 0u);
    ASSERT_EQ(memory_resource.do_deallocate_counter(), 0u);
    ASSERT_EQ(*value, test::tracked_memory_resource::default_value);

    value->~string_type();
}

#endif
<commit_msg>test: avoid using aligned_storage_t if possible (see #919)<commit_after>#include <cmath>
#include <cstddef>
#include <limits>
#include <memory>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
#include <gtest/gtest.h>
#include <entt/core/memory.hpp>
#include "../common/basic_test_allocator.hpp"
#include "../common/config.h"
#include "../common/throwing_allocator.hpp"
#include "../common/throwing_type.hpp"
#include "../common/tracked_memory_resource.hpp"

TEST(ToAddress, Functionalities) {
    std::shared_ptr<int> shared = std::make_shared<int>();
    auto *plain = std::addressof(*shared);

    ASSERT_EQ(entt::to_address(shared), plain);
    ASSERT_EQ(entt::to_address(plain), plain);
}

TEST(PoccaPocmaAndPocs, Functionalities) {
    test::basic_test_allocator<int> lhs, rhs;
    // honestly, I don't even know how one is supposed to test such a thing :)
    entt::propagate_on_container_copy_assignment(lhs, rhs);
    entt::propagate_on_container_move_assignment(lhs, rhs);
    entt::propagate_on_container_swap(lhs, rhs);
}

TEST(IsPowerOfTwo, Functionalities) {
    // constexpr-ness guaranteed
    constexpr auto zero_is_power_of_two = entt::is_power_of_two(0u);

    ASSERT_FALSE(zero_is_power_of_two);
    ASSERT_TRUE(entt::is_power_of_two(1u));
    ASSERT_TRUE(entt::is_power_of_two(2u));
    ASSERT_TRUE(entt::is_power_of_two(4u));
    ASSERT_FALSE(entt::is_power_of_two(7u));
    ASSERT_TRUE(entt::is_power_of_two(128u));
    ASSERT_FALSE(entt::is_power_of_two(200u));
}

TEST(NextPowerOfTwo, Functionalities) {
    // constexpr-ness guaranteed
    constexpr auto next_power_of_two_of_zero = entt::next_power_of_two(0u);

    ASSERT_EQ(next_power_of_two_of_zero, 1u);
    ASSERT_EQ(entt::next_power_of_two(1u), 1u);
    ASSERT_EQ(entt::next_power_of_two(2u), 2u);
    ASSERT_EQ(entt::next_power_of_two(3u), 4u);
    ASSERT_EQ(entt::next_power_of_two(17u), 32u);
    ASSERT_EQ(entt::next_power_of_two(32u), 32u);
    ASSERT_EQ(entt::next_power_of_two(33u), 64u);
    ASSERT_EQ(entt::next_power_of_two(std::pow(2, 16)), std::pow(2, 16));
    ASSERT_EQ(entt::next_power_of_two(std::pow(2, 16) + 1u), std::pow(2, 17));
}

ENTT_DEBUG_TEST(NextPowerOfTwoDeathTest, Functionalities) {
    ASSERT_DEATH(static_cast<void>(entt::next_power_of_two((std::size_t{1u} << (std::numeric_limits<std::size_t>::digits - 1)) + 1)), "");
}

TEST(FastMod, Functionalities) {
    // constexpr-ness guaranteed
    constexpr auto fast_mod_of_zero = entt::fast_mod(0u, 8u);

    ASSERT_EQ(fast_mod_of_zero, 0u);
    ASSERT_EQ(entt::fast_mod(7u, 8u), 7u);
    ASSERT_EQ(entt::fast_mod(8u, 8u), 0u);
}

TEST(AllocateUnique, Functionalities) {
    test::throwing_allocator<test::throwing_type> allocator{};
    test::throwing_allocator<test::throwing_type>::trigger_on_allocate = true;
    test::throwing_type::trigger_on_value = 0;

    ASSERT_THROW((entt::allocate_unique<test::throwing_type>(allocator, 0)), test::throwing_allocator<test::throwing_type>::exception_type);
    ASSERT_THROW((entt::allocate_unique<test::throwing_type>(allocator, test::throwing_type{0})), test::throwing_type::exception_type);

    std::unique_ptr<test::throwing_type, entt::allocation_deleter<test::throwing_allocator<test::throwing_type>>> ptr = entt::allocate_unique<test::throwing_type>(allocator, 42);

    ASSERT_TRUE(ptr);
    ASSERT_EQ(*ptr, 42);

    ptr.reset();

    ASSERT_FALSE(ptr);
}

#if defined(ENTT_HAS_TRACKED_MEMORY_RESOURCE)

TEST(AllocateUnique, NoUsesAllocatorConstruction) {
    test::tracked_memory_resource memory_resource{};
    std::pmr::polymorphic_allocator<int> allocator{&memory_resource};

    using type = std::unique_ptr<int, entt::allocation_deleter<std::pmr::polymorphic_allocator<int>>>;
    type ptr = entt::allocate_unique<int>(allocator, 0);

    ASSERT_EQ(memory_resource.do_allocate_counter(), 1u);
    ASSERT_EQ(memory_resource.do_deallocate_counter(), 0u);
}

TEST(AllocateUnique, UsesAllocatorConstruction) {
    using string_type = typename test::tracked_memory_resource::string_type;

    test::tracked_memory_resource memory_resource{};
    std::pmr::polymorphic_allocator<string_type> allocator{&memory_resource};

    using type = std::unique_ptr<string_type, entt::allocation_deleter<std::pmr::polymorphic_allocator<string_type>>>;
    type ptr = entt::allocate_unique<string_type>(allocator, test::tracked_memory_resource::default_value);

    ASSERT_GT(memory_resource.do_allocate_counter(), 1u);
    ASSERT_EQ(memory_resource.do_deallocate_counter(), 0u);
}

#endif

TEST(UsesAllocatorConstructionArgs, NoUsesAllocatorConstruction) {
    const auto value = 42;
    const auto args = entt::uses_allocator_construction_args<int>(std::allocator<int>{}, value);

    static_assert(std::tuple_size_v<decltype(args)> == 1u);
    static_assert(std::is_same_v<decltype(args), const std::tuple<const int &>>);

    ASSERT_EQ(std::get<0>(args), value);
}

TEST(UsesAllocatorConstructionArgs, LeadingAllocatorConvention) {
    const auto value = 42;
    const auto args = entt::uses_allocator_construction_args<std::tuple<int, char>>(std::allocator<int>{}, value, 'c');

    static_assert(std::tuple_size_v<decltype(args)> == 4u);
    static_assert(std::is_same_v<decltype(args), const std::tuple<std::allocator_arg_t, const std::allocator<int> &, const int &, char &&>>);

    ASSERT_EQ(std::get<2>(args), value);
}

TEST(UsesAllocatorConstructionArgs, TrailingAllocatorConvention) {
    const auto size = 42u;
    const auto args = entt::uses_allocator_construction_args<std::vector<int>>(std::allocator<int>{}, size);

    static_assert(std::tuple_size_v<decltype(args)> == 2u);
    static_assert(std::is_same_v<decltype(args), const std::tuple<const unsigned int &, const std::allocator<int> &>>);

    ASSERT_EQ(std::get<0>(args), size);
}

TEST(UsesAllocatorConstructionArgs, PairPiecewiseConstruct) {
    const auto size = 42u;
    const auto tup = std::make_tuple(size);
    const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{}, std::piecewise_construct, std::make_tuple(3), tup);

    static_assert(std::tuple_size_v<decltype(args)> == 3u);
    static_assert(std::is_same_v<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<int &&>, std::tuple<const unsigned int &, const std::allocator<int> &>>>);

    ASSERT_EQ(std::get<0>(std::get<2>(args)), size);
}

TEST(UsesAllocatorConstructionArgs, PairNoArgs) {
    [[maybe_unused]] const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{});

    static_assert(std::tuple_size_v<decltype(args)> == 3u);
    static_assert(std::is_same_v<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<>, std::tuple<const std::allocator<int> &>>>);
}

TEST(UsesAllocatorConstructionArgs, PairValues) {
    const auto size = 42u;
    const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{}, 3, size);

    static_assert(std::tuple_size_v<decltype(args)> == 3u);
    static_assert(std::is_same_v<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<int &&>, std::tuple<const unsigned int &, const std::allocator<int> &>>>);

    ASSERT_EQ(std::get<0>(std::get<2>(args)), size);
}

TEST(UsesAllocatorConstructionArgs, PairConstLValueReference) {
    const auto value = std::make_pair(3, 42u);
    const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{}, value);

    static_assert(std::tuple_size_v<decltype(args)> == 3u);
    static_assert(std::is_same_v<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<const int &>, std::tuple<const unsigned int &, const std::allocator<int> &>>>);

    ASSERT_EQ(std::get<0>(std::get<1>(args)), 3);
    ASSERT_EQ(std::get<0>(std::get<2>(args)), 42u);
}

TEST(UsesAllocatorConstructionArgs, PairRValueReference) {
    [[maybe_unused]] const auto args = entt::uses_allocator_construction_args<std::pair<int, std::vector<int>>>(std::allocator<int>{}, std::make_pair(3, 42u));

    static_assert(std::tuple_size_v<decltype(args)> == 3u);
    static_assert(std::is_same_v<decltype(args), const std::tuple<std::piecewise_construct_t, std::tuple<int &&>, std::tuple<unsigned int &&, const std::allocator<int> &>>>);
}

TEST(MakeObjUsingAllocator, Functionalities) {
    const auto size = 42u;
    test::throwing_allocator<int>::trigger_on_allocate = true;

    ASSERT_THROW((entt::make_obj_using_allocator<std::vector<int, test::throwing_allocator<int>>>(test::throwing_allocator<int>{}, size)), test::throwing_allocator<int>::exception_type);

    const auto vec = entt::make_obj_using_allocator<std::vector<int>>(std::allocator<int>{}, size);

    ASSERT_FALSE(vec.empty());
    ASSERT_EQ(vec.size(), size);
}

TEST(UninitializedConstructUsingAllocator, NoUsesAllocatorConstruction) {
    alignas(int) std::byte storage[sizeof(int)];
    std::allocator<int> allocator{};

    int *value = entt::uninitialized_construct_using_allocator(reinterpret_cast<int *>(&storage), allocator, 42);

    ASSERT_EQ(*value, 42);
}

#if defined(ENTT_HAS_TRACKED_MEMORY_RESOURCE)

TEST(UninitializedConstructUsingAllocator, UsesAllocatorConstruction) {
    using string_type = typename test::tracked_memory_resource::string_type;

    test::tracked_memory_resource memory_resource{};
    std::pmr::polymorphic_allocator<string_type> allocator{&memory_resource};
    alignas(string_type) std::byte storage[sizeof(string_type)];

    string_type *value = entt::uninitialized_construct_using_allocator(reinterpret_cast<string_type *>(&storage), allocator, test::tracked_memory_resource::default_value);

    ASSERT_GT(memory_resource.do_allocate_counter(), 0u);
    ASSERT_EQ(memory_resource.do_deallocate_counter(), 0u);
    ASSERT_EQ(*value, test::tracked_memory_resource::default_value);

    value->~string_type();
}

#endif
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifdef ETL_VECTORIZE_IMPL
#ifdef __AVX__
#define TEST_VEC
#elif defined(__SSE3__)
#define TEST_VEC
#endif
#endif

#define DOT_FUNCTOR(name, ...)                        \
    struct name {                                     \
        template <typename A, typename B, typename C> \
        static void apply(A&& a, B&& b, C&& c) {      \
            __VA_ARGS__;                              \
        }                                             \
    };

DOT_FUNCTOR(default_dot, c = etl::dot(a, b))
DOT_FUNCTOR(std_dot, SELECTED_SECTION(etl::dot_impl::STD) { c = etl::dot(a, b); })

#define DOT_TEST_CASE_SECTION_DEFAULT DOT_TEST_CASE_SECTIONS(default_dot)
#define DOT_TEST_CASE_SECTION_STD DOT_TEST_CASE_SECTIONS(std_dot)

#ifdef TEST_VEC
DOT_FUNCTOR(vec_dot, SELECTED_SECTION(etl::dot_impl::VEC) { c = etl::dot(a, b); })

#define DOT_TEST_CASE_SECTION_VEC DOT_TEST_CASE_SECTIONS(vec_dot)
#else
#define DOT_TEST_CASE_SECTION_VEC
#endif

#ifdef ETL_BLAS_MODE
DOT_FUNCTOR(blas_dot, SELECTED_SECTION(etl::dot_impl::BLAS) { c = etl::dot(a, b); })

#define DOT_TEST_CASE_SECTION_BLAS DOT_TEST_CASE_SECTIONS(blas_dot)
#else
#define DOT_TEST_CASE_SECTION_BLAS
#endif

#define DOT_TEST_CASE_DECL(name, description)                                 \
    template <typename T, typename Impl>                                       \
    static void UNIQUE_NAME(____C_A_T_C_H____T_E_M_P_L_A_TE____T_E_S_T____)(); \
    ETL_TEST_CASE(name, description)

#define DOT_TEST_CASE_SECTION(Tn, Impln)                                         \
    ETL_SECTION(#Tn "_" #Impln) {                                                 \
        UNIQUE_NAME(____C_A_T_C_H____T_E_M_P_L_A_TE____T_E_S_T____)<Tn, Impln>(); \
    }

#define DOT_TEST_CASE_DEFN              \
    template <typename T, typename Impl> \
    static void UNIQUE_NAME(____C_A_T_C_H____T_E_M_P_L_A_TE____T_E_S_T____)()

#define DOT_TEST_CASE_SECTIONS(S1) \
    DOT_TEST_CASE_SECTION(float, S1)   \
    DOT_TEST_CASE_SECTION(double, S1)

#define DOT_TEST_CASE(name, description)     \
    DOT_TEST_CASE_DECL(name, description) { \
        DOT_TEST_CASE_SECTION_DEFAULT        \
        DOT_TEST_CASE_SECTION_STD            \
        DOT_TEST_CASE_SECTION_VEC            \
        DOT_TEST_CASE_SECTION_BLAS           \
    }                                        \
    DOT_TEST_CASE_DEFN
<commit_msg>Tests for CUBLAS dot<commit_after>//=======================================================================
// Copyright (c) 2014-2016 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

#ifdef ETL_VECTORIZE_IMPL
#ifdef __AVX__
#define TEST_VEC
#elif defined(__SSE3__)
#define TEST_VEC
#endif
#endif

#define DOT_FUNCTOR(name, ...)                        \
    struct name {                                     \
        template <typename A, typename B, typename C> \
        static void apply(A&& a, B&& b, C&& c) {      \
            __VA_ARGS__;                              \
        }                                             \
    };

DOT_FUNCTOR(default_dot, c = etl::dot(a, b))
DOT_FUNCTOR(std_dot, SELECTED_SECTION(etl::dot_impl::STD) { c = etl::dot(a, b); })

#define DOT_TEST_CASE_SECTION_DEFAULT DOT_TEST_CASE_SECTIONS(default_dot)
#define DOT_TEST_CASE_SECTION_STD DOT_TEST_CASE_SECTIONS(std_dot)

#ifdef TEST_VEC
DOT_FUNCTOR(vec_dot, SELECTED_SECTION(etl::dot_impl::VEC) { c = etl::dot(a, b); })

#define DOT_TEST_CASE_SECTION_VEC DOT_TEST_CASE_SECTIONS(vec_dot)
#else
#define DOT_TEST_CASE_SECTION_VEC
#endif

#ifdef ETL_BLAS_MODE
DOT_FUNCTOR(blas_dot, SELECTED_SECTION(etl::dot_impl::BLAS) { c = etl::dot(a, b); })

#define DOT_TEST_CASE_SECTION_BLAS DOT_TEST_CASE_SECTIONS(blas_dot)
#else
#define DOT_TEST_CASE_SECTION_BLAS
#endif

#ifdef ETL_CUBLAS_MODE
DOT_FUNCTOR(cublas_dot, SELECTED_SECTION(etl::dot_impl::CUBLAS) { c = etl::dot(a, b); })

#define DOT_TEST_CASE_SECTION_CUBLAS DOT_TEST_CASE_SECTIONS(cublas_dot)
#else
#define DOT_TEST_CASE_SECTION_CUBLAS
#endif

#define DOT_TEST_CASE_DECL(name, description)                                 \
    template <typename T, typename Impl>                                       \
    static void UNIQUE_NAME(____C_A_T_C_H____T_E_M_P_L_A_TE____T_E_S_T____)(); \
    ETL_TEST_CASE(name, description)

#define DOT_TEST_CASE_SECTION(Tn, Impln)                                         \
    ETL_SECTION(#Tn "_" #Impln) {                                                 \
        UNIQUE_NAME(____C_A_T_C_H____T_E_M_P_L_A_TE____T_E_S_T____)<Tn, Impln>(); \
    }

#define DOT_TEST_CASE_DEFN              \
    template <typename T, typename Impl> \
    static void UNIQUE_NAME(____C_A_T_C_H____T_E_M_P_L_A_TE____T_E_S_T____)()

#define DOT_TEST_CASE_SECTIONS(S1) \
    DOT_TEST_CASE_SECTION(float, S1)   \
    DOT_TEST_CASE_SECTION(double, S1)

#define DOT_TEST_CASE(name, description)     \
    DOT_TEST_CASE_DECL(name, description) { \
        DOT_TEST_CASE_SECTION_DEFAULT        \
        DOT_TEST_CASE_SECTION_STD            \
        DOT_TEST_CASE_SECTION_VEC            \
        DOT_TEST_CASE_SECTION_BLAS           \
        DOT_TEST_CASE_SECTION_CUBLAS           \
    }                                        \
    DOT_TEST_CASE_DEFN
<|endoftext|>