1 | /* |
2 | * Copyright 2016-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | #pragma once |
18 | |
19 | #include <folly/CPortability.h> |
20 | |
21 | #include <cstdint> |
22 | #include <cstring> |
23 | #include <type_traits> |
24 | |
25 | namespace folly { |
26 | |
27 | namespace detail { |
28 | |
29 | template <typename Char> |
30 | constexpr size_t constexpr_strlen_internal(const Char* s, size_t len) { |
31 | // clang-format off |
32 | return |
33 | *(s + 0) == Char(0) ? len + 0 : |
34 | *(s + 1) == Char(0) ? len + 1 : |
35 | *(s + 2) == Char(0) ? len + 2 : |
36 | *(s + 3) == Char(0) ? len + 3 : |
37 | *(s + 4) == Char(0) ? len + 4 : |
38 | *(s + 5) == Char(0) ? len + 5 : |
39 | *(s + 6) == Char(0) ? len + 6 : |
40 | *(s + 7) == Char(0) ? len + 7 : |
41 | constexpr_strlen_internal(s + 8, len + 8); |
42 | // clang-format on |
43 | } |
44 | static_assert( |
45 | constexpr_strlen_internal("123456789" , 0) == 9, |
46 | "Someone appears to have broken constexpr_strlen..." ); |
47 | |
48 | template <typename Char> |
49 | constexpr int constexpr_strcmp_internal(const Char* s1, const Char* s2) { |
50 | return (*s1 == '\0' || *s1 != *s2) |
51 | ? (static_cast<int>(*s1 - *s2)) |
52 | : constexpr_strcmp_internal(s1 + 1, s2 + 1); |
53 | } |
54 | } // namespace detail |
55 | |
56 | template <typename Char> |
57 | constexpr size_t constexpr_strlen(const Char* s) { |
58 | return detail::constexpr_strlen_internal(s, 0); |
59 | } |
60 | |
61 | template <> |
62 | constexpr size_t constexpr_strlen(const char* s) { |
63 | #if FOLLY_HAS_FEATURE(cxx_constexpr_string_builtins) |
64 | // clang provides a constexpr builtin |
65 | return __builtin_strlen(s); |
66 | #elif defined(__GNUC__) && !defined(__clang__) |
67 | // strlen() happens to already be constexpr under gcc |
68 | return std::strlen(s); |
69 | #else |
70 | return detail::constexpr_strlen_internal(s, 0); |
71 | #endif |
72 | } |
73 | |
74 | template <typename Char> |
75 | constexpr int constexpr_strcmp(const Char* s1, const Char* s2) { |
76 | return detail::constexpr_strcmp_internal(s1, s2); |
77 | } |
78 | |
79 | template <> |
80 | constexpr int constexpr_strcmp(const char* s1, const char* s2) { |
81 | #if FOLLY_HAS_FEATURE(cxx_constexpr_string_builtins) |
82 | // clang provides a constexpr builtin |
83 | return __builtin_strcmp(s1, s2); |
84 | #elif defined(__GNUC__) && !defined(__clang__) |
85 | // strcmp() happens to already be constexpr under gcc |
86 | return std::strcmp(s1, s2); |
87 | #else |
88 | return detail::constexpr_strcmp_internal(s1, s2); |
89 | #endif |
90 | } |
91 | } // namespace folly |
92 | |