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
25namespace folly {
26
27namespace detail {
28
29template <typename Char>
30constexpr 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}
44static_assert(
45 constexpr_strlen_internal("123456789", 0) == 9,
46 "Someone appears to have broken constexpr_strlen...");
47
48template <typename Char>
49constexpr 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
56template <typename Char>
57constexpr size_t constexpr_strlen(const Char* s) {
58 return detail::constexpr_strlen_internal(s, 0);
59}
60
61template <>
62constexpr 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
74template <typename Char>
75constexpr int constexpr_strcmp(const Char* s1, const Char* s2) {
76 return detail::constexpr_strcmp_internal(s1, s2);
77}
78
79template <>
80constexpr 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