| // Copyright 2023 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <stdint.h> |
| |
| #include <memory> |
| #include <string_view> |
| |
| #ifndef LOCKDEP_LOCK_NAME_HELPER_H_ |
| #define LOCKDEP_LOCK_NAME_HELPER_H_ |
| |
| namespace lockdep::internal { |
| |
| template <typename Class, int Line> |
| class LockNameHelperStorage { |
| public: |
| constexpr LockNameHelperStorage() : LockNameHelperStorage(std::make_index_sequence<Size>{}) {} |
| constexpr const char* Name() const { return name_; } |
| |
| private: |
| struct Range { |
| const size_t size; |
| const size_t offset; |
| }; |
| |
| struct Info { |
| const char* const buffer; |
| const Range class_name; |
| const Range line_num; |
| }; |
| |
| static constexpr const char* kClassPrefix = "Class = "; |
| #if defined(__clang__) |
| static constexpr const char* kLinePrefix = ", Line = "; |
| #elif defined(__GNUC__) |
| static constexpr const char* kLinePrefix = "; int Line = "; |
| #endif |
| |
| static constexpr Info Get() { |
| const char* const function_name = __PRETTY_FUNCTION__; |
| const size_t class_name_start = |
| Find(function_name, kClassPrefix) + std::string_view(kClassPrefix).size(); |
| const size_t class_name_end = |
| Find(function_name + class_name_start, kLinePrefix) + class_name_start; |
| const size_t class_name_size = class_name_end - class_name_start; |
| |
| const size_t line_num_start = class_name_end + std::string_view(kLinePrefix).size(); |
| const size_t line_num_end = Find(function_name + line_num_start, "]") + line_num_start; |
| const size_t line_num_size = line_num_end - line_num_start; |
| |
| return {function_name, {class_name_size, class_name_start}, {line_num_size, line_num_start}}; |
| } |
| |
| inline static constexpr Range ClassName = Get().class_name; |
| inline static constexpr Range LineNum = Get().line_num; |
| inline static constexpr size_t Size = ClassName.size + LineNum.size + 2; |
| inline static constexpr const char* Data = Get().buffer; |
| |
| static constexpr size_t Find(const char* string, const char* substring) { |
| size_t i = 0; |
| |
| while (string[i]) { |
| for (size_t j = 0; true; ++j) { |
| if (!substring[j]) { |
| return i; |
| } |
| |
| if (string[i + j] != substring[j]) { |
| break; |
| } |
| } |
| ++i; |
| } |
| |
| return i; |
| } |
| |
| // A helper method which makes the index_sequence constructor's initializers a |
| // bit easier to read. This method takes the index of our constant string and |
| // returns the character which belongs at that position. |
| inline static constexpr char GetChar(size_t index) { |
| // If we are within the class name size, return a character from there. |
| if (index < ClassName.size) |
| return Data[index + ClassName.offset]; |
| |
| // If we are one after the class name, add the ':' separator. |
| if (index == ClassName.size) |
| return ':'; |
| |
| // If we are still within the buffer, then the character must be from the |
| // line number section. |
| if (index < Size - 1) |
| return Data[index - ClassName.size - 1 + LineNum.offset]; |
| |
| // Anything else means we are at, or beyond, the end of our string. Return |
| // the null terminator. |
| return '\0'; |
| } |
| |
| template <size_t... ndx> |
| explicit constexpr LockNameHelperStorage(std::index_sequence<ndx...>) |
| : name_{(GetChar(ndx))...} {} |
| |
| const char name_[Size]; |
| }; |
| |
| template <typename Class, int Line> |
| class LockNameHelper { |
| public: |
| static constexpr const char* Name() { return storage_.Name(); } |
| |
| private: |
| static constexpr LockNameHelperStorage<Class, Line> storage_{}; |
| }; |
| |
| } // namespace lockdep::internal |
| |
| #endif // LOCKDEP_LOCK_NAME_HELPER_H_ |