Skip to content

Commit

Permalink
[libc] Add a library of standalone C++ utilities.
Browse files Browse the repository at this point in the history
Some of the existing utils in utils/UnitTest/Test.h have been moved to
this new library.

Reviewers: abrachet, gchatelet

Tags: #libc-project

Differential Revision: https://reviews.llvm.org/D73530
  • Loading branch information
Siva Chandra Reddy committed Jan 29, 2020
1 parent 4f2e2ac commit c6bc106
Show file tree
Hide file tree
Showing 12 changed files with 317 additions and 81 deletions.
3 changes: 3 additions & 0 deletions libc/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
44 changes: 44 additions & 0 deletions libc/cmake/modules/LLVMLibCRules.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -375,3 +375,47 @@ function(add_libc_testsuite suite_name)
add_custom_target(${suite_name})
add_dependencies(check-libc ${suite_name})
endfunction(add_libc_testsuite)

# Rule to add header only libraries.
# Usage
# add_header_library(
# <target name>
# HDRS <list of .h files part of the library>
# DEPENDS <list of dependencies>
# )
function(add_header_library target_name)
cmake_parse_arguments(
"ADD_HEADER"
"" # No optional arguments
"" # No Single value arguments
"HDRS;DEPENDS" # Multi-value arguments
${ARGN}
)

if(NOT ADD_HEADER_HDRS)
message(FATAL_ERROR "'add_header_library' target requires a HDRS list of .h files.")
endif()

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_HDRS)
list(APPEND FULL_HDR_PATHS ${CMAKE_CURRENT_SOURCE_DIR}/${hdr})
endforeach()

set(interface_target_name "${target_name}_header_library__")

add_library(${interface_target_name} INTERFACE)
target_sources(${interface_target_name} INTERFACE ${FULL_HDR_PATHS})
if(ADD_HEADER_DEPENDS)
add_dependencies(${interface_target_name} ${ADD_HEADER_DEPENDS})
endif()

add_custom_target(${target_name})
add_dependencies(${target_name} ${interface_target_name})
set_target_properties(
${target_name}
PROPERTIES
"TARGET_TYPE" "HDR_LIBRARY"
)
endfunction(add_header_library)
1 change: 1 addition & 0 deletions libc/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
add_subdirectory(CPP)
add_subdirectory(HdrGen)
add_subdirectory(UnitTest)
add_subdirectory(benchmarks)
47 changes: 47 additions & 0 deletions libc/utils/CPP/Array.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//===--------- 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 <stddef.h> // For size_t.

namespace __llvm_libc {
namespace cpp {

template <class T, size_t N> struct Array {
static_assert(N != 0, "Cannot create a __llvm_libc::cpp::Array of size 0.");

T Data[N];

using iterator = T *;
using const_iterator = const T *;

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 N; }

constexpr bool empty() const { return N == 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
90 changes: 90 additions & 0 deletions libc/utils/CPP/ArrayRef.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//===----------------- 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 "Array.h"

#include <stddef.h> // 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 <typename T> class ArrayRef {
public:
using iterator = const T *;

private:
const T *Data = nullptr;
size_t Length = 0;

public:
ArrayRef() = default;

// From Array.
template <size_t N>
ArrayRef(const Array<T, N> &Arr) : Data(Arr.Data), Length(N) {}

// Construct an ArrayRef from a single element.
explicit 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 <size_t N>
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 <typename T> class MutableArrayRef : public ArrayRef<T> {
public:
using iterator = T *;

// From Array.
template <size_t N> MutableArrayRef(Array<T, N> &Arr) : ArrayRef<T>(Arr) {}

// Construct from a single element.
explicit MutableArrayRef(T &OneElt) : ArrayRef<T>(OneElt) {}

// Construct from a pointer and length.
MutableArrayRef(T *data, size_t length) : ArrayRef<T>(data, length) {}

// Construct from a range.
MutableArrayRef(T *begin, T *end) : ArrayRef<T>(begin, end) {}

// Construct from a C array.
template <size_t N>
constexpr MutableArrayRef(T (&Arr)[N]) : ArrayRef<T>(Arr) {}

T *data() const { return const_cast<T *>(ArrayRef<T>::data()); }

iterator begin() const { return data(); }
iterator end() const { return data() + size(); }

T &operator[](size_t Index) const { return data()[Index]; }
};

} // namespace cpp
} // namespace __llvm_libc
7 changes: 7 additions & 0 deletions libc/utils/CPP/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
add_header_library(
standalone_cpp
HDRS
Array.h
ArrayRef.h
TypeTraits.h
)
12 changes: 12 additions & 0 deletions libc/utils/CPP/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
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 <stddef.h>` and not `#include <cstddef>`.
3. The utilities should be defined in the namespace `__llvm_libc::cpp`. The
higher level namespace should have a `__` prefix to avoid symbol name pollution
when the utilities are used in implementation of public functions.
19 changes: 19 additions & 0 deletions libc/utils/CPP/StringRef.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//===----------------- A standalone StringRef 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 "ArrayRef.h"

namespace __llvm_libc {
namespace cpp {

class StringRef : public ArrayRef<char> {
// More methods like those in llvm::StringRef can be added as needed.
};

} // namespace cpp
} // namespace __llvm_libc
50 changes: 50 additions & 0 deletions libc/utils/CPP/TypeTraits.h
Original file line number Diff line number Diff line change
@@ -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 <bool B, typename T> struct EnableIf;
template <typename T> struct EnableIf<true, T> { typedef T Type; };

template <bool B, typename T>
using EnableIfType = typename EnableIf<B, T>::Type;

struct TrueValue {
static constexpr bool Value = true;
};

struct FalseValue {
static constexpr bool Value = false;
};

template <typename Type> struct IsIntegral : public FalseValue {};
template <> struct IsIntegral<char> : public TrueValue {};
template <> struct IsIntegral<signed char> : public TrueValue {};
template <> struct IsIntegral<unsigned char> : public TrueValue {};
template <> struct IsIntegral<short> : public TrueValue {};
template <> struct IsIntegral<unsigned short> : public TrueValue {};
template <> struct IsIntegral<int> : public TrueValue {};
template <> struct IsIntegral<unsigned int> : public TrueValue {};
template <> struct IsIntegral<long> : public TrueValue {};
template <> struct IsIntegral<unsigned long> : public TrueValue {};
template <> struct IsIntegral<long long> : public TrueValue {};
template <> struct IsIntegral<unsigned long long> : public TrueValue {};
template <> struct IsIntegral<bool> : public TrueValue {};

template <typename Type> struct IsIntegralNotBool : public IsIntegral<Type> {};
template <> struct IsIntegralNotBool<bool> : public FalseValue {};

template <typename T> struct IsPointerType : public FalseValue {};
template <typename T> struct IsPointerType<T *> : public TrueValue {};

template <typename T1, typename T2> struct IsSame : public FalseValue {};
template <typename T> struct IsSame<T, T> : public TrueValue {};

} // namespace cpp
} // namespace __llvm_libc
2 changes: 2 additions & 0 deletions libc/utils/UnitTest/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ add_llvm_library(
Test.h
LINK_COMPONENTS Support
)
target_include_directories(LibcUnitTest PUBLIC ${LIBC_SOURCE_DIR})
add_dependencies(LibcUnitTest standalone_cpp)
6 changes: 3 additions & 3 deletions libc/utils/UnitTest/Test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"

namespace llvm_libc {
namespace __llvm_libc {
namespace testing {

// This need not be a class as all it has is a single read-write state variable.
Expand Down Expand Up @@ -224,6 +224,6 @@ bool Test::testStrNe(RunContext &Ctx, const char *LHS, const char *RHS,
}

} // namespace testing
} // namespace llvm_libc
} // namespace __llvm_libc

int main() { return llvm_libc::testing::Test::runTests(); }
int main() { return __llvm_libc::testing::Test::runTests(); }
Loading

0 comments on commit c6bc106

Please sign in to comment.