Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:45:13

0001 /*
0002  * SPDX-FileCopyrightText: Copyright (c) 2020-2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
0003  * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0004  *
0005  * Licensed under the Apache License, Version 2.0 (the "License");
0006  * you may not use this file except in compliance with the License.
0007  * You may obtain a copy of the License at
0008  *
0009  *     http://www.apache.org/licenses/LICENSE-2.0
0010  *
0011  * Unless required by applicable law or agreed to in writing, software
0012  * distributed under the License is distributed on an "AS IS" BASIS,
0013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014  * See the License for the specific language governing permissions and
0015  * limitations under the License.
0016  *
0017  * Licensed under the Apache License v2.0 with LLVM Exceptions.
0018  * See https://nvidia.github.io/NVTX/LICENSE.txt for license information.
0019  */
0020 
0021 #if defined(NVTX_AS_SYSTEM_HEADER)
0022 #if defined(__clang__)
0023 #pragma clang system_header
0024 #elif defined(__GNUC__) || defined(__NVCOMPILER)
0025 #pragma GCC system_header
0026 #elif defined(_MSC_VER)
0027 #pragma system_header
0028 #endif
0029 #endif
0030 
0031 /* Temporary helper #defines, #undef'ed at end of header */
0032 #define NVTX3_CPP_VERSION_MAJOR 1
0033 #define NVTX3_CPP_VERSION_MINOR 1
0034 
0035 /* This section handles the decision of whether to provide unversioned symbols.
0036  * If NVTX3_CPP_REQUIRE_EXPLICIT_VERSION is #defined, unversioned symbols are
0037  * not provided, and explicit-version symbols such as nvtx3::v1::scoped_range
0038  * and NVTX3_V1_FUNC_RANGE must be used.  By default, the first #include of this
0039  * header will define the unversioned symbols such as nvtx3::scoped_range and
0040  * NVTX3_FUNC_RANGE.  Subsequently including a different major version of this
0041  * header without #defining NVTX3_CPP_REQUIRE_EXPLICIT_VERSION triggers an error
0042  * since the symbols would conflict.  Subsequently including of a different
0043  * minor version within the same major version is allowed. Functionality of
0044  * minor versions is cumulative, regardless of include order.
0045  *
0046  * Since NVTX3_CPP_REQUIRE_EXPLICIT_VERSION allows all combinations of versions
0047  * to coexist without problems within a translation unit, the recommended best
0048  * practice for instrumenting header-based libraries with NVTX C++ Wrappers is
0049  * is to #define NVTX3_CPP_REQUIRE_EXPLICIT_VERSION before including nvtx3.hpp,
0050  * #undef it afterward, and only use explicit-version symbols.  This is not
0051  * necessary in common cases, such as instrumenting a standalone application, or
0052  * static/shared libraries in .cpp files or headers private to those projects.
0053  */
0054 /* clang-format off */
0055 #if !defined(NVTX3_CPP_REQUIRE_EXPLICIT_VERSION)
0056   /* Define macro used by all definitions in this header to indicate the
0057    * unversioned symbols should be defined in addition to the versioned ones.
0058    */
0059   #define NVTX3_INLINE_THIS_VERSION
0060 
0061   #if !defined(NVTX3_CPP_INLINED_VERSION_MAJOR)
0062     /* First occurrence of this header in the translation unit.  Define macros
0063      * indicating which version shall be used for unversioned symbols.
0064      */
0065 
0066     /**
0067      * @brief Semantic major version number for NVTX C++ wrappers of unversioned symbols
0068      *
0069      * Breaking changes may occur between major versions, and different major versions
0070      * cannot provide unversioned symbols in the same translation unit (.cpp file).
0071      *
0072      * Note: If NVTX3_CPP_REQUIRE_EXPLICIT_VERSION is defined, this macro is not defined.
0073      *
0074      * Not to be confused with the version number of the NVTX core library.
0075      */
0076     #define NVTX3_CPP_INLINED_VERSION_MAJOR 1  // NVTX3_CPP_VERSION_MAJOR
0077 
0078     /**
0079      * @brief Semantic minor version number for NVTX C++ wrappers of unversioned symbols
0080      *
0081      * No breaking changes occur between minor versions -- minor version changes within
0082      * a major version are purely additive.
0083      *
0084      * Note: If NVTX3_CPP_REQUIRE_EXPLICIT_VERSION is defined, this macro is not defined.
0085      *
0086      * Not to be confused with the version number of the NVTX core library.
0087      */
0088     #define NVTX3_CPP_INLINED_VERSION_MINOR 1  // NVTX3_CPP_VERSION_MINOR
0089   #elif NVTX3_CPP_INLINED_VERSION_MAJOR != NVTX3_CPP_VERSION_MAJOR
0090     /* Unsupported case -- cannot define unversioned symbols for different major versions
0091      * in the same translation unit.
0092      */
0093     #error \
0094       "Two different major versions of the NVTX C++ Wrappers are being included in a single .cpp file, with unversioned symbols enabled in both.  Only one major version can enable unversioned symbols in a .cpp file.  To disable unversioned symbols, #define NVTX3_CPP_REQUIRE_EXPLICIT_VERSION before #including nvtx3.hpp, and use the explicit-version symbols instead -- this is the preferred way to use nvtx3.hpp from a header file."
0095   #elif (NVTX3_CPP_INLINED_VERSION_MAJOR == NVTX3_CPP_VERSION_MAJOR) && \
0096     (NVTX3_CPP_INLINED_VERSION_MINOR < NVTX3_CPP_VERSION_MINOR)
0097     /* An older minor version of the same major version already defined unversioned
0098      * symbols.  The new features provided in this header will be inlined
0099      * redefine the minor version macro to this header's version.
0100      */
0101     #undef NVTX3_CPP_INLINED_VERSION_MINOR
0102     #define NVTX3_CPP_INLINED_VERSION_MINOR 1  // NVTX3_CPP_VERSION_MINOR
0103     // else, already have this version or newer, nothing to do
0104   #endif
0105 #endif
0106 /* clang-format on */
0107 
0108 /**
0109  * @file nvtx3.hpp
0110  *
0111  * @brief Provides C++ constructs making the NVTX library safer and easier to
0112  * use with zero overhead.
0113  */
0114 
0115 /**
0116  * \mainpage
0117  * \tableofcontents
0118  *
0119  * \section QUICK_START Quick Start
0120  *
0121  * To add NVTX ranges to your code, use the `nvtx3::scoped_range` RAII object. A
0122  * range begins when the object is created, and ends when the object is
0123  * destroyed.
0124  *
0125  * \code{.cpp}
0126  * #include "nvtx3/nvtx3.hpp"
0127  * void some_function() {
0128  *    // Begins a NVTX range with the message "some_function"
0129  *    // The range ends when some_function() returns and `r` is destroyed
0130  *    nvtx3::scoped_range r{"some_function"};
0131  *
0132  *    for(int i = 0; i < 5; ++i) {
0133  *       nvtx3::scoped_range loop{"loop range"};
0134  *       std::this_thread::sleep_for(std::chrono::seconds{1});
0135  *    }
0136  * } // Range ends when `r` is destroyed
0137  * \endcode
0138  *
0139  * The example code above generates the following timeline view in Nsight
0140  * Systems:
0141  *
0142  * \image html
0143  * https://raw.githubusercontent.com/NVIDIA/NVTX/release-v3/docs/images/example_range.png
0144  *
0145  * Alternatively, use the \ref MACROS like `NVTX3_FUNC_RANGE()` to add
0146  * ranges to your code that automatically use the name of the enclosing function
0147  * as the range's message.
0148  *
0149  * \code{.cpp}
0150  * #include "nvtx3/nvtx3.hpp"
0151  * void some_function() {
0152  *    // Creates a range with a message "some_function" that ends when the
0153  *    // enclosing function returns
0154  *    NVTX3_FUNC_RANGE();
0155  *    ...
0156  * }
0157  * \endcode
0158  *
0159  *
0160  * \section Overview
0161  *
0162  * The NVTX library provides a set of functions for users to annotate their code
0163  * to aid in performance profiling and optimization. These annotations provide
0164  * information to tools like Nsight Systems to improve visualization of
0165  * application timelines.
0166  *
0167  * \ref RANGES are one of the most commonly used NVTX constructs for annotating
0168  * a span of time. For example, imagine a user wanted to see every time a
0169  * function, `my_function`, is called and how long it takes to execute. This can
0170  * be accomplished with an NVTX range created on the entry to the function and
0171  * terminated on return from `my_function` using the push/pop C APIs:
0172  *
0173  * \code{.cpp}
0174  * void my_function(...) {
0175  *    nvtxRangePushA("my_function"); // Begins NVTX range
0176  *    // do work
0177  *    nvtxRangePop(); // Ends NVTX range
0178  * }
0179  * \endcode
0180  *
0181  * One of the challenges with using the NVTX C API is that it requires manually
0182  * terminating the end of the range with `nvtxRangePop`. This can be challenging
0183  * if `my_function()` has multiple returns or can throw exceptions as it
0184  * requires calling `nvtxRangePop()` before all possible return points.
0185  *
0186  * NVTX C++ solves this inconvenience through the "RAII" technique by providing
0187  * a `nvtx3::scoped_range` class that begins a range at construction and ends
0188  * the range on destruction. The above example then becomes:
0189  *
0190  * \code{.cpp}
0191  * void my_function(...) {
0192  *    nvtx3::scoped_range r{"my_function"}; // Begins NVTX range
0193  *    // do work
0194  * } // Range ends on exit from `my_function` when `r` is destroyed
0195  * \endcode
0196  *
0197  * The range object `r` is deterministically destroyed whenever `my_function`
0198  * returns---ending the NVTX range without manual intervention. For more
0199  * information, see \ref RANGES and `nvtx3::scoped_range_in`.
0200  *
0201  * Another inconvenience of the NVTX C APIs are the several constructs where the
0202  * user is expected to initialize an object at the beginning of an application
0203  * and reuse that object throughout the lifetime of the application. For example
0204  * see domains, categories, and registered messages.
0205  *
0206  * Example:
0207  * \code{.cpp}
0208  * nvtxDomainHandle_t D = nvtxDomainCreateA("my domain");
0209  * // Reuse `D` throughout the rest of the application
0210  * \endcode
0211  *
0212  * This can be problematic if the user application or library does not have an
0213  * explicit initialization function called before all other functions to
0214  * ensure that these long-lived objects are initialized before being used.
0215  *
0216  * NVTX C++ makes use of the "construct on first use" technique to alleviate
0217  * this inconvenience. In short, a function local static object is constructed
0218  * upon the first invocation of a function and returns a reference to that
0219  * object on all future invocations. See the documentation for `nvtx3::domain`,
0220  * `nvtx3::named_category`, `nvtx3::registered_string`, and
0221  * https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use for more
0222  * information.
0223  *
0224  * Using construct on first use, the above example becomes:
0225  * \code{.cpp}
0226  * struct my_domain{ static constexpr char const* name{"my domain"}; };
0227  *
0228  * // The first invocation of `domain::get` for the type `my_domain` will
0229  * // construct a `nvtx3::domain` object and return a reference to it. Future
0230  * // invocations simply return a reference.
0231  * nvtx3::domain const& D = nvtx3::domain::get<my_domain>();
0232  * \endcode
0233  * For more information about NVTX and how it can be used, see
0234  * https://docs.nvidia.com/cuda/profiler-users-guide/index.html#nvtx and
0235  * https://devblogs.nvidia.com/cuda-pro-tip-generate-custom-application-profile-timelines-nvtx/
0236  * for more information.
0237  *
0238  * \section RANGES Ranges
0239  *
0240  * Ranges are used to describe a span of time during the execution of an
0241  * application. Common examples are using ranges to annotate the time it takes
0242  * to execute a function or an iteration of a loop.
0243  *
0244  * NVTX C++ uses RAII to automate the generation of ranges that are tied to the
0245  * lifetime of objects. Similar to `std::lock_guard` in the C++ Standard
0246  * Template Library.
0247  *
0248  * \subsection scoped_range Scoped Range
0249  *
0250  * `nvtx3::scoped_range_in` is a class that begins a range upon construction
0251  * and ends the range at destruction. This is one of the most commonly used
0252  * constructs in NVTX C++ and is useful for annotating spans of time on a
0253  * particular thread. These ranges can be nested to arbitrary depths.
0254  *
0255  * `nvtx3::scoped_range` is an alias for a `nvtx3::scoped_range_in` in the
0256  * global NVTX domain. For more information about Domains, see \ref DOMAINS.
0257  *
0258  * Various attributes of a range can be configured constructing a
0259  * `nvtx3::scoped_range_in` with a `nvtx3::event_attributes` object. For
0260  * more information, see \ref ATTRIBUTES.
0261  *
0262  * Example:
0263  *
0264  * \code{.cpp}
0265  * void some_function() {
0266  *    // Creates a range for the duration of `some_function`
0267  *    nvtx3::scoped_range r{};
0268  *
0269  *    while(true) {
0270  *       // Creates a range for every loop iteration
0271  *       // `loop_range` is nested inside `r`
0272  *       nvtx3::scoped_range loop_range{};
0273  *    }
0274  * }
0275  * \endcode
0276  *
0277  * \subsection unique_range Unique Range
0278  *
0279  * `nvtx3::unique_range` is similar to `nvtx3::scoped_range`, with a few key differences:
0280  * - `unique_range` objects can be destroyed in any order whereas `scoped_range` objects must be
0281  *    destroyed in exact reverse creation order
0282  * - `unique_range` can start and end on different threads
0283  * - `unique_range` is movable
0284  * - `unique_range` objects can be constructed as heap objects
0285  *
0286  * There is extra overhead associated with `unique_range` constructs and therefore use of
0287  * `nvtx3::scoped_range_in` should be preferred.
0288  *
0289  * \section MARKS Marks
0290  *
0291  * `nvtx3::mark` annotates an instantaneous point in time with a "marker".
0292  *
0293  * Unlike a "range" which has a beginning and an end, a marker is a single event
0294  * in an application, such as detecting a problem:
0295  *
0296  * \code{.cpp}
0297  * bool success = do_operation(...);
0298  * if (!success) {
0299  *    nvtx3::mark("operation failed!");
0300  * }
0301  * \endcode
0302  *
0303  * \section DOMAINS Domains
0304  *
0305  * Similar to C++ namespaces, domains allow for scoping NVTX events. By default,
0306  * all NVTX events belong to the "global" domain. Libraries and applications
0307  * should scope their events to use a custom domain to differentiate where the
0308  * events originate from.
0309  *
0310  * It is common for a library or application to have only a single domain and
0311  * for the name of that domain to be known at compile time. Therefore, Domains
0312  * in NVTX C++ are represented by _tag types_.
0313  *
0314  * For example, to define a custom domain, simply define a new concrete type
0315  * (a `class` or `struct`) with a `static` member called `name` that contains
0316  * the desired name of the domain.
0317  *
0318  * \code{.cpp}
0319  * struct my_domain{ static constexpr char const* name{"my domain"}; };
0320  * \endcode
0321  *
0322  * For any NVTX C++ construct that can be scoped to a domain, the type
0323  * `my_domain` can be passed as an explicit template argument to scope it to
0324  * the custom domain.
0325  *
0326  * The tag type `nvtx3::domain::global` represents the global NVTX domain.
0327  *
0328  * \code{.cpp}
0329  * // By default, `scoped_range_in` belongs to the global domain
0330  * nvtx3::scoped_range_in<> r0{};
0331  *
0332  * // Alias for a `scoped_range_in` in the global domain
0333  * nvtx3::scoped_range r1{};
0334  *
0335  * // `r` belongs to the custom domain
0336  * nvtx3::scoped_range_in<my_domain> r{};
0337  * \endcode
0338  *
0339  * When using a custom domain, it is recommended to define type aliases for NVTX
0340  * constructs in the custom domain.
0341  * \code{.cpp}
0342  * using my_scoped_range = nvtx3::scoped_range_in<my_domain>;
0343  * using my_registered_string = nvtx3::registered_string_in<my_domain>;
0344  * using my_named_category = nvtx3::named_category_in<my_domain>;
0345  * \endcode
0346  *
0347  * See `nvtx3::domain` for more information.
0348  *
0349  * \section ATTRIBUTES Event Attributes
0350  *
0351  * NVTX events can be customized with various attributes to provide additional
0352  * information (such as a custom message) or to control visualization of the
0353  * event (such as the color used). These attributes can be specified per-event
0354  * via arguments to a `nvtx3::event_attributes` object.
0355  *
0356  * NVTX events can be customized via five "attributes":
0357  * - \ref COLOR : color used to visualize the event in tools.
0358  * - \ref MESSAGES :  Custom message string.
0359  * - \ref PAYLOAD :  User-defined numerical value.
0360  * - \ref PAYLOAD_DATA : User-defined structured data (exclusive of payload).
0361  * - \ref CATEGORY : Intra-domain grouping.
0362  *
0363  * It is possible to construct a `nvtx3::event_attributes` from any number of
0364  * attribute objects (nvtx3::color, nvtx3::message, nvtx3::payload,
0365  * nvtx3::category, nvtx3::payload_data, or a container of nvtx3::payload_data)
0366  * in any order. If an attribute is not specified, a tool specific default value
0367  * is used. See `nvtx3::event_attributes` for more information.
0368  *
0369  * \code{.cpp}
0370  * // Set message, same as passing nvtx3::message{"message"}
0371  * nvtx3::event_attributes attr{"message"};
0372  *
0373  * // Set message and color
0374  * nvtx3::event_attributes attr{"message", nvtx3::rgb{127, 255, 0}};
0375  *
0376  * // Set message, color, payload, category
0377  * nvtx3::event_attributes attr{"message",
0378  *                              nvtx3::rgb{127, 255, 0},
0379  *                              nvtx3::payload{42},
0380  *                              nvtx3::category{1}};
0381  *
0382  * // Same as above -- can use any order of arguments
0383  * nvtx3::event_attributes attr{nvtx3::payload{42},
0384  *                              nvtx3::category{1},
0385  *                              "message",
0386  *                              nvtx3::rgb{127, 255, 0}};
0387  *
0388  * // Multiple arguments of the same type are allowed, but only the first is
0389  * // used -- in this example, payload is set to 42:
0390  * nvtx3::event_attributes attr{ nvtx3::payload{42}, nvtx3::payload{7} };
0391  * // payload and payload_data should not be used together.
0392  *
0393  * // Using the nvtx3 namespace in a local scope makes the syntax more succinct:
0394  * using namespace nvtx3;
0395  * event_attributes attr{"message", rgb{127, 255, 0}, payload{42}, category{1}};
0396  * \endcode
0397  *
0398  * \subsection MESSAGES message
0399  *
0400  * `nvtx3::message` sets the message string for an NVTX event.
0401  *
0402  * Example:
0403  * \code{.cpp}
0404  * // Create an `event_attributes` with the message "my message"
0405  * nvtx3::event_attributes attr{nvtx3::message{"my message"}};
0406  *
0407  * // strings and string literals implicitly assumed to be a `nvtx3::message`
0408  * nvtx3::event_attributes attr{"my message"};
0409  * \endcode
0410  *
0411  * \subsubsection REGISTERED_MESSAGE Registered Messages
0412  *
0413  * Associating a `nvtx3::message` with an event requires copying the contents of
0414  * the message every time the message is used, i.e., copying the entire message
0415  * string. This may cause non-trivial overhead in performance sensitive code.
0416  *
0417  * To eliminate this overhead, NVTX allows registering a message string,
0418  * yielding a "handle" that is inexpensive to copy that may be used in place of
0419  * a message string. When visualizing the events, tools such as Nsight Systems
0420  * will take care of mapping the message handle to its string.
0421  *
0422  * A message should be registered once and the handle reused throughout the rest
0423  * of the application. This can be done by either explicitly creating static
0424  * `nvtx3::registered_string` objects, or using the
0425  * `nvtx3::registered_string::get` construct on first use helper (recommended).
0426  *
0427  * Similar to \ref DOMAINS, `nvtx3::registered_string::get` requires defining a
0428  * custom tag type with a static `message` member whose value will be the
0429  * contents of the registered string.
0430  *
0431  * Example:
0432  * \code{.cpp}
0433  * // Explicitly constructed, static `registered_string` in my_domain:
0434  * static registered_string_in<my_domain> static_message{"my message"};
0435  *
0436  * // Or use construct on first use:
0437  * // Define a tag type with a `message` member string to register
0438  * struct my_message{ static constexpr char const* message{ "my message" }; };
0439  *
0440  * // Uses construct on first use to register the contents of
0441  * // `my_message::message`
0442  * auto& msg = nvtx3::registered_string_in<my_domain>::get<my_message>();
0443  * \endcode
0444  *
0445  * A `nvtx3::registered_string_in` can also be used inside of a struct for
0446  * `nvtx3::payload_data` using `TYPE_NVTX_REGISTERED_STRING_HANDLE`.
0447  *
0448  * \code{.cpp}
0449  *
0450  * \endcode
0451  *
0452  * \subsection COLOR color
0453  *
0454  * Associating a `nvtx3::color` with an event allows controlling how the event
0455  * is visualized in a tool such as Nsight Systems. This is a convenient way to
0456  * visually differentiate among different events.
0457  *
0458  * \code{.cpp}
0459  * // Define a color via rgb color values
0460  * nvtx3::color c{nvtx3::rgb{127, 255, 0}};
0461  * nvtx3::event_attributes attr{c};
0462  *
0463  * // rgb color values can be passed directly to an `event_attributes`
0464  * nvtx3::event_attributes attr1{nvtx3::rgb{127,255,0}};
0465  * \endcode
0466  *
0467  * \subsection CATEGORY category
0468  *
0469  * A `nvtx3::category` is simply an integer id that allows for fine-grain
0470  * grouping of NVTX events. For example, one might use separate categories for
0471  * IO, memory allocation, compute, etc.
0472  *
0473  * \code{.cpp}
0474  * nvtx3::event_attributes{nvtx3::category{1}};
0475  * \endcode
0476  *
0477  * \subsubsection NAMED_CATEGORIES Named Categories
0478  *
0479  * Associates a `name` string with a category `id` to help differentiate among
0480  * categories.
0481  *
0482  * For any given category id `Id`, a `named_category{Id, "name"}` should only
0483  * be constructed once and reused throughout an application. This can be done by
0484  * either explicitly creating static `nvtx3::named_category` objects, or using
0485  * the `nvtx3::named_category::get` construct on first use helper (recommended).
0486  *
0487  * Similar to \ref DOMAINS, `nvtx3::named_category::get` requires defining a
0488  * custom tag type with static `name` and `id` members.
0489  *
0490  * \code{.cpp}
0491  * // Explicitly constructed, static `named_category` in my_domain:
0492  * static nvtx3::named_category_in<my_domain> static_category{42, "my category"};
0493  *
0494  * // Or use construct on first use:
0495  * // Define a tag type with `name` and `id` members
0496  * struct my_category {
0497  *    static constexpr char const* name{"my category"}; // category name
0498  *    static constexpr uint32_t id{42}; // category id
0499  * };
0500  *
0501  * // Use construct on first use to name the category id `42`
0502  * // with name "my category":
0503  * auto& cat = named_category_in<my_domain>::get<my_category>();
0504  *
0505  * // Range `r` associated with category id `42`
0506  * nvtx3::event_attributes attr{cat};
0507  * \endcode
0508  *
0509  * \subsection PAYLOAD payload
0510  *
0511  * Allows associating a user-defined numerical value with an event.
0512  *
0513  * \code{.cpp}
0514  * // Constructs a payload from the `int32_t` value 42
0515  * nvtx3:: event_attributes attr{nvtx3::payload{42}};
0516  * \endcode
0517  *
0518  * \subsection PAYLOAD_DATA payload_data
0519  *
0520  * `nvtx3::payload_data` allows associating arbitrary structured data with an NVTX event.
0521  *
0522  * First, define a `struct` that is *standard-layout* and *trivially copyable*.
0523  * Then use `NVTX3_DEFINE_SCHEMA_GET` (`NVTX3_V1_DEFINE_SCHEMA_GET()`) to define the schema layout.
0524  * Finally you can use any such instance wrapped in `nvtx3::payload_data` in an
0525  * `nvtx3::event_attributes` object.
0526  * You can also pass containers (e.g., `std::vector`, `std::array`) of `payload_data` objects.
0527  * \note Constructing `nvtx3::payload_data` from temporaries or using tempoarary
0528  * `nvtx3::payload_data` objects is disabled to prevent dangling pointers.
0529  *
0530  * \section EXAMPLE Example
0531  *
0532  * Putting it all together:
0533  * \code{.cpp}
0534  * // Define a custom domain tag type
0535  * struct my_domain{ static constexpr char const* name{"my domain"}; };
0536  *
0537  * // Define a named category tag type
0538  * struct my_category{
0539  *    static constexpr char const* name{"my category"};
0540  *    static constexpr uint32_t id{42};
0541  * };
0542  *
0543  * // Define a registered string tag type
0544  * struct my_message{ static constexpr char const* message{"my message"}; };
0545  *
0546  * // For convenience, use aliases for domain scoped objects
0547  * using my_scoped_range = nvtx3::scoped_range_in<my_domain>;
0548  * using my_registered_string = nvtx3::registered_string_in<my_domain>;
0549  * using my_named_category = nvtx3::named_category_in<my_domain>;
0550  *
0551  * // Custom payload data
0552  * struct my_payload_data {
0553  *     uint32_t iteration;
0554  *     float    temperature;
0555  * };
0556  * NVTX3_DEFINE_SCHEMA_GET(
0557  *     my_domain,
0558  *     my_payload_data,
0559  *     "MyPayloadData",
0560  *     NVTX_PAYLOAD_ENTRIES((iteration, TYPE_UINT32, "Iteration Count"),
0561  *                          (temperature, TYPE_FLOAT, "Temperature"))
0562  * )
0563  *
0564  * // Default values for all attributes
0565  * nvtx3::event_attributes attr{};
0566  * my_scoped_range r0{attr};
0567  *
0568  * // Custom (unregistered) message, and unnamed category
0569  * nvtx3::event_attributes attr1{"message", nvtx3::category{2}};
0570  * my_scoped_range r1{attr1};
0571  *
0572  * // Alternatively, pass arguments of `event_attributes` constructor directly
0573  * // to `my_scoped_range`
0574  * my_scoped_range r2{"message", nvtx3::category{2}};
0575  *
0576  * // construct on first use a registered string
0577  * auto& msg = my_registered_string::get<my_message>();
0578  *
0579  * // construct on first use a named category
0580  * auto& cat = my_named_category::get<my_category>();
0581  *
0582  * // Use registered string and named category with a custom payload
0583  * my_scoped_range r3{msg, cat, nvtx3::payload{42}};
0584  *
0585  * // Use custom payload data
0586  * my_payload_data extras{42, 0.7f};
0587  * nvtx3::payload_data pd{extras};
0588  * my_scoped_range r4{pd};
0589  *
0590  * // Use a container of payload_data, can use different struct types
0591  * auto multiple = std::to_array({pd, pd2});
0592  * my_scoped_range r5{multiple};
0593  *
0594  * // Any number of arguments in any order
0595  * my_scoped_range r{nvtx3::rgb{127, 255, 0}, msg};
0596  *
0597  * \endcode
0598  * \section MACROS Convenience Macros
0599  *
0600  * Oftentimes users want to quickly and easily add NVTX ranges to their library
0601  * or application to aid in profiling and optimization.
0602  *
0603  * A convenient way to do this is to use the \ref NVTX3_FUNC_RANGE and
0604  * \ref NVTX3_FUNC_RANGE_IN macros. These macros take care of constructing an
0605  * `nvtx3::scoped_range_in` with the name of the enclosing function as the
0606  * range's message.
0607  *
0608  * \code{.cpp}
0609  * void some_function() {
0610  *    // Automatically generates an NVTX range for the duration of the function
0611  *    // using "some_function" as the event's message.
0612  *    NVTX3_FUNC_RANGE();
0613  * }
0614  * \endcode
0615  *
0616  */
0617 
0618 /* Temporary helper #defines, removed with #undef at end of header */
0619 
0620 /* Some compilers do not correctly support SFINAE, which is used in this API
0621  * to detect common usage errors and provide clearer error messages (by using
0622  * static_assert) than the compiler would produce otherwise.  These compilers
0623  * will generate errors while compiling this file such as:
0624  *
0625  *  error: 'name' is not a member of 'nvtx3::v1::domain::global'
0626  *
0627  * The following compiler versions are known to have this problem, and so are
0628  * set by default to disable the SFINAE-based checks:
0629  *
0630  * - All MSVC versions prior to VS2017 Update 7 (15.7)
0631  * - GCC 8.1-8.3 (the problem was fixed in GCC 8.4)
0632  *
0633  * If you find your compiler hits this problem, you can work around it by
0634  * defining NVTX3_USE_CHECKED_OVERLOADS_FOR_GET to 0 before including this
0635  * header, or you can add a check for your compiler version to this #if.
0636  * Also, please report the issue on the NVTX GitHub page.
0637  */
0638 #if !defined(NVTX3_USE_CHECKED_OVERLOADS_FOR_GET)
0639 #if defined(_MSC_VER) && _MSC_VER < 1914 \
0640   || defined(__GNUC__) && __GNUC__ == 8 && __GNUC_MINOR__ < 4
0641 #define NVTX3_USE_CHECKED_OVERLOADS_FOR_GET 0
0642 #else
0643 #define NVTX3_USE_CHECKED_OVERLOADS_FOR_GET 1
0644 #endif
0645 #define NVTX3_USE_CHECKED_OVERLOADS_FOR_GET_DEFINED_HERE
0646 #endif
0647 
0648 /* Within this header, nvtx3::NVTX3_VERSION_NAMESPACE resolves to nvtx3::vX,
0649  * where "X" is the major version number. */
0650 #define NVTX3_CONCAT(A, B) A##B
0651 #define NVTX3_NAMESPACE_FOR(VERSION) NVTX3_CONCAT(v, VERSION)
0652 #define NVTX3_VERSION_NAMESPACE NVTX3_NAMESPACE_FOR(NVTX3_CPP_VERSION_MAJOR)
0653 /* We use a different prefix to avoid ambiguity with the version namespace */
0654 #define NVTX3_MINOR_NAMESPACE_FOR(VERSION) NVTX3_CONCAT(mv, VERSION)
0655 #define NVTX3_MINOR_VERSION_NAMESPACE NVTX3_MINOR_NAMESPACE_FOR(NVTX3_CPP_VERSION_MINOR)
0656 
0657 /* Avoid duplicating #if defined(NVTX3_INLINE_THIS_VERSION) for namespaces
0658  * in each minor version by making a macro to use unconditionally, which
0659  * resolves to "inline" or nothing as appropriate. */
0660 #if defined(NVTX3_INLINE_THIS_VERSION)
0661 #define NVTX3_INLINE_IF_REQUESTED inline
0662 #else
0663 #define NVTX3_INLINE_IF_REQUESTED
0664 #endif
0665 
0666 /* Enables the use of constexpr when support for C++14 constexpr is present.
0667  *
0668  * Initialization of a class member that is a union to a specific union member
0669  * can only be done in the body of a constructor, not in a member initializer
0670  * list.  A constexpr constructor must have an empty body until C++14, so there
0671  * is no way to make an initializer of a member union constexpr in C++11.  This
0672  * macro allows making functions constexpr in C++14 or newer, but non-constexpr
0673  * in C++11 compilation.  It is used here on constructors that initialize their
0674  * member unions.
0675  */
0676 #if __cpp_constexpr >= 201304L
0677 #define NVTX3_CONSTEXPR_IF_CPP14 constexpr
0678 #else
0679 #define NVTX3_CONSTEXPR_IF_CPP14
0680 #endif
0681 
0682 /* Enables the use of constexpr when support for C++20 constexpr is present.
0683  */
0684 #if __cplusplus >= 202002L
0685 #define NVTX3_CONSTEXPR_IF_CPP20 constexpr
0686 #else
0687 #define NVTX3_CONSTEXPR_IF_CPP20
0688 #endif
0689 
0690 // Macro wrappers for C++ attributes
0691 #if !defined(__has_cpp_attribute)
0692 #define __has_cpp_attribute(x) 0
0693 #endif
0694 #if __has_cpp_attribute(maybe_unused)
0695 #define NVTX3_MAYBE_UNUSED [[maybe_unused]]
0696 #else
0697 #define NVTX3_MAYBE_UNUSED
0698 #endif
0699 #if __has_cpp_attribute(nodiscard)
0700 #define NVTX3_NO_DISCARD [[nodiscard]]
0701 #else
0702 #define NVTX3_NO_DISCARD
0703 #endif
0704 
0705  /* Use a macro for static asserts, which defaults to static_assert, but that
0706   * testing tools can replace with a logging function.  For example:
0707   * #define NVTX3_STATIC_ASSERT(c, m) \
0708   *   do { if (!(c)) printf("static_assert would fail: %s\n", m); } while (0)
0709   */
0710 #if !defined(NVTX3_STATIC_ASSERT)
0711 #define NVTX3_STATIC_ASSERT(condition, message) static_assert(condition, message)
0712 #define NVTX3_STATIC_ASSERT_DEFINED_HERE
0713 #endif
0714 
0715 /* Implementation sections, enclosed in guard macros for each minor version */
0716 
0717 #ifndef NVTX3_CPP_DEFINITIONS_V1_0
0718 #define NVTX3_CPP_DEFINITIONS_V1_0
0719 
0720 #include "nvToolsExt.h"
0721 #include "nvToolsExtPayload.h"
0722 #include "nvToolsExtPayloadHelper.h"
0723 
0724 #include <memory>
0725 #include <string>
0726 #include <type_traits>
0727 #include <utility>
0728 #include <cstddef>
0729 #include <cstdint>
0730 
0731 namespace nvtx3 {
0732 
0733 NVTX3_INLINE_IF_REQUESTED namespace NVTX3_VERSION_NAMESPACE
0734 {
0735 inline namespace NVTX3_MINOR_VERSION_NAMESPACE
0736 {
0737 
0738 namespace detail {
0739 
0740 template <typename Unused>
0741 struct always_false : std::false_type {};
0742 
0743 template <typename T, typename = void>
0744 struct has_name : std::false_type {};
0745 template <typename T>
0746 struct has_name<T, decltype((void)T::name, void())> : std::true_type {};
0747 
0748 template <typename T, typename = void>
0749 struct has_id : std::false_type {};
0750 template <typename T>
0751 struct has_id<T, decltype((void)T::id, void())> : std::true_type {};
0752 
0753 template <typename T, typename = void>
0754 struct has_message : std::false_type {};
0755 template <typename T>
0756 struct has_message<T, decltype((void)T::message, void())> : std::true_type {};
0757 
0758 template <typename T, typename = void>
0759 struct is_c_string : std::false_type {};
0760 template <typename T>
0761 struct is_c_string<T, typename std::enable_if<
0762   std::is_convertible<T, char const*   >::value ||
0763   std::is_convertible<T, wchar_t const*>::value
0764 >::type> : std::true_type {};
0765 
0766 template <typename T>
0767 using is_uint32 = std::is_same<typename std::decay<T>::type, uint32_t>;
0768 
0769 template <typename... Args>
0770 static inline void silence_unused(Args const&...) noexcept {}
0771 
0772 // Type trait to check for a .data() member returning T* or const T*
0773 // Some day, we can just use std::span
0774 template <typename T, typename TD>
0775 struct has_data_member
0776 {
0777 private:
0778     template <typename U>
0779     static auto test_data(int) -> decltype(std::declval<const U>().data());
0780     template <typename>
0781     static auto test_data(...) -> void;
0782     using return_type = decltype(test_data<T>(0));
0783 
0784 public:
0785     static constexpr bool value =
0786         std::is_same<return_type, TD*>::value || std::is_same<return_type, TD const*>::value;
0787 };
0788 
0789 // Type trait to check for a .size() member returning something convertible to size_t
0790 template <typename T>
0791 struct has_size_member
0792 {
0793 private:
0794     template <typename U>
0795     static auto test_size(int) -> decltype(std::declval<const U>().size());
0796     template <typename>
0797     static auto test_size(...) -> void;
0798     using return_type = decltype(test_size<T>(0));
0799 
0800 public:
0801     static constexpr bool value = !std::is_same<return_type, void>::value &&
0802                                     std::is_convertible<return_type, size_t>::value;
0803 };
0804 
0805 /**
0806     * To ensure that we can "safely" use one type as another, for pointers, in
0807     * arrays or in structs. This is used for our wrappers around C-types so that
0808     * we can pass them back to C.
0809     *
0810     * This is by no means perfect and foolproof.
0811     *
0812     * @tparam W The wrapper type.
0813     * @tparam U The type it is wrapping.
0814     */
0815 template <typename W, typename U, typename = void>
0816 struct is_safe_wrapper_of : std::false_type
0817 {
0818 };
0819 
0820 template <typename W, typename U>
0821 struct is_safe_wrapper_of<
0822     W,
0823     U,
0824     typename std::enable_if<
0825         std::is_standard_layout<W>::value && std::is_standard_layout<U>::value &&
0826         std::is_trivially_copyable<W>::value && std::is_trivially_copyable<U>::value &&
0827         sizeof(W) == sizeof(U)>::type> : std::true_type
0828 {
0829 };
0830 } // namespace detail
0831 
0832 /**
0833  * @brief `domain`s allow for grouping NVTX events into a single scope to
0834  * differentiate them from events in other `domain`s.
0835  *
0836  * By default, all NVTX constructs are placed in the "global" NVTX domain.
0837  *
0838  * A custom `domain` may be used in order to differentiate a library's or
0839  * application's NVTX events from other events.
0840  *
0841  * `domain`s are expected to be long-lived and unique to a library or
0842  * application. As such, it is assumed a domain's name is known at compile
0843  * time. Therefore, all NVTX constructs that can be associated with a domain
0844  * require the domain to be specified via a *type* `D` passed as an
0845  * explicit template parameter.
0846  *
0847  * The type `domain::global` may be used to indicate that the global NVTX
0848  * domain should be used.
0849  *
0850  * None of the C++ NVTX constructs require the user to manually construct a
0851  * `domain` object. Instead, if a custom domain is desired, the user is
0852  * expected to define a type `D` that contains a member
0853  * `D::name` which resolves to either a `char const*` or `wchar_t
0854  * const*`. The value of `D::name` is used to name and uniquely
0855  * identify the custom domain.
0856  *
0857  * Upon the first use of an NVTX construct associated with the type
0858  * `D`, the "construct on first use" pattern is used to construct a
0859  * function local static `domain` object. All future NVTX constructs
0860  * associated with `D` will use a reference to the previously
0861  * constructed `domain` object. See `domain::get`.
0862  *
0863  * Example:
0864  * \code{.cpp}
0865  * // The type `my_domain` defines a `name` member used to name and identify
0866  * // the `domain` object identified by `my_domain`.
0867  * struct my_domain{ static constexpr char const* name{"my_domain"}; };
0868  *
0869  * // The NVTX range `r` will be grouped with all other NVTX constructs
0870  * // associated with  `my_domain`.
0871  * nvtx3::scoped_range_in<my_domain> r{};
0872  *
0873  * // An alias can be created for a `scoped_range_in` in the custom domain
0874  * using my_scoped_range = nvtx3::scoped_range_in<my_domain>;
0875  * my_scoped_range my_range{};
0876  *
0877  * // `domain::global` indicates that the global NVTX domain is used
0878  * nvtx3::scoped_range_in<domain::global> r2{};
0879  *
0880  * // For convenience, `nvtx3::scoped_range` is an alias for a range in the
0881  * // global domain
0882  * nvtx3::scoped_range r3{};
0883  * \endcode
0884  */
0885 class domain {
0886  public:
0887   domain(domain const&) = delete;
0888   domain& operator=(domain const&) = delete;
0889   domain(domain&&) = delete;
0890   domain& operator=(domain&&) = delete;
0891 
0892   /**
0893    * @brief Tag type for the "global" NVTX domain.
0894    *
0895    * This type may be passed as a template argument to any function/class
0896    * expecting a type to identify a domain to indicate that the global domain
0897    * should be used.
0898    *
0899    * All NVTX events in the global domain across all libraries and
0900    * applications will be grouped together.
0901    *
0902    */
0903   struct global {
0904   };
0905 
0906 #if NVTX3_USE_CHECKED_OVERLOADS_FOR_GET
0907   /**
0908    * @brief Returns reference to an instance of a function local static
0909    * `domain` object.
0910    *
0911    * Uses the "construct on first use" idiom to safely ensure the `domain`
0912    * object is initialized exactly once upon first invocation of
0913    * `domain::get<D>()`. All following invocations will return a
0914    * reference to the previously constructed `domain` object. See
0915    * https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use
0916    *
0917    * None of the constructs in this header require the user to directly invoke
0918    * `domain::get`. It is automatically invoked when constructing objects like
0919    * a `scoped_range_in` or `category`. Advanced users may wish to use
0920    * `domain::get` for the convenience of the "construct on first use" idiom
0921    * when using domains with their own use of the NVTX C API.
0922    *
0923    * This function is thread-safe as of C++11. If two or more threads call
0924    * `domain::get<D>` concurrently, exactly one of them is guaranteed
0925    * to construct the `domain` object and the other(s) will receive a
0926    * reference to the object after it is fully constructed.
0927    *
0928    * The domain's name is specified via the type `D` pass as an
0929    * explicit template parameter. `D` is required to contain a
0930    * member `D::name` that resolves to either a `char const*` or
0931    * `wchar_t const*`. The value of `D::name` is used to name and
0932    * uniquely identify the `domain`.
0933    *
0934    * Example:
0935    * \code{.cpp}
0936    * // The type `my_domain` defines a `name` member used to name and identify
0937    * // the `domain` object identified by `my_domain`.
0938    * struct my_domain{ static constexpr char const* name{"my domain"}; };
0939    *
0940    * auto& D1 = domain::get<my_domain>(); // First invocation constructs a
0941    *                                      // `domain` with the name "my domain"
0942    *
0943    * auto& D2 = domain::get<my_domain>(); // Quickly returns reference to
0944    *                                      // previously constructed `domain`.
0945    * \endcode
0946    *
0947    * @tparam D Type that contains a `D::name` member used to
0948    * name the `domain` object.
0949    * @return Reference to the `domain` corresponding to the type `D`.
0950    */
0951   template <typename D = global,
0952     typename std::enable_if<
0953       detail::is_c_string<decltype(D::name)>::value
0954     , int>::type = 0>
0955   NVTX3_NO_DISCARD static domain const& get() noexcept
0956   {
0957     static domain const d(D::name);
0958     return d;
0959   }
0960 
0961   /**
0962    * @brief Overload of `domain::get` to provide a clear compile error when
0963    * `D` has a `name` member that is not directly convertible to either
0964    * `char const*` or `wchar_t const*`.
0965    */
0966   template <typename D = global,
0967     typename std::enable_if<
0968       !detail::is_c_string<decltype(D::name)>::value
0969     , int>::type = 0>
0970   NVTX3_NO_DISCARD static domain const& get() noexcept
0971   {
0972     NVTX3_STATIC_ASSERT(detail::always_false<D>::value,
0973       "Type used to identify an NVTX domain must contain a static constexpr member "
0974       "called 'name' of type const char* or const wchar_t* -- 'name' member is not "
0975       "convertible to either of those types");
0976     static domain const unused;
0977     return unused;  // Function must compile for static_assert to be triggered
0978   }
0979 
0980   /**
0981    * @brief Overload of `domain::get` to provide a clear compile error when
0982    * `D` does not have a `name` member.
0983    */
0984   template <typename D = global,
0985     typename std::enable_if<
0986       !detail::has_name<D>::value
0987     , int>::type = 0>
0988   NVTX3_NO_DISCARD static domain const& get() noexcept
0989   {
0990     NVTX3_STATIC_ASSERT(detail::always_false<D>::value,
0991       "Type used to identify an NVTX domain must contain a static constexpr member "
0992       "called 'name' of type const char* or const wchar_t* -- 'name' member is missing");
0993     static domain const unused;
0994     return unused;  // Function must compile for static_assert to be triggered
0995   }
0996 #else
0997   template <typename D = global>
0998   NVTX3_NO_DISCARD static domain const& get() noexcept
0999   {
1000     static domain const d(D::name);
1001     return d;
1002   }
1003 #endif
1004 
1005   /**
1006    * @brief Conversion operator to `nvtxDomainHandle_t`.
1007    *
1008    * Allows transparently passing a domain object into an API expecting a
1009    * native `nvtxDomainHandle_t` object.
1010    */
1011   operator nvtxDomainHandle_t() const noexcept { return _domain; }
1012 
1013  private:
1014   /**
1015    * @brief Construct a new domain with the specified `name`.
1016    *
1017    * This constructor is private as it is intended that `domain` objects only
1018    * be created through the `domain::get` function.
1019    *
1020    * @param name A unique name identifying the domain
1021    */
1022   explicit domain(char const* name) noexcept : _domain{nvtxDomainCreateA(name)} {}
1023 
1024   /**
1025    * @brief Construct a new domain with the specified `name`.
1026    *
1027    * This constructor is private as it is intended that `domain` objects only
1028    * be created through the `domain::get` function.
1029    *
1030    * @param name A unique name identifying the domain
1031    */
1032   explicit domain(wchar_t const* name) noexcept : _domain{nvtxDomainCreateW(name)} {}
1033 
1034   /**
1035    * @brief Construct a new domain with the specified `name`.
1036    *
1037    * This constructor is private as it is intended that `domain` objects only
1038    * be created through the `domain::get` function.
1039    *
1040    * @param name A unique name identifying the domain
1041    */
1042   explicit domain(std::string const& name) noexcept : domain{name.c_str()} {}
1043 
1044   /**
1045    * @brief Construct a new domain with the specified `name`.
1046    *
1047    * This constructor is private as it is intended that `domain` objects only
1048    * be created through the `domain::get` function.
1049    *
1050    * @param name A unique name identifying the domain
1051    */
1052   explicit domain(std::wstring const& name) noexcept : domain{name.c_str()} {}
1053 
1054   /**
1055    * @brief Default constructor creates a `domain` representing the
1056    * "global" NVTX domain.
1057    *
1058    * All events not associated with a custom `domain` are grouped in the
1059    * "global" NVTX domain.
1060    *
1061    */
1062   constexpr domain() noexcept {}
1063 
1064   /**
1065    * @brief Intentionally avoid calling nvtxDomainDestroy on the `domain` object.
1066    *
1067    * No currently-available tools attempt to free domain resources when the
1068    * nvtxDomainDestroy function is called, due to the thread-safety and
1069    * efficiency challenges of freeing thread-local storage for other threads.
1070    * Since libraries may be disallowed from introducing static destructors,
1071    * and destroying the domain is likely to have no effect, the destructor
1072    * for `domain` intentionally chooses to not destroy the domain.
1073    *
1074    * In a situation where domain destruction is necessary, either manually
1075    * call nvtxDomainDestroy on the domain's handle, or make a class that
1076    * derives from `domain` and calls nvtxDomainDestroy in its destructor.
1077    */
1078   ~domain() = default;
1079 
1080  private:
1081   nvtxDomainHandle_t const _domain{};  ///< The `domain`s NVTX handle
1082 };
1083 
1084 /**
1085  * @brief Returns reference to the `domain` object that represents the global
1086  * NVTX domain.
1087  *
1088  * This specialization for `domain::global` returns a default constructed,
1089  * `domain` object for use when the "global" domain is desired.
1090  *
1091  * All NVTX events in the global domain across all libraries and applications
1092  * will be grouped together.
1093  *
1094  * @return Reference to the `domain` corresponding to the global NVTX domain.
1095  *
1096  */
1097 template <>
1098 NVTX3_NO_DISCARD inline domain const& domain::get<domain::global>() noexcept
1099 {
1100   static domain const d{};
1101   return d;
1102 }
1103 
1104 /**
1105  * @brief Indicates the values of the red, green, and blue color channels for
1106  * an RGB color to use as an event attribute (assumes no transparency).
1107  *
1108  */
1109 struct rgb {
1110   /// Type used for component values
1111   using component_type = uint8_t;
1112 
1113   /**
1114    * @brief Construct a rgb with red, green, and blue channels
1115    * specified by `red_`, `green_`, and `blue_`, respectively.
1116    *
1117    * Valid values are in the range `[0,255]`.
1118    *
1119    * @param red_ Value of the red channel
1120    * @param green_ Value of the green channel
1121    * @param blue_ Value of the blue channel
1122    */
1123   constexpr rgb(
1124     component_type red_,
1125     component_type green_,
1126     component_type blue_) noexcept
1127     : red{red_}, green{green_}, blue{blue_}
1128   {
1129   }
1130 
1131   component_type red{};    ///< Red channel value
1132   component_type green{};  ///< Green channel value
1133   component_type blue{};   ///< Blue channel value
1134 };
1135 
1136 /**
1137  * @brief Indicates the value of the alpha, red, green, and blue color
1138  * channels for an ARGB color to use as an event attribute.
1139  *
1140  */
1141 struct argb final : rgb {
1142   /**
1143    * @brief Construct an argb with alpha, red, green, and blue channels
1144    * specified by `alpha_`, `red_`, `green_`, and `blue_`, respectively.
1145    *
1146    * Valid values are in the range `[0,255]`.
1147    *
1148    * @param alpha_  Value of the alpha channel (opacity)
1149    * @param red_  Value of the red channel
1150    * @param green_  Value of the green channel
1151    * @param blue_  Value of the blue channel
1152    *
1153    */
1154   constexpr argb(
1155     component_type alpha_,
1156     component_type red_,
1157     component_type green_,
1158     component_type blue_) noexcept
1159     : rgb{red_, green_, blue_}, alpha{alpha_}
1160   {
1161   }
1162 
1163   component_type alpha{};  ///< Alpha channel value
1164 };
1165 
1166 /**
1167  * @brief Represents a custom color that can be associated with an NVTX event
1168  * via its `event_attributes`.
1169  *
1170  * Specifying colors for NVTX events is a convenient way to visually
1171  * differentiate among different events in a visualization tool such as Nsight
1172  * Systems.
1173  *
1174  */
1175 class color {
1176  public:
1177   /// Type used for the color's value
1178   using value_type = uint32_t;
1179 
1180   /**
1181    * @brief Constructs a `color` using the value provided by `hex_code`.
1182    *
1183    * `hex_code` is expected to be a 4 byte argb hex code.
1184    *
1185    * The most significant byte indicates the value of the alpha channel
1186    * (opacity) (0-255)
1187    *
1188    * The next byte indicates the value of the red channel (0-255)
1189    *
1190    * The next byte indicates the value of the green channel (0-255)
1191    *
1192    * The least significant byte indicates the value of the blue channel
1193    * (0-255)
1194    *
1195    * @param hex_code The hex code used to construct the `color`
1196    */
1197   constexpr explicit color(value_type hex_code) noexcept : _value{hex_code} {}
1198 
1199   /**
1200    * @brief Construct a `color` using the alpha, red, green, blue components
1201    * in `argb`.
1202    *
1203    * @param argb_ The alpha, red, green, blue components of the desired `color`
1204    */
1205   constexpr color(argb argb_) noexcept
1206     : color{from_bytes_msb_to_lsb(argb_.alpha, argb_.red, argb_.green, argb_.blue)}
1207   {
1208   }
1209 
1210   /**
1211    * @brief Construct a `color` using the red, green, blue components in
1212    * `rgb`.
1213    *
1214    * Uses maximum value for the alpha channel (opacity) of the `color`.
1215    *
1216    * @param rgb_ The red, green, blue components of the desired `color`
1217    */
1218   constexpr color(rgb rgb_) noexcept
1219     : color{from_bytes_msb_to_lsb(0xFF, rgb_.red, rgb_.green, rgb_.blue)}
1220   {
1221   }
1222 
1223   /**
1224    * @brief Returns the `color`s argb hex code
1225    *
1226    */
1227   constexpr value_type get_value() const noexcept { return _value; }
1228 
1229   /**
1230    * @brief Return the NVTX color type of the color.
1231    *
1232    */
1233   constexpr nvtxColorType_t get_type() const noexcept { return _type; }
1234 
1235   color() = delete;
1236   ~color() = default;
1237   color(color const&) = default;
1238   color& operator=(color const&) = default;
1239   color(color&&) = default;
1240   color& operator=(color&&) = default;
1241 
1242  private:
1243   /**
1244    * @brief Constructs an unsigned, 4B integer from the component bytes in
1245    * most to least significant byte order.
1246    *
1247    */
1248   constexpr static value_type from_bytes_msb_to_lsb(
1249     uint8_t byte3,
1250     uint8_t byte2,
1251     uint8_t byte1,
1252     uint8_t byte0) noexcept
1253   {
1254     return uint32_t{byte3} << 24 | uint32_t{byte2} << 16 | uint32_t{byte1} << 8 | uint32_t{byte0};
1255   }
1256 
1257   value_type _value{};                     ///< color's argb color code
1258   nvtxColorType_t _type{NVTX_COLOR_ARGB};  ///< NVTX color type code
1259 };
1260 
1261 /**
1262  * @brief Object for intra-domain grouping of NVTX events.
1263  *
1264  * A `category` is simply an integer id that allows for fine-grain grouping of
1265  * NVTX events. For example, one might use separate categories for IO, memory
1266  * allocation, compute, etc.
1267  *
1268  * Example:
1269  * \code{.cpp}
1270  * nvtx3::category cat1{1};
1271  *
1272  * // Range `r1` belongs to the category identified by the value `1`.
1273  * nvtx3::scoped_range r1{cat1};
1274  *
1275  * // Range `r2` belongs to the same category as `r1`
1276  * nvtx3::scoped_range r2{nvtx3::category{1}};
1277  * \endcode
1278  *
1279  * To associate a name string with a category id, see `named_category`.
1280  *
1281  */
1282 class category {
1283  public:
1284   /// Type used for `category`s integer id.
1285   using id_type = uint32_t;
1286 
1287   /**
1288    * @brief Construct a `category` with the specified `id`.
1289    *
1290    * The `category` will be unnamed and identified only by its `id` value.
1291    *
1292    * All `category`s in a domain sharing the same `id` are equivalent.
1293    *
1294    * @param[in] id The `category`'s identifying value
1295    */
1296   constexpr explicit category(id_type id) noexcept : id_{id} {}
1297 
1298   /**
1299    * @brief Returns the id of the category.
1300    *
1301    */
1302   constexpr id_type get_id() const noexcept { return id_; }
1303 
1304   category() = delete;
1305   ~category() = default;
1306   category(category const&) = default;
1307   category& operator=(category const&) = default;
1308   category(category&&) = default;
1309   category& operator=(category&&) = default;
1310 
1311  private:
1312   id_type id_{};  ///< category's unique identifier
1313 };
1314 
1315 /**
1316  * @brief A `category` with an associated name string.
1317  *
1318  * Associates a `name` string with a category `id` to help differentiate among
1319  * categories.
1320  *
1321  * For any given category id `Id`, a `named_category(Id, "name")` should only
1322  * be constructed once and reused throughout an application. This can be done
1323  * by either explicitly creating static `named_category` objects, or using the
1324  * `named_category::get` construct on first use helper (recommended).
1325  *
1326  * Creating two or more `named_category` objects with the same value for `id`
1327  * in the same domain results in undefined behavior.
1328  *
1329  * Similarly, behavior is undefined when a `named_category` and `category`
1330  * share the same value of `id`.
1331  *
1332  * Example:
1333  * \code{.cpp}
1334  * // Explicitly constructed, static `named_category` in global domain:
1335  * static nvtx3::named_category static_category{42, "my category"};
1336  *
1337  * // Range `r` associated with category id `42`
1338  * nvtx3::scoped_range r{static_category};
1339  *
1340  * // OR use construct on first use:
1341  *
1342  * // Define a type with `name` and `id` members
1343  * struct my_category {
1344  *    static constexpr char const* name{"my category"}; // category name
1345  *    static constexpr uint32_t id{42}; // category id
1346  * };
1347  *
1348  * // Use construct on first use to name the category id `42`
1349  * // with name "my category"
1350  * auto& cat = named_category_in<my_domain>::get<my_category>();
1351  *
1352  * // Range `r` associated with category id `42`
1353  * nvtx3::scoped_range r{cat};
1354  * \endcode
1355  *
1356  * `named_category_in<D>`'s association of a name to a category id is local to
1357  * the domain specified by the type `D`. An id may have a different name in
1358  * another domain.
1359  *
1360  * @tparam D Type containing `name` member used to identify the `domain` to
1361  * which the `named_category_in` belongs. Else, `domain::global` to indicate
1362  * that the global NVTX domain should be used.
1363  */
1364 template <typename D = domain::global>
1365 class named_category_in final : public category {
1366  public:
1367 #if NVTX3_USE_CHECKED_OVERLOADS_FOR_GET
1368   /**
1369    * @brief Returns a global instance of a `named_category_in` as a
1370    * function-local static.
1371    *
1372    * Creates a `named_category_in<D>` with name and id specified by the contents
1373    * of a type `C`. `C::name` determines the name and `C::id` determines the
1374    * category id.
1375    *
1376    * This function is useful for constructing a named `category` exactly once
1377    * and reusing the same instance throughout an application.
1378    *
1379    * Example:
1380    * \code{.cpp}
1381    * // Define a type with `name` and `id` members
1382    * struct my_category {
1383    *    static constexpr char const* name{"my category"}; // category name
1384    *    static constexpr uint32_t id{42}; // category id
1385    * };
1386    *
1387    * // Use construct on first use to name the category id `42`
1388    * // with name "my category"
1389    * auto& cat = named_category_in<my_domain>::get<my_category>();
1390    *
1391    * // Range `r` associated with category id `42`
1392    * nvtx3::scoped_range r{cat};
1393    * \endcode
1394    *
1395    * Uses the "construct on first use" idiom to safely ensure the `category`
1396    * object is initialized exactly once. See
1397    * https://isocpp.org/wiki/faq/ctors#static-init-order-on-first-use
1398    *
1399    * @tparam C Type containing a member `C::name` that resolves to either a
1400    * `char const*` or `wchar_t const*` and `C::id`.
1401    */
1402   template <typename C,
1403     typename std::enable_if<
1404       detail::is_c_string<decltype(C::name)>::value &&
1405       detail::is_uint32<decltype(C::id)>::value
1406     , int>::type = 0>
1407   static named_category_in const& get() noexcept
1408   {
1409     static named_category_in const cat(C::id, C::name);
1410     return cat;
1411   }
1412 
1413   /**
1414    * @brief Overload of `named_category_in::get` to provide a clear compile error
1415    * when `C` has the required `name` and `id` members, but they are not the
1416    * required types.  `name` must be directly convertible to `char const*` or
1417    * `wchar_t const*`, and `id` must be `uint32_t`.
1418    */
1419   template <typename C,
1420     typename std::enable_if<
1421       !detail::is_c_string<decltype(C::name)>::value ||
1422       !detail::is_uint32<decltype(C::id)>::value
1423     , int>::type = 0>
1424   NVTX3_NO_DISCARD static named_category_in const& get() noexcept
1425   {
1426     NVTX3_STATIC_ASSERT(detail::is_c_string<decltype(C::name)>::value,
1427       "Type used to name an NVTX category must contain a static constexpr member "
1428       "called 'name' of type const char* or const wchar_t* -- 'name' member is not "
1429       "convertible to either of those types");
1430     NVTX3_STATIC_ASSERT(detail::is_uint32<decltype(C::id)>::value,
1431       "Type used to name an NVTX category must contain a static constexpr member "
1432       "called 'id' of type uint32_t -- 'id' member is the wrong type");
1433     static named_category_in const unused;
1434     return unused;  // Function must compile for static_assert to be triggered
1435   }
1436 
1437   /**
1438    * @brief Overload of `named_category_in::get` to provide a clear compile error
1439    * when `C` does not have the required `name` and `id` members.
1440    */
1441   template <typename C,
1442     typename std::enable_if<
1443       !detail::has_name<C>::value ||
1444       !detail::has_id<C>::value
1445     , int>::type = 0>
1446   NVTX3_NO_DISCARD static named_category_in const& get() noexcept
1447   {
1448     NVTX3_STATIC_ASSERT(detail::has_name<C>::value,
1449       "Type used to name an NVTX category must contain a static constexpr member "
1450       "called 'name' of type const char* or const wchar_t* -- 'name' member is missing");
1451     NVTX3_STATIC_ASSERT(detail::has_id<C>::value,
1452       "Type used to name an NVTX category must contain a static constexpr member "
1453       "called 'id' of type uint32_t -- 'id' member is missing");
1454     static named_category_in const unused;
1455     return unused;  // Function must compile for static_assert to be triggered
1456   }
1457 #else
1458   template <typename C>
1459   NVTX3_NO_DISCARD static named_category_in const& get() noexcept
1460   {
1461     static named_category_in const cat(C::id, C::name);
1462     return cat;
1463   }
1464 #endif
1465 
1466  private:
1467   // Default constructor is only used internally for static_assert(false) cases.
1468   named_category_in() noexcept : category{0} {}
1469 
1470  public:
1471   /**
1472    * @brief Construct a `named_category_in` with the specified `id` and `name`.
1473    *
1474    * The name `name` will be registered with `id`.
1475    *
1476    * Every unique value of `id` should only be named once.
1477    *
1478    * @param[in] id The category id to name
1479    * @param[in] name The name to associated with `id`
1480    */
1481   named_category_in(id_type id, char const* name) noexcept : category{id}
1482   {
1483 #ifndef NVTX_DISABLE
1484     nvtxDomainNameCategoryA(domain::get<D>(), get_id(), name);
1485 #else
1486     (void)id;
1487     (void)name;
1488 #endif
1489   }
1490 
1491   /**
1492    * @brief Construct a `named_category_in` with the specified `id` and `name`.
1493    *
1494    * The name `name` will be registered with `id`.
1495    *
1496    * Every unique value of `id` should only be named once.
1497    *
1498    * @param[in] id The category id to name
1499    * @param[in] name The name to associated with `id`
1500    */
1501   named_category_in(id_type id, wchar_t const* name) noexcept : category{id}
1502   {
1503 #ifndef NVTX_DISABLE
1504     nvtxDomainNameCategoryW(domain::get<D>(), get_id(), name);
1505 #else
1506     (void)id;
1507     (void)name;
1508 #endif
1509   }
1510 };
1511 
1512 /**
1513  * @brief Alias for a `named_category_in` in the global NVTX domain.
1514  *
1515  */
1516 using named_category = named_category_in<domain::global>;
1517 
1518 /**
1519  * @brief A message registered with NVTX.
1520  *
1521  * Normally, associating a `message` with an NVTX event requires copying the
1522  * contents of the message string. This may cause non-trivial overhead in
1523  * highly performance sensitive regions of code.
1524  *
1525  * message registration is an optimization to lower the overhead of
1526  * associating a message with an NVTX event. Registering a message yields a
1527  * handle that is inexpensive to copy that may be used in place of a message
1528  * string.
1529  *
1530  * A particular message should only be registered once and the handle
1531  * reused throughout the rest of the application. This can be done by either
1532  * explicitly creating static `registered_string_in` objects, or using the
1533  * `registered_string_in::get` construct on first use helper (recommended).
1534  *
1535  * Example:
1536  * \code{.cpp}
1537  * // Explicitly constructed, static `registered_string` in my_domain:
1538  * static registered_string_in<my_domain> static_message{"message"};
1539  *
1540  * // "message" is associated with the range `r`
1541  * nvtx3::scoped_range r{static_message};
1542  *
1543  * // Or use construct on first use:
1544  *
1545  * // Define a type with a `message` member that defines the contents of the
1546  * // registered string
1547  * struct my_message{ static constexpr char const* message{ "my message" }; };
1548  *
1549  * // Uses construct on first use to register the contents of
1550  * // `my_message::message`
1551  * auto& msg = registered_string_in<my_domain>::get<my_message>();
1552  *
1553  * // "my message" is associated with the range `r`
1554  * nvtx3::scoped_range r{msg};
1555  * \endcode
1556  *
1557  * `registered_string_in`s are local to a particular domain specified via
1558  * the type `D`.
1559  *
1560  * @tparam D Type containing `name` member used to identify the `domain` to
1561  * which the `registered_string_in` belongs. Else, `domain::global` to indicate
1562  * that the global NVTX domain should be used.
1563  */
1564 template <typename D = domain::global>
1565 class registered_string_in {
1566  public:
1567 #if NVTX3_USE_CHECKED_OVERLOADS_FOR_GET
1568   /**
1569    * @brief Returns a global instance of a `registered_string_in` as a function
1570    * local static.
1571    *
1572    * Provides a convenient way to register a message with NVTX without having
1573    * to explicitly register the message.
1574    *
1575    * Upon first invocation, constructs a `registered_string_in` whose contents
1576    * are specified by `message::message`.
1577    *
1578    * All future invocations will return a reference to the object constructed
1579    * in the first invocation.
1580    *
1581    * Example:
1582    * \code{.cpp}
1583    * // Define a type with a `message` member that defines the contents of the
1584    * // registered string
1585    * struct my_message{ static constexpr char const* message{ "my message" };
1586    * };
1587    *
1588    * // Uses construct on first use to register the contents of
1589    * // `my_message::message`
1590    * auto& msg = registered_string_in<my_domain>::get<my_message>();
1591    *
1592    * // "my message" is associated with the range `r`
1593    * nvtx3::scoped_range r{msg};
1594    * \endcode
1595    *
1596    * @tparam M Type required to contain a member `M::message` that
1597    * resolves to either a `char const*` or `wchar_t const*` used as the
1598    * registered string's contents.
1599    * @return Reference to a `registered_string_in` associated with the type `M`.
1600    */
1601   template <typename M,
1602     typename std::enable_if<
1603       detail::is_c_string<decltype(M::message)>::value
1604     , int>::type = 0>
1605   NVTX3_NO_DISCARD static registered_string_in const& get() noexcept
1606   {
1607     static registered_string_in const regstr(M::message);
1608     return regstr;
1609   }
1610 
1611   /**
1612    * @brief Overload of `registered_string_in::get` to provide a clear compile error
1613    * when `M` has a `message` member that is not directly convertible to either
1614    * `char const*` or `wchar_t const*`.
1615    */
1616   template <typename M,
1617     typename std::enable_if<
1618       !detail::is_c_string<decltype(M::message)>::value
1619     , int>::type = 0>
1620   NVTX3_NO_DISCARD static registered_string_in const& get() noexcept
1621   {
1622     NVTX3_STATIC_ASSERT(detail::always_false<M>::value,
1623       "Type used to register an NVTX string must contain a static constexpr member "
1624       "called 'message' of type const char* or const wchar_t* -- 'message' member is "
1625       "not convertible to either of those types");
1626     static registered_string_in const unused;
1627     return unused;  // Function must compile for static_assert to be triggered
1628   }
1629 
1630   /**
1631    * @brief Overload of `registered_string_in::get` to provide a clear compile error when
1632    * `M` does not have a `message` member.
1633    */
1634   template <typename M,
1635     typename std::enable_if<
1636       !detail::has_message<M>::value
1637     , int>::type = 0>
1638   NVTX3_NO_DISCARD static registered_string_in const& get() noexcept
1639   {
1640     NVTX3_STATIC_ASSERT(detail::always_false<M>::value,
1641       "Type used to register an NVTX string must contain a static constexpr member "
1642       "called 'message' of type const char* or const wchar_t* -- 'message' member "
1643       "is missing");
1644     static registered_string_in const unused;
1645     return unused;  // Function must compile for static_assert to be triggered
1646   }
1647 #else
1648   template <typename M>
1649   NVTX3_NO_DISCARD static registered_string_in const& get() noexcept
1650   {
1651     static registered_string_in const regstr(M::message);
1652     return regstr;
1653   }
1654 #endif
1655 
1656   /**
1657    * @brief Constructs a `registered_string_in` from the specified `msg` string.
1658    *
1659    * Registers `msg` with NVTX and associates a handle with the registered
1660    * message.
1661    *
1662    * A particular message should should only be registered once and the handle
1663    * reused throughout the rest of the application.
1664    *
1665    * @param msg The contents of the message
1666    */
1667   explicit registered_string_in(char const* msg) noexcept
1668     : handle_{nvtxDomainRegisterStringA(domain::get<D>(), msg)}
1669   {
1670   }
1671 
1672   /**
1673    * @brief Constructs a `registered_string_in` from the specified `msg` string.
1674    *
1675    * Registers `msg` with NVTX and associates a handle with the registered
1676    * message.
1677    *
1678    * A particular message should should only be registered once and the handle
1679    * reused throughout the rest of the application.
1680    *
1681    * @param msg The contents of the message
1682    */
1683   explicit registered_string_in(std::string const& msg) noexcept
1684     : registered_string_in{msg.c_str()} {}
1685 
1686   /**
1687    * @brief Constructs a `registered_string_in` from the specified `msg` string.
1688    *
1689    * Registers `msg` with NVTX and associates a handle with the registered
1690    * message.
1691    *
1692    * A particular message should should only be registered once and the handle
1693    * reused throughout the rest of the application.
1694    *
1695    * @param msg The contents of the message
1696    */
1697   explicit registered_string_in(wchar_t const* msg) noexcept
1698     : handle_{nvtxDomainRegisterStringW(domain::get<D>(), msg)}
1699   {
1700   }
1701 
1702   /**
1703    * @brief Constructs a `registered_string_in` from the specified `msg` string.
1704    *
1705    * Registers `msg` with NVTX and associates a handle with the registered
1706    * message.
1707    *
1708    * A particular message should only be registered once and the handle
1709    * reused throughout the rest of the application.
1710    *
1711    * @param msg The contents of the message
1712    */
1713   explicit registered_string_in(std::wstring const& msg) noexcept
1714     : registered_string_in{msg.c_str()} {}
1715 
1716   /**
1717    * @brief Returns the registered string's handle
1718    *
1719    */
1720   nvtxStringHandle_t get_handle() const noexcept
1721   {
1722     // We want to ensure that we can use the registered_string in place of a handle
1723     // in a payload data struct.
1724     NVTX3_STATIC_ASSERT(
1725       (detail::is_safe_wrapper_of<registered_string_in<D>, nvtxStringHandle_t>::value),
1726       "Internal error! registered_string_in is potentially unsafe.");
1727     return handle_;
1728   }
1729 
1730 private:
1731   // Default constructor is only used internally for static_assert(false) cases.
1732   registered_string_in() noexcept {}
1733 public:
1734   ~registered_string_in() = default;
1735   registered_string_in(registered_string_in const&) = default;
1736   registered_string_in& operator=(registered_string_in const&) = default;
1737   registered_string_in(registered_string_in&&) = default;
1738   registered_string_in& operator=(registered_string_in&&) = default;
1739 
1740  private:
1741   nvtxStringHandle_t handle_{};  ///< The handle returned from
1742                                  ///< registering the message with NVTX
1743 };
1744 
1745 /**
1746  * @brief Alias for a `registered_string_in` in the global NVTX domain.
1747  *
1748  */
1749 using registered_string = registered_string_in<domain::global>;
1750 
1751 /**
1752  * @brief Allows associating a message string with an NVTX event via
1753  * its `EventAttribute`s.
1754  *
1755  * Associating a `message` with an NVTX event through its `event_attributes`
1756  * allows for naming events to easily differentiate them from other events.
1757  *
1758  * Every time an NVTX event is created with an associated `message`, the
1759  * contents of the message string must be copied.  This may cause non-trivial
1760  * overhead in highly performance sensitive sections of code. Use of a
1761  * `nvtx3::registered_string` is recommended in these situations.
1762  *
1763  * Example:
1764  * \code{.cpp}
1765  * // Creates an `event_attributes` with message "message 0"
1766  * nvtx3::event_attributes attr0{nvtx3::message{"message 0"}};
1767  *
1768  * // `range0` contains message "message 0"
1769  * nvtx3::scoped_range range0{attr0};
1770  *
1771  * // `std::string` and string literals are implicitly assumed to be
1772  * // the contents of an `nvtx3::message`
1773  * // Creates an `event_attributes` with message "message 1"
1774  * nvtx3::event_attributes attr1{"message 1"};
1775  *
1776  * // `range1` contains message "message 1"
1777  * nvtx3::scoped_range range1{attr1};
1778  *
1779  * // `range2` contains message "message 2"
1780  * nvtx3::scoped_range range2{nvtx3::message{"message 2"}};
1781  *
1782  * // `std::string` and string literals are implicitly assumed to be
1783  * // the contents of an `nvtx3::message`
1784  * // `range3` contains message "message 3"
1785  * nvtx3::scoped_range range3{"message 3"};
1786  * \endcode
1787  */
1788 class message {
1789  public:
1790   using value_type = nvtxMessageValue_t;
1791 
1792   /**
1793    * @brief Construct a `message` whose contents are specified by `msg`.
1794    *
1795    * @param msg The contents of the message
1796    */
1797   NVTX3_CONSTEXPR_IF_CPP14 message(char const* msg) noexcept : type_{NVTX_MESSAGE_TYPE_ASCII}
1798   {
1799     value_.ascii = msg;
1800   }
1801 
1802   /**
1803    * @brief Construct a `message` whose contents are specified by `msg`.
1804    *
1805    * @param msg The contents of the message
1806    */
1807   message(std::string const& msg) noexcept : message{msg.c_str()} {}
1808 
1809   /**
1810    * @brief Disallow construction for `std::string` r-value
1811    *
1812    * `message` is a non-owning type and therefore cannot take ownership of an
1813    * r-value. Therefore, constructing from an r-value is disallowed to prevent
1814    * a dangling pointer.
1815    *
1816    */
1817 #ifndef NVTX3_ALLOW_RVALUE_CONSTRUCTORS
1818   message(std::string&&) = delete;
1819 #endif
1820 
1821   /**
1822    * @brief Construct a `message` whose contents are specified by `msg`.
1823    *
1824    * @param msg The contents of the message
1825    */
1826   NVTX3_CONSTEXPR_IF_CPP14 message(wchar_t const* msg) noexcept : type_{NVTX_MESSAGE_TYPE_UNICODE}
1827   {
1828     value_.unicode = msg;
1829   }
1830 
1831   /**
1832    * @brief Construct a `message` whose contents are specified by `msg`.
1833    *
1834    * @param msg The contents of the message
1835    */
1836   message(std::wstring const& msg) noexcept : message{msg.c_str()} {}
1837 
1838   /**
1839    * @brief Disallow construction for `std::wstring` r-value
1840    *
1841    * `message` is a non-owning type and therefore cannot take ownership of an
1842    * r-value. Therefore, constructing from an r-value is disallowed to prevent
1843    * a dangling pointer.
1844    *
1845    */
1846 #ifndef NVTX3_ALLOW_RVALUE_CONSTRUCTORS
1847   message(std::wstring&&) = delete;
1848 #endif
1849 
1850   /**
1851    * @brief Construct a `message` from a `registered_string_in`.
1852    *
1853    * @tparam D Type containing `name` member used to identify the `domain`
1854    * to which the `registered_string_in` belongs. Else, `domain::global` to
1855    * indicate that the global NVTX domain should be used.
1856    * @param msg The message that has already been registered with NVTX.
1857    */
1858   template <typename D>
1859   NVTX3_CONSTEXPR_IF_CPP14 message(registered_string_in<D> const& msg) noexcept
1860     : type_{NVTX_MESSAGE_TYPE_REGISTERED}
1861   {
1862     value_.registered = msg.get_handle();
1863   }
1864 
1865   /**
1866    * @brief Construct a `message` from NVTX C API type and value.
1867    *
1868    * @param type nvtxMessageType_t enum value indicating type of the payload
1869    * @param value nvtxMessageValue_t union containing message
1870    */
1871   constexpr message(
1872     nvtxMessageType_t const& type,
1873     nvtxMessageValue_t const& value) noexcept
1874     : type_{type}, value_(value)
1875   {
1876   }
1877 
1878   /**
1879    * @brief Construct a `message` from NVTX C API registered string handle.
1880    *
1881    * @param handle nvtxStringHandle_t value of registered string handle
1882    */
1883   NVTX3_CONSTEXPR_IF_CPP14 message(nvtxStringHandle_t handle) noexcept
1884     : type_{NVTX_MESSAGE_TYPE_REGISTERED}
1885   {
1886     value_.registered = handle;
1887   }
1888 
1889   /**
1890    * @brief Return the union holding the value of the message.
1891    *
1892    */
1893   constexpr value_type get_value() const noexcept { return value_; }
1894 
1895   /**
1896    * @brief Return the type information about the value the union holds.
1897    *
1898    */
1899   constexpr nvtxMessageType_t get_type() const noexcept { return type_; }
1900 
1901  private:
1902   nvtxMessageType_t type_{};    ///< message type
1903   nvtxMessageValue_t value_{};  ///< message contents
1904 };
1905 
1906 /**
1907  * @brief A numerical value that can be associated with an NVTX event via
1908  * its `event_attributes`.
1909  *
1910  * Example:
1911  * \code{.cpp}
1912  * // Constructs a payload from the int32_t value 42
1913  * nvtx3:: event_attributes attr{nvtx3::payload{42}};
1914  *
1915  * // `range0` will have an int32_t payload of 42
1916  * nvtx3::scoped_range range0{attr};
1917  *
1918  * // range1 has double payload of 3.14
1919  * nvtx3::scoped_range range1{nvtx3::payload{3.14}};
1920  * \endcode
1921  */
1922 class payload {
1923  public:
1924   using value_type = typename nvtxEventAttributes_v2::payload_t;
1925 
1926   /**
1927    * @brief Construct a `payload` from a signed, 8 byte integer.
1928    *
1929    * @param value Value to use as contents of the payload
1930    */
1931   NVTX3_CONSTEXPR_IF_CPP14 explicit payload(int64_t value) noexcept
1932     : type_{NVTX_PAYLOAD_TYPE_INT64}, value_{}
1933   {
1934     value_.llValue = value;
1935   }
1936 
1937   /**
1938    * @brief Construct a `payload` from a signed, 4 byte integer.
1939    *
1940    * @param value Value to use as contents of the payload
1941    */
1942   NVTX3_CONSTEXPR_IF_CPP14 explicit payload(int32_t value) noexcept
1943     : type_{NVTX_PAYLOAD_TYPE_INT32}, value_{}
1944   {
1945     value_.iValue = value;
1946   }
1947 
1948   /**
1949    * @brief Construct a `payload` from an unsigned, 8 byte integer.
1950    *
1951    * @param value Value to use as contents of the payload
1952    */
1953   NVTX3_CONSTEXPR_IF_CPP14 explicit payload(uint64_t value) noexcept
1954     : type_{NVTX_PAYLOAD_TYPE_UNSIGNED_INT64}, value_{}
1955   {
1956     value_.ullValue = value;
1957   }
1958 
1959   /**
1960    * @brief Construct a `payload` from an unsigned, 4 byte integer.
1961    *
1962    * @param value Value to use as contents of the payload
1963    */
1964   NVTX3_CONSTEXPR_IF_CPP14 explicit payload(uint32_t value) noexcept
1965     : type_{NVTX_PAYLOAD_TYPE_UNSIGNED_INT32}, value_{}
1966   {
1967     value_.uiValue = value;
1968   }
1969 
1970   /**
1971    * @brief Construct a `payload` from a single-precision floating point
1972    * value.
1973    *
1974    * @param value Value to use as contents of the payload
1975    */
1976   NVTX3_CONSTEXPR_IF_CPP14 explicit payload(float value) noexcept
1977     : type_{NVTX_PAYLOAD_TYPE_FLOAT}, value_{}
1978   {
1979     value_.fValue = value;
1980   }
1981 
1982   /**
1983    * @brief Construct a `payload` from a double-precision floating point
1984    * value.
1985    *
1986    * @param value Value to use as contents of the payload
1987    */
1988   NVTX3_CONSTEXPR_IF_CPP14 explicit payload(double value) noexcept
1989     : type_{NVTX_PAYLOAD_TYPE_DOUBLE}, value_{}
1990   {
1991     value_.dValue = value;
1992   }
1993 
1994   /**
1995    * @brief Construct a `payload` from NVTX C API type and value.
1996    *
1997    * @param type nvtxPayloadType_t enum value indicating type of the payload
1998    * @param value nvtxEventAttributes_t::payload_t union containing payload
1999    */
2000   constexpr payload(
2001     nvtxPayloadType_t const& type,
2002     value_type const& value) noexcept
2003     : type_{type}, value_(value)
2004   {
2005   }
2006 
2007   /**
2008    * @brief Return the union holding the value of the payload
2009    *
2010    */
2011   constexpr value_type get_value() const noexcept { return value_; }
2012 
2013   /**
2014    * @brief Return the information about the type the union holds.
2015    *
2016    */
2017   constexpr nvtxPayloadType_t get_type() const noexcept { return type_; }
2018 
2019  private:
2020   nvtxPayloadType_t type_;  ///< Type of the payload value
2021   value_type value_;        ///< Union holding the payload value
2022 };
2023 
2024 /**
2025  * @brief Represents the registered schema for a payload struct.
2026  *
2027  * This class encapsulates the schema ID obtained by registering a payload struct
2028  * using `nvtxPayloadSchemaRegister`. The primary mechanism for obtaining an
2029  * instance is via the static template function `get<T>()`, which must be
2030  * specialized for each payload struct type `T` using the
2031  * `NVTX3_DEFINE_SCHEMA_GET` (`NVTX3_V1_DEFINE_SCHEMA_GET()`) macro.
2032  *
2033  * The schema ID is used internally when constructing `payload_data` objects.
2034  */
2035 class schema
2036 {
2037 private:
2038   /**
2039    * @brief Private default constructor.
2040    *
2041    * Used only internally for static_assert(false) cases.
2042    */
2043   schema()
2044       : _schema_id{0}
2045   {}
2046 
2047   public:
2048   schema(schema const&) = delete;
2049   schema& operator=(schema const&) = delete;
2050   schema(schema&&) = delete;
2051   schema& operator=(schema&&) = delete;
2052 
2053   /**
2054    * @brief Constructs a schema object directly from a schema ID.
2055    *
2056    * This constructor is primarily for internal use or advanced scenarios where
2057    * the schema ID is obtained manually.
2058    *
2059    * @param id The NVTX schema ID.
2060    */
2061   explicit schema(uint64_t id)
2062       : _schema_id{id}
2063   {}
2064 
2065   /**
2066    * @brief Gets the schema instance for a specific payload struct type.
2067    *
2068    * This function relies on template specialization. Users must provide a
2069    * specialization for each payload struct type `T` using the
2070    * `NVTX3_DEFINE_SCHEMA_GET` (`NVTX3_V1_DEFINE_SCHEMA_GET()`) macro.
2071    *
2072    * @tparam T The payload struct type for which to get the schema.
2073    * @return A constant reference to the schema object for type `T`.
2074    */
2075   template <typename T>
2076   NVTX3_NO_DISCARD static schema const& get() noexcept
2077   {
2078     NVTX3_STATIC_ASSERT(
2079         detail::always_false<T>::value,
2080         "payload_data schema deduction requires a template specialization. Use the macro "
2081         "NVTX3_DEFINE_SCHEMA_GET to generate this specialization.");
2082     static schema unused;
2083     return unused;
2084   }
2085 
2086   /**
2087    * @brief Return the underlying C handle of the schema.
2088    */
2089   uint64_t get_handle() const noexcept
2090   {
2091     return _schema_id;
2092   }
2093 
2094 private:
2095   uint64_t const _schema_id;
2096 };
2097 
2098 /**
2099  * @brief Wrapper around the NVTX C API `nvtxPayloadData_t` struct.
2100  *
2101  * This class facilitates associating a structured payload with an NVTX event.
2102  * It combines a pointer to the payload data instance with its registered schema
2103  * ID and size.
2104  */
2105 class payload_data
2106 {
2107 public:
2108   /**
2109    * @brief Constructs `payload_data` from an existing NVTX C API struct.
2110    *
2111    * Provides interoperability with code using the NVTX C API directly.
2112    *
2113    * @param pd An existing `nvtxPayloadData_t` struct.
2114    */
2115   explicit payload_data(nvtxPayloadData_t const& pd)
2116       : data_(pd)
2117   {}
2118 
2119   /**
2120    * @brief Constructs `payload_data` for a specific payload struct instance.
2121    *
2122    * This template constructor automatically retrieves the necessary information
2123    * from the given struct type `T` and the reference to the instance.
2124    * The type `T` must be standard layout and trivially copyable as well as
2125    * have a `schema::get<T>()` specialization via `NVTX3_DEFINE_SCHEMA_GET` (`NVTX3_V1_DEFINE_SCHEMA_GET()`).
2126    *
2127    * Make sure the provided referenace is valid for the lifetime of the created
2128    * `payload_data` object.
2129    *
2130    * @param t A constant reference to the payload struct instance.
2131    */
2132   // We cannot simply delete the rvalue constructor here because with a template
2133   // parameter that would be a forwarding reference. Thus, we have this one
2134   // ctor with a forwarding reference and use a static assert for the rvalue check.
2135   // Disable this for the C-style nvtxPayloadData_t to prefer above ctor for non-const.
2136   template <
2137       typename R,
2138       typename T = typename std::remove_cv<typename std::remove_reference<R>::type>::type,
2139       typename = typename std::enable_if<!std::is_same<T, nvtxPayloadData_t>::value>::type>
2140   explicit payload_data(R&& t)
2141       : data_{schema::get<T>().get_handle(), sizeof(T), &t}
2142   {
2143 #ifndef NVTX3_ALLOW_RVALUE_CONSTRUCTORS
2144     NVTX3_STATIC_ASSERT(
2145         std::is_lvalue_reference<R>::value,
2146         "payload_data requires an lvalue reference to the underlying data. Constructing "
2147         "from an rvalue is potentially unsafe and therefore forbidden.");
2148 #endif
2149     NVTX3_STATIC_ASSERT(
2150         std::is_standard_layout<T>::value && std::is_trivially_copyable<T>::value,
2151         "structs used for NVTX3 payload schema must be standard layout and trivially copyable");
2152   }
2153 
2154   /**
2155    * @brief Constructs `payload_data` for a payload instance with a given schema.
2156    *
2157    * Use this constructor if you have a dynamic schema for your struct rather than
2158    * a static one defined by `NVTX3_DEFINE_SCHEMA_GET` (`NVTX3_V1_DEFINE_SCHEMA_GET()`).
2159    *
2160    * Make sure the provided referenace is valid for the lifetime of the created
2161    * `payload_data` object.
2162    *
2163    * @param t A constant reference to the payload struct instance.
2164    * @param s The schema to use for the payload data.
2165    */
2166   template <typename T>
2167   explicit payload_data(T const& t, schema s)
2168       : data_{s.get_handle(), sizeof(T), &t}
2169   {
2170     NVTX3_STATIC_ASSERT(
2171         std::is_standard_layout<T>::value && std::is_trivially_copyable<T>::value,
2172         "structs used for NVTX3 payload schema must be standard layout and trivially copyable");
2173   }
2174 
2175   /**
2176    * @return A pointer to the `nvtxPayloadData_t` struct as ullValue to use
2177    * with NVTX C API functions.
2178    */
2179   uint64_t as_ull_value() const noexcept
2180   {
2181     NVTX3_STATIC_ASSERT(
2182         (detail::is_safe_wrapper_of<payload_data, nvtxPayloadData_t>::value),
2183         "Internal error! payload_data is potentially unsafe.");
2184     return NVTX_POINTER_AS_PAYLOAD_ULLVALUE(&data_);
2185   }
2186 
2187 private:
2188   nvtxPayloadData_t data_;
2189 };
2190 
2191 /**
2192  * @brief Describes the attributes of a NVTX event.
2193  *
2194  * NVTX events can be customized via four "attributes":
2195  *
2196  * - color:    color used to visualize the event in tools such as Nsight
2197  *             Systems. See `color`.
2198  * - message:  Custom message string. See `message`.
2199  * - payload:  User-defined numerical value. See `payload`.
2200  * - category: Intra-domain grouping. See `category`.
2201  *
2202  * These component attributes are specified via an `event_attributes` object.
2203  * See `nvtx3::color`, `nvtx3::message`, `nvtx3::payload`, and
2204  * `nvtx3::category` for how these individual attributes are constructed.
2205  *
2206  * While it is possible to specify all four attributes, it is common to want
2207  * to only specify a subset of attributes and use default values for the
2208  * others. For convenience, `event_attributes` can be constructed from any
2209  * number of attribute components in any order.
2210  *
2211  * Example:
2212  * \code{.cpp}
2213  * // Set message, same as using nvtx3::message{"message"}
2214  * event_attributes attr{"message"};
2215  *
2216  * // Set message and color
2217  * event_attributes attr{"message", nvtx3::rgb{127, 255, 0}};
2218  *
2219  * // Set message, color, payload, category
2220  * event_attributes attr{"message",
2221  *                       nvtx3::rgb{127, 255, 0},
2222  *                       nvtx3::payload{42},
2223  *                       nvtx3::category{1}};
2224  *
2225  * // Same as above -- can use any order of arguments
2226  * event_attributes attr{nvtx3::payload{42},
2227  *                       nvtx3::category{1},
2228  *                       "message",
2229  *                       nvtx3::rgb{127, 255, 0}};
2230  *
2231  * // Multiple arguments of the same type are allowed, but only the first is
2232  * // used -- in this example, payload is set to 42:
2233  * event_attributes attr{ nvtx3::payload{42}, nvtx3::payload{7} };
2234  *
2235  * // Range `r` will be customized according the attributes in `attr`
2236  * nvtx3::scoped_range r{attr};
2237  *
2238  * // For convenience, `event_attributes` constructor arguments may be passed
2239  * // to the `scoped_range_in` constructor -- they are forwarded to the
2240  * // `event_attributes` constructor
2241  * nvtx3::scoped_range r{nvtx3::payload{42}, nvtx3::category{1}, "message"};
2242  *
2243  * // Using the nvtx3 namespace in a local scope makes the syntax more succinct:
2244  * using namespace nvtx3;
2245  * scoped_range r{payload{42}, category{1}, "message"};
2246  * \endcode
2247  *
2248  */
2249 class event_attributes {
2250  public:
2251   using value_type = nvtxEventAttributes_t;
2252 
2253   /**
2254    * @brief Default constructor creates an `event_attributes` with no
2255    * category, color, payload, nor message.
2256    */
2257   constexpr event_attributes() noexcept
2258     : attributes_{
2259         NVTX_VERSION,                   // version
2260         sizeof(nvtxEventAttributes_t),  // size
2261         0,                              // category
2262         NVTX_COLOR_UNKNOWN,             // color type
2263         0,                              // color value
2264         NVTX_PAYLOAD_UNKNOWN,           // payload type
2265         0,                              // reserved 4B
2266         {0},                            // payload value (union)
2267         NVTX_MESSAGE_UNKNOWN,           // message type
2268         {nullptr}                       // message value (union)
2269       }
2270   {
2271   }
2272 
2273   /**
2274    * @brief Variadic constructor where the first argument is a `category`.
2275    *
2276    * Sets the value of the `EventAttribute`s category based on `c` and
2277    * forwards the remaining variadic parameter pack to the next constructor.
2278    *
2279    */
2280   template <typename... Args>
2281   NVTX3_CONSTEXPR_IF_CPP14 explicit event_attributes(category const& c, Args const&... args) noexcept
2282     : event_attributes(args...)
2283   {
2284     attributes_.category = c.get_id();
2285   }
2286 
2287   /**
2288    * @brief Variadic constructor where the first argument is a `color`.
2289    *
2290    * Sets the value of the `EventAttribute`s color based on `c` and forwards
2291    * the remaining variadic parameter pack to the next constructor.
2292    *
2293    */
2294   template <typename... Args>
2295   NVTX3_CONSTEXPR_IF_CPP14 explicit event_attributes(color const& c, Args const&... args) noexcept
2296     : event_attributes(args...)
2297   {
2298     attributes_.color     = c.get_value();
2299     attributes_.colorType = c.get_type();
2300   }
2301 
2302   /**
2303    * @brief Variadic constructor where the first argument is a `payload`.
2304    *
2305    * Sets the value of the `EventAttribute`s payload based on `p` and forwards
2306    * the remaining variadic parameter pack to the next constructor.
2307    *
2308    */
2309   template <typename... Args>
2310   NVTX3_CONSTEXPR_IF_CPP14 explicit event_attributes(payload const& p, Args const&... args) noexcept
2311     : event_attributes(args...)
2312   {
2313     attributes_.payload     = p.get_value();
2314     attributes_.payloadType = p.get_type();
2315   }
2316 
2317   /**
2318    * @brief Variadic constructor where the first argument is a single `payload_data`.
2319    *
2320    * Sets the value of the `EventAttribute`s payload data based on `pd` and forwards
2321    * the remaining variadic parameter pack to the next constructor.
2322    *
2323    */
2324   template <typename... Args>
2325   NVTX3_CONSTEXPR_IF_CPP14 explicit event_attributes(payload_data const& pd, Args const&... args) noexcept
2326       : event_attributes(args...)
2327   {
2328     attributes_.payloadType = NVTX_PAYLOAD_TYPE_EXT;
2329     attributes_.reserved0 = 1;
2330     attributes_.payload.ullValue = pd.as_ull_value();
2331   }
2332 
2333   /**
2334    * @brief Deleted constructor for `payload_data` rvalue references.
2335    *
2336    * `event_attributes` is non-owning and therefore cannot take ownership of an r-value
2337    * `payload_data`. Therefore this constructor is deleted by default to prevent dangling
2338    * pointers.
2339    */
2340 #ifndef NVTX3_ALLOW_RVALUE_CONSTRUCTORS
2341   template <typename... Args>
2342   NVTX3_CONSTEXPR_IF_CPP14 explicit event_attributes(payload_data&& pd, Args const&... args) = delete;
2343 #endif
2344 
2345   /**
2346    * @brief Variadic constructor template for containers of `payload_data`.
2347    *
2348    * Associates multiple structured payloads contained in `pdc` with the event attributes.
2349    * This constructor is enabled for types that have both a `data()` member function
2350    * returning `payload_data*` or `const payload_data*` and a `size()` member function.
2351    * E.g., `std::vector` or `std::array` can be used.
2352    * Forwards the remaining variadic parameter pack to the next constructor.
2353    */
2354   template <
2355       typename T,
2356       typename... Args,
2357       typename = typename std::enable_if<
2358           detail::has_data_member<T, payload_data>::value && detail::has_size_member<T>::value>::type>
2359   NVTX3_CONSTEXPR_IF_CPP20 explicit event_attributes(T&& pdc, Args const&... args) noexcept
2360       : event_attributes(args...)
2361   {
2362     NVTX3_STATIC_ASSERT(
2363         std::is_lvalue_reference<T>::value,
2364         "event_attributes requires an lvalue reference to the underlying data. "
2365         "Constructing from an rvalue is potentially unsafe and therefore forbidden.");
2366     attributes_.payloadType = NVTX_PAYLOAD_TYPE_EXT;
2367     attributes_.reserved0 = static_cast<int32_t>(pdc.size()); // Cast size to int32_t
2368     attributes_.payload.ullValue = pdc.data()->as_ull_value();
2369   }
2370 
2371   /**
2372    * @brief Variadic constructor where the first argument is a `message`.
2373    *
2374    * Sets the value of the `EventAttribute`s message based on `m` and forwards
2375    * the remaining variadic parameter pack to the next constructor.
2376    *
2377    */
2378   template <typename... Args>
2379   NVTX3_CONSTEXPR_IF_CPP14 explicit event_attributes(message const& m, Args const&... args) noexcept
2380     : event_attributes(args...)
2381   {
2382     attributes_.message     = m.get_value();
2383     attributes_.messageType = m.get_type();
2384   }
2385 
2386   ~event_attributes() = default;
2387   event_attributes(event_attributes const&) = default;
2388   event_attributes& operator=(event_attributes const&) = default;
2389   event_attributes(event_attributes&&) = default;
2390   event_attributes& operator=(event_attributes&&) = default;
2391 
2392   /**
2393    * @brief Get raw pointer to underlying NVTX attributes object.
2394    *
2395    */
2396   constexpr value_type const* get() const noexcept { return &attributes_; }
2397 
2398  private:
2399   value_type attributes_{};  ///< The NVTX attributes structure
2400 };
2401 
2402 /**
2403  * @brief A RAII object for creating a NVTX range local to a thread within a
2404  * domain.
2405  *
2406  * When constructed, begins a nested NVTX range on the calling thread in the
2407  * specified domain. Upon destruction, ends the NVTX range.
2408  *
2409  * Behavior is undefined if a `scoped_range_in` object is
2410  * created/destroyed on different threads.
2411  *
2412  * `scoped_range_in` is neither movable nor copyable.
2413  *
2414  * `scoped_range_in`s may be nested within other ranges.
2415  *
2416  * The domain of the range is specified by the template type parameter `D`.
2417  * By default, the `domain::global` is used, which scopes the range to the
2418  * global NVTX domain. The convenience alias `scoped_range` is provided for
2419  * ranges scoped to the global domain.
2420  *
2421  * A custom domain can be defined by creating a type, `D`, with a static
2422  * member `D::name` whose value is used to name the domain associated with
2423  * `D`. `D::name` must resolve to either `char const*` or `wchar_t const*`
2424  *
2425  * Example:
2426  * \code{.cpp}
2427  * // Define a type `my_domain` with a member `name` used to name the domain
2428  * // associated with the type `my_domain`.
2429  * struct my_domain{
2430  *    static constexpr char const* name{"my domain"};
2431  * };
2432  * \endcode
2433  *
2434  * Usage:
2435  * \code{.cpp}
2436  * nvtx3::scoped_range_in<my_domain> r1{"range 1"}; // Range in my domain
2437  *
2438  * // Three equivalent ways to make a range in the global domain:
2439  * nvtx3::scoped_range_in<nvtx3::domain::global> r2{"range 2"};
2440  * nvtx3::scoped_range_in<> r3{"range 3"};
2441  * nvtx3::scoped_range r4{"range 4"};
2442  *
2443  * // Create an alias to succinctly make ranges in my domain:
2444  * using my_scoped_range = nvtx3::scoped_range_in<my_domain>;
2445  *
2446  * my_scoped_range r3{"range 3"};
2447  * \endcode
2448  */
2449 template <class D = domain::global>
2450 class NVTX3_MAYBE_UNUSED scoped_range_in {
2451  public:
2452   /**
2453    * @brief Construct a `scoped_range_in` with the specified
2454    * `event_attributes`
2455    *
2456    * Example:
2457    * \code{cpp}
2458    * nvtx3::event_attributes attr{"msg", nvtx3::rgb{127,255,0}};
2459    * nvtx3::scoped_range range{attr}; // Creates a range with message contents
2460    *                                  // "msg" and green color
2461    * \endcode
2462    *
2463    * @param[in] attr `event_attributes` that describes the desired attributes
2464    * of the range.
2465    */
2466   explicit scoped_range_in(event_attributes const& attr) noexcept
2467   {
2468 #ifndef NVTX_DISABLE
2469     nvtxDomainRangePushEx(domain::get<D>(), attr.get());
2470 #else
2471     (void)attr;
2472 #endif
2473   }
2474 
2475   /**
2476    * @brief Constructs a `scoped_range_in` from the constructor arguments
2477    * of an `event_attributes`.
2478    *
2479    * Forwards the arguments `args...` to construct an
2480    * `event_attributes` object. The `event_attributes` object is then
2481    * associated with the `scoped_range_in`.
2482    *
2483    * For more detail, see `event_attributes` documentation.
2484    *
2485    * Example:
2486    * \code{cpp}
2487    * // Creates a range with message "message" and green color
2488    * nvtx3::scoped_range r{"message", nvtx3::rgb{127,255,0}};
2489    * \endcode
2490    *
2491    * @param[in] args Arguments to used to construct an `event_attributes` associated with this
2492    * range.
2493    *
2494    */
2495   template <typename... Args>
2496   explicit scoped_range_in(Args const&... args) noexcept
2497     : scoped_range_in{event_attributes{args...}}
2498   {
2499   }
2500 
2501   /**
2502    * @brief Default constructor creates a `scoped_range_in` with no
2503    * message, color, payload, nor category.
2504    *
2505    */
2506   scoped_range_in() noexcept : scoped_range_in{event_attributes{}} {}
2507 
2508   /**
2509    * @brief Delete `operator new` to disallow heap allocated objects.
2510    *
2511    * `scoped_range_in` must follow RAII semantics to guarantee proper push/pop semantics.
2512    *
2513    */
2514   void* operator new(std::size_t) = delete;
2515 
2516   scoped_range_in(scoped_range_in const&) = delete;
2517   scoped_range_in& operator=(scoped_range_in const&) = delete;
2518   scoped_range_in(scoped_range_in&&) = delete;
2519   scoped_range_in& operator=(scoped_range_in&&) = delete;
2520 
2521   /**
2522    * @brief Destroy the scoped_range_in, ending the NVTX range event.
2523    */
2524   ~scoped_range_in() noexcept
2525   {
2526 #ifndef NVTX_DISABLE
2527     nvtxDomainRangePop(domain::get<D>());
2528 #endif
2529   }
2530 };
2531 
2532 /**
2533  * @brief Alias for a `scoped_range_in` in the global NVTX domain.
2534  *
2535  */
2536 using scoped_range = scoped_range_in<domain::global>;
2537 
2538 namespace detail {
2539 
2540 /// @cond internal
2541 template <typename D = domain::global>
2542 class NVTX3_MAYBE_UNUSED optional_scoped_range_in
2543 {
2544 public:
2545   optional_scoped_range_in() = default;
2546 
2547   void begin(event_attributes const& attr) noexcept
2548   {
2549 #ifndef NVTX_DISABLE
2550     // This class is not meant to be part of the public NVTX C++ API and should
2551     // only be used in the `NVTX3_FUNC_RANGE_IF` and `NVTX3_FUNC_RANGE_IF_IN`
2552     // macros. However, to prevent developers from misusing this class, make
2553     // sure to not start multiple ranges.
2554     if (initialized) { return; }
2555 
2556     nvtxDomainRangePushEx(domain::get<D>(), attr.get());
2557     initialized = true;
2558 #else
2559     (void)attr;
2560 #endif
2561   }
2562 
2563   ~optional_scoped_range_in() noexcept
2564   {
2565 #ifndef NVTX_DISABLE
2566     if (initialized) { nvtxDomainRangePop(domain::get<D>()); }
2567 #endif
2568   }
2569 
2570   void* operator new(std::size_t) = delete;
2571   optional_scoped_range_in(optional_scoped_range_in const&) = delete;
2572   optional_scoped_range_in& operator=(optional_scoped_range_in const&) = delete;
2573   optional_scoped_range_in(optional_scoped_range_in&&) = delete;
2574   optional_scoped_range_in& operator=(optional_scoped_range_in&&) = delete;
2575 
2576 private:
2577 #ifndef NVTX_DISABLE
2578   bool initialized = false;
2579 #endif
2580 };
2581 /// @endcond
2582 
2583 } // namespace detail
2584 
2585 /**
2586  * @brief Handle used for correlating explicit range start and end events.
2587  *
2588  * A handle is "null" if it does not correspond to any range.
2589  *
2590  */
2591 struct range_handle {
2592   /// Type used for the handle's value
2593   using value_type = nvtxRangeId_t;
2594 
2595 
2596   /**
2597    * @brief Construct a `range_handle` from the given id.
2598    *
2599    */
2600   constexpr explicit range_handle(value_type id) noexcept : _range_id{id} {}
2601 
2602   /**
2603    * @brief Constructs a null range handle.
2604    *
2605    * A null range_handle corresponds to no range. Calling `end_range` on a
2606    * null handle is undefined behavior when a tool is active.
2607    *
2608    */
2609   constexpr range_handle() noexcept = default;
2610 
2611   /**
2612    * @brief Checks whether this handle is null
2613    *
2614    * Provides contextual conversion to `bool`.
2615    *
2616    * \code{cpp}
2617    * range_handle handle{};
2618    * if (handle) {...}
2619    * \endcode
2620    *
2621    */
2622   constexpr explicit operator bool() const noexcept { return get_value() != null_range_id; }
2623 
2624   /**
2625    * @brief Implicit conversion from `nullptr` constructs a null handle.
2626    *
2627    * Satisfies the "NullablePointer" requirement to make `range_handle` comparable with `nullptr`.
2628    *
2629    */
2630   constexpr range_handle(std::nullptr_t) noexcept {}
2631 
2632   /**
2633    * @brief Returns the `range_handle`'s value
2634    *
2635    * @return value_type The handle's value
2636    */
2637   constexpr value_type get_value() const noexcept { return _range_id; }
2638 
2639  private:
2640   /// Sentinel value for a null handle that corresponds to no range
2641   static constexpr value_type null_range_id = nvtxRangeId_t{0};
2642 
2643   value_type _range_id{null_range_id};  ///< The underlying NVTX range id
2644 };
2645 
2646 /**
2647  * @brief Compares two range_handles for equality
2648  *
2649  * @param lhs The first range_handle to compare
2650  * @param rhs The second range_handle to compare
2651  */
2652 inline constexpr bool operator==(range_handle lhs, range_handle rhs) noexcept
2653 {
2654   return lhs.get_value() == rhs.get_value();
2655 }
2656 
2657 /**
2658  * @brief Compares two range_handles for inequality
2659  *
2660  * @param lhs The first range_handle to compare
2661  * @param rhs The second range_handle to compare
2662  */
2663 inline constexpr bool operator!=(range_handle lhs, range_handle rhs) noexcept { return !(lhs == rhs); }
2664 
2665 /**
2666  * @brief Manually begin an NVTX range.
2667  *
2668  * Explicitly begins an NVTX range and returns a unique handle. To end the
2669  * range, pass the handle to `end_range_in<D>()`.
2670  *
2671  * `nvtx3::start_range(...)` is equivalent to `nvtx3::start_range_in<>(...)` and
2672  * `nvtx3::start_range_in<nvtx3::domain::global>(...)`.
2673  *
2674  * `start_range_in/end_range_in` are the most explicit and lowest level APIs
2675  * provided for creating ranges.  Use of `nvtx3::unique_range_in` should be
2676  * preferred unless one is unable to tie the range to the lifetime of an object.
2677  *
2678  * Example:
2679  * \code{.cpp}
2680  * nvtx3::event_attributes attr{"msg", nvtx3::rgb{127,255,0}};
2681  * // Manually begin a range
2682  * nvtx3::range_handle h = nvtx3::start_range_in<my_domain>(attr);
2683  * ...
2684  * nvtx3::end_range_in<my_domain>(h); // End the range
2685  * \endcode
2686  *
2687  * @tparam D Type containing `name` member used to identify the `domain`
2688  * to which the range belongs. Else, `domain::global` to indicate that the
2689  * global NVTX domain should be used.
2690  * @param[in] attr `event_attributes` that describes the desired attributes
2691  * of the range.
2692  * @return Unique handle to be passed to `end_range_in` to end the range.
2693  */
2694 template <typename D = domain::global>
2695 NVTX3_NO_DISCARD inline range_handle start_range_in(event_attributes const& attr) noexcept
2696 {
2697 #ifndef NVTX_DISABLE
2698   return range_handle{nvtxDomainRangeStartEx(domain::get<D>(), attr.get())};
2699 #else
2700   (void)attr;
2701   return {};
2702 #endif
2703 }
2704 
2705 /**
2706  * @brief Manually begin an NVTX range.
2707  *
2708  * Explicitly begins an NVTX range and returns a unique handle. To end the
2709  * range, pass the handle to `end_range_in<D>()`.
2710  *
2711  * `nvtx3::start_range(...)` is equivalent to `nvtx3::start_range_in<>(...)` and
2712  * `nvtx3::start_range_in<nvtx3::domain::global>(...)`.
2713  *
2714  * `start_range_in/end_range_in` are the most explicit and lowest level APIs
2715  * provided for creating ranges.  Use of `nvtx3::unique_range_in` should be
2716  * preferred unless one is unable to tie the range to the lifetime of an object.
2717  *
2718  * This overload uses `args...` to construct an  `event_attributes` to
2719  * associate with the range.  For more detail, see `event_attributes`.
2720  *
2721  * Example:
2722  * \code{cpp}
2723  * // Manually begin a range
2724  * nvtx3::range_handle h = nvtx3::start_range_in<D>("msg", nvtx3::rgb{127,255,0});
2725  * ...
2726  * nvtx3::end_range_in<D>(h); // Ends the range
2727  * \endcode
2728  *
2729  * @tparam D Type containing `name` member used to identify the `domain`
2730  * to which the range belongs. Else, `domain::global` to indicate that the
2731  * global NVTX domain should be used.
2732  * @param[in] args Variadic parameter pack of the arguments for an `event_attributes`.
2733  * @return Unique handle to be passed to `end_range` to end the range.
2734  */
2735 template <typename D = domain::global, typename... Args>
2736 NVTX3_NO_DISCARD inline range_handle start_range_in(Args const&... args) noexcept
2737 {
2738 #ifndef NVTX_DISABLE
2739   return start_range_in<D>(event_attributes{args...});
2740 #else
2741   detail::silence_unused(args...);
2742   return {};
2743 #endif
2744 }
2745 
2746 /**
2747  * @brief Manually begin an NVTX range in the global domain.
2748  *
2749  * Explicitly begins an NVTX range and returns a unique handle. To end the
2750  * range, pass the handle to `end_range()`.
2751  *
2752  * `nvtx3::start_range(...)` is equivalent to `nvtx3::start_range_in<>(...)` and
2753  * `nvtx3::start_range_in<nvtx3::domain::global>(...)`.
2754  *
2755  * `start_range/end_range` are the most explicit and lowest level APIs
2756  * provided for creating ranges.  Use of `nvtx3::unique_range` should be
2757  * preferred unless one is unable to tie the range to the lifetime of an object.
2758  *
2759  * Example:
2760  * \code{.cpp}
2761  * nvtx3::event_attributes attr{"msg", nvtx3::rgb{127,255,0}};
2762  * // Manually begin a range
2763  * nvtx3::range_handle h = nvtx3::start_range(attr);
2764  * ...
2765  * nvtx3::end_range(h); // End the range
2766  * \endcode
2767  *
2768  * @param[in] attr `event_attributes` that describes the desired attributes
2769  * of the range.
2770  * @return Unique handle to be passed to `end_range_in` to end the range.
2771  */
2772 NVTX3_NO_DISCARD inline range_handle start_range(event_attributes const& attr) noexcept
2773 {
2774 #ifndef NVTX_DISABLE
2775   return start_range_in<domain::global>(attr);
2776 #else
2777   (void)attr;
2778   return {};
2779 #endif
2780 }
2781 
2782 /**
2783  * @brief Manually begin an NVTX range in the global domain.
2784  *
2785  * Explicitly begins an NVTX range and returns a unique handle. To end the
2786  * range, pass the handle to `end_range_in<D>()`.
2787  *
2788  * `nvtx3::start_range(...)` is equivalent to `nvtx3::start_range_in<>(...)` and
2789  * `nvtx3::start_range_in<nvtx3::domain::global>(...)`.
2790  *
2791  * `start_range_in/end_range_in` are the most explicit and lowest level APIs
2792  * provided for creating ranges.  Use of `nvtx3::unique_range_in` should be
2793  * preferred unless one is unable to tie the range to the lifetime of an object.
2794  *
2795  * This overload uses `args...` to construct an  `event_attributes` to
2796  * associate with the range.  For more detail, see `event_attributes`.
2797  *
2798  * Example:
2799  * \code{cpp}
2800  * // Manually begin a range
2801  * nvtx3::range_handle h = nvtx3::start_range("msg", nvtx3::rgb{127,255,0});
2802  * ...
2803  * nvtx3::end_range(h); // Ends the range
2804  * \endcode
2805  *
2806  * @param[in] args Variadic parameter pack of the arguments for an `event_attributes`.
2807  * @return Unique handle to be passed to `end_range` to end the range.
2808  */
2809 template <typename... Args>
2810 NVTX3_NO_DISCARD inline range_handle start_range(Args const&... args) noexcept
2811 {
2812 #ifndef NVTX_DISABLE
2813   return start_range_in<domain::global>(args...);
2814 #else
2815   detail::silence_unused(args...);
2816   return {};
2817 #endif
2818 }
2819 
2820 /**
2821  * @brief Manually end the range associated with the handle `r` in domain `D`.
2822  *
2823  * Explicitly ends the NVTX range indicated by the handle `r` returned from a
2824  * prior call to `start_range_in<D>`. The range may end on a different thread
2825  * from where it began.
2826  *
2827  * @tparam D Type containing `name` member used to identify the `domain` to
2828  * which the range belongs. Else, `domain::global` to indicate that the global
2829  * NVTX domain should be used.
2830  * @param r Handle to a range started by a prior call to `start_range_in`.
2831  *
2832  * @warning The domain type specified as template parameter to this function
2833  * must be the same that was specified on the associated `start_range_in` call.
2834  */
2835 template <typename D = domain::global>
2836 inline void end_range_in(range_handle r) noexcept
2837 {
2838 #ifndef NVTX_DISABLE
2839   nvtxDomainRangeEnd(domain::get<D>(), r.get_value());
2840 #else
2841   (void)r;
2842 #endif
2843 }
2844 
2845 /**
2846  * @brief Manually end the range associated with the handle `r` in the global
2847  * domain.
2848  *
2849  * Explicitly ends the NVTX range indicated by the handle `r` returned from a
2850  * prior call to `start_range`. The range may end on a different thread from
2851  * where it began.
2852  *
2853  * @param r Handle to a range started by a prior call to `start_range`.
2854  *
2855  * @warning The domain type specified as template parameter to this function
2856  * must be the same that was specified on the associated `start_range` call.
2857  */
2858 inline void end_range(range_handle r) noexcept
2859 {
2860 #ifndef NVTX_DISABLE
2861   end_range_in<domain::global>(r);
2862 #else
2863   (void)r;
2864 #endif
2865 }
2866 
2867 /**
2868  * @brief A RAII object for creating a NVTX range within a domain that can
2869  * be created and destroyed on different threads.
2870  *
2871  * When constructed, begins a NVTX range in the specified domain. Upon
2872  * destruction, ends the NVTX range.
2873  *
2874  * Similar to `nvtx3::scoped_range_in`, with a few key differences:
2875  * - `unique_range` objects can be destroyed in an order whereas `scoped_range` objects must be
2876  *    destroyed in exact reverse creation order
2877  * - `unique_range` can start and end on different threads
2878  * - `unique_range` is movable
2879  * - `unique_range` objects can be constructed as heap objects
2880  *
2881  * There is extra overhead associated with `unique_range` constructs and therefore use of
2882  * `nvtx3::scoped_range_in` should be preferred.
2883  *
2884  * @tparam D Type containing `name` member used to identify the `domain`
2885  * to which the `unique_range_in` belongs. Else, `domain::global` to
2886  * indicate that the global NVTX domain should be used.
2887  */
2888 template <typename D = domain::global>
2889 class NVTX3_MAYBE_UNUSED unique_range_in {
2890  public:
2891   /**
2892    * @brief Construct a new unique_range_in object with the specified event attributes
2893    *
2894    * Example:
2895    * \code{cpp}
2896    * nvtx3::event_attributes attr{"msg", nvtx3::rgb{127,255,0}};
2897    * nvtx3::unique_range_in<my_domain> range{attr}; // Creates a range with message contents
2898    *                                            // "msg" and green color
2899    * \endcode
2900    *
2901    * @param[in] attr `event_attributes` that describes the desired attributes
2902    * of the range.
2903    */
2904   explicit unique_range_in(event_attributes const& attr) noexcept
2905     : handle_{start_range_in<D>(attr)}
2906   {
2907   }
2908 
2909   /**
2910    * @brief Constructs a `unique_range_in` from the constructor arguments
2911    * of an `event_attributes`.
2912    *
2913    * Forwards the arguments `args...` to construct an
2914    * `event_attributes` object. The `event_attributes` object is then
2915    * associated with the `unique_range_in`.
2916    *
2917    * For more detail, see `event_attributes` documentation.
2918    *
2919    * Example:
2920    * \code{.cpp}
2921    * // Creates a range with message "message" and green color
2922    * nvtx3::unique_range_in<> r{"message", nvtx3::rgb{127,255,0}};
2923    * \endcode
2924    *
2925    * @param[in] args Variadic parameter pack of arguments to construct an `event_attributes`
2926    * associated with this range.
2927    */
2928   template <typename... Args>
2929   explicit unique_range_in(Args const&... args) noexcept
2930     : unique_range_in{event_attributes{args...}}
2931   {
2932   }
2933 
2934   /**
2935    * @brief Default constructor creates a `unique_range_in` with no
2936    * message, color, payload, nor category.
2937    *
2938    */
2939   constexpr unique_range_in() noexcept : unique_range_in{event_attributes{}} {}
2940 
2941   /**
2942    * @brief Destroy the `unique_range_in` ending the range.
2943    *
2944    */
2945   ~unique_range_in() noexcept = default;
2946 
2947   /**
2948    * @brief Move constructor allows taking ownership of the NVTX range from
2949    * another `unique_range_in`.
2950    *
2951    * @param other The range to take ownership of
2952    */
2953   unique_range_in(unique_range_in&& other) noexcept = default;
2954 
2955   /**
2956    * @brief Move assignment operator allows taking ownership of an NVTX range
2957    * from another `unique_range_in`.
2958    *
2959    * @param other The range to take ownership of
2960    */
2961   unique_range_in& operator=(unique_range_in&& other) noexcept = default;
2962 
2963   /// Copy construction is not allowed to prevent multiple objects from owning
2964   /// the same range handle
2965   unique_range_in(unique_range_in const&) = delete;
2966 
2967   /// Copy assignment is not allowed to prevent multiple objects from owning the
2968   /// same range handle
2969   unique_range_in& operator=(unique_range_in const&) = delete;
2970 
2971  private:
2972 
2973   struct end_range_handle {
2974     using pointer = range_handle;  /// Override the pointer type of the unique_ptr
2975     void operator()(range_handle h) const noexcept { end_range_in<D>(h); }
2976   };
2977 
2978   /// Range handle used to correlate the start/end of the range
2979   std::unique_ptr<range_handle, end_range_handle> handle_;
2980 };
2981 
2982 /**
2983  * @brief Alias for a `unique_range_in` in the global NVTX domain.
2984  *
2985  */
2986 using unique_range = unique_range_in<domain::global>;
2987 
2988 /**
2989  * @brief Annotates an instantaneous point in time with a "marker", using the
2990  * attributes specified by `attr`.
2991  *
2992  * Unlike a "range" which has a beginning and an end, a marker is a single event
2993  * in an application, such as detecting a problem:
2994  *
2995  * \code{.cpp}
2996  * bool success = do_operation(...);
2997  * if (!success) {
2998  *    nvtx3::event_attributes attr{"operation failed!", nvtx3::rgb{255,0,0}};
2999  *    nvtx3::mark_in<my_domain>(attr);
3000  * }
3001  * \endcode
3002  *
3003  * Note that nvtx3::mark_in<D> is a function, not a class like scoped_range_in<D>.
3004  *
3005  * @tparam D Type containing `name` member used to identify the `domain`
3006  * to which the `unique_range_in` belongs. Else, `domain::global` to
3007  * indicate that the global NVTX domain should be used.
3008  * @param[in] attr `event_attributes` that describes the desired attributes
3009  * of the mark.
3010  */
3011 template <typename D = domain::global>
3012 inline void mark_in(event_attributes const& attr) noexcept
3013 {
3014 #ifndef NVTX_DISABLE
3015   nvtxDomainMarkEx(domain::get<D>(), attr.get());
3016 #else
3017   (void)(attr);
3018 #endif
3019 }
3020 
3021 /**
3022  * @brief Annotates an instantaneous point in time with a "marker", using the
3023  * arguments to construct an `event_attributes`.
3024  *
3025  * Unlike a "range" which has a beginning and an end, a marker is a single event
3026  * in an application, such as detecting a problem:
3027  *
3028  * \code{.cpp}
3029  * bool success = do_operation(...);
3030  * if (!success) {
3031  *    nvtx3::mark_in<my_domain>("operation failed!", nvtx3::rgb{255,0,0});
3032  * }
3033  * \endcode
3034  *
3035  * Note that nvtx3::mark_in<D> is a function, not a class like scoped_range_in<D>.
3036  *
3037  * Forwards the arguments `args...` to construct an `event_attributes` object.
3038  * The attributes are then associated with the marker. For more detail, see
3039  * the `event_attributes` documentation.
3040  *
3041  * @tparam D Type containing `name` member used to identify the `domain`
3042  * to which the `unique_range_in` belongs. Else `domain::global` to
3043  * indicate that the global NVTX domain should be used.
3044  * @param[in] args Variadic parameter pack of arguments to construct an `event_attributes`
3045  * associated with this range.
3046  *
3047  */
3048 template <typename D = domain::global, typename... Args>
3049 inline void mark_in(Args const&... args) noexcept
3050 {
3051 #ifndef NVTX_DISABLE
3052   mark_in<D>(event_attributes{args...});
3053 #else
3054   detail::silence_unused(args...);
3055 #endif
3056 }
3057 
3058 /**
3059  * @brief Annotates an instantaneous point in time with a "marker", using the
3060  * attributes specified by `attr`, in the global domain.
3061  *
3062  * Unlike a "range" which has a beginning and an end, a marker is a single event
3063  * in an application, such as detecting a problem:
3064  *
3065  * \code{.cpp}
3066  * bool success = do_operation(...);
3067  * if (!success) {
3068  *    nvtx3::event_attributes attr{"operation failed!", nvtx3::rgb{255,0,0}};
3069  *    nvtx3::mark(attr);
3070  * }
3071  * \endcode
3072  *
3073  * Note that nvtx3::mark is a function, not a class like scoped_range.
3074  *
3075  * @param[in] attr `event_attributes` that describes the desired attributes
3076  * of the mark.
3077  */
3078 inline void mark(event_attributes const& attr) noexcept
3079 {
3080 #ifndef NVTX_DISABLE
3081   mark_in<domain::global>(attr);
3082 #else
3083   (void)attr;
3084 #endif
3085 }
3086 
3087 /**
3088  * @brief Annotates an instantaneous point in time with a "marker", using the
3089  * arguments to construct an `event_attributes`, in the global domain.
3090  *
3091  * Unlike a "range" which has a beginning and an end, a marker is a single event
3092  * in an application, such as detecting a problem:
3093  *
3094  * \code{.cpp}
3095  * bool success = do_operation(...);
3096  * if (!success) {
3097  *    nvtx3::mark("operation failed!", nvtx3::rgb{255,0,0});
3098  * }
3099  * \endcode
3100  *
3101  * Note that nvtx3::mark is a function, not a class like scoped_range.
3102  *
3103  * Forwards the arguments `args...` to construct an `event_attributes` object.
3104  * The attributes are then associated with the marker. For more detail, see
3105  * the `event_attributes` documentation.
3106  *
3107  * @param[in] args Variadic parameter pack of arguments to construct an
3108  * `event_attributes` associated with this range.
3109  *
3110  */
3111 template <typename... Args>
3112 inline void mark(Args const&... args) noexcept
3113 {
3114 #ifndef NVTX_DISABLE
3115   mark_in<domain::global>(args...);
3116 #else
3117   detail::silence_unused(args...);
3118 #endif
3119 }
3120 
3121 }  // namespace NVTX3_MINOR_VERSION_NAMESPACE
3122 }  // namespace NVTX3_VERSION_NAMESPACE
3123 } // namespace nvtx3
3124 
3125 #ifndef NVTX_DISABLE
3126 /**
3127  * @brief Convenience macro for generating a range in the specified `domain`
3128  * from the lifetime of a function
3129  *
3130  * This macro is useful for generating an NVTX range in `domain` from
3131  * the entry point of a function to its exit. It is intended to be the first
3132  * line of the function.
3133  *
3134  * Constructs a static `registered_string_in` using the name of the immediately
3135  * enclosing function returned by `__func__` and constructs a
3136  * `nvtx3::scoped_range` using the registered function name as the range's
3137  * message.
3138  *
3139  * Example:
3140  * \code{.cpp}
3141  * struct my_domain{static constexpr char const* name{"my_domain"};};
3142  *
3143  * void foo(...) {
3144  *    NVTX3_FUNC_RANGE_IN(my_domain); // Range begins on entry to foo()
3145  *    // do stuff
3146  *    ...
3147  * } // Range ends on return from foo()
3148  * \endcode
3149  *
3150  * @param[in] D Type containing `name` member used to identify the
3151  * `domain` to which the `registered_string_in` belongs. Else,
3152  * `domain::global` to  indicate that the global NVTX domain should be used.
3153  */
3154 #define NVTX3_V1_FUNC_RANGE_IN(D)                                                  \
3155   static ::nvtx3::v1::registered_string_in<D> const nvtx3_func_name__{__func__};   \
3156   static ::nvtx3::v1::event_attributes const nvtx3_func_attr__{nvtx3_func_name__}; \
3157   ::nvtx3::v1::scoped_range_in<D> const nvtx3_range__{nvtx3_func_attr__}
3158 
3159 /**
3160  * @brief Convenience macro for generating a range in the specified `domain`
3161  * from the lifetime of a function if the given boolean expression evaluates
3162  * to true.
3163  *
3164  * Similar to `NVTX3_V1_FUNC_RANGE_IN(D)`, the only difference being that
3165  * `NVTX3_V1_FUNC_RANGE_IF_IN(D, C)` only generates a range if the given boolean
3166  * expression evaluates to true.
3167  *
3168  * @param[in] D Type containing `name` member used to identify the
3169  * `domain` to which the `registered_string_in` belongs. Else,
3170  * `domain::global` to indicate that the global NVTX domain should be used.
3171  *
3172  * @param[in] C Boolean expression used to determine if a range should be
3173  * generated.
3174  */
3175 #define NVTX3_V1_FUNC_RANGE_IF_IN(D, C) \
3176   ::nvtx3::v1::detail::optional_scoped_range_in<D> optional_nvtx3_range__;           \
3177   if (C) {                                                                           \
3178     static ::nvtx3::v1::registered_string_in<D> const nvtx3_func_name__{__func__};   \
3179     static ::nvtx3::v1::event_attributes const nvtx3_func_attr__{nvtx3_func_name__}; \
3180     optional_nvtx3_range__.begin(nvtx3_func_attr__);                                 \
3181   } (void)0
3182 #else /* NVTX_DISABLE */
3183 #define NVTX3_V1_FUNC_RANGE_IN(D) (void)0
3184 #define NVTX3_V1_FUNC_RANGE_IF_IN(D, C) (void)(C)
3185 #endif /* NVTX_DISABLE */
3186 
3187 /**
3188  * @brief Convenience macro for generating a range in the global domain from the
3189  * lifetime of a function.
3190  *
3191  * This macro is useful for generating an NVTX range in the global domain from
3192  * the entry point of a function to its exit. It is intended to be the first
3193  * line of the function.
3194  *
3195  * Constructs a static `registered_string_in` using the name of the immediately
3196  * enclosing function returned by `__func__` and constructs a
3197  * `nvtx3::scoped_range` using the registered function name as the range's
3198  * message.
3199  *
3200  * Example:
3201  * \code{.cpp}
3202  * void foo(...) {
3203  *    NVTX3_FUNC_RANGE(); // Range begins on entry to foo()
3204  *    // do stuff
3205  *    ...
3206  * } // Range ends on return from foo()
3207  * \endcode
3208  */
3209 #define NVTX3_V1_FUNC_RANGE() NVTX3_V1_FUNC_RANGE_IN(::nvtx3::v1::domain::global)
3210 
3211 /**
3212  * @brief Convenience macro for generating a range in the global domain from the
3213  * lifetime of a function if the given boolean expression evaluates to true.
3214  *
3215  * Similar to `NVTX3_V1_FUNC_RANGE()`, the only difference being that
3216  * `NVTX3_V1_FUNC_RANGE_IF(C)` only generates a range if the given boolean
3217  * expression evaluates to true.
3218  *
3219  * @param[in] C Boolean expression used to determine if a range should be
3220  * generated.
3221  */
3222 #define NVTX3_V1_FUNC_RANGE_IF(C) NVTX3_V1_FUNC_RANGE_IF_IN(::nvtx3::v1::domain::global, C)
3223 
3224 // We need another helper macro because the other one will get undefined
3225 #if __has_cpp_attribute(nodiscard)
3226 #define NVTX3_V1_NO_DISCARD [[nodiscard]]
3227 #else
3228 #define NVTX3_V1_NO_DISCARD
3229 #endif
3230 /**
3231  * @brief Convenience macro for generating a sspecialization of nvtx3::schema::get
3232  * for an existing `struct`.
3233  *
3234  * Use this macro after your struct to enable the struct to be used as a payload.
3235  *
3236  * \note This macro must not be used inside a namespace.
3237  *
3238  * Example:
3239  * \code{.cpp}
3240  * struct SensorData
3241  * {
3242  *     int32_t sensorId;
3243  *     uint8_t channelId;
3244  * };
3245  *
3246  * NVTX3_DEFINE_SCHEMA_GET(
3247  *     my_domain,
3248  *     SensorData,
3249  *     "SensorEvent",
3250  *     NVTX_PAYLOAD_ENTRIES(
3251  *         (sensorId, TYPE_INT32, "SensorID"),
3252  *         (channelId, TYPE_UINT8, "ChannelID")
3253  *     )
3254  * )
3255  * \endcode
3256  *
3257  * @param[in] dom The NVTX domain.
3258  * @param[in] struct_id The name of the struct.
3259  * @param[in] schema_name Name of the payload schema.
3260  * @param[in] entries Payload schema entries using NVTX_PAYLOAD_ENTRIES macro.
3261  */
3262 #define NVTX3_V1_DEFINE_SCHEMA_GET(dom, struct_id, schema_name, entries)                               \
3263     template <>                                                                                        \
3264     NVTX3_V1_NO_DISCARD inline nvtx3::v1::schema const& nvtx3::v1::schema::get<struct_id>() noexcept   \
3265     {                                                                                                  \
3266         static_assert(                                                                                 \
3267             std::is_standard_layout<struct_id>::value,                                                 \
3268             "structs used for NVTX3 payload schema must be standard layout");                          \
3269         static_assert(                                                                                 \
3270             std::is_trivially_copyable<struct_id>::value,                                              \
3271             "structs used for NVTX3 payload schema must be trivially copyable");                       \
3272         using nvtx_struct_id = struct_id; /* avoids issues with namespaced struct_id */                \
3273         _NVTX_DEFINE_SCHEMA_FOR_STRUCT(nvtx_struct_id, schema_name, static constexpr, entries)         \
3274         static const schema s{                                                                         \
3275             nvtxPayloadSchemaRegister(nvtx3::v1::domain::get<dom>(), &nvtx_struct_id##Attr)};          \
3276         return s;                                                                                      \
3277     }
3278 
3279 /* When inlining this version, versioned macros must have unversioned aliases.
3280  * For each NVTX3_Vx_ #define, make an NVTX3_ alias of it here.*/
3281 #if defined(NVTX3_INLINE_THIS_VERSION)
3282 /* clang format off */
3283 #define NVTX3_FUNC_RANGE        NVTX3_V1_FUNC_RANGE
3284 #define NVTX3_FUNC_RANGE_IF     NVTX3_V1_FUNC_RANGE_IF
3285 #define NVTX3_FUNC_RANGE_IN     NVTX3_V1_FUNC_RANGE_IN
3286 #define NVTX3_FUNC_RANGE_IF_IN  NVTX3_V1_FUNC_RANGE_IF_IN
3287 #define NVTX3_DEFINE_SCHEMA_GET NVTX3_V1_DEFINE_SCHEMA_GET
3288 /* clang format on */
3289 #endif
3290 
3291 #endif  // NVTX3_CPP_DEFINITIONS_V1_0
3292 
3293 /* Add functionality for new minor versions here, by copying the above section enclosed
3294  * in #ifndef NVTX3_CPP_DEFINITIONS_Vx_y, and incrementing the minor version.  This code
3295  * is an example of how additions for version 1.2 would look, indented for clarity.  Note
3296  * that the versioned symbols and macros are always provided, and the unversioned symbols
3297  * are only provided if NVTX3_INLINE_THIS_VERSION was defined at the top of this header.
3298  *
3299  * \code{.cpp}
3300  * #ifndef NVTX3_CPP_DEFINITIONS_V1_2
3301  * #define NVTX3_CPP_DEFINITIONS_V1_2
3302  *     namespace nvtx3 {
3303  *         NVTX3_INLINE_IF_REQUESTED namespace NVTX3_VERSION_NAMESPACE {
3304  *             class new_class {};
3305  *             inline void new_function() {}
3306  *         }
3307  *     }
3308  *
3309  *     // Macros must have the major version in their names:
3310  *     #define NVTX3_V1_NEW_MACRO_A() ...
3311  *     #define NVTX3_V1_NEW_MACRO_B() ...
3312  *
3313  *     // If inlining, make aliases for the macros with the version number omitted
3314  *     #if defined(NVTX3_INLINE_THIS_VERSION)
3315  *         #define NVTX3_NEW_MACRO_A NVTX3_V1_NEW_MACRO_A
3316  *         #define NVTX3_NEW_MACRO_B NVTX3_V1_NEW_MACRO_B
3317  *     #endif
3318  * #endif // NVTX3_CPP_DEFINITIONS_V1_2
3319  * \endcode
3320  */
3321 
3322 /* Undefine all temporarily-defined unversioned macros, which would conflict with
3323  * subsequent includes of different versions of this header. */
3324 #undef NVTX3_CPP_VERSION_MAJOR
3325 #undef NVTX3_CPP_VERSION_MINOR
3326 #undef NVTX3_CONCAT
3327 #undef NVTX3_NAMESPACE_FOR
3328 #undef NVTX3_VERSION_NAMESPACE
3329 #undef NVTX3_MINOR_NAMESPACE_FOR
3330 #undef NVTX3_MINOR_VERSION_NAMESPACE
3331 #undef NVTX3_INLINE_IF_REQUESTED
3332 #undef NVTX3_CONSTEXPR_IF_CPP14
3333 #undef NVTX3_MAYBE_UNUSED
3334 #undef NVTX3_NO_DISCARD
3335 
3336 #if defined(NVTX3_INLINE_THIS_VERSION)
3337 #undef NVTX3_INLINE_THIS_VERSION
3338 #endif
3339 
3340 #if defined(NVTX3_USE_CHECKED_OVERLOADS_FOR_GET_DEFINED_HERE)
3341 #undef NVTX3_USE_CHECKED_OVERLOADS_FOR_GET_DEFINED_HERE
3342 #undef NVTX3_USE_CHECKED_OVERLOADS_FOR_GET
3343 #endif
3344 
3345 #if defined(NVTX3_STATIC_ASSERT_DEFINED_HERE)
3346 #undef NVTX3_STATIC_ASSERT_DEFINED_HERE
3347 #undef NVTX3_STATIC_ASSERT
3348 #endif