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

A better naming system using tag dispatch #41

Open
shohirose opened this issue Apr 4, 2020 · 1 comment
Open

A better naming system using tag dispatch #41

shohirose opened this issue Apr 4, 2020 · 1 comment

Comments

@shohirose
Copy link
Contributor

shohirose commented Apr 4, 2020

Hi,

You mentioned in TODO that a better naming system is required. I solved the issue by using a combination of tag dispatch, function overloading, and partial specialization of template classes. Please see the implementation in shohirose/morton for details.

A brief overview of my idea is the following:

namespace tag {

// Tags representing each implementation
struct bmi {};
struct preshifted_lookup_table {};
struct lookup_table {};

} // namespace tag

namespace detail {

template <typename MortonCode, typename Coordinate, typename Tag>
class morton2d {};

// Partial specialization of morton2d for tag::bmi
template <typename MortonCode, typename Coordinate>
class morton2d<MortonCode, Coordinate, tag::bmi> {
 public:
  static MortonCode encode(const Coordinate x, const Coordinate y) noexcept {
    // ...
  }
  static void decode(const MortonCode m, Coordinate& x, Coordinate& y) noexcept {
    // ...
  }
};

// Partial specialization of morton2d for tag::preshifted_lookup_table
template <typename MortonCode, typename Coordinate>
class morton2d<MortonCode, Coordinate, tag::preshifted_lookup_table> {
  // ...
};

// Partial specialization of morton2d for tag::lookup_table
template <typename MortonCode, typename Coordinate>
class morton2d<MortonCode, Coordinate, tag::lookup_table> {
  // ...
};

} // namespace detail

// Switch implementation by using a tag dispatch technique.
template <typename Tag>
inline uint_fast32_t encode(const uint_fast16_t x, const uint_fast16_t y, Tag) noexcept {
  return detail::morton2d<uint_fast32_t, uint_fast16_t, Tag>::encode(x, y);
}

template <typename Tag>
inline void decode(const uint_fast32_t m, uint_fast16_t& x, uint_fast16_t& y, Tag) noexcept {
  detail::morton2d<uint_fast32_t, uint_fast16_t, Tag>::decode(x, y);
}

Then, we can specify an implementation through a uniform API:

uint_fast16_t x = // ...
uint_fast16_t y = // ...

// Encode using BMI instruction set (if available)
const auto m1 = encode(x, y, tag::bmi{});
// Encode using preshifted lookup table
const auto m2 = encode(x, y, tag::preshifted_lookup_table{});
// Encode using lookup table
const auto m3 = encode(x, y, tag::lookup_table{});

I hope this might help you.

@Forceflow
Copy link
Owner

This is some C++-fu I'm not familiar with, but definitely looks interesting! Thanks man. I will look into integrating this in a next version

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants