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

Strong types #1309

Open
wants to merge 23 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
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 src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ install( DIRECTORY t8_forest DESTINATION ${CMAKE_INSTALL_PREFIX}/include FILES_M
install( DIRECTORY t8_geometry DESTINATION ${CMAKE_INSTALL_PREFIX}/include FILES_MATCHING PATTERN "*.hxx" )
install( DIRECTORY t8_schemes DESTINATION ${CMAKE_INSTALL_PREFIX}/include FILES_MATCHING PATTERN "*.hxx" )
install( DIRECTORY t8_vtk DESTINATION ${CMAKE_INSTALL_PREFIX}/include FILES_MATCHING PATTERN "*.hxx" )
install( DIRECTORY t8_types DESTINATION ${CMAKE_INSTALL_PREFIX}/include FILES_MATCHING PATTERN "*.hxx" )

install( TARGETS T8 DESTINATION ${CMAKE_INSTALL_PREFIX}/lib )
install( TARGETS T8 EXPORT ${PROJECT_NAME}-targets )
Expand Down
239 changes: 239 additions & 0 deletions src/t8_types/t8_operators.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
/*
This file is part of t8code.
t8code is a C library to manage a collection (a forest) of multiple
connected adaptive space-trees of general element classes in parallel.

Copyright (C) 2024 the developers

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

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

You should have received a copy of the GNU General Public License
along with t8code; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#ifndef T8_OPERATORS_HXX
#define T8_OPERATORS_HXX

#include <iostream>
#include <t8_types/t8_type.hxx>

/**
* \file This file provides the CRTP pattern for operators.
* The operators can be used by a \a T8Type to extend the functionality of the type.
*/

/**
* \brief The CRTP pattern for operators.
*
* \tparam T
* \tparam crtpType
*/
template <typename T, template <typename> class crtpType>
Davknapp marked this conversation as resolved.
Show resolved Hide resolved
struct crtp
{
T&
underlying ()
{
return static_cast<T&> (*this);
}

T const&
underlying () const
{
return static_cast<T const&> (*this);
}
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we combine this with src/t8_schemes/t8_crtp.hxx?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thaught about it and had a short look into it. But this struct has an additional template argument than your implementation and I think that this is a detail that matters.


/*
* The following is a list of competences that can be added to a type.
* Each competence provides access to an operator of the underlying type. That way instead of
* typing `my_int.get() + my_other_int.get()` you can type `my_int + my_other_int`.
*/

/**
* \brief A template for addable types. Provides the + operator.
*
* \tparam T
*/
template <typename T>
Davknapp marked this conversation as resolved.
Show resolved Hide resolved
struct Addable: crtp<T, Addable>
{

T
operator+ (T const& other)
{
return T (this->underlying ().get () + other.get ());
}
};

/**
* \brief A template for subtractable types. Provides the - operator.
*
* \tparam T
*/
template <typename T>
Davknapp marked this conversation as resolved.
Show resolved Hide resolved
struct Subtractable: crtp<T, Subtractable>
{
T
operator- (T const& other)
{
return T (this->underlying ().get () - other.get ());
}
};

/**
* \brief A template for multipliable types. Provides the * operator.
*
* \tparam T
*/
template <typename T>
Davknapp marked this conversation as resolved.
Show resolved Hide resolved
struct Multipliable: crtp<T, Multipliable>
{
T
operator* (T const& other)
{
return T (this->underlying ().get () * other.get ());
}
};

/**
* \brief A template for dividable types. Provides the / operator.
*
* \tparam T
*/
template <typename T>
Davknapp marked this conversation as resolved.
Show resolved Hide resolved
struct Dividable: crtp<T, Dividable>
{
T
operator/ (T const& other)
{
return T (this->underlying ().get () / other.get ());
}
};

/**
* \brief A template for add-assignable types. Provides the += operator.
*
* \tparam T
*/
template <typename T>
Davknapp marked this conversation as resolved.
Show resolved Hide resolved
struct AddAssignable: crtp<T, AddAssignable>
{
T&
operator+= (T const& other)
{
this->underlying ().get () += other.get ();
return this->underlying ();
}
};

/**
* \brief A template for incrementable types. Provides the ++ operator.
*
* \tparam T
*
* \note The operator is a prefix operator.
*/
template <typename T>
Davknapp marked this conversation as resolved.
Show resolved Hide resolved
struct PrefixIncrementable: crtp<T, PrefixIncrementable>
{
T&
operator++ ()
{
this->underlying ().get ()++;
return this->underlying ();
}
};

/**
* \brief A template for decrementable types. Provides the -- operator.
*
* \tparam T
*
* \note The operator is a prefix operator.
*/
template <typename T>
Davknapp marked this conversation as resolved.
Show resolved Hide resolved
struct PrefixDecrementable: crtp<T, PrefixDecrementable>
{
T&
operator-- ()
{
this->underlying ().get ()--;
return this->underlying ();
}
};

template <typename T>
Davknapp marked this conversation as resolved.
Show resolved Hide resolved
struct Printable: crtp<T, Printable>
{
void
print (std::ostream& os) const
{
os << this->underlying ().get ();
}
};

/**
* \brief A template for swapping types. Used to make a type swappable.
*
* \tparam T
*/
template <typename T>
Davknapp marked this conversation as resolved.
Show resolved Hide resolved
struct Swapable: crtp<T, Swapable>
{
void
swap (T& other)
{
std::swap (this->underlying ().get (), other.get ());
}
};

/**
* \brief A template for equality comparable types. Provides the == operator.
*
* \tparam T
*/
template <typename T>
Davknapp marked this conversation as resolved.
Show resolved Hide resolved
struct EqualityComparable: crtp<T, EqualityComparable>
{
bool
operator== (T const& other) const
{
return this->underlying ().get () == other.get ();
}
};

/**
* \brief A template for << types. Provides the << operator.
*
* \tparam T
*/
template <typename T, typename Parameter>
std::ostream&
operator<< (std::ostream& os, T8Type<T, Parameter> const& p)
{
p.print (os);
return os;
}

/**
* \brief A template for hashable types. Used to make a type hashable.
*
* \tparam T
*/
template <typename T>
struct Hashable
{
static constexpr bool is_hashable = true;
};

#endif /* T8_OPERATORS_HXX */
114 changes: 114 additions & 0 deletions src/t8_types/t8_type.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
This file is part of t8code.
t8code is a C library to manage a collection (a forest) of multiple
connected adaptive space-trees of general element classes in parallel.

Copyright (C) 2024 the developers

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

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

You should have received a copy of the GNU General Public License
along with t8code; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

/**
* \file This files gives a template for strong types in t8code.
*/

#ifndef T8_TYPE_HXX
#define T8_TYPE_HXX

#include <t8.h>

/**
* \brief An implementation of strong type with additional competences.
*
* This class template allows the creation of a type that can be extended with
* multiple competences. Each competence is a template class that takes the
* main type as a template parameter.
*
* This is heavily inspired by (and taken from) https://www.fluentcpp.com/2016/12/08/strong-types-for-strong-interfaces/
*
* \tparam T The type of the value to be stored.
* \tparam Parameter An additional parameter for the type.
* \tparam competence Variadic template parameter for the competences.
*/
template <typename T, typename Parameter, template <typename> class... competence>
class T8Type: public competence<T8Type<T, Parameter, competence...>>... {
public:
explicit T8Type () = default;

explicit T8Type (T const& value): value_ (value)
{
}

/**
* \brief Construct a new T8Type object
*
* \tparam T_ref
* \param value
*
* \note This constructor is only enabled if T is not a reference.
*/
template <typename T_ref = T>
explicit T8Type (T&& value, typename std::enable_if<!std::is_reference<T_ref> {}, std::nullptr_t>::type = nullptr)
: value_ (std::move (value))
{
}

T&
get ()
{
return value_;
}

T const&
get () const
{
return value_;
}

private:
T value_;
};

namespace std
{
/**
* \brief Functor for hashing T8Type objects.
*
* This struct defines a functor that computes the hash value of a T8Type object.
* It uses the std::hash function to generate the hash value based on the underlying
* type T of the T8Type object.
*
* \tparam T The underlying type of the T8Type object.
* \tparam Parameter Additional parameters for the T8Type object.
* \tparam competence Variadic template parameters for additional competencies.
*
* \note This functor is enabled only if the T8Type object is hashable, as determined
* by the is_hashable member of the T8TypeImpl type.
*/
template <typename T, typename Parameter, template <typename> class... competence>
struct hash<T8Type<T, Parameter, competence...>>
{
using T8TypeImpl = T8Type<T, Parameter, competence...>;
using checkIfHashable = typename std::enable_if<T8TypeImpl::is_hashable, void>::type;

size_t
operator() (T8Type<T, Parameter, competence...> const& x) const
{
return std::hash<T> {}(x.get ());
}
};
} // namespace std

#endif /* T8_TYPE_HXX */
2 changes: 2 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ add_t8_test( NAME t8_gtest_basics_serial SOURCES t8_gtest_main.cxx t8
add_t8_test( NAME t8_gtest_netcdf_linkage_serial SOURCES t8_gtest_main.cxx t8_gtest_netcdf_linkage.cxx )
add_t8_test( NAME t8_gtest_vtk_linkage_serial SOURCES t8_gtest_main.cxx t8_gtest_vtk_linkage.cxx )

add_t8_test( NAME t8_gtest_type_serial SOURCES t8_gtest_main.cxx t8_types/t8_gtest_type.cxx )

add_t8_test( NAME t8_gtest_hypercube_parallel SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_hypercube.cxx )
add_t8_test( NAME t8_gtest_cmesh_readmshfile_serial SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_readmshfile.cxx )
add_t8_test( NAME t8_gtest_cmesh_copy_serial SOURCES t8_gtest_main.cxx t8_cmesh/t8_gtest_cmesh_copy.cxx )
Expand Down
Loading
Loading