| //===- llvm/ADT/ilist_node_options.h - ilist_node Options -------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_ADT_ILIST_NODE_OPTIONS_H |
| #define LLVM_ADT_ILIST_NODE_OPTIONS_H |
| |
| #include "llvm/Config/abi-breaking.h" |
| |
| #include <type_traits> |
| |
| namespace llvm { |
| |
| template <bool EnableSentinelTracking> class ilist_node_base; |
| template <bool EnableSentinelTracking> class ilist_base; |
| |
| /// Option to choose whether to track sentinels. |
| /// |
| /// This option affects the ABI for the nodes. When not specified explicitly, |
| /// the ABI depends on LLVM_ENABLE_ABI_BREAKING_CHECKS. Specify explicitly to |
| /// enable \a ilist_node::isSentinel(). |
| template <bool EnableSentinelTracking> struct ilist_sentinel_tracking {}; |
| |
| /// Option to specify a tag for the node type. |
| /// |
| /// This option allows a single value type to be inserted in multiple lists |
| /// simultaneously. See \a ilist_node for usage examples. |
| template <class Tag> struct ilist_tag {}; |
| |
| namespace ilist_detail { |
| |
| /// Helper trait for recording whether an option is specified explicitly. |
| template <bool IsExplicit> struct explicitness { |
| static const bool is_explicit = IsExplicit; |
| }; |
| typedef explicitness<true> is_explicit; |
| typedef explicitness<false> is_implicit; |
| |
| /// Check whether an option is valid. |
| /// |
| /// The steps for adding and enabling a new ilist option include: |
| /// \li define the option, ilist_foo<Bar>, above; |
| /// \li add new parameters for Bar to \a ilist_detail::node_options; |
| /// \li add an extraction meta-function, ilist_detail::extract_foo; |
| /// \li call extract_foo from \a ilist_detail::compute_node_options and pass it |
| /// into \a ilist_detail::node_options; and |
| /// \li specialize \c is_valid_option<ilist_foo<Bar>> to inherit from \c |
| /// std::true_type to get static assertions passing in \a simple_ilist and \a |
| /// ilist_node. |
| template <class Option> struct is_valid_option : std::false_type {}; |
| |
| /// Extract sentinel tracking option. |
| /// |
| /// Look through \p Options for the \a ilist_sentinel_tracking option, with the |
| /// default depending on LLVM_ENABLE_ABI_BREAKING_CHECKS. |
| template <class... Options> struct extract_sentinel_tracking; |
| template <bool EnableSentinelTracking, class... Options> |
| struct extract_sentinel_tracking< |
| ilist_sentinel_tracking<EnableSentinelTracking>, Options...> |
| : std::integral_constant<bool, EnableSentinelTracking>, is_explicit {}; |
| template <class Option1, class... Options> |
| struct extract_sentinel_tracking<Option1, Options...> |
| : extract_sentinel_tracking<Options...> {}; |
| #if LLVM_ENABLE_ABI_BREAKING_CHECKS |
| template <> struct extract_sentinel_tracking<> : std::true_type, is_implicit {}; |
| #else |
| template <> |
| struct extract_sentinel_tracking<> : std::false_type, is_implicit {}; |
| #endif |
| template <bool EnableSentinelTracking> |
| struct is_valid_option<ilist_sentinel_tracking<EnableSentinelTracking>> |
| : std::true_type {}; |
| |
| /// Extract custom tag option. |
| /// |
| /// Look through \p Options for the \a ilist_tag option, pulling out the |
| /// custom tag type, using void as a default. |
| template <class... Options> struct extract_tag; |
| template <class Tag, class... Options> |
| struct extract_tag<ilist_tag<Tag>, Options...> { |
| typedef Tag type; |
| }; |
| template <class Option1, class... Options> |
| struct extract_tag<Option1, Options...> : extract_tag<Options...> {}; |
| template <> struct extract_tag<> { |
| typedef void type; |
| }; |
| template <class Tag> struct is_valid_option<ilist_tag<Tag>> : std::true_type {}; |
| |
| /// Check whether options are valid. |
| /// |
| /// The conjunction of \a is_valid_option on each individual option. |
| template <class... Options> struct check_options; |
| template <> struct check_options<> : std::true_type {}; |
| template <class Option1, class... Options> |
| struct check_options<Option1, Options...> |
| : std::integral_constant<bool, is_valid_option<Option1>::value && |
| check_options<Options...>::value> {}; |
| |
| /// Traits for options for \a ilist_node. |
| /// |
| /// This is usually computed via \a compute_node_options. |
| template <class T, bool EnableSentinelTracking, bool IsSentinelTrackingExplicit, |
| class TagT> |
| struct node_options { |
| typedef T value_type; |
| typedef T *pointer; |
| typedef T &reference; |
| typedef const T *const_pointer; |
| typedef const T &const_reference; |
| |
| static const bool enable_sentinel_tracking = EnableSentinelTracking; |
| static const bool is_sentinel_tracking_explicit = IsSentinelTrackingExplicit; |
| typedef TagT tag; |
| typedef ilist_node_base<enable_sentinel_tracking> node_base_type; |
| typedef ilist_base<enable_sentinel_tracking> list_base_type; |
| }; |
| |
| template <class T, class... Options> struct compute_node_options { |
| typedef node_options<T, extract_sentinel_tracking<Options...>::value, |
| extract_sentinel_tracking<Options...>::is_explicit, |
| typename extract_tag<Options...>::type> |
| type; |
| }; |
| |
| } // end namespace ilist_detail |
| } // end namespace llvm |
| |
| #endif // LLVM_ADT_ILIST_NODE_OPTIONS_H |