Loading files
// Copyright 2026 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef MUJOCO_SRC_EXPERIMENTAL_PLATFORM_ENUM_UTILS_H_
#define MUJOCO_SRC_EXPERIMENTAL_PLATFORM_ENUM_UTILS_H_
#include <array>
#include <bit>
#include <cstdio>
#include <string_view>
#include <utility>
// Provides compile-time utilities for C++ enums, inspired by magic_enum.
// https://github.com/Neargye/magic_enum.
//
// It provides two useful functions:
// - enum_to_string: converts an enum to a string.
// - entries_v: returns an array of pairs of enums and their names.
//
// It relies on non-standard language extensions, so use should be limited to
// non-critical debugging code only. Specifically, it makes assumptions about
// the format of __PRETTY_FUNCTION__ in order to extract the name of an enum
// from a template function.
namespace mujoco::platform::enum_utils {
// Range of values to check for valid enums. This range should be large enough
// to accommodate MuJoCo enums, but not flags. Any enum value that falls outside
// of this range will be ignored by this library.
constexpr int ENUM_MIN_VALUE = -1;
constexpr int ENUM_MAX_VALUE = 1024;
// Fixed-size string for use in compile-time expressions.
template <int N>
struct fixed_string {
constexpr fixed_string(std::string_view sv) noexcept {
for (int n = 0; n < N; ++n) str[n] = sv[n];
}
constexpr operator std::string_view() const noexcept {
return {str.data(), N};
}
std::array<char, N + 1> str{};
};
// Characters that are valid parts of an enum name.
constexpr auto is_valid_char(char ch) noexcept {
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch == '_') ||
(ch >= '0' && ch <= '9');
}
// Extracts the name of an enum from a string generated by __PRETTY_FUNCTION__.
constexpr auto pretty_name(std::string_view sv) noexcept {
for (int n = sv.size() - 1; n > 0; --n) {
if (!is_valid_char(sv[n])) {
sv.remove_prefix(n + 1);
break;
}
}
if (sv[0] >= '0' && sv[0] <= '9') {
return std::string_view();
}
return sv;
}
// Returns the name of the V which is an enum value of type E.
template <typename E, E V>
constexpr auto n() noexcept {
#if defined(__GNUC__) || defined(__clang__)
return pretty_name({__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 2});
#elif defined(_MSC_VER)
return pretty_name({__FUNCSIG__, sizeof(__FUNCSIG__) - 17});
#endif
}
// Returns true if the value V is a valid enum value of type E.
template <typename E, int V>
constexpr auto is_valid() {
return !n<E, std::bit_cast<E>(V)>().empty();
}
// Returns the value of the Nth element of enum E.
template <typename E>
constexpr auto nth(int v) {
return std::bit_cast<E>(ENUM_MIN_VALUE + v);
}
// Returns the number of bits set to true in the given array.
template <int N>
constexpr auto count_values(const bool (&valid)[N]) {
int count = 0;
for (int n = 0; n < N; ++n)
if (valid[n]) ++count;
return count;
}
// Returns an array of the valid values of enum E. This is a subset of the
// values in the range defined by the index sequence. If an enum has a value
// outside this range, it will be ignored.
template <typename E, std::size_t... I>
constexpr auto values(std::index_sequence<I...>) noexcept {
constexpr bool valid[sizeof...(I)] = {is_valid<E, nth<E>(I)>()...};
constexpr auto num_valid = count_values(valid);
static_assert(num_valid > 0, "no support for empty enums");
std::array<E, num_valid> values = {};
for (int offset = 0, n = 0; n < num_valid; ++offset) {
if (valid[offset]) {
values[n] = nth<E>(offset);
++n;
}
}
return values;
}
// Returns an array of valid values of enum E. The possible range of values is
// defined by the range [ENUM_MIN_VALUE, ENUM_MAX_VALUE]. If the enum has a
// value outside this range, it will be ignored.
template <typename E>
constexpr auto values() noexcept {
constexpr int enum_size = ENUM_MAX_VALUE - ENUM_MIN_VALUE + 1;
return values<E>(std::make_index_sequence<enum_size>({}));
}
template <typename E>
inline constexpr auto values_v = values<E>();
// Returns the name of V which is an enum value of type E.
template <typename E, E V>
constexpr auto enum_name() {
constexpr auto name = n<E, V>();
return fixed_string<name.size()>(name);
}
template <typename E, E V>
inline constexpr auto enum_name_v = enum_name<E, V>();
// Returns an array of pairs of enum values and their names.
template <typename E, std::size_t... I>
constexpr auto entries(std::index_sequence<I...>) noexcept {
return std::array<std::pair<E, std::string_view>, sizeof...(I)>{
{{values_v<E>[I], enum_name_v<E, values_v<E>[I]>}...}};
}
template <typename E>
inline constexpr auto entries_v =
entries<E>(std::make_index_sequence<values_v<E>.size()>());
// Returns the name of the given enum value.
template <typename E>
constexpr std::string_view enum_to_string(E value) {
for (const auto& [key, name] : entries_v<E>) {
if (value == key) return name;
}
return {};
}
} // namespace mujoco::platform::enum_utils
#endif // MUJOCO_SRC_EXPERIMENTAL_PLATFORM_ENUM_UTILS_H_
314965a3cThis file is pinned to the selected release. Download the original to open it in your design tool.