Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(Multilevel) Scheme CRTP concept #1243

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
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
2 changes: 2 additions & 0 deletions example/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,5 @@ add_t8_example( NAME t8_example_gauss_blob SOURCES remove/t8_exampl
add_t8_example( NAME t8_example_empty_trees SOURCES remove/t8_example_empty_trees.cxx )

add_t8_example( NAME t8_version SOURCES version/t8_version.cxx )

add_t8_example( NAME t8_example_multilevel SOURCES multilevel/t8_example_multilevel.cxx multilevel/t8_multilevel_concept_base.hxx multilevel/t8_multilevel_concept_default.hxx multilevel/t8_multilevel_concept_multilevel.hxx)
53 changes: 53 additions & 0 deletions example/multilevel/t8_example_multilevel.cxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#include <example/multilevel/t8_multilevel_concept_base.hxx>
#include <example/multilevel/t8_multilevel_concept_default.hxx>
#include <example/multilevel/t8_multilevel_concept_multilevel.hxx>
#include <example/multilevel/t8_multilevel_concept_scheme.hxx>

#include <iostream>

int
main ()
{
Scheme default_scheme = new_default_scheme ();
Scheme multilevel_scheme = new_default_scheme (true);

triangle tri;
tri.level = 1;
tri.orientation = 0;
element_t *tri_elem = (element_t *) (&tri);

std::cout << "Triangle level: " << default_scheme.get_level (triangle_eclass, tri_elem) << std::endl;
std::cout << "Triangle num children: " << default_scheme.get_num_children (triangle_eclass, tri_elem) << std::endl;
std::cout << "Triangle num vertices: " << default_scheme.get_num_vertices (triangle_eclass) << std::endl;

quad q;
q.level = 1;
element_t *q_elem = (element_t *) (&q);

std::cout << "Quad level: " << default_scheme.get_level (quad_eclass, q_elem) << std::endl;
std::cout << "Quad num children: " << default_scheme.get_num_children (quad_eclass, q_elem) << std::endl;
std::cout << "Quad num vertices: " << default_scheme.get_num_vertices (quad_eclass) << std::endl;

multilevel_element<triangle> tri_m;
tri_m.elem = tri;
tri_m.multilevel_level = 1;
element_t *tri_m_elem = (element_t *) (&tri_m);

multilevel_element<quad> q_m;
q_m.elem = q;
q_m.multilevel_level = 2;
element_t *q_m_elem = (element_t *) (&q_m);

std::cout << "Multilevel triangle level: " << multilevel_scheme.get_level (triangle_eclass, tri_m_elem) << std::endl;
std::cout << "Multilevel triangle num children: " << multilevel_scheme.get_num_children (triangle_eclass, tri_m_elem)
<< std::endl;
std::cout << "Multilevel triangle num vertices: " << multilevel_scheme.get_num_vertices (triangle_eclass)
<< std::endl;

std::cout << "Multilevel quad level: " << multilevel_scheme.get_level (quad_eclass, q_m_elem) << std::endl;
std::cout << "Multilevel quad num children: " << multilevel_scheme.get_num_children (quad_eclass, q_m_elem)
<< std::endl;
std::cout << "Multilevel quad num vertices: " << multilevel_scheme.get_num_vertices (quad_eclass) << std::endl;

return 0;
}
46 changes: 46 additions & 0 deletions example/multilevel/t8_multilevel_concept_base.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#pragma once

#include <array>
#include <variant>
#include <vector>

typedef enum { triangle_eclass, quad_eclass, eclass_count } eclass;

// Opaque pointer to cast the element type into
typedef struct element element_t;

// Using CRTP to avoid virtual function calls
template <class Derived_scheme_t>
class Scheme_base {
public:
~Scheme_base ()
{
}

inline int
get_level (element_t *elem)
{
// cast derived class into base class to avoid virtual functions
return static_cast<Derived_scheme_t const &> (*this).get_level (elem);
};

inline int
get_num_children (element_t *elem)
{
// cast derived class into base class to avoid virtual functions
return static_cast<Derived_scheme_t const &> (*this).get_num_children (elem);
};

inline int
get_num_vertices ()
{
// cast derived class into base class to avoid virtual functions
return static_cast<Derived_scheme_t const &> (*this).get_num_vertices ();
};

private:
// This way the derived class and only the derived class can use this constructor.
// This way you get an error when doing: `class triangle_scheme: public scheme_base <quad_scheme>`
Scheme_base () {};
friend Derived_scheme_t;
};
79 changes: 79 additions & 0 deletions example/multilevel/t8_multilevel_concept_default.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#pragma once

#include <array>
#include <variant>
#include <vector>
#include <example/multilevel/t8_multilevel_concept_base.hxx>

struct triangle
{
int level;
int orientation;
};

struct quad
{
int level;
};

// inherits from base which is a template for this class
class Triangle_scheme: public Scheme_base<Triangle_scheme> {
public:
Triangle_scheme () {};

inline int
get_level (element_t *elem) const
{
elem_type *tri = (elem_type *) elem;
return tri->level;
};

inline int
get_num_children (element_t *elem) const
{
return 4;
};

inline int
get_num_vertices () const
{
return 3;
};

protected:
// When the multilevel class inherits from this it needs to know the element type of this scheme
using elem_type = triangle;

private:
};

// inherits from base which is a template for this class
class Quad_scheme: public Scheme_base<Quad_scheme> {
public:
Quad_scheme () {};

inline int
get_level (element_t *elem) const
{
elem_type *q = (elem_type *) elem;
return q->level;
};

int
get_num_children (element_t *elem) const
{
return 4;
};

int
get_num_vertices () const
{
return 4;
};

protected:
// When the multilevel class inherits from this it needs to know the element type of this scheme
using elem_type = quad;

private:
};
50 changes: 50 additions & 0 deletions example/multilevel/t8_multilevel_concept_multilevel.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#pragma once
#include <array>
#include <variant>
#include <vector>
#include <example/multilevel/t8_multilevel_concept_base.hxx>

// Multilevel element, which adds the actual hierarchical level of the element
// The level inside the element will determine its size
template <class eclass>
struct multilevel_element
{
eclass elem;
int multilevel_level;
};

template <class Scheme_impl_t>
class Multilevel_element_scheme: public Scheme_base<Multilevel_element_scheme<Scheme_impl_t>>, private Scheme_impl_t {
public:
using Scheme_impl_t::Scheme_impl_t;
using elem_type = typename Scheme_impl_t::elem_type;
~Multilevel_element_scheme () {};

int
get_level (element_t *elem) const
{
multilevel_element<elem_type> *m_elem = (multilevel_element<elem_type> *) elem;
return m_elem->multilevel_level;
};

int
get_num_children (element_t *elem) const
{
multilevel_element<elem_type> *m_elem = (multilevel_element<elem_type> *) elem;
const int elem_level = Scheme_impl_t::get_level ((element_t *) &(m_elem->elem));
if (elem_level == get_level (elem)) {
return Scheme_impl_t::get_num_children ((element_t *) &(m_elem->elem)) + 1;
}
else {
return 0;
}
};

int
get_num_vertices () const
{
return Scheme_impl_t::get_num_vertices ();
};

private:
};
80 changes: 80 additions & 0 deletions example/multilevel/t8_multilevel_concept_scheme.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#pragma once

#include <array>
#include <variant>
#include <vector>
#include <example/multilevel/t8_multilevel_concept_base.hxx>
#include <example/multilevel/t8_multilevel_concept_default.hxx>
#include <example/multilevel/t8_multilevel_concept_multilevel.hxx>

class Scheme {
friend class Scheme_builder;

public:
Scheme () {};
~Scheme () {};

using Scheme_v = std::variant<Triangle_scheme, Quad_scheme, Multilevel_element_scheme<Triangle_scheme>,
Multilevel_element_scheme<Quad_scheme>>;
using Scheme_container = std::array<Scheme_v, eclass_count>;

int
get_level (eclass eclass, element_t *elem) const
{
return std::visit ([elem] (auto &&scheme) { return scheme.get_level (elem); }, eclass_schemes[eclass]);
}

int
get_num_children (eclass eclass, element_t *elem) const
{
return std::visit ([elem] (auto &&scheme) { return scheme.get_num_children (elem); }, eclass_schemes[eclass]);
}

int
get_num_vertices (eclass eclass) const
{
return std::visit ([] (auto &&scheme) { return scheme.get_num_vertices (); }, eclass_schemes[eclass]);
}

private:
Scheme_container eclass_schemes;
};

class Scheme_builder {
public:
Scheme_builder (bool convert_to_multilevel = false): multilevel (convert_to_multilevel) {};
~Scheme_builder () {};

using Scheme_v = Scheme::Scheme_v;

template <typename Eclass_scheme, typename... _args>
void
add_eclass_scheme (eclass eclass, _args &&...args)
{
if (!multilevel) {
scheme.eclass_schemes[eclass] = Eclass_scheme (std::forward<_args> (args)...);
}
else {
scheme.eclass_schemes[eclass] = Multilevel_element_scheme<Eclass_scheme> (std::forward<_args> (args)...);
}
}

Scheme
build_scheme ()
{
return scheme;
}

private:
Scheme scheme;
bool multilevel;
};

Scheme
new_default_scheme (bool multilevel = false)
{
Scheme_builder builder (multilevel);
builder.add_eclass_scheme<Triangle_scheme> (triangle_eclass);
builder.add_eclass_scheme<Quad_scheme> (quad_eclass);
return builder.build_scheme ();
}