Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/test/base/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ ginkgo_create_test(range_accessors)
ginkgo_create_test(sanitizers ADDITIONAL_LIBRARIES Threads::Threads)
ginkgo_create_test(segmented_array LABELS distributed)
ginkgo_create_test(segmented_range)
ginkgo_create_test(temporary_conversion)
ginkgo_create_test(types)
ginkgo_create_test(precision)
ginkgo_create_test(utils)
Expand Down
266 changes: 266 additions & 0 deletions core/test/base/temporary_conversion.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
// SPDX-FileCopyrightText: 2017 - 2026 The Ginkgo authors
//
// SPDX-License-Identifier: BSD-3-Clause

#include "ginkgo/core/base/temporary_conversion.hpp"

#include <memory>

#include <gtest/gtest.h>

#include <ginkgo/core/base/executor.hpp>
#include <ginkgo/core/matrix/dense.hpp>
#include <ginkgo/core/matrix/multivector.hpp>

#include "core/test/utils.hpp"


class LinOpA : public gko::LinOp {
public:
LinOpA(const std::shared_ptr<const gko::Executor>& exec, double value = 0.0)
: LinOp(exec, {}, gko::precision::fp64), value(value)
{}

static std::unique_ptr<LinOpA> create(
const std::shared_ptr<const gko::Executor>& exec, double value = 0.0)
{
return std::make_unique<LinOpA>(exec, value);
}

virtual double get_value() const { return value; }

// unused but required to compile
template <typename Other>
void convert_to(Other* ptr)
{}

protected:
void apply_impl(const LinOp* b, LinOp* x) const override {}
void apply_impl(const LinOp* alpha, const LinOp* b, const LinOp* beta,
LinOp* x) const override
{}

private:
double value;
};

class LinOpB : public LinOpA {
public:
LinOpB(const std::shared_ptr<const gko::Executor>& exec, double value = 0.0)
: LinOpA(exec, 0.0), value(value)
{}

static std::unique_ptr<LinOpB> create(
const std::shared_ptr<const gko::Executor>& exec, double value = 0.0)
{
return std::make_unique<LinOpB>(exec, value);
}


double get_value() const override { return value; }

private:
double value;
};


class alloc : public gko::log::Logger {
public:
mutable int count = 0;

protected:
void on_allocation_started(const gko::Executor* exec,
const gko::size_type& num_bytes) const override
{
count++;
}
};


class TemporaryConversion : public ::testing::Test {
protected:
using value_type = double;
using Vec = gko::matrix::MultiVector<float>;

void SetUp() override
{
log->count = 0;
exec->add_logger(log);
}

std::shared_ptr<alloc> log = std::make_shared<alloc>();
std::shared_ptr<gko::ReferenceExecutor> exec =
gko::ReferenceExecutor::create();
std::unique_ptr<Vec> vec = gko::initialize<Vec>({2, 3}, exec);
std::unique_ptr<LinOpA> lA = std::make_unique<LinOpA>(exec, 3);
std::unique_ptr<LinOpB> lB = std::make_unique<LinOpB>(exec, 4);
};

TEST_F(TemporaryConversion, CreateFromNullptr)
{
auto tmp =
gko::temporary_conversion<Vec>::create(static_cast<Vec*>(nullptr));

EXPECT_EQ(typeid(tmp.get()), typeid(Vec*));
EXPECT_EQ(tmp.get(), nullptr);
}


TEST_F(TemporaryConversion, ConstCreateFromSameType)
{
auto tmp = gko::temporary_conversion<const Vec>::create(vec.get());

EXPECT_EQ(typeid(tmp.get()), typeid(const Vec*));
EXPECT_EQ(tmp->get_const_values(), vec->get_values());
EXPECT_EQ(log->count, 0);
GKO_ASSERT_EQUAL_DIMENSIONS(tmp, vec);
}


TEST_F(TemporaryConversion, ConstCreateFromDerivedType)
{
auto tmp = gko::temporary_conversion<const LinOpA>::create(lB.get());

EXPECT_EQ(typeid(tmp.get()), typeid(const LinOpA*));
EXPECT_EQ(tmp->get_value(), lB->get_value());
EXPECT_EQ(log->count, 0);
}


TEST_F(TemporaryConversion, ConstCreateFromBaseType)
{
auto tmp = gko::temporary_conversion<const LinOpB>::create(
gko::as<LinOpA>(lB.get()));

EXPECT_EQ(typeid(tmp.get()), typeid(const LinOpB*));
EXPECT_EQ(tmp->get_value(), lB->get_value());
EXPECT_EQ(log->count, 0);
}


TEST_F(TemporaryConversion, ConstCreateFromConvertibleType)
{
using NewVec = gko::matrix::MultiVector<double>;
auto tmp = gko::temporary_conversion<const NewVec>::create(vec.get());

EXPECT_EQ(typeid(tmp.get()), typeid(const NewVec*));
EXPECT_NE(reinterpret_cast<std::uintptr_t>(tmp->get_const_values()),
reinterpret_cast<std::uintptr_t>(vec->get_values()));
EXPECT_GT(log->count, 0);
GKO_ASSERT_MTX_NEAR(tmp.get(), vec, 0);
}


TEST_F(TemporaryConversion, CreateFromSameType)
{
auto tmp = gko::temporary_conversion<Vec>::create(vec.get());

EXPECT_EQ(typeid(tmp.get()), typeid(Vec*));
EXPECT_EQ(tmp->get_values(), vec->get_values());
EXPECT_EQ(log->count, 0);
GKO_ASSERT_EQUAL_DIMENSIONS(tmp, vec);
}


TEST_F(TemporaryConversion, CreateFromDerivedType)
{
auto tmp = gko::temporary_conversion<LinOpA>::create(lB.get());

EXPECT_EQ(typeid(tmp.get()), typeid(LinOpA*));
EXPECT_EQ(tmp->get_value(), lB->get_value());
EXPECT_EQ(log->count, 0);
}


TEST_F(TemporaryConversion, CreateFromBaseType)
{
auto tmp =
gko::temporary_conversion<LinOpB>::create(gko::as<LinOpA>(lB.get()));

EXPECT_EQ(typeid(tmp.get()), typeid(LinOpB*));
EXPECT_EQ(tmp->get_value(), lB->get_value());
EXPECT_EQ(log->count, 0);
}


TEST_F(TemporaryConversion, CreateFromConvertibleType)
{
using NewVec = gko::matrix::MultiVector<double>;
auto tmp = gko::temporary_conversion<NewVec>::create(vec.get());

EXPECT_EQ(typeid(tmp.get()), typeid(NewVec*));
EXPECT_NE(reinterpret_cast<std::uintptr_t>(tmp->get_const_values()),
reinterpret_cast<std::uintptr_t>(vec->get_values()));
EXPECT_GT(log->count, 0);
GKO_ASSERT_MTX_NEAR(tmp.get(), vec, 0);
}


TEST_F(TemporaryConversion, CreateNonConstCopiesBack)
{
{
auto tmp = gko::temporary_conversion<Vec>::create(vec.get());
tmp->at(0, 0) = -1.0;
tmp->at(0, 1) = -2.0;
}

EXPECT_EQ(vec->at(0, 0), -1.0);
EXPECT_EQ(vec->at(0, 1), -2.0);
}


TEST_F(TemporaryConversion, ConstCreateChainFromDerivedType)
{
auto tmp = gko::temporary_conversion<const Vec>::create(vec.get());

auto tmp_linop =
gko::temporary_conversion<const gko::LinOp>::create_from_derived(
std::move(tmp));

EXPECT_EQ(typeid(tmp_linop.get()), typeid(const gko::LinOp*));
EXPECT_NE(dynamic_cast<const Vec*>(tmp_linop.get()), nullptr);
EXPECT_EQ(dynamic_cast<const Vec*>(tmp_linop.get())->get_const_values(),
vec->get_values());
EXPECT_EQ(log->count, 0);
}


TEST_F(TemporaryConversion, ConstCreateChainFromBaseType)
{
auto tmp = gko::temporary_conversion<const LinOpA>::create(lB.get());

auto tmp_linop = gko::temporary_conversion<const LinOpB>::create_from_base(
std::move(tmp));

EXPECT_EQ(typeid(tmp_linop.get()), typeid(const LinOpB*));
EXPECT_EQ(lB->get_value(), lB->get_value());
EXPECT_EQ(log->count, 0);
}


TEST_F(TemporaryConversion, CreateChainFromDerivedType)
{
auto tmp = gko::temporary_conversion<Vec>::create(vec.get());

auto tmp_linop = gko::temporary_conversion<gko::LinOp>::create_from_derived(
std::move(tmp));

EXPECT_EQ(typeid(tmp_linop.get()), typeid(gko::LinOp*));
EXPECT_NE(dynamic_cast<Vec*>(tmp_linop.get()), nullptr);
EXPECT_EQ(dynamic_cast<Vec*>(tmp_linop.get())->get_values(),
vec->get_values());
EXPECT_EQ(log->count, 0);
}


TEST_F(TemporaryConversion, CreateChainFromBaseType)
{
auto tmp = gko::temporary_conversion<LinOpA>::create(lB.get());

auto tmp_linop =
gko::temporary_conversion<LinOpB>::create_from_base(std::move(tmp));

EXPECT_EQ(typeid(tmp_linop.get()), typeid(LinOpB*));
EXPECT_EQ(lB->get_value(), lB->get_value());
EXPECT_EQ(log->count, 0);
}
Loading
Loading