diff --git a/libc/CMakeLists.txt b/libc/CMakeLists.txt --- a/libc/CMakeLists.txt +++ b/libc/CMakeLists.txt @@ -1,5 +1,8 @@ cmake_minimum_required(VERSION 3.4.3) +# Use old version of target_sources command which converts the source +# file paths to full paths. +cmake_policy(SET CMP0076 OLD) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules") # The top-level source directory of libc. diff --git a/libc/cmake/modules/LLVMLibCRules.cmake b/libc/cmake/modules/LLVMLibCRules.cmake --- a/libc/cmake/modules/LLVMLibCRules.cmake +++ b/libc/cmake/modules/LLVMLibCRules.cmake @@ -375,3 +375,26 @@ add_custom_target(${suite_name}) add_dependencies(check-libc ${suite_name}) endfunction(add_libc_testsuite) + +function(add_header_library target_name) + cmake_parse_arguments( + "ADD_HEADER_LIB" + "" # No optional arguments + "" # Single value arguments + "HDRS;DEPENDS" # Multi-value arguments + ${ARGN} + ) + + set(FULL_HDR_PATHS "") + # TODO: Remove this foreach block when we can switch to the new + # version of the CMake policy CMP0076. + foreach(hdr IN LISTS ADD_HEADER_LIB_HDRS) + list(APPEND FULL_HDR_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/${hdr}) + endforeach() + + add_library(${target_name} INTERFACE) + target_sources(${target_name} INTERFACE ${FULL_HDR_PATHS}) + if(ADD_HEADER_DEPENDS) + add_dependencies(${target_name} ${ADD_HEADER_DEPENDS}) + endif() +endfunction(add_header_library) diff --git a/libc/utils/CMakeLists.txt b/libc/utils/CMakeLists.txt --- a/libc/utils/CMakeLists.txt +++ b/libc/utils/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(CPP) add_subdirectory(HdrGen) add_subdirectory(UnitTest) add_subdirectory(benchmarks) diff --git a/libc/utils/CPP/Array.h b/libc/utils/CPP/Array.h new file mode 100644 --- /dev/null +++ b/libc/utils/CPP/Array.h @@ -0,0 +1,56 @@ +//===--------- A self contained equivalent of std::array --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include // For size_t. + +namespace llvm_libc { +namespace cpp { + +template class Array { +private: + T Data[N]; + size_t Length = N; + +public: + using iterator = T *; + using const_iterator = const T *; + + Array() = default; + + Array(const T (&Arr)[N]) { + for (size_t i = 0; i < N; ++i) { + Data[i] = Arr[i]; + } + } + + constexpr T *data() { return Data; } + constexpr const T *data() const { return Data; } + + constexpr T &front() { return Data[0]; } + constexpr T &front() const { return Data[0]; } + + constexpr T &back() { return Data[N - 1]; } + constexpr T &back() const { return Data[N - 1]; } + + constexpr T &operator[](size_t Index) { return Data[Index]; } + + constexpr const T &operator[](size_t Index) const { return Data[Index]; } + + constexpr size_t size() const { return Length; } + + constexpr bool empty() const { return Length == 0; } + + constexpr iterator begin() { return Data; } + constexpr const_iterator begin() const { return Data; } + + constexpr iterator end() { return Data + N; } + const_iterator end() const { return Data + N; } +}; + +} // namespace cpp +} // namespace llvm_libc diff --git a/libc/utils/CPP/ArrayRef.h b/libc/utils/CPP/ArrayRef.h new file mode 100644 --- /dev/null +++ b/libc/utils/CPP/ArrayRef.h @@ -0,0 +1,89 @@ +//===----------------- Self contained ArrayRef type -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include // For size_t. + +namespace llvm_libc { +namespace cpp { + +// The implementations of ArrayRef and MutualArrayRef in this file are based +// on the implementations of the types with the same names in +// llvm/ADT/ArrayRef.h. The implementations in this file are of a limited +// functionality, but can be extended in an as needed basis. + +template class ArrayRef { +public: + using iterator = const T *; + using const_iterator = const T *; + +private: + const T *Data = nullptr; + size_t Length = 0; + +public: + ArrayRef() = default; + + // Construct an ArrayRef from a single element. + ArrayRef(const T &OneElt) : Data(&OneElt), Length(1) {} + + // Construct an ArrayRef from a pointer and length. + ArrayRef(const T *data, size_t length) : Data(data), Length(length) {} + + // Construct an ArrayRef from a range. + ArrayRef(const T *begin, const T *end) : Data(begin), Length(end - begin) {} + + // Construct an ArrayRef from a C array. + template + constexpr ArrayRef(const T (&Arr)[N]) : Data(Arr), Length(N) {} + + iterator begin() const { return Data; } + iterator end() const { return Data + Length; } + + bool empty() const { return Length == 0; } + + const T *data() const { return Data; } + + size_t size() const { return Length; } + + const T &operator[](size_t Index) const { return Data[Index]; } +}; + +template class MutableArrayRef : public ArrayRef { +public: + using iterator = T *; +#ifdef __size_t__ + using size_t = __size_t__; +#else + using size_t = unsigned long long; +#endif // __size_t__ + + MutableArrayRef() = default; + + // Construct an ArrayRef from a single element. + MutableArrayRef(const T &OneElt) : ArrayRef(OneElt) {} + + // Construct an ArrayRef from a pointer and length. + MutableArrayRef(const T *data, size_t length) : ArrayRef(data, length) {} + + // Construct an ArrayRef from a range. + MutableArrayRef(const T *begin, const T *end) : ArrayRef(begin, end) {} + + // Construct an ArrayRef from a C array. + template + constexpr MutableArrayRef(const T (&Arr)[N]) : ArrayRef(Arr) {} + + T *data() const { return const_cast(ArrayRef::data()); } + + iterator begin() const { return data(); } + iterator end() const { return data() + this->size(); } + + T &operator[](size_t Index) const { return data()[Index]; } +}; + +} // namespace cpp +} // namespace llvm_libc diff --git a/libc/utils/CPP/CMakeLists.txt b/libc/utils/CPP/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/utils/CPP/CMakeLists.txt @@ -0,0 +1,7 @@ +add_header_library( + standalone_cpp + HDRS + Array.h + ArrayRef.h + TypeTraits.h +) diff --git a/libc/utils/CPP/README.md b/libc/utils/CPP/README.md new file mode 100644 --- /dev/null +++ b/libc/utils/CPP/README.md @@ -0,0 +1,9 @@ +This directory contains re-implementations of some C++ standard library as well +as some LLVM utilities. These are to be used with internal LLVM libc code and +tests. More utilities will be added on an as needed basis. There are certain +rules to be followed for future changes and additions: + +1. Only two kind of headers can be included: Other headers from this directory, +and free standing C headers. +2. Free standing C headers are to be included as C headers and not as C++ +headers. That is, use `#include ` and not `#include `. diff --git a/libc/utils/CPP/TypeTraits.h b/libc/utils/CPP/TypeTraits.h new file mode 100644 --- /dev/null +++ b/libc/utils/CPP/TypeTraits.h @@ -0,0 +1,50 @@ +//===----------------- Self contained C++ type traits -----------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +namespace llvm_libc { +namespace cpp { + +template struct EnableIf; +template struct EnableIf { typedef T Type; }; + +template +using EnableIfType = typename EnableIf::Type; + +struct TrueValue { + static constexpr bool Value = true; +}; + +struct FalseValue { + static constexpr bool Value = false; +}; + +template struct IsIntegral : public FalseValue {}; +template <> struct IsIntegral : public TrueValue {}; +template <> struct IsIntegral : public TrueValue {}; +template <> struct IsIntegral : public TrueValue {}; +template <> struct IsIntegral : public TrueValue {}; +template <> struct IsIntegral : public TrueValue {}; +template <> struct IsIntegral : public TrueValue {}; +template <> struct IsIntegral : public TrueValue {}; +template <> struct IsIntegral : public TrueValue {}; +template <> struct IsIntegral : public TrueValue {}; +template <> struct IsIntegral : public TrueValue {}; +template <> struct IsIntegral : public TrueValue {}; +template <> struct IsIntegral : public TrueValue {}; + +template struct IsIntegralNotBool : public IsIntegral {}; +template <> struct IsIntegralNotBool : public FalseValue {}; + +template struct IsPointerType : public FalseValue {}; +template struct IsPointerType : public TrueValue {}; + +template struct IsSame : public FalseValue {}; +template struct IsSame : public TrueValue {}; + +} // namespace cpp +} // namespace llvm_libc diff --git a/libc/utils/UnitTest/CMakeLists.txt b/libc/utils/UnitTest/CMakeLists.txt --- a/libc/utils/UnitTest/CMakeLists.txt +++ b/libc/utils/UnitTest/CMakeLists.txt @@ -4,3 +4,5 @@ Test.h LINK_COMPONENTS Support ) +target_include_directories(LibcUnitTest PUBLIC ${LIBC_SOURCE_DIR}) +add_dependencies(LibcUnitTest standalone_cpp) diff --git a/libc/utils/UnitTest/Test.h b/libc/utils/UnitTest/Test.h --- a/libc/utils/UnitTest/Test.h +++ b/libc/utils/UnitTest/Test.h @@ -6,55 +6,14 @@ // //===----------------------------------------------------------------------===// -// This file should stricly not include any other file. Not even standard -// library headers. +// This file can only include headers from utils/CPP/. No other header should be +// included. + +#include "utils/CPP/TypeTraits.h" namespace llvm_libc { namespace testing { -// We define our own EnableIf and IsIntegerType traits because we do not want to -// include even the standard header . -template struct EnableIf; -template struct EnableIf { typedef T Type; }; - -template -using EnableIfType = typename EnableIf::Type; - -template struct IsIntegerType { - static const bool Value = false; -}; - -template <> struct IsIntegerType { static const bool Value = true; }; -template <> struct IsIntegerType { - static const bool Value = true; -}; - -template <> struct IsIntegerType { static const bool Value = true; }; -template <> struct IsIntegerType { - static const bool Value = true; -}; - -template <> struct IsIntegerType { static const bool Value = true; }; -template <> struct IsIntegerType { - static const bool Value = true; -}; - -template <> struct IsIntegerType { static const bool Value = true; }; -template <> struct IsIntegerType { - static const bool Value = true; -}; - -template <> struct IsIntegerType { static const bool Value = true; }; -template <> struct IsIntegerType { - static const bool Value = true; -}; - -template struct IsPointerType; - -template struct IsPointerType { - static const bool Value = true; -}; - class RunContext; // Only the following conditions are supported. Notice that we do not have @@ -104,16 +63,18 @@ // is the result of the |Cond| operation on |LHS| and |RHS|. Though not bad, // mismatched |LHS| and |RHS| types can potentially succeed because of type // promotion. - template ::Value, ValType> = 0> + template < + typename ValType, + cpp::EnableIfType::Value, ValType> = 0> static bool test(RunContext &Ctx, TestCondition Cond, ValType LHS, ValType RHS, const char *LHSStr, const char *RHSStr, const char *File, unsigned long Line) { return internal::test(Ctx, Cond, LHS, RHS, LHSStr, RHSStr, File, Line); } - template ::Value, ValType> = nullptr> + template < + typename ValType, + cpp::EnableIfType::Value, ValType> = nullptr> static bool test(RunContext &Ctx, TestCondition Cond, ValType LHS, ValType RHS, const char *LHSStr, const char *RHSStr, const char *File, unsigned long Line) {