diff --git a/include/llvm/AlignOf.h b/include/llvm/AlignOf.h new file mode 100644 index 0000000000..5ff04d8c04 --- /dev/null +++ b/include/llvm/AlignOf.h @@ -0,0 +1,234 @@ +//===--- AlignOf.h - Portable calculation of type alignment -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the AlignOf function that computes alignments for +// arbitrary types. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_ALIGNOF_H +#define LLVM_SUPPORT_ALIGNOF_H + +#include + +#ifndef __has_feature +# define __has_feature(x) 0 +#endif + +namespace llvm { +template +struct AlignmentCalcImpl { + char x; +#if defined(_MSC_VER) +// Disables "structure was padded due to __declspec(align())" warnings that are +// generated by any class using AlignOf with a manually specified alignment. +// Although the warning is disabled in the LLVM project we need this pragma +// as AlignOf.h is a published support header that's available for use +// out-of-tree, and we would like that to compile cleanly at /W4. +#pragma warning(suppress : 4324) +#endif + T t; +private: + AlignmentCalcImpl() {} // Never instantiate. +}; + +/// AlignOf - A templated class that contains an enum value representing +/// the alignment of the template argument. For example, +/// AlignOf::Alignment represents the alignment of type "int". The +/// alignment calculated is the minimum alignment, and not necessarily +/// the "desired" alignment returned by GCC's __alignof__ (for example). Note +/// that because the alignment is an enum value, it can be used as a +/// compile-time constant (e.g., for template instantiation). +template +struct AlignOf { +#ifndef _MSC_VER + // Avoid warnings from GCC like: + // comparison between 'enum llvm::AlignOf::' and 'enum + // llvm::AlignOf::' [-Wenum-compare] + // by using constexpr instead of enum. + // (except on MSVC, since it doesn't support constexpr yet). + static constexpr unsigned Alignment = + static_cast(sizeof(AlignmentCalcImpl) - sizeof(T)); +#else + enum { Alignment = + static_cast(sizeof(AlignmentCalcImpl) - sizeof(T)) }; +#endif + enum { Alignment_GreaterEqual_2Bytes = Alignment >= 2 ? 1 : 0 }; + enum { Alignment_GreaterEqual_4Bytes = Alignment >= 4 ? 1 : 0 }; + enum { Alignment_GreaterEqual_8Bytes = Alignment >= 8 ? 1 : 0 }; + enum { Alignment_GreaterEqual_16Bytes = Alignment >= 16 ? 1 : 0 }; + + enum { Alignment_LessEqual_2Bytes = Alignment <= 2 ? 1 : 0 }; + enum { Alignment_LessEqual_4Bytes = Alignment <= 4 ? 1 : 0 }; + enum { Alignment_LessEqual_8Bytes = Alignment <= 8 ? 1 : 0 }; + enum { Alignment_LessEqual_16Bytes = Alignment <= 16 ? 1 : 0 }; +}; + +#ifndef _MSC_VER +template constexpr unsigned AlignOf::Alignment; +#endif + +/// alignOf - A templated function that returns the minimum alignment of +/// of a type. This provides no extra functionality beyond the AlignOf +/// class besides some cosmetic cleanliness. Example usage: +/// alignOf() returns the alignment of an int. +template +inline unsigned alignOf() { return AlignOf::Alignment; } + +/// \struct AlignedCharArray +/// \brief Helper for building an aligned character array type. +/// +/// This template is used to explicitly build up a collection of aligned +/// character array types. We have to build these up using a macro and explicit +/// specialization to cope with old versions of MSVC and GCC where only an +/// integer literal can be used to specify an alignment constraint. Once built +/// up here, we can then begin to indirect between these using normal C++ +/// template parameters. + +// MSVC requires special handling here. +#ifndef _MSC_VER + +#if __has_feature(cxx_alignas) +template +struct AlignedCharArray { + alignas(Alignment) char buffer[Size]; +}; + +#elif defined(__GNUC__) || defined(__IBM_ATTRIBUTES) +/// \brief Create a type with an aligned char buffer. +template +struct AlignedCharArray; + +#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \ + template \ + struct AlignedCharArray { \ + __attribute__((aligned(x))) char buffer[Size]; \ + }; + +LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(1) +LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(2) +LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(4) +LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(8) +LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(16) +LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(32) +LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(64) +LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(128) + +#undef LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT + +#else +# error No supported align as directive. +#endif + +#else // _MSC_VER + +/// \brief Create a type with an aligned char buffer. +template +struct AlignedCharArray; + +// We provide special variations of this template for the most common +// alignments because __declspec(align(...)) doesn't actually work when it is +// a member of a by-value function argument in MSVC, even if the alignment +// request is something reasonably like 8-byte or 16-byte. Note that we can't +// even include the declspec with the union that forces the alignment because +// MSVC warns on the existence of the declspec despite the union member forcing +// proper alignment. + +template +struct AlignedCharArray<1, Size> { + union { + char aligned; + char buffer[Size]; + }; +}; + +template +struct AlignedCharArray<2, Size> { + union { + short aligned; + char buffer[Size]; + }; +}; + +template +struct AlignedCharArray<4, Size> { + union { + int aligned; + char buffer[Size]; + }; +}; + +template +struct AlignedCharArray<8, Size> { + union { + double aligned; + char buffer[Size]; + }; +}; + + +// The rest of these are provided with a __declspec(align(...)) and we simply +// can't pass them by-value as function arguments on MSVC. + +#define LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(x) \ + template \ + struct AlignedCharArray { \ + __declspec(align(x)) char buffer[Size]; \ + }; + +LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(16) +LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(32) +LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(64) +LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT(128) + +#undef LLVM_ALIGNEDCHARARRAY_TEMPLATE_ALIGNMENT + +#endif // _MSC_VER + +namespace detail { +template +class AlignerImpl { + T1 t1; T2 t2; T3 t3; T4 t4; T5 t5; T6 t6; T7 t7; T8 t8; T9 t9; T10 t10; + + AlignerImpl(); // Never defined or instantiated. +}; + +template +union SizerImpl { + char arr1[sizeof(T1)], arr2[sizeof(T2)], arr3[sizeof(T3)], arr4[sizeof(T4)], + arr5[sizeof(T5)], arr6[sizeof(T6)], arr7[sizeof(T7)], arr8[sizeof(T8)], + arr9[sizeof(T9)], arr10[sizeof(T10)]; +}; +} // end namespace detail + +/// \brief This union template exposes a suitably aligned and sized character +/// array member which can hold elements of any of up to ten types. +/// +/// These types may be arrays, structs, or any other types. The goal is to +/// expose a char array buffer member which can be used as suitable storage for +/// a placement new of any of these types. Support for more than ten types can +/// be added at the cost of more boilerplate. +template +struct AlignedCharArrayUnion : llvm::AlignedCharArray< + AlignOf >::Alignment, + sizeof(detail::SizerImpl)> { +}; +} // end namespace llvm +#endif diff --git a/include/llvm/ArrayRef.h b/include/llvm/ArrayRef.h new file mode 100644 index 0000000000..e7203ae461 --- /dev/null +++ b/include/llvm/ArrayRef.h @@ -0,0 +1,399 @@ +//===--- ArrayRef.h - Array Reference Wrapper -------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_ARRAYREF_H +#define LLVM_ADT_ARRAYREF_H + +#include "llvm/None.h" +#include "llvm/SmallVector.h" +#include + +#ifndef LLVM_CONSTEXPR +# ifdef _MSC_VER +# if _MSC_VER >= 1900 +# define LLVM_CONSTEXPR constexpr +# else +# define LLVM_CONSTEXPR +# endif +# elif defined(__has_feature) +# if __has_feature(cxx_constexpr) +# define LLVM_CONSTEXPR constexpr +# else +# define LLVM_CONSTEXPR +# endif +# elif defined(__GXX_EXPERIMENTAL_CXX0X__) +# define LLVM_CONSTEXPR constexpr +# elif defined(__has_constexpr) +# define LLVM_CONSTEXPR constexpr +# else +# define LLVM_CONSTEXPR +# endif +# define DEFINED_LLVM_CONSTEXPR +#endif + +namespace llvm { + + /// ArrayRef - Represent a constant reference to an array (0 or more elements + /// consecutively in memory), i.e. a start pointer and a length. It allows + /// various APIs to take consecutive elements easily and conveniently. + /// + /// This class does not own the underlying data, it is expected to be used in + /// situations where the data resides in some other buffer, whose lifetime + /// extends past that of the ArrayRef. For this reason, it is not in general + /// safe to store an ArrayRef. + /// + /// This is intended to be trivially copyable, so it should be passed by + /// value. + template + class ArrayRef { + public: + typedef const T *iterator; + typedef const T *const_iterator; + typedef size_t size_type; + + typedef std::reverse_iterator reverse_iterator; + + private: + /// The start of the array, in an external buffer. + const T *Data; + + /// The number of elements. + size_type Length; + + public: + /// @name Constructors + /// @{ + + /// Construct an empty ArrayRef. + /*implicit*/ ArrayRef() : Data(nullptr), Length(0) {} + + /// Construct an empty ArrayRef from None. + /*implicit*/ ArrayRef(NoneType) : Data(nullptr), Length(0) {} + + /// Construct an ArrayRef from a single element. + /*implicit*/ ArrayRef(const T &OneElt) + : Data(&OneElt), Length(1) {} + + /// Construct an ArrayRef from a pointer and length. + /*implicit*/ 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 SmallVector. This is templated in order to + /// avoid instantiating SmallVectorTemplateCommon whenever we + /// copy-construct an ArrayRef. + template + /*implicit*/ ArrayRef(const SmallVectorTemplateCommon &Vec) + : Data(Vec.data()), Length(Vec.size()) { + } + + /// Construct an ArrayRef from a std::vector. + template + /*implicit*/ ArrayRef(const std::vector &Vec) + : Data(Vec.data()), Length(Vec.size()) {} + + /// Construct an ArrayRef from a C array. + template + /*implicit*/ LLVM_CONSTEXPR ArrayRef(const T (&Arr)[N]) + : Data(Arr), Length(N) {} + + /// Construct an ArrayRef from a std::initializer_list. + /*implicit*/ ArrayRef(const std::initializer_list &Vec) + : Data(Vec.begin() == Vec.end() ? (T*)0 : Vec.begin()), + Length(Vec.size()) {} + + /// Construct an ArrayRef from ArrayRef. This uses SFINAE to + /// ensure that only ArrayRefs of pointers can be converted. + template + ArrayRef(const ArrayRef &A, + typename std::enable_if< + std::is_convertible::value>::type* = 0) + : Data(A.data()), Length(A.size()) {} + + /// Construct an ArrayRef from a SmallVector. This is + /// templated in order to avoid instantiating SmallVectorTemplateCommon + /// whenever we copy-construct an ArrayRef. + template + /*implicit*/ ArrayRef(const SmallVectorTemplateCommon &Vec, + typename std::enable_if< + std::is_convertible::value>::type* = 0) + : Data(Vec.data()), Length(Vec.size()) { + } + + /// Construct an ArrayRef from std::vector. This uses SFINAE + /// to ensure that only vectors of pointers can be converted. + template + ArrayRef(const std::vector &Vec, + typename std::enable_if< + std::is_convertible::value>::type* = 0) + : Data(Vec.data()), Length(Vec.size()) {} + + /// @} + /// @name Simple Operations + /// @{ + + iterator begin() const { return Data; } + iterator end() const { return Data + Length; } + + reverse_iterator rbegin() const { return reverse_iterator(end()); } + reverse_iterator rend() const { return reverse_iterator(begin()); } + + /// empty - Check if the array is empty. + bool empty() const { return Length == 0; } + + const T *data() const { return Data; } + + /// size - Get the array size. + size_t size() const { return Length; } + + /// front - Get the first element. + const T &front() const { + assert(!empty()); + return Data[0]; + } + + /// back - Get the last element. + const T &back() const { + assert(!empty()); + return Data[Length-1]; + } + + // copy - Allocate copy in Allocator and return ArrayRef to it. + template ArrayRef copy(Allocator &A) { + T *Buff = A.template Allocate(Length); + std::copy(begin(), end(), Buff); + return ArrayRef(Buff, Length); + } + + /// equals - Check for element-wise equality. + bool equals(ArrayRef RHS) const { + if (Length != RHS.Length) + return false; + if (Length == 0) + return true; + return std::equal(begin(), end(), RHS.begin()); + } + + /// slice(n) - Chop off the first N elements of the array. + ArrayRef slice(unsigned N) const { + assert(N <= size() && "Invalid specifier"); + return ArrayRef(data()+N, size()-N); + } + + /// slice(n, m) - Chop off the first N elements of the array, and keep M + /// elements in the array. + ArrayRef slice(unsigned N, unsigned M) const { + assert(N+M <= size() && "Invalid specifier"); + return ArrayRef(data()+N, M); + } + + // \brief Drop the last \p N elements of the array. + ArrayRef drop_back(unsigned N = 1) const { + assert(size() >= N && "Dropping more elements than exist"); + return slice(0, size() - N); + } + + /// @} + /// @name Operator Overloads + /// @{ + const T &operator[](size_t Index) const { + assert(Index < Length && "Invalid index!"); + return Data[Index]; + } + + /// @} + /// @name Expensive Operations + /// @{ + std::vector vec() const { + return std::vector(Data, Data+Length); + } + + /// @} + /// @name Conversion operators + /// @{ + operator std::vector() const { + return std::vector(Data, Data+Length); + } + + /// @} + }; + + /// MutableArrayRef - Represent a mutable reference to an array (0 or more + /// elements consecutively in memory), i.e. a start pointer and a length. It + /// allows various APIs to take and modify consecutive elements easily and + /// conveniently. + /// + /// This class does not own the underlying data, it is expected to be used in + /// situations where the data resides in some other buffer, whose lifetime + /// extends past that of the MutableArrayRef. For this reason, it is not in + /// general safe to store a MutableArrayRef. + /// + /// This is intended to be trivially copyable, so it should be passed by + /// value. + template + class MutableArrayRef : public ArrayRef { + public: + typedef T *iterator; + + typedef std::reverse_iterator reverse_iterator; + + /// Construct an empty MutableArrayRef. + /*implicit*/ MutableArrayRef() : ArrayRef() {} + + /// Construct an empty MutableArrayRef from None. + /*implicit*/ MutableArrayRef(NoneType) : ArrayRef() {} + + /// Construct an MutableArrayRef from a single element. + /*implicit*/ MutableArrayRef(T &OneElt) : ArrayRef(OneElt) {} + + /// Construct an MutableArrayRef from a pointer and length. + /*implicit*/ MutableArrayRef(T *data, size_t length) + : ArrayRef(data, length) {} + + /// Construct an MutableArrayRef from a range. + MutableArrayRef(T *begin, T *end) : ArrayRef(begin, end) {} + + /// Construct an MutableArrayRef from a SmallVector. + /*implicit*/ MutableArrayRef(SmallVectorImpl &Vec) + : ArrayRef(Vec) {} + + /// Construct a MutableArrayRef from a std::vector. + /*implicit*/ MutableArrayRef(std::vector &Vec) + : ArrayRef(Vec) {} + + /// Construct an MutableArrayRef from a C array. + template + /*implicit*/ LLVM_CONSTEXPR MutableArrayRef(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(); } + + reverse_iterator rbegin() const { return reverse_iterator(end()); } + reverse_iterator rend() const { return reverse_iterator(begin()); } + + /// front - Get the first element. + T &front() const { + assert(!this->empty()); + return data()[0]; + } + + /// back - Get the last element. + T &back() const { + assert(!this->empty()); + return data()[this->size()-1]; + } + + /// slice(n) - Chop off the first N elements of the array. + MutableArrayRef slice(unsigned N) const { + assert(N <= this->size() && "Invalid specifier"); + return MutableArrayRef(data()+N, this->size()-N); + } + + /// slice(n, m) - Chop off the first N elements of the array, and keep M + /// elements in the array. + MutableArrayRef slice(unsigned N, unsigned M) const { + assert(N+M <= this->size() && "Invalid specifier"); + return MutableArrayRef(data()+N, M); + } + + MutableArrayRef drop_back(unsigned N) const { + assert(this->size() >= N && "Dropping more elements than exist"); + return slice(0, this->size() - N); + } + + /// @} + /// @name Operator Overloads + /// @{ + T &operator[](size_t Index) const { + assert(Index < this->size() && "Invalid index!"); + return data()[Index]; + } + }; + + /// @name ArrayRef Convenience constructors + /// @{ + + /// Construct an ArrayRef from a single element. + template + ArrayRef makeArrayRef(const T &OneElt) { + return OneElt; + } + + /// Construct an ArrayRef from a pointer and length. + template + ArrayRef makeArrayRef(const T *data, size_t length) { + return ArrayRef(data, length); + } + + /// Construct an ArrayRef from a range. + template + ArrayRef makeArrayRef(const T *begin, const T *end) { + return ArrayRef(begin, end); + } + + /// Construct an ArrayRef from a SmallVector. + template + ArrayRef makeArrayRef(const SmallVectorImpl &Vec) { + return Vec; + } + + /// Construct an ArrayRef from a SmallVector. + template + ArrayRef makeArrayRef(const SmallVector &Vec) { + return Vec; + } + + /// Construct an ArrayRef from a std::vector. + template + ArrayRef makeArrayRef(const std::vector &Vec) { + return Vec; + } + + /// Construct an ArrayRef from a C array. + template + ArrayRef makeArrayRef(const T (&Arr)[N]) { + return ArrayRef(Arr); + } + + /// @} + /// @name ArrayRef Comparison Operators + /// @{ + + template + inline bool operator==(ArrayRef LHS, ArrayRef RHS) { + return LHS.equals(RHS); + } + + template + inline bool operator!=(ArrayRef LHS, ArrayRef RHS) { + return !(LHS == RHS); + } + + /// @} + + // ArrayRefs can be treated like a POD type. + template struct isPodLike; + template struct isPodLike > { + static const bool value = true; + }; +} // namespace llvm + +#ifdef DEFINED_LLVM_CONSTEXPR +# undef DEFINED_LLVM_CONSTEXPR +# undef LLVM_CONSTEXPR +#endif + +#endif diff --git a/include/llvm/Compiler.h b/include/llvm/Compiler.h new file mode 100644 index 0000000000..b690218b0f --- /dev/null +++ b/include/llvm/Compiler.h @@ -0,0 +1,68 @@ +//===-- llvm/Support/Compiler.h - Compiler abstraction support --*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines several macros, based on the current compiler. This allows +// use of compiler-specific features in a way that remains portable. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_COMPILER_H +#define LLVM_SUPPORT_COMPILER_H + +#ifndef __has_feature +# define __has_feature(x) 0 +#endif + +#ifndef __has_extension +# define __has_extension(x) 0 +#endif + +#ifndef __has_attribute +# define __has_attribute(x) 0 +#endif + +#ifndef __has_builtin +# define __has_builtin(x) 0 +#endif + +/// \macro LLVM_GNUC_PREREQ +/// \brief Extend the default __GNUC_PREREQ even if glibc's features.h isn't +/// available. +#ifndef LLVM_GNUC_PREREQ +# if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) +# define LLVM_GNUC_PREREQ(maj, min, patch) \ + ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) + __GNUC_PATCHLEVEL__ >= \ + ((maj) << 20) + ((min) << 10) + (patch)) +# elif defined(__GNUC__) && defined(__GNUC_MINOR__) +# define LLVM_GNUC_PREREQ(maj, min, patch) \ + ((__GNUC__ << 20) + (__GNUC_MINOR__ << 10) >= ((maj) << 20) + ((min) << 10)) +# else +# define LLVM_GNUC_PREREQ(maj, min, patch) 0 +# endif +#endif + +#ifndef LLVM_ATTRIBUTE_UNUSED_RESULT +#if __has_attribute(warn_unused_result) || LLVM_GNUC_PREREQ(3, 4, 0) +#define LLVM_ATTRIBUTE_UNUSED_RESULT __attribute__((__warn_unused_result__)) +#else +#define LLVM_ATTRIBUTE_UNUSED_RESULT +#endif +#endif + +#ifndef LLVM_UNLIKELY +#if __has_builtin(__builtin_expect) || LLVM_GNUC_PREREQ(4, 0, 0) +#define LLVM_LIKELY(EXPR) __builtin_expect((bool)(EXPR), true) +#define LLVM_UNLIKELY(EXPR) __builtin_expect((bool)(EXPR), false) +#else +#define LLVM_LIKELY(EXPR) (EXPR) +#define LLVM_UNLIKELY(EXPR) (EXPR) +#endif +#endif + +#endif diff --git a/include/llvm/ConvertUTF.h b/include/llvm/ConvertUTF.h new file mode 100644 index 0000000000..5b025331b8 --- /dev/null +++ b/include/llvm/ConvertUTF.h @@ -0,0 +1,255 @@ +/*===--- ConvertUTF.h - Universal Character Names conversions ---------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + *==------------------------------------------------------------------------==*/ +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* --------------------------------------------------------------------- + + Conversions between UTF32, UTF-16, and UTF-8. Header file. + + Several funtions are included here, forming a complete set of + conversions between the three formats. UTF-7 is not included + here, but is handled in a separate source file. + + Each of these routines takes pointers to input buffers and output + buffers. The input buffers are const. + + Each routine converts the text between *sourceStart and sourceEnd, + putting the result into the buffer between *targetStart and + targetEnd. Note: the end pointers are *after* the last item: e.g. + *(sourceEnd - 1) is the last item. + + The return result indicates whether the conversion was successful, + and if not, whether the problem was in the source or target buffers. + (Only the first encountered problem is indicated.) + + After the conversion, *sourceStart and *targetStart are both + updated to point to the end of last text successfully converted in + the respective buffers. + + Input parameters: + sourceStart - pointer to a pointer to the source buffer. + The contents of this are modified on return so that + it points at the next thing to be converted. + targetStart - similarly, pointer to pointer to the target buffer. + sourceEnd, targetEnd - respectively pointers to the ends of the + two buffers, for overflow checking only. + + These conversion functions take a ConversionFlags argument. When this + flag is set to strict, both irregular sequences and isolated surrogates + will cause an error. When the flag is set to lenient, both irregular + sequences and isolated surrogates are converted. + + Whether the flag is strict or lenient, all illegal sequences will cause + an error return. This includes sequences such as: , , + or in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code + must check for illegal sequences. + + When the flag is set to lenient, characters over 0x10FFFF are converted + to the replacement character; otherwise (when the flag is set to strict) + they constitute an error. + + Output parameters: + The value "sourceIllegal" is returned from some routines if the input + sequence is malformed. When "sourceIllegal" is returned, the source + value will point to the illegal value that caused the problem. E.g., + in UTF-8 when a sequence is malformed, it points to the start of the + malformed sequence. + + Author: Mark E. Davis, 1994. + Rev History: Rick McGowan, fixes & updates May 2001. + Fixes & updates, Sept 2001. + +------------------------------------------------------------------------ */ + +#ifndef LLVM_SUPPORT_CONVERTUTF_H +#define LLVM_SUPPORT_CONVERTUTF_H + +/* --------------------------------------------------------------------- + The following 4 definitions are compiler-specific. + The C standard does not guarantee that wchar_t has at least + 16 bits, so wchar_t is no less portable than unsigned short! + All should be unsigned values to avoid sign extension during + bit mask & shift operations. +------------------------------------------------------------------------ */ + +typedef unsigned int UTF32; /* at least 32 bits */ +typedef unsigned short UTF16; /* at least 16 bits */ +typedef unsigned char UTF8; /* typically 8 bits */ +typedef bool Boolean; /* 0 or 1 */ + +/* Some fundamental constants */ +#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD +#define UNI_MAX_BMP (UTF32)0x0000FFFF +#define UNI_MAX_UTF16 (UTF32)0x0010FFFF +#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF +#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF + +#define UNI_MAX_UTF8_BYTES_PER_CODE_POINT 4 + +#define UNI_UTF16_BYTE_ORDER_MARK_NATIVE 0xFEFF +#define UNI_UTF16_BYTE_ORDER_MARK_SWAPPED 0xFFFE + +typedef enum { + conversionOK, /* conversion successful */ + sourceExhausted, /* partial character in source, but hit end */ + targetExhausted, /* insuff. room in target for conversion */ + sourceIllegal /* source sequence is illegal/malformed */ +} ConversionResult; + +typedef enum { + strictConversion = 0, + lenientConversion +} ConversionFlags; + +/* This is for C++ and does no harm in C */ +#ifdef __cplusplus +extern "C" { +#endif + +ConversionResult ConvertUTF8toUTF16 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + +/** + * Convert a partial UTF8 sequence to UTF32. If the sequence ends in an + * incomplete code unit sequence, returns \c sourceExhausted. + */ +ConversionResult ConvertUTF8toUTF32Partial( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +/** + * Convert a partial UTF8 sequence to UTF32. If the sequence ends in an + * incomplete code unit sequence, returns \c sourceIllegal. + */ +ConversionResult ConvertUTF8toUTF32( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF8 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF8 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF16toUTF32 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags); + +ConversionResult ConvertUTF32toUTF16 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags); + +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd); + +Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd); + +unsigned getNumBytesForUTF8(UTF8 firstByte); + +#ifdef __cplusplus +} + +/*************************************************************************/ +/* Below are LLVM-specific wrappers of the functions above. */ + +#include "llvm/ArrayRef.h" +#include "llvm/StringRef.h" + +namespace llvm { + +/** + * Convert an Unicode code point to UTF8 sequence. + * + * \param Source a Unicode code point. + * \param [in,out] ResultPtr pointer to the output buffer, needs to be at least + * \c UNI_MAX_UTF8_BYTES_PER_CODE_POINT bytes. On success \c ResultPtr is + * updated one past end of the converted sequence. + * + * \returns true on success. + */ +bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr); + +/** + * Convert the first UTF8 sequence in the given source buffer to a UTF32 + * code point. + * + * \param [in,out] source A pointer to the source buffer. If the conversion + * succeeds, this pointer will be updated to point to the byte just past the + * end of the converted sequence. + * \param sourceEnd A pointer just past the end of the source buffer. + * \param [out] target The converted code + * \param flags Whether the conversion is strict or lenient. + * + * \returns conversionOK on success + * + * \sa ConvertUTF8toUTF32 + */ +static inline ConversionResult convertUTF8Sequence(const UTF8 **source, + const UTF8 *sourceEnd, + UTF32 *target, + ConversionFlags flags) { + if (*source == sourceEnd) + return sourceExhausted; + unsigned size = getNumBytesForUTF8(**source); + if ((ptrdiff_t)size > sourceEnd - *source) + return sourceExhausted; + return ConvertUTF8toUTF32(source, *source + size, &target, target + 1, flags); +} + +/** + * Returns true if a blob of text starts with a UTF-16 big or little endian byte + * order mark. + */ +bool hasUTF16ByteOrderMark(ArrayRef SrcBytes); + +/** + * Converts a UTF-16 string into a UTF-8 string. + * + * \returns true on success + */ +bool convertUTF16ToUTF8String(ArrayRef SrcUTF16, + SmallVectorImpl &DstUTF8); + +/** + * Converts a UTF-8 string into a UTF-16 string with native endianness. + * + * \returns true on success + */ +bool convertUTF8ToUTF16String(StringRef SrcUTF8, + SmallVectorImpl &DstUTF16); + +} /* end namespace llvm */ + +#endif + +/* --------------------------------------------------------------------- */ + +#endif diff --git a/include/llvm/DenseMap.h b/include/llvm/DenseMap.h new file mode 100644 index 0000000000..58f3a52ef4 --- /dev/null +++ b/include/llvm/DenseMap.h @@ -0,0 +1,1073 @@ +//===- llvm/ADT/DenseMap.h - Dense probed hash table ------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DenseMap class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_DENSEMAP_H +#define LLVM_ADT_DENSEMAP_H + +#include "llvm/DenseMapInfo.h" +#include "llvm/EpochTracker.h" +#include "llvm/AlignOf.h" +#include "llvm/Compiler.h" +#include "llvm/MathExtras.h" +#include "llvm/type_traits.h" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace llvm { + +namespace detail { +// We extend a pair to allow users to override the bucket type with their own +// implementation without requiring two members. +template +struct DenseMapPair : public std::pair { + KeyT &getFirst() { return std::pair::first; } + const KeyT &getFirst() const { return std::pair::first; } + ValueT &getSecond() { return std::pair::second; } + const ValueT &getSecond() const { return std::pair::second; } +}; +} // namespace detail + +template < + typename KeyT, typename ValueT, typename KeyInfoT = DenseMapInfo, + typename Bucket = detail::DenseMapPair, bool IsConst = false> +class DenseMapIterator; + +template +class DenseMapBase : public DebugEpochBase { +public: + typedef unsigned size_type; + typedef KeyT key_type; + typedef ValueT mapped_type; + typedef BucketT value_type; + + typedef DenseMapIterator iterator; + typedef DenseMapIterator + const_iterator; + inline iterator begin() { + // When the map is empty, avoid the overhead of AdvancePastEmptyBuckets(). + return empty() ? end() : iterator(getBuckets(), getBucketsEnd(), *this); + } + inline iterator end() { + return iterator(getBucketsEnd(), getBucketsEnd(), *this, true); + } + inline const_iterator begin() const { + return empty() ? end() + : const_iterator(getBuckets(), getBucketsEnd(), *this); + } + inline const_iterator end() const { + return const_iterator(getBucketsEnd(), getBucketsEnd(), *this, true); + } + + bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const { + return getNumEntries() == 0; + } + unsigned size() const { return getNumEntries(); } + + /// Grow the densemap so that it has at least Size buckets. Does not shrink + void resize(size_type Size) { + incrementEpoch(); + if (Size > getNumBuckets()) + grow(Size); + } + + void clear() { + incrementEpoch(); + if (getNumEntries() == 0 && getNumTombstones() == 0) return; + + // If the capacity of the array is huge, and the # elements used is small, + // shrink the array. + if (getNumEntries() * 4 < getNumBuckets() && getNumBuckets() > 64) { + shrink_and_clear(); + return; + } + + const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey(); + unsigned NumEntries = getNumEntries(); + for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) { + if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey)) { + if (!KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) { + P->getSecond().~ValueT(); + --NumEntries; + } + P->getFirst() = EmptyKey; + } + } + assert(NumEntries == 0 && "Node count imbalance!"); + setNumEntries(0); + setNumTombstones(0); + } + + /// Return 1 if the specified key is in the map, 0 otherwise. + size_type count(const KeyT &Val) const { + const BucketT *TheBucket; + return LookupBucketFor(Val, TheBucket) ? 1 : 0; + } + + iterator find(const KeyT &Val) { + BucketT *TheBucket; + if (LookupBucketFor(Val, TheBucket)) + return iterator(TheBucket, getBucketsEnd(), *this, true); + return end(); + } + const_iterator find(const KeyT &Val) const { + const BucketT *TheBucket; + if (LookupBucketFor(Val, TheBucket)) + return const_iterator(TheBucket, getBucketsEnd(), *this, true); + return end(); + } + + /// Alternate version of find() which allows a different, and possibly + /// less expensive, key type. + /// The DenseMapInfo is responsible for supplying methods + /// getHashValue(LookupKeyT) and isEqual(LookupKeyT, KeyT) for each key + /// type used. + template + iterator find_as(const LookupKeyT &Val) { + BucketT *TheBucket; + if (LookupBucketFor(Val, TheBucket)) + return iterator(TheBucket, getBucketsEnd(), *this, true); + return end(); + } + template + const_iterator find_as(const LookupKeyT &Val) const { + const BucketT *TheBucket; + if (LookupBucketFor(Val, TheBucket)) + return const_iterator(TheBucket, getBucketsEnd(), *this, true); + return end(); + } + + /// lookup - Return the entry for the specified key, or a default + /// constructed value if no such entry exists. + ValueT lookup(const KeyT &Val) const { + const BucketT *TheBucket; + if (LookupBucketFor(Val, TheBucket)) + return TheBucket->getSecond(); + return ValueT(); + } + + // Inserts key,value pair into the map if the key isn't already in the map. + // If the key is already in the map, it returns false and doesn't update the + // value. + std::pair insert(const std::pair &KV) { + BucketT *TheBucket; + if (LookupBucketFor(KV.first, TheBucket)) + return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true), + false); // Already in map. + + // Otherwise, insert the new element. + TheBucket = InsertIntoBucket(KV.first, KV.second, TheBucket); + return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true), + true); + } + + // Inserts key,value pair into the map if the key isn't already in the map. + // If the key is already in the map, it returns false and doesn't update the + // value. + std::pair insert(std::pair &&KV) { + BucketT *TheBucket; + if (LookupBucketFor(KV.first, TheBucket)) + return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true), + false); // Already in map. + + // Otherwise, insert the new element. + TheBucket = InsertIntoBucket(std::move(KV.first), + std::move(KV.second), + TheBucket); + return std::make_pair(iterator(TheBucket, getBucketsEnd(), *this, true), + true); + } + + /// insert - Range insertion of pairs. + template + void insert(InputIt I, InputIt E) { + for (; I != E; ++I) + insert(*I); + } + + + bool erase(const KeyT &Val) { + BucketT *TheBucket; + if (!LookupBucketFor(Val, TheBucket)) + return false; // not in map. + + TheBucket->getSecond().~ValueT(); + TheBucket->getFirst() = getTombstoneKey(); + decrementNumEntries(); + incrementNumTombstones(); + return true; + } + void erase(iterator I) { + BucketT *TheBucket = &*I; + TheBucket->getSecond().~ValueT(); + TheBucket->getFirst() = getTombstoneKey(); + decrementNumEntries(); + incrementNumTombstones(); + } + + value_type& FindAndConstruct(const KeyT &Key) { + BucketT *TheBucket; + if (LookupBucketFor(Key, TheBucket)) + return *TheBucket; + + return *InsertIntoBucket(Key, ValueT(), TheBucket); + } + + ValueT &operator[](const KeyT &Key) { + return FindAndConstruct(Key).second; + } + + value_type& FindAndConstruct(KeyT &&Key) { + BucketT *TheBucket; + if (LookupBucketFor(Key, TheBucket)) + return *TheBucket; + + return *InsertIntoBucket(std::move(Key), ValueT(), TheBucket); + } + + ValueT &operator[](KeyT &&Key) { + return FindAndConstruct(std::move(Key)).second; + } + + /// isPointerIntoBucketsArray - Return true if the specified pointer points + /// somewhere into the DenseMap's array of buckets (i.e. either to a key or + /// value in the DenseMap). + bool isPointerIntoBucketsArray(const void *Ptr) const { + return Ptr >= getBuckets() && Ptr < getBucketsEnd(); + } + + /// getPointerIntoBucketsArray() - Return an opaque pointer into the buckets + /// array. In conjunction with the previous method, this can be used to + /// determine whether an insertion caused the DenseMap to reallocate. + const void *getPointerIntoBucketsArray() const { return getBuckets(); } + +protected: + DenseMapBase() = default; + + void destroyAll() { + if (getNumBuckets() == 0) // Nothing to do. + return; + + const KeyT EmptyKey = getEmptyKey(), TombstoneKey = getTombstoneKey(); + for (BucketT *P = getBuckets(), *E = getBucketsEnd(); P != E; ++P) { + if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey) && + !KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) + P->getSecond().~ValueT(); + P->getFirst().~KeyT(); + } + } + + void initEmpty() { + setNumEntries(0); + setNumTombstones(0); + + assert((getNumBuckets() & (getNumBuckets()-1)) == 0 && + "# initial buckets must be a power of two!"); + const KeyT EmptyKey = getEmptyKey(); + for (BucketT *B = getBuckets(), *E = getBucketsEnd(); B != E; ++B) + new (&B->getFirst()) KeyT(EmptyKey); + } + + void moveFromOldBuckets(BucketT *OldBucketsBegin, BucketT *OldBucketsEnd) { + initEmpty(); + + // Insert all the old elements. + const KeyT EmptyKey = getEmptyKey(); + const KeyT TombstoneKey = getTombstoneKey(); + for (BucketT *B = OldBucketsBegin, *E = OldBucketsEnd; B != E; ++B) { + if (!KeyInfoT::isEqual(B->getFirst(), EmptyKey) && + !KeyInfoT::isEqual(B->getFirst(), TombstoneKey)) { + // Insert the key/value into the new table. + BucketT *DestBucket; + bool FoundVal = LookupBucketFor(B->getFirst(), DestBucket); + (void)FoundVal; // silence warning. + assert(!FoundVal && "Key already in new map?"); + DestBucket->getFirst() = std::move(B->getFirst()); + new (&DestBucket->getSecond()) ValueT(std::move(B->getSecond())); + incrementNumEntries(); + + // Free the value. + B->getSecond().~ValueT(); + } + B->getFirst().~KeyT(); + } + } + + template + void copyFrom( + const DenseMapBase &other) { + assert(&other != this); + assert(getNumBuckets() == other.getNumBuckets()); + + setNumEntries(other.getNumEntries()); + setNumTombstones(other.getNumTombstones()); + + if (isPodLike::value && isPodLike::value) + memcpy(getBuckets(), other.getBuckets(), + getNumBuckets() * sizeof(BucketT)); + else + for (size_t i = 0; i < getNumBuckets(); ++i) { + new (&getBuckets()[i].getFirst()) + KeyT(other.getBuckets()[i].getFirst()); + if (!KeyInfoT::isEqual(getBuckets()[i].getFirst(), getEmptyKey()) && + !KeyInfoT::isEqual(getBuckets()[i].getFirst(), getTombstoneKey())) + new (&getBuckets()[i].getSecond()) + ValueT(other.getBuckets()[i].getSecond()); + } + } + + static unsigned getHashValue(const KeyT &Val) { + return KeyInfoT::getHashValue(Val); + } + template + static unsigned getHashValue(const LookupKeyT &Val) { + return KeyInfoT::getHashValue(Val); + } + static const KeyT getEmptyKey() { + return KeyInfoT::getEmptyKey(); + } + static const KeyT getTombstoneKey() { + return KeyInfoT::getTombstoneKey(); + } + +private: + unsigned getNumEntries() const { + return static_cast(this)->getNumEntries(); + } + void setNumEntries(unsigned Num) { + static_cast(this)->setNumEntries(Num); + } + void incrementNumEntries() { + setNumEntries(getNumEntries() + 1); + } + void decrementNumEntries() { + setNumEntries(getNumEntries() - 1); + } + unsigned getNumTombstones() const { + return static_cast(this)->getNumTombstones(); + } + void setNumTombstones(unsigned Num) { + static_cast(this)->setNumTombstones(Num); + } + void incrementNumTombstones() { + setNumTombstones(getNumTombstones() + 1); + } + void decrementNumTombstones() { + setNumTombstones(getNumTombstones() - 1); + } + const BucketT *getBuckets() const { + return static_cast(this)->getBuckets(); + } + BucketT *getBuckets() { + return static_cast(this)->getBuckets(); + } + unsigned getNumBuckets() const { + return static_cast(this)->getNumBuckets(); + } + BucketT *getBucketsEnd() { + return getBuckets() + getNumBuckets(); + } + const BucketT *getBucketsEnd() const { + return getBuckets() + getNumBuckets(); + } + + void grow(unsigned AtLeast) { + static_cast(this)->grow(AtLeast); + } + + void shrink_and_clear() { + static_cast(this)->shrink_and_clear(); + } + + + BucketT *InsertIntoBucket(const KeyT &Key, const ValueT &Value, + BucketT *TheBucket) { + TheBucket = InsertIntoBucketImpl(Key, TheBucket); + + TheBucket->getFirst() = Key; + new (&TheBucket->getSecond()) ValueT(Value); + return TheBucket; + } + + BucketT *InsertIntoBucket(const KeyT &Key, ValueT &&Value, + BucketT *TheBucket) { + TheBucket = InsertIntoBucketImpl(Key, TheBucket); + + TheBucket->getFirst() = Key; + new (&TheBucket->getSecond()) ValueT(std::move(Value)); + return TheBucket; + } + + BucketT *InsertIntoBucket(KeyT &&Key, ValueT &&Value, BucketT *TheBucket) { + TheBucket = InsertIntoBucketImpl(Key, TheBucket); + + TheBucket->getFirst() = std::move(Key); + new (&TheBucket->getSecond()) ValueT(std::move(Value)); + return TheBucket; + } + + BucketT *InsertIntoBucketImpl(const KeyT &Key, BucketT *TheBucket) { + incrementEpoch(); + + // If the load of the hash table is more than 3/4, or if fewer than 1/8 of + // the buckets are empty (meaning that many are filled with tombstones), + // grow the table. + // + // The later case is tricky. For example, if we had one empty bucket with + // tons of tombstones, failing lookups (e.g. for insertion) would have to + // probe almost the entire table until it found the empty bucket. If the + // table completely filled with tombstones, no lookup would ever succeed, + // causing infinite loops in lookup. + unsigned NewNumEntries = getNumEntries() + 1; + unsigned NumBuckets = getNumBuckets(); + if (LLVM_UNLIKELY(NewNumEntries * 4 >= NumBuckets * 3)) { + this->grow(NumBuckets * 2); + LookupBucketFor(Key, TheBucket); + NumBuckets = getNumBuckets(); + } else if (LLVM_UNLIKELY(NumBuckets-(NewNumEntries+getNumTombstones()) <= + NumBuckets/8)) { + this->grow(NumBuckets); + LookupBucketFor(Key, TheBucket); + } + assert(TheBucket); + + // Only update the state after we've grown our bucket space appropriately + // so that when growing buckets we have self-consistent entry count. + incrementNumEntries(); + + // If we are writing over a tombstone, remember this. + const KeyT EmptyKey = getEmptyKey(); + if (!KeyInfoT::isEqual(TheBucket->getFirst(), EmptyKey)) + decrementNumTombstones(); + + return TheBucket; + } + + /// LookupBucketFor - Lookup the appropriate bucket for Val, returning it in + /// FoundBucket. If the bucket contains the key and a value, this returns + /// true, otherwise it returns a bucket with an empty marker or tombstone and + /// returns false. + template + bool LookupBucketFor(const LookupKeyT &Val, + const BucketT *&FoundBucket) const { + const BucketT *BucketsPtr = getBuckets(); + const unsigned NumBuckets = getNumBuckets(); + + if (NumBuckets == 0) { + FoundBucket = nullptr; + return false; + } + + // FoundTombstone - Keep track of whether we find a tombstone while probing. + const BucketT *FoundTombstone = nullptr; + const KeyT EmptyKey = getEmptyKey(); + const KeyT TombstoneKey = getTombstoneKey(); + assert(!KeyInfoT::isEqual(Val, EmptyKey) && + !KeyInfoT::isEqual(Val, TombstoneKey) && + "Empty/Tombstone value shouldn't be inserted into map!"); + + unsigned BucketNo = getHashValue(Val) & (NumBuckets-1); + unsigned ProbeAmt = 1; + while (1) { + const BucketT *ThisBucket = BucketsPtr + BucketNo; + // Found Val's bucket? If so, return it. + if (LLVM_LIKELY(KeyInfoT::isEqual(Val, ThisBucket->getFirst()))) { + FoundBucket = ThisBucket; + return true; + } + + // If we found an empty bucket, the key doesn't exist in the set. + // Insert it and return the default value. + if (LLVM_LIKELY(KeyInfoT::isEqual(ThisBucket->getFirst(), EmptyKey))) { + // If we've already seen a tombstone while probing, fill it in instead + // of the empty bucket we eventually probed to. + FoundBucket = FoundTombstone ? FoundTombstone : ThisBucket; + return false; + } + + // If this is a tombstone, remember it. If Val ends up not in the map, we + // prefer to return it than something that would require more probing. + if (KeyInfoT::isEqual(ThisBucket->getFirst(), TombstoneKey) && + !FoundTombstone) + FoundTombstone = ThisBucket; // Remember the first tombstone found. + + // Otherwise, it's a hash collision or a tombstone, continue quadratic + // probing. + BucketNo += ProbeAmt++; + BucketNo &= (NumBuckets-1); + } + } + + template + bool LookupBucketFor(const LookupKeyT &Val, BucketT *&FoundBucket) { + const BucketT *ConstFoundBucket; + bool Result = const_cast(this) + ->LookupBucketFor(Val, ConstFoundBucket); + FoundBucket = const_cast(ConstFoundBucket); + return Result; + } + +public: + /// Return the approximate size (in bytes) of the actual map. + /// This is just the raw memory used by DenseMap. + /// If entries are pointers to objects, the size of the referenced objects + /// are not included. + size_t getMemorySize() const { + return getNumBuckets() * sizeof(BucketT); + } +}; + +template , + typename BucketT = detail::DenseMapPair> +class DenseMap : public DenseMapBase, + KeyT, ValueT, KeyInfoT, BucketT> { + // Lift some types from the dependent base class into this class for + // simplicity of referring to them. + typedef DenseMapBase BaseT; + friend class DenseMapBase; + + BucketT *Buckets; + unsigned NumEntries; + unsigned NumTombstones; + unsigned NumBuckets; + +public: + explicit DenseMap(unsigned NumInitBuckets = 0) { + init(NumInitBuckets); + } + + DenseMap(const DenseMap &other) : BaseT() { + init(0); + copyFrom(other); + } + + DenseMap(DenseMap &&other) : BaseT() { + init(0); + swap(other); + } + + template + DenseMap(const InputIt &I, const InputIt &E) { + init(NextPowerOf2(std::distance(I, E))); + this->insert(I, E); + } + + ~DenseMap() { + this->destroyAll(); + operator delete(Buckets); + } + + void swap(DenseMap& RHS) { + this->incrementEpoch(); + RHS.incrementEpoch(); + std::swap(Buckets, RHS.Buckets); + std::swap(NumEntries, RHS.NumEntries); + std::swap(NumTombstones, RHS.NumTombstones); + std::swap(NumBuckets, RHS.NumBuckets); + } + + DenseMap& operator=(const DenseMap& other) { + if (&other != this) + copyFrom(other); + return *this; + } + + DenseMap& operator=(DenseMap &&other) { + this->destroyAll(); + operator delete(Buckets); + init(0); + swap(other); + return *this; + } + + void copyFrom(const DenseMap& other) { + this->destroyAll(); + operator delete(Buckets); + if (allocateBuckets(other.NumBuckets)) { + this->BaseT::copyFrom(other); + } else { + NumEntries = 0; + NumTombstones = 0; + } + } + + void init(unsigned InitBuckets) { + if (allocateBuckets(InitBuckets)) { + this->BaseT::initEmpty(); + } else { + NumEntries = 0; + NumTombstones = 0; + } + } + + void grow(unsigned AtLeast) { + unsigned OldNumBuckets = NumBuckets; + BucketT *OldBuckets = Buckets; + + allocateBuckets(std::max(64, static_cast(NextPowerOf2(AtLeast-1)))); + assert(Buckets); + if (!OldBuckets) { + this->BaseT::initEmpty(); + return; + } + + this->moveFromOldBuckets(OldBuckets, OldBuckets+OldNumBuckets); + + // Free the old table. + operator delete(OldBuckets); + } + + void shrink_and_clear() { + unsigned OldNumEntries = NumEntries; + this->destroyAll(); + + // Reduce the number of buckets. + unsigned NewNumBuckets = 0; + if (OldNumEntries) + NewNumBuckets = std::max(64, 1 << (Log2_32_Ceil(OldNumEntries) + 1)); + if (NewNumBuckets == NumBuckets) { + this->BaseT::initEmpty(); + return; + } + + operator delete(Buckets); + init(NewNumBuckets); + } + +private: + unsigned getNumEntries() const { + return NumEntries; + } + void setNumEntries(unsigned Num) { + NumEntries = Num; + } + + unsigned getNumTombstones() const { + return NumTombstones; + } + void setNumTombstones(unsigned Num) { + NumTombstones = Num; + } + + BucketT *getBuckets() const { + return Buckets; + } + + unsigned getNumBuckets() const { + return NumBuckets; + } + + bool allocateBuckets(unsigned Num) { + NumBuckets = Num; + if (NumBuckets == 0) { + Buckets = nullptr; + return false; + } + + Buckets = static_cast(operator new(sizeof(BucketT) * NumBuckets)); + return true; + } +}; + +template , + typename BucketT = detail::DenseMapPair> +class SmallDenseMap + : public DenseMapBase< + SmallDenseMap, KeyT, + ValueT, KeyInfoT, BucketT> { + // Lift some types from the dependent base class into this class for + // simplicity of referring to them. + typedef DenseMapBase BaseT; + friend class DenseMapBase; + + unsigned Small : 1; + unsigned NumEntries : 31; + unsigned NumTombstones; + + struct LargeRep { + BucketT *Buckets; + unsigned NumBuckets; + }; + + /// A "union" of an inline bucket array and the struct representing + /// a large bucket. This union will be discriminated by the 'Small' bit. + AlignedCharArrayUnion storage; + +public: + explicit SmallDenseMap(unsigned NumInitBuckets = 0) { + init(NumInitBuckets); + } + + SmallDenseMap(const SmallDenseMap &other) : BaseT() { + init(0); + copyFrom(other); + } + + SmallDenseMap(SmallDenseMap &&other) : BaseT() { + init(0); + swap(other); + } + + template + SmallDenseMap(const InputIt &I, const InputIt &E) { + init(NextPowerOf2(std::distance(I, E))); + this->insert(I, E); + } + + ~SmallDenseMap() { + this->destroyAll(); + deallocateBuckets(); + } + + void swap(SmallDenseMap& RHS) { + unsigned TmpNumEntries = RHS.NumEntries; + RHS.NumEntries = NumEntries; + NumEntries = TmpNumEntries; + std::swap(NumTombstones, RHS.NumTombstones); + + const KeyT EmptyKey = this->getEmptyKey(); + const KeyT TombstoneKey = this->getTombstoneKey(); + if (Small && RHS.Small) { + // If we're swapping inline bucket arrays, we have to cope with some of + // the tricky bits of DenseMap's storage system: the buckets are not + // fully initialized. Thus we swap every key, but we may have + // a one-directional move of the value. + for (unsigned i = 0, e = InlineBuckets; i != e; ++i) { + BucketT *LHSB = &getInlineBuckets()[i], + *RHSB = &RHS.getInlineBuckets()[i]; + bool hasLHSValue = (!KeyInfoT::isEqual(LHSB->getFirst(), EmptyKey) && + !KeyInfoT::isEqual(LHSB->getFirst(), TombstoneKey)); + bool hasRHSValue = (!KeyInfoT::isEqual(RHSB->getFirst(), EmptyKey) && + !KeyInfoT::isEqual(RHSB->getFirst(), TombstoneKey)); + if (hasLHSValue && hasRHSValue) { + // Swap together if we can... + std::swap(*LHSB, *RHSB); + continue; + } + // Swap separately and handle any assymetry. + std::swap(LHSB->getFirst(), RHSB->getFirst()); + if (hasLHSValue) { + new (&RHSB->getSecond()) ValueT(std::move(LHSB->getSecond())); + LHSB->getSecond().~ValueT(); + } else if (hasRHSValue) { + new (&LHSB->getSecond()) ValueT(std::move(RHSB->getSecond())); + RHSB->getSecond().~ValueT(); + } + } + return; + } + if (!Small && !RHS.Small) { + std::swap(getLargeRep()->Buckets, RHS.getLargeRep()->Buckets); + std::swap(getLargeRep()->NumBuckets, RHS.getLargeRep()->NumBuckets); + return; + } + + SmallDenseMap &SmallSide = Small ? *this : RHS; + SmallDenseMap &LargeSide = Small ? RHS : *this; + + // First stash the large side's rep and move the small side across. + LargeRep TmpRep = std::move(*LargeSide.getLargeRep()); + LargeSide.getLargeRep()->~LargeRep(); + LargeSide.Small = true; + // This is similar to the standard move-from-old-buckets, but the bucket + // count hasn't actually rotated in this case. So we have to carefully + // move construct the keys and values into their new locations, but there + // is no need to re-hash things. + for (unsigned i = 0, e = InlineBuckets; i != e; ++i) { + BucketT *NewB = &LargeSide.getInlineBuckets()[i], + *OldB = &SmallSide.getInlineBuckets()[i]; + new (&NewB->getFirst()) KeyT(std::move(OldB->getFirst())); + OldB->getFirst().~KeyT(); + if (!KeyInfoT::isEqual(NewB->getFirst(), EmptyKey) && + !KeyInfoT::isEqual(NewB->getFirst(), TombstoneKey)) { + new (&NewB->getSecond()) ValueT(std::move(OldB->getSecond())); + OldB->getSecond().~ValueT(); + } + } + + // The hard part of moving the small buckets across is done, just move + // the TmpRep into its new home. + SmallSide.Small = false; + new (SmallSide.getLargeRep()) LargeRep(std::move(TmpRep)); + } + + SmallDenseMap& operator=(const SmallDenseMap& other) { + if (&other != this) + copyFrom(other); + return *this; + } + + SmallDenseMap& operator=(SmallDenseMap &&other) { + this->destroyAll(); + deallocateBuckets(); + init(0); + swap(other); + return *this; + } + + void copyFrom(const SmallDenseMap& other) { + this->destroyAll(); + deallocateBuckets(); + Small = true; + if (other.getNumBuckets() > InlineBuckets) { + Small = false; + new (getLargeRep()) LargeRep(allocateBuckets(other.getNumBuckets())); + } + this->BaseT::copyFrom(other); + } + + void init(unsigned InitBuckets) { + Small = true; + if (InitBuckets > InlineBuckets) { + Small = false; + new (getLargeRep()) LargeRep(allocateBuckets(InitBuckets)); + } + this->BaseT::initEmpty(); + } + + void grow(unsigned AtLeast) { + if (AtLeast >= InlineBuckets) + AtLeast = std::max(64, NextPowerOf2(AtLeast-1)); + + if (Small) { + if (AtLeast < InlineBuckets) + return; // Nothing to do. + + // First move the inline buckets into a temporary storage. + AlignedCharArrayUnion TmpStorage; + BucketT *TmpBegin = reinterpret_cast(TmpStorage.buffer); + BucketT *TmpEnd = TmpBegin; + + // Loop over the buckets, moving non-empty, non-tombstones into the + // temporary storage. Have the loop move the TmpEnd forward as it goes. + const KeyT EmptyKey = this->getEmptyKey(); + const KeyT TombstoneKey = this->getTombstoneKey(); + for (BucketT *P = getBuckets(), *E = P + InlineBuckets; P != E; ++P) { + if (!KeyInfoT::isEqual(P->getFirst(), EmptyKey) && + !KeyInfoT::isEqual(P->getFirst(), TombstoneKey)) { + assert(size_t(TmpEnd - TmpBegin) < InlineBuckets && + "Too many inline buckets!"); + new (&TmpEnd->getFirst()) KeyT(std::move(P->getFirst())); + new (&TmpEnd->getSecond()) ValueT(std::move(P->getSecond())); + ++TmpEnd; + P->getSecond().~ValueT(); + } + P->getFirst().~KeyT(); + } + + // Now make this map use the large rep, and move all the entries back + // into it. + Small = false; + new (getLargeRep()) LargeRep(allocateBuckets(AtLeast)); + this->moveFromOldBuckets(TmpBegin, TmpEnd); + return; + } + + LargeRep OldRep = std::move(*getLargeRep()); + getLargeRep()->~LargeRep(); + if (AtLeast <= InlineBuckets) { + Small = true; + } else { + new (getLargeRep()) LargeRep(allocateBuckets(AtLeast)); + } + + this->moveFromOldBuckets(OldRep.Buckets, OldRep.Buckets+OldRep.NumBuckets); + + // Free the old table. + operator delete(OldRep.Buckets); + } + + void shrink_and_clear() { + unsigned OldSize = this->size(); + this->destroyAll(); + + // Reduce the number of buckets. + unsigned NewNumBuckets = 0; + if (OldSize) { + NewNumBuckets = 1 << (Log2_32_Ceil(OldSize) + 1); + if (NewNumBuckets > InlineBuckets && NewNumBuckets < 64u) + NewNumBuckets = 64; + } + if ((Small && NewNumBuckets <= InlineBuckets) || + (!Small && NewNumBuckets == getLargeRep()->NumBuckets)) { + this->BaseT::initEmpty(); + return; + } + + deallocateBuckets(); + init(NewNumBuckets); + } + +private: + unsigned getNumEntries() const { + return NumEntries; + } + void setNumEntries(unsigned Num) { + assert(Num < INT_MAX && "Cannot support more than INT_MAX entries"); + NumEntries = Num; + } + + unsigned getNumTombstones() const { + return NumTombstones; + } + void setNumTombstones(unsigned Num) { + NumTombstones = Num; + } + + const BucketT *getInlineBuckets() const { + assert(Small); + // Note that this cast does not violate aliasing rules as we assert that + // the memory's dynamic type is the small, inline bucket buffer, and the + // 'storage.buffer' static type is 'char *'. + return reinterpret_cast(storage.buffer); + } + BucketT *getInlineBuckets() { + return const_cast( + const_cast(this)->getInlineBuckets()); + } + const LargeRep *getLargeRep() const { + assert(!Small); + // Note, same rule about aliasing as with getInlineBuckets. + return reinterpret_cast(storage.buffer); + } + LargeRep *getLargeRep() { + return const_cast( + const_cast(this)->getLargeRep()); + } + + const BucketT *getBuckets() const { + return Small ? getInlineBuckets() : getLargeRep()->Buckets; + } + BucketT *getBuckets() { + return const_cast( + const_cast(this)->getBuckets()); + } + unsigned getNumBuckets() const { + return Small ? InlineBuckets : getLargeRep()->NumBuckets; + } + + void deallocateBuckets() { + if (Small) + return; + + operator delete(getLargeRep()->Buckets); + getLargeRep()->~LargeRep(); + } + + LargeRep allocateBuckets(unsigned Num) { + assert(Num > InlineBuckets && "Must allocate more buckets than are inline"); + LargeRep Rep = { + static_cast(operator new(sizeof(BucketT) * Num)), Num + }; + return Rep; + } +}; + +template +class DenseMapIterator : DebugEpochBase::HandleBase { + typedef DenseMapIterator ConstIterator; + friend class DenseMapIterator; + friend class DenseMapIterator; + +public: + typedef ptrdiff_t difference_type; + typedef typename std::conditional::type + value_type; + typedef value_type *pointer; + typedef value_type &reference; + typedef std::forward_iterator_tag iterator_category; +private: + pointer Ptr, End; +public: + DenseMapIterator() : Ptr(nullptr), End(nullptr) {} + + DenseMapIterator(pointer Pos, pointer E, const DebugEpochBase &Epoch, + bool NoAdvance = false) + : DebugEpochBase::HandleBase(&Epoch), Ptr(Pos), End(E) { + assert(isHandleInSync() && "invalid construction!"); + if (!NoAdvance) AdvancePastEmptyBuckets(); + } + + // Converting ctor from non-const iterators to const iterators. SFINAE'd out + // for const iterator destinations so it doesn't end up as a user defined copy + // constructor. + template ::type> + DenseMapIterator( + const DenseMapIterator &I) + : DebugEpochBase::HandleBase(I), Ptr(I.Ptr), End(I.End) {} + + reference operator*() const { + assert(isHandleInSync() && "invalid iterator access!"); + return *Ptr; + } + pointer operator->() const { + assert(isHandleInSync() && "invalid iterator access!"); + return Ptr; + } + + bool operator==(const ConstIterator &RHS) const { + assert((!Ptr || isHandleInSync()) && "handle not in sync!"); + assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!"); + assert(getEpochAddress() == RHS.getEpochAddress() && + "comparing incomparable iterators!"); + return Ptr == RHS.Ptr; + } + bool operator!=(const ConstIterator &RHS) const { + assert((!Ptr || isHandleInSync()) && "handle not in sync!"); + assert((!RHS.Ptr || RHS.isHandleInSync()) && "handle not in sync!"); + assert(getEpochAddress() == RHS.getEpochAddress() && + "comparing incomparable iterators!"); + return Ptr != RHS.Ptr; + } + + inline DenseMapIterator& operator++() { // Preincrement + assert(isHandleInSync() && "invalid iterator access!"); + ++Ptr; + AdvancePastEmptyBuckets(); + return *this; + } + DenseMapIterator operator++(int) { // Postincrement + assert(isHandleInSync() && "invalid iterator access!"); + DenseMapIterator tmp = *this; ++*this; return tmp; + } + +private: + void AdvancePastEmptyBuckets() { + const KeyT Empty = KeyInfoT::getEmptyKey(); + const KeyT Tombstone = KeyInfoT::getTombstoneKey(); + + while (Ptr != End && (KeyInfoT::isEqual(Ptr->getFirst(), Empty) || + KeyInfoT::isEqual(Ptr->getFirst(), Tombstone))) + ++Ptr; + } +}; + +template +static inline size_t +capacity_in_bytes(const DenseMap &X) { + return X.getMemorySize(); +} + +} // end namespace llvm + +#endif diff --git a/include/llvm/DenseMapInfo.h b/include/llvm/DenseMapInfo.h new file mode 100644 index 0000000000..17793d5e19 --- /dev/null +++ b/include/llvm/DenseMapInfo.h @@ -0,0 +1,168 @@ +//===- llvm/ADT/DenseMapInfo.h - Type traits for DenseMap -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines DenseMapInfo traits for DenseMap. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_DENSEMAPINFO_H +#define LLVM_ADT_DENSEMAPINFO_H + +#include "llvm/PointerLikeTypeTraits.h" +#include "llvm/type_traits.h" + +namespace llvm { + +template +struct DenseMapInfo { + //static inline T getEmptyKey(); + //static inline T getTombstoneKey(); + //static unsigned getHashValue(const T &Val); + //static bool isEqual(const T &LHS, const T &RHS); +}; + +// Provide DenseMapInfo for all pointers. +template +struct DenseMapInfo { + static inline T* getEmptyKey() { + uintptr_t Val = static_cast(-1); + Val <<= PointerLikeTypeTraits::NumLowBitsAvailable; + return reinterpret_cast(Val); + } + static inline T* getTombstoneKey() { + uintptr_t Val = static_cast(-2); + Val <<= PointerLikeTypeTraits::NumLowBitsAvailable; + return reinterpret_cast(Val); + } + static unsigned getHashValue(const T *PtrVal) { + return (unsigned((uintptr_t)PtrVal) >> 4) ^ + (unsigned((uintptr_t)PtrVal) >> 9); + } + static bool isEqual(const T *LHS, const T *RHS) { return LHS == RHS; } +}; + +// Provide DenseMapInfo for chars. +template<> struct DenseMapInfo { + static inline char getEmptyKey() { return ~0; } + static inline char getTombstoneKey() { return ~0 - 1; } + static unsigned getHashValue(const char& Val) { return Val * 37U; } + static bool isEqual(const char &LHS, const char &RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for unsigned ints. +template<> struct DenseMapInfo { + static inline unsigned getEmptyKey() { return ~0U; } + static inline unsigned getTombstoneKey() { return ~0U - 1; } + static unsigned getHashValue(const unsigned& Val) { return Val * 37U; } + static bool isEqual(const unsigned& LHS, const unsigned& RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for unsigned longs. +template<> struct DenseMapInfo { + static inline unsigned long getEmptyKey() { return ~0UL; } + static inline unsigned long getTombstoneKey() { return ~0UL - 1L; } + static unsigned getHashValue(const unsigned long& Val) { + return (unsigned)(Val * 37UL); + } + static bool isEqual(const unsigned long& LHS, const unsigned long& RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for unsigned long longs. +template<> struct DenseMapInfo { + static inline unsigned long long getEmptyKey() { return ~0ULL; } + static inline unsigned long long getTombstoneKey() { return ~0ULL - 1ULL; } + static unsigned getHashValue(const unsigned long long& Val) { + return (unsigned)(Val * 37ULL); + } + static bool isEqual(const unsigned long long& LHS, + const unsigned long long& RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for ints. +template<> struct DenseMapInfo { + static inline int getEmptyKey() { return 0x7fffffff; } + static inline int getTombstoneKey() { return -0x7fffffff - 1; } + static unsigned getHashValue(const int& Val) { return (unsigned)(Val * 37U); } + static bool isEqual(const int& LHS, const int& RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for longs. +template<> struct DenseMapInfo { + static inline long getEmptyKey() { + return (1UL << (sizeof(long) * 8 - 1)) - 1UL; + } + static inline long getTombstoneKey() { return getEmptyKey() - 1L; } + static unsigned getHashValue(const long& Val) { + return (unsigned)(Val * 37UL); + } + static bool isEqual(const long& LHS, const long& RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for long longs. +template<> struct DenseMapInfo { + static inline long long getEmptyKey() { return 0x7fffffffffffffffLL; } + static inline long long getTombstoneKey() { return -0x7fffffffffffffffLL-1; } + static unsigned getHashValue(const long long& Val) { + return (unsigned)(Val * 37ULL); + } + static bool isEqual(const long long& LHS, + const long long& RHS) { + return LHS == RHS; + } +}; + +// Provide DenseMapInfo for all pairs whose members have info. +template +struct DenseMapInfo > { + typedef std::pair Pair; + typedef DenseMapInfo FirstInfo; + typedef DenseMapInfo SecondInfo; + + static inline Pair getEmptyKey() { + return std::make_pair(FirstInfo::getEmptyKey(), + SecondInfo::getEmptyKey()); + } + static inline Pair getTombstoneKey() { + return std::make_pair(FirstInfo::getTombstoneKey(), + SecondInfo::getTombstoneKey()); + } + static unsigned getHashValue(const Pair& PairVal) { + uint64_t key = (uint64_t)FirstInfo::getHashValue(PairVal.first) << 32 + | (uint64_t)SecondInfo::getHashValue(PairVal.second); + key += ~(key << 32); + key ^= (key >> 22); + key += ~(key << 13); + key ^= (key >> 8); + key += (key << 3); + key ^= (key >> 15); + key += ~(key << 27); + key ^= (key >> 31); + return (unsigned)key; + } + static bool isEqual(const Pair &LHS, const Pair &RHS) { + return FirstInfo::isEqual(LHS.first, RHS.first) && + SecondInfo::isEqual(LHS.second, RHS.second); + } +}; + +} // end namespace llvm + +#endif diff --git a/include/llvm/EpochTracker.h b/include/llvm/EpochTracker.h new file mode 100644 index 0000000000..f589136247 --- /dev/null +++ b/include/llvm/EpochTracker.h @@ -0,0 +1,97 @@ +//===- llvm/ADT/EpochTracker.h - ADT epoch tracking --------------*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the DebugEpochBase and DebugEpochBase::HandleBase classes. +// These can be used to write iterators that are fail-fast when LLVM is built +// with asserts enabled. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_EPOCH_TRACKER_H +#define LLVM_ADT_EPOCH_TRACKER_H + +#include + +namespace llvm { + +#ifdef NDEBUG //ifndef LLVM_ENABLE_ABI_BREAKING_CHECKS + +class DebugEpochBase { +public: + void incrementEpoch() {} + + class HandleBase { + public: + HandleBase() = default; + explicit HandleBase(const DebugEpochBase *) {} + bool isHandleInSync() const { return true; } + const void *getEpochAddress() const { return nullptr; } + }; +}; + +#else + +/// \brief A base class for data structure classes wishing to make iterators +/// ("handles") pointing into themselves fail-fast. When building without +/// asserts, this class is empty and does nothing. +/// +/// DebugEpochBase does not by itself track handles pointing into itself. The +/// expectation is that routines touching the handles will poll on +/// isHandleInSync at appropriate points to assert that the handle they're using +/// is still valid. +/// +class DebugEpochBase { + uint64_t Epoch; + +public: + DebugEpochBase() : Epoch(0) {} + + /// \brief Calling incrementEpoch invalidates all handles pointing into the + /// calling instance. + void incrementEpoch() { ++Epoch; } + + /// \brief The destructor calls incrementEpoch to make use-after-free bugs + /// more likely to crash deterministically. + ~DebugEpochBase() { incrementEpoch(); } + + /// \brief A base class for iterator classes ("handles") that wish to poll for + /// iterator invalidating modifications in the underlying data structure. + /// When LLVM is built without asserts, this class is empty and does nothing. + /// + /// HandleBase does not track the parent data structure by itself. It expects + /// the routines modifying the data structure to call incrementEpoch when they + /// make an iterator-invalidating modification. + /// + class HandleBase { + const uint64_t *EpochAddress; + uint64_t EpochAtCreation; + + public: + HandleBase() : EpochAddress(nullptr), EpochAtCreation(UINT64_MAX) {} + + explicit HandleBase(const DebugEpochBase *Parent) + : EpochAddress(&Parent->Epoch), EpochAtCreation(Parent->Epoch) {} + + /// \brief Returns true if the DebugEpochBase this Handle is linked to has + /// not called incrementEpoch on itself since the creation of this + /// HandleBase instance. + bool isHandleInSync() const { return *EpochAddress == EpochAtCreation; } + + /// \brief Returns a pointer to the epoch word stored in the data structure + /// this handle points into. Can be used to check if two iterators point + /// into the same data structure. + const void *getEpochAddress() const { return EpochAddress; } + }; +}; + +#endif // LLVM_ENABLE_ABI_BREAKING_CHECKS + +} // namespace llvm + +#endif diff --git a/include/llvm/MathExtras.h b/include/llvm/MathExtras.h new file mode 100644 index 0000000000..1152dbe289 --- /dev/null +++ b/include/llvm/MathExtras.h @@ -0,0 +1,189 @@ +//===-- llvm/Support/MathExtras.h - Useful math functions -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains some functions that are useful for math stuff. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_MATHEXTRAS_H +#define LLVM_SUPPORT_MATHEXTRAS_H + +#include "llvm/Compiler.h" +#include +#include + +namespace llvm { +/// \brief The behavior an operation has on an input of 0. +enum ZeroBehavior { + /// \brief The returned value is undefined. + ZB_Undefined, + /// \brief The returned value is numeric_limits::max() + ZB_Max, + /// \brief The returned value is numeric_limits::digits + ZB_Width +}; + +namespace detail { +template struct LeadingZerosCounter { + static std::size_t count(T Val, ZeroBehavior) { + if (!Val) + return std::numeric_limits::digits; + + // Bisection method. + std::size_t ZeroBits = 0; + for (T Shift = std::numeric_limits::digits >> 1; Shift; Shift >>= 1) { + T Tmp = Val >> Shift; + if (Tmp) + Val = Tmp; + else + ZeroBits |= Shift; + } + return ZeroBits; + } +}; + +#if __GNUC__ >= 4 || _MSC_VER +template struct LeadingZerosCounter { + static std::size_t count(T Val, ZeroBehavior ZB) { + if (ZB != ZB_Undefined && Val == 0) + return 32; + +#if __has_builtin(__builtin_clz) || LLVM_GNUC_PREREQ(4, 0, 0) + return __builtin_clz(Val); +#elif _MSC_VER + unsigned long Index; + _BitScanReverse(&Index, Val); + return Index ^ 31; +#endif + } +}; + +#if !defined(_MSC_VER) || defined(_M_X64) +template struct LeadingZerosCounter { + static std::size_t count(T Val, ZeroBehavior ZB) { + if (ZB != ZB_Undefined && Val == 0) + return 64; + +#if __has_builtin(__builtin_clzll) || LLVM_GNUC_PREREQ(4, 0, 0) + return __builtin_clzll(Val); +#elif _MSC_VER + unsigned long Index; + _BitScanReverse64(&Index, Val); + return Index ^ 63; +#endif + } +}; +#endif +#endif +} // namespace detail + +/// \brief Count number of 0's from the most significant bit to the least +/// stopping at the first 1. +/// +/// Only unsigned integral types are allowed. +/// +/// \param ZB the behavior on an input of 0. Only ZB_Width and ZB_Undefined are +/// valid arguments. +template +std::size_t countLeadingZeros(T Val, ZeroBehavior ZB = ZB_Width) { + static_assert(std::numeric_limits::is_integer && + !std::numeric_limits::is_signed, + "Only unsigned integral types are allowed."); + return detail::LeadingZerosCounter::count(Val, ZB); +} + +/// Log2_32 - This function returns the floor log base 2 of the specified value, +/// -1 if the value is zero. (32 bit edition.) +/// Ex. Log2_32(32) == 5, Log2_32(1) == 0, Log2_32(0) == -1, Log2_32(6) == 2 +inline unsigned Log2_32(uint32_t Value) { + return 31 - countLeadingZeros(Value); +} + +/// Log2_64 - This function returns the floor log base 2 of the specified value, +/// -1 if the value is zero. (64 bit edition.) +inline unsigned Log2_64(uint64_t Value) { + return 63 - countLeadingZeros(Value); +} + +/// Log2_32_Ceil - This function returns the ceil log base 2 of the specified +/// value, 32 if the value is zero. (32 bit edition). +/// Ex. Log2_32_Ceil(32) == 5, Log2_32_Ceil(1) == 0, Log2_32_Ceil(6) == 3 +inline unsigned Log2_32_Ceil(uint32_t Value) { + return 32 - countLeadingZeros(Value - 1); +} + +/// Log2_64_Ceil - This function returns the ceil log base 2 of the specified +/// value, 64 if the value is zero. (64 bit edition.) +inline unsigned Log2_64_Ceil(uint64_t Value) { + return 64 - countLeadingZeros(Value - 1); +} + +/// BitsToDouble - This function takes a 64-bit integer and returns the bit +/// equivalent double. +inline double BitsToDouble(uint64_t Bits) { + union { + uint64_t L; + double D; + } T; + T.L = Bits; + return T.D; +} + +/// BitsToFloat - This function takes a 32-bit integer and returns the bit +/// equivalent float. +inline float BitsToFloat(uint32_t Bits) { + union { + uint32_t I; + float F; + } T; + T.I = Bits; + return T.F; +} + +/// DoubleToBits - This function takes a double and returns the bit +/// equivalent 64-bit integer. Note that copying doubles around +/// changes the bits of NaNs on some hosts, notably x86, so this +/// routine cannot be used if these bits are needed. +inline uint64_t DoubleToBits(double Double) { + union { + uint64_t L; + double D; + } T; + T.D = Double; + return T.L; +} + +/// FloatToBits - This function takes a float and returns the bit +/// equivalent 32-bit integer. Note that copying floats around +/// changes the bits of NaNs on some hosts, notably x86, so this +/// routine cannot be used if these bits are needed. +inline uint32_t FloatToBits(float Float) { + union { + uint32_t I; + float F; + } T; + T.F = Float; + return T.I; +} + +/// NextPowerOf2 - Returns the next power of two (in 64-bits) +/// that is strictly greater than A. Returns zero on overflow. +inline uint64_t NextPowerOf2(uint64_t A) { + A |= (A >> 1); + A |= (A >> 2); + A |= (A >> 4); + A |= (A >> 8); + A |= (A >> 16); + A |= (A >> 32); + return A + 1; +} + +} // namespace llvm + +#endif diff --git a/include/llvm/None.h b/include/llvm/None.h new file mode 100644 index 0000000000..d69ec17c15 --- /dev/null +++ b/include/llvm/None.h @@ -0,0 +1,26 @@ +//===-- None.h - Simple null value for implicit construction ------*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides None, an enumerator for use in implicit constructors +// of various (usually templated) types to make such construction more +// terse. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_NONE_H +#define LLVM_ADT_NONE_H + +namespace llvm { +/// \brief A simple null object to allow implicit construction of Optional +/// and similar types without having to spell out the specialization's name. +enum class NoneType { None }; +const NoneType None = None; +} + +#endif diff --git a/include/llvm/PointerLikeTypeTraits.h b/include/llvm/PointerLikeTypeTraits.h new file mode 100644 index 0000000000..b4d5a858d1 --- /dev/null +++ b/include/llvm/PointerLikeTypeTraits.h @@ -0,0 +1,81 @@ +//===- llvm/Support/PointerLikeTypeTraits.h - Pointer Traits ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the PointerLikeTypeTraits class. This allows data +// structures to reason about pointers and other things that are pointer sized. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_POINTERLIKETYPETRAITS_H +#define LLVM_SUPPORT_POINTERLIKETYPETRAITS_H + +#include + +namespace llvm { + +/// PointerLikeTypeTraits - This is a traits object that is used to handle +/// pointer types and things that are just wrappers for pointers as a uniform +/// entity. +template +class PointerLikeTypeTraits { + // getAsVoidPointer + // getFromVoidPointer + // getNumLowBitsAvailable +}; + +// Provide PointerLikeTypeTraits for non-cvr pointers. +template +class PointerLikeTypeTraits { +public: + static inline void *getAsVoidPointer(T* P) { return P; } + static inline T *getFromVoidPointer(void *P) { + return static_cast(P); + } + + /// Note, we assume here that malloc returns objects at least 4-byte aligned. + /// However, this may be wrong, or pointers may be from something other than + /// malloc. In this case, you should specialize this template to reduce this. + /// + /// All clients should use assertions to do a run-time check to ensure that + /// this is actually true. + enum { NumLowBitsAvailable = 2 }; +}; + +// Provide PointerLikeTypeTraits for const pointers. +template +class PointerLikeTypeTraits { + typedef PointerLikeTypeTraits NonConst; + +public: + static inline const void *getAsVoidPointer(const T* P) { + return NonConst::getAsVoidPointer(const_cast(P)); + } + static inline const T *getFromVoidPointer(const void *P) { + return NonConst::getFromVoidPointer(const_cast(P)); + } + enum { NumLowBitsAvailable = NonConst::NumLowBitsAvailable }; +}; + +// Provide PointerLikeTypeTraits for uintptr_t. +template<> +class PointerLikeTypeTraits { +public: + static inline void *getAsVoidPointer(uintptr_t P) { + return reinterpret_cast(P); + } + static inline uintptr_t getFromVoidPointer(void *P) { + return reinterpret_cast(P); + } + // No bits are available! + enum { NumLowBitsAvailable = 0 }; +}; + +} // end namespace llvm + +#endif diff --git a/include/llvm/SmallPtrSet.h b/include/llvm/SmallPtrSet.h new file mode 100644 index 0000000000..41905fd18a --- /dev/null +++ b/include/llvm/SmallPtrSet.h @@ -0,0 +1,346 @@ +//===- llvm/ADT/SmallPtrSet.h - 'Normally small' pointer set ----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the SmallPtrSet class. See the doxygen comment for +// SmallPtrSetImplBase for more details on the algorithm used. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_SMALLPTRSET_H +#define LLVM_ADT_SMALLPTRSET_H + +#include "llvm/Compiler.h" +#include "llvm/PointerLikeTypeTraits.h" +#include +#include +#include +#include +#include + +namespace llvm { + +class SmallPtrSetIteratorImpl; + +/// SmallPtrSetImplBase - This is the common code shared among all the +/// SmallPtrSet<>'s, which is almost everything. SmallPtrSet has two modes, one +/// for small and one for large sets. +/// +/// Small sets use an array of pointers allocated in the SmallPtrSet object, +/// which is treated as a simple array of pointers. When a pointer is added to +/// the set, the array is scanned to see if the element already exists, if not +/// the element is 'pushed back' onto the array. If we run out of space in the +/// array, we grow into the 'large set' case. SmallSet should be used when the +/// sets are often small. In this case, no memory allocation is used, and only +/// light-weight and cache-efficient scanning is used. +/// +/// Large sets use a classic exponentially-probed hash table. Empty buckets are +/// represented with an illegal pointer value (-1) to allow null pointers to be +/// inserted. Tombstones are represented with another illegal pointer value +/// (-2), to allow deletion. The hash table is resized when the table is 3/4 or +/// more. When this happens, the table is doubled in size. +/// +class SmallPtrSetImplBase { + friend class SmallPtrSetIteratorImpl; +protected: + /// SmallArray - Points to a fixed size set of buckets, used in 'small mode'. + const void **SmallArray; + /// CurArray - This is the current set of buckets. If equal to SmallArray, + /// then the set is in 'small mode'. + const void **CurArray; + /// CurArraySize - The allocated size of CurArray, always a power of two. + unsigned CurArraySize; + + // If small, this is # elts allocated consecutively + unsigned NumElements; + unsigned NumTombstones; + + // Helpers to copy and move construct a SmallPtrSet. + SmallPtrSetImplBase(const void **SmallStorage, const SmallPtrSetImplBase &that); + SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize, + SmallPtrSetImplBase &&that); + explicit SmallPtrSetImplBase(const void **SmallStorage, unsigned SmallSize) : + SmallArray(SmallStorage), CurArray(SmallStorage), CurArraySize(SmallSize) { + assert(SmallSize && (SmallSize & (SmallSize-1)) == 0 && + "Initial size must be a power of two!"); + clear(); + } + ~SmallPtrSetImplBase(); + +public: + typedef unsigned size_type; + bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const { return size() == 0; } + size_type size() const { return NumElements; } + + void clear() { + // If the capacity of the array is huge, and the # elements used is small, + // shrink the array. + if (!isSmall() && NumElements*4 < CurArraySize && CurArraySize > 32) + return shrink_and_clear(); + + // Fill the array with empty markers. + memset(CurArray, -1, CurArraySize*sizeof(void*)); + NumElements = 0; + NumTombstones = 0; + } + +protected: + static void *getTombstoneMarker() { return reinterpret_cast(-2); } + static void *getEmptyMarker() { + // Note that -1 is chosen to make clear() efficiently implementable with + // memset and because it's not a valid pointer value. + return reinterpret_cast(-1); + } + + /// insert_imp - This returns true if the pointer was new to the set, false if + /// it was already in the set. This is hidden from the client so that the + /// derived class can check that the right type of pointer is passed in. + std::pair insert_imp(const void *Ptr); + + /// erase_imp - If the set contains the specified pointer, remove it and + /// return true, otherwise return false. This is hidden from the client so + /// that the derived class can check that the right type of pointer is passed + /// in. + bool erase_imp(const void * Ptr); + + bool count_imp(const void * Ptr) const { + if (isSmall()) { + // Linear search for the item. + for (const void *const *APtr = SmallArray, + *const *E = SmallArray+NumElements; APtr != E; ++APtr) + if (*APtr == Ptr) + return true; + return false; + } + + // Big set case. + return *FindBucketFor(Ptr) == Ptr; + } + +private: + bool isSmall() const { return CurArray == SmallArray; } + + const void * const *FindBucketFor(const void *Ptr) const; + void shrink_and_clear(); + + /// Grow - Allocate a larger backing store for the buckets and move it over. + void Grow(unsigned NewSize); + + void operator=(const SmallPtrSetImplBase &RHS) = delete; +protected: + /// swap - Swaps the elements of two sets. + /// Note: This method assumes that both sets have the same small size. + void swap(SmallPtrSetImplBase &RHS); + + void CopyFrom(const SmallPtrSetImplBase &RHS); + void MoveFrom(unsigned SmallSize, SmallPtrSetImplBase &&RHS); +}; + +/// SmallPtrSetIteratorImpl - This is the common base class shared between all +/// instances of SmallPtrSetIterator. +class SmallPtrSetIteratorImpl { +protected: + const void *const *Bucket; + const void *const *End; +public: + explicit SmallPtrSetIteratorImpl(const void *const *BP, const void*const *E) + : Bucket(BP), End(E) { + AdvanceIfNotValid(); + } + + bool operator==(const SmallPtrSetIteratorImpl &RHS) const { + return Bucket == RHS.Bucket; + } + bool operator!=(const SmallPtrSetIteratorImpl &RHS) const { + return Bucket != RHS.Bucket; + } + +protected: + /// AdvanceIfNotValid - If the current bucket isn't valid, advance to a bucket + /// that is. This is guaranteed to stop because the end() bucket is marked + /// valid. + void AdvanceIfNotValid() { + assert(Bucket <= End); + while (Bucket != End && + (*Bucket == SmallPtrSetImplBase::getEmptyMarker() || + *Bucket == SmallPtrSetImplBase::getTombstoneMarker())) + ++Bucket; + } +}; + +/// SmallPtrSetIterator - This implements a const_iterator for SmallPtrSet. +template +class SmallPtrSetIterator : public SmallPtrSetIteratorImpl { + typedef PointerLikeTypeTraits PtrTraits; + +public: + typedef PtrTy value_type; + typedef PtrTy reference; + typedef PtrTy pointer; + typedef std::ptrdiff_t difference_type; + typedef std::forward_iterator_tag iterator_category; + + explicit SmallPtrSetIterator(const void *const *BP, const void *const *E) + : SmallPtrSetIteratorImpl(BP, E) {} + + // Most methods provided by baseclass. + + const PtrTy operator*() const { + assert(Bucket < End); + return PtrTraits::getFromVoidPointer(const_cast(*Bucket)); + } + + inline SmallPtrSetIterator& operator++() { // Preincrement + ++Bucket; + AdvanceIfNotValid(); + return *this; + } + + SmallPtrSetIterator operator++(int) { // Postincrement + SmallPtrSetIterator tmp = *this; ++*this; return tmp; + } +}; + +/// RoundUpToPowerOfTwo - This is a helper template that rounds N up to the next +/// power of two (which means N itself if N is already a power of two). +template +struct RoundUpToPowerOfTwo; + +/// RoundUpToPowerOfTwoH - If N is not a power of two, increase it. This is a +/// helper template used to implement RoundUpToPowerOfTwo. +template +struct RoundUpToPowerOfTwoH { + enum { Val = N }; +}; +template +struct RoundUpToPowerOfTwoH { + enum { + // We could just use NextVal = N+1, but this converges faster. N|(N-1) sets + // the right-most zero bits to one all at once, e.g. 0b0011000 -> 0b0011111. + Val = RoundUpToPowerOfTwo<(N|(N-1)) + 1>::Val + }; +}; + +template +struct RoundUpToPowerOfTwo { + enum { Val = RoundUpToPowerOfTwoH::Val }; +}; + + +/// \brief A templated base class for \c SmallPtrSet which provides the +/// typesafe interface that is common across all small sizes. +/// +/// This is particularly useful for passing around between interface boundaries +/// to avoid encoding a particular small size in the interface boundary. +template +class SmallPtrSetImpl : public SmallPtrSetImplBase { + typedef PointerLikeTypeTraits PtrTraits; + + SmallPtrSetImpl(const SmallPtrSetImpl&) = delete; +protected: + // Constructors that forward to the base. + SmallPtrSetImpl(const void **SmallStorage, const SmallPtrSetImpl &that) + : SmallPtrSetImplBase(SmallStorage, that) {} + SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize, + SmallPtrSetImpl &&that) + : SmallPtrSetImplBase(SmallStorage, SmallSize, std::move(that)) {} + explicit SmallPtrSetImpl(const void **SmallStorage, unsigned SmallSize) + : SmallPtrSetImplBase(SmallStorage, SmallSize) {} + +public: + typedef SmallPtrSetIterator iterator; + typedef SmallPtrSetIterator const_iterator; + + /// Inserts Ptr if and only if there is no element in the container equal to + /// Ptr. The bool component of the returned pair is true if and only if the + /// insertion takes place, and the iterator component of the pair points to + /// the element equal to Ptr. + std::pair insert(PtrType Ptr) { + auto p = insert_imp(PtrTraits::getAsVoidPointer(Ptr)); + return std::make_pair(iterator(p.first, CurArray + CurArraySize), p.second); + } + + /// erase - If the set contains the specified pointer, remove it and return + /// true, otherwise return false. + bool erase(PtrType Ptr) { + return erase_imp(PtrTraits::getAsVoidPointer(Ptr)); + } + + /// count - Return 1 if the specified pointer is in the set, 0 otherwise. + size_type count(PtrType Ptr) const { + return count_imp(PtrTraits::getAsVoidPointer(Ptr)) ? 1 : 0; + } + + template + void insert(IterT I, IterT E) { + for (; I != E; ++I) + insert(*I); + } + + inline iterator begin() const { + return iterator(CurArray, CurArray+CurArraySize); + } + inline iterator end() const { + return iterator(CurArray+CurArraySize, CurArray+CurArraySize); + } +}; + +/// SmallPtrSet - This class implements a set which is optimized for holding +/// SmallSize or less elements. This internally rounds up SmallSize to the next +/// power of two if it is not already a power of two. See the comments above +/// SmallPtrSetImplBase for details of the algorithm. +template +class SmallPtrSet : public SmallPtrSetImpl { + typedef SmallPtrSetImpl BaseT; + + // Make sure that SmallSize is a power of two, round up if not. + enum { SmallSizePowTwo = RoundUpToPowerOfTwo::Val }; + /// SmallStorage - Fixed size storage used in 'small mode'. + const void *SmallStorage[SmallSizePowTwo]; +public: + SmallPtrSet() : BaseT(SmallStorage, SmallSizePowTwo) {} + SmallPtrSet(const SmallPtrSet &that) : BaseT(SmallStorage, that) {} + SmallPtrSet(SmallPtrSet &&that) + : BaseT(SmallStorage, SmallSizePowTwo, std::move(that)) {} + + template + SmallPtrSet(It I, It E) : BaseT(SmallStorage, SmallSizePowTwo) { + this->insert(I, E); + } + + SmallPtrSet & + operator=(const SmallPtrSet &RHS) { + if (&RHS != this) + this->CopyFrom(RHS); + return *this; + } + + SmallPtrSet& + operator=(SmallPtrSet &&RHS) { + if (&RHS != this) + this->MoveFrom(SmallSizePowTwo, std::move(RHS)); + return *this; + } + + /// swap - Swaps the elements of two sets. + void swap(SmallPtrSet &RHS) { + SmallPtrSetImplBase::swap(RHS); + } +}; + +} // namespace llvm + +namespace std { + /// Implement std::swap in terms of SmallPtrSet swap. + template + inline void swap(llvm::SmallPtrSet &LHS, llvm::SmallPtrSet &RHS) { + LHS.swap(RHS); + } +} + +#endif diff --git a/include/llvm/SmallSet.h b/include/llvm/SmallSet.h new file mode 100644 index 0000000000..3dfd1f9bd9 --- /dev/null +++ b/include/llvm/SmallSet.h @@ -0,0 +1,136 @@ +//===- llvm/ADT/SmallSet.h - 'Normally small' sets --------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the SmallSet class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_SMALLSET_H +#define LLVM_ADT_SMALLSET_H + +#include "llvm/None.h" +#include "llvm/SmallPtrSet.h" +#include "llvm/SmallVector.h" +#include + +namespace llvm { + +/// SmallSet - This maintains a set of unique values, optimizing for the case +/// when the set is small (less than N). In this case, the set can be +/// maintained with no mallocs. If the set gets large, we expand to using an +/// std::set to maintain reasonable lookup times. +/// +/// Note that this set does not provide a way to iterate over members in the +/// set. +template > +class SmallSet { + /// Use a SmallVector to hold the elements here (even though it will never + /// reach its 'large' stage) to avoid calling the default ctors of elements + /// we will never use. + SmallVector Vector; + std::set Set; + typedef typename SmallVector::const_iterator VIterator; + typedef typename SmallVector::iterator mutable_iterator; + + // In small mode SmallPtrSet uses linear search for the elements, so it is + // not a good idea to choose this value too high. You may consider using a + // DenseSet<> instead if you expect many elements in the set. + static_assert(N <= 32, "N should be small"); + +public: + typedef size_t size_type; + SmallSet() {} + + bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const { + return Vector.empty() && Set.empty(); + } + + size_type size() const { + return isSmall() ? Vector.size() : Set.size(); + } + + /// count - Return 1 if the element is in the set, 0 otherwise. + size_type count(const T &V) const { + if (isSmall()) { + // Since the collection is small, just do a linear search. + return vfind(V) == Vector.end() ? 0 : 1; + } else { + return Set.count(V); + } + } + + /// insert - Insert an element into the set if it isn't already there. + /// Returns true if the element is inserted (it was not in the set before). + /// The first value of the returned pair is unused and provided for + /// partial compatibility with the standard library self-associative container + /// concept. + // FIXME: Add iterators that abstract over the small and large form, and then + // return those here. + std::pair insert(const T &V) { + if (!isSmall()) + return std::make_pair(None, Set.insert(V).second); + + VIterator I = vfind(V); + if (I != Vector.end()) // Don't reinsert if it already exists. + return std::make_pair(None, false); + if (Vector.size() < N) { + Vector.push_back(V); + return std::make_pair(None, true); + } + + // Otherwise, grow from vector to set. + while (!Vector.empty()) { + Set.insert(Vector.back()); + Vector.pop_back(); + } + Set.insert(V); + return std::make_pair(None, true); + } + + template + void insert(IterT I, IterT E) { + for (; I != E; ++I) + insert(*I); + } + + bool erase(const T &V) { + if (!isSmall()) + return Set.erase(V); + for (mutable_iterator I = Vector.begin(), E = Vector.end(); I != E; ++I) + if (*I == V) { + Vector.erase(I); + return true; + } + return false; + } + + void clear() { + Vector.clear(); + Set.clear(); + } + +private: + bool isSmall() const { return Set.empty(); } + + VIterator vfind(const T &V) const { + for (VIterator I = Vector.begin(), E = Vector.end(); I != E; ++I) + if (*I == V) + return I; + return Vector.end(); + } +}; + +/// If this set is of pointer values, transparently switch over to using +/// SmallPtrSet for performance. +template +class SmallSet : public SmallPtrSet {}; + +} // end namespace llvm + +#endif diff --git a/include/llvm/SmallString.h b/include/llvm/SmallString.h new file mode 100644 index 0000000000..3f89ca806b --- /dev/null +++ b/include/llvm/SmallString.h @@ -0,0 +1,297 @@ +//===- llvm/ADT/SmallString.h - 'Normally small' strings --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the SmallString class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_SMALLSTRING_H +#define LLVM_ADT_SMALLSTRING_H + +#include "llvm/SmallVector.h" +#include "llvm/StringRef.h" + +namespace llvm { + +/// SmallString - A SmallString is just a SmallVector with methods and accessors +/// that make it work better as a string (e.g. operator+ etc). +template +class SmallString : public SmallVector { +public: + /// Default ctor - Initialize to empty. + SmallString() {} + + /// Initialize from a StringRef. + SmallString(StringRef S) : SmallVector(S.begin(), S.end()) {} + + /// Initialize with a range. + template + SmallString(ItTy S, ItTy E) : SmallVector(S, E) {} + + // Note that in order to add new overloads for append & assign, we have to + // duplicate the inherited versions so as not to inadvertently hide them. + + /// @} + /// @name String Assignment + /// @{ + + /// Assign from a repeated element. + void assign(size_t NumElts, char Elt) { + this->SmallVectorImpl::assign(NumElts, Elt); + } + + /// Assign from an iterator pair. + template + void assign(in_iter S, in_iter E) { + this->clear(); + SmallVectorImpl::append(S, E); + } + + /// Assign from a StringRef. + void assign(StringRef RHS) { + this->clear(); + SmallVectorImpl::append(RHS.begin(), RHS.end()); + } + + /// Assign from a SmallVector. + void assign(const SmallVectorImpl &RHS) { + this->clear(); + SmallVectorImpl::append(RHS.begin(), RHS.end()); + } + + /// @} + /// @name String Concatenation + /// @{ + + /// Append from an iterator pair. + template + void append(in_iter S, in_iter E) { + SmallVectorImpl::append(S, E); + } + + void append(size_t NumInputs, char Elt) { + SmallVectorImpl::append(NumInputs, Elt); + } + + + /// Append from a StringRef. + void append(StringRef RHS) { + SmallVectorImpl::append(RHS.begin(), RHS.end()); + } + + /// Append from a SmallVector. + void append(const SmallVectorImpl &RHS) { + SmallVectorImpl::append(RHS.begin(), RHS.end()); + } + + /// @} + /// @name String Comparison + /// @{ + + /// Check for string equality. This is more efficient than compare() when + /// the relative ordering of inequal strings isn't needed. + bool equals(StringRef RHS) const { + return str().equals(RHS); + } + + /// Check for string equality, ignoring case. + bool equals_lower(StringRef RHS) const { + return str().equals_lower(RHS); + } + + /// Compare two strings; the result is -1, 0, or 1 if this string is + /// lexicographically less than, equal to, or greater than the \p RHS. + int compare(StringRef RHS) const { + return str().compare(RHS); + } + + /// compare_lower - Compare two strings, ignoring case. + int compare_lower(StringRef RHS) const { + return str().compare_lower(RHS); + } + + /// compare_numeric - Compare two strings, treating sequences of digits as + /// numbers. + int compare_numeric(StringRef RHS) const { + return str().compare_numeric(RHS); + } + + /// @} + /// @name String Predicates + /// @{ + + /// startswith - Check if this string starts with the given \p Prefix. + bool startswith(StringRef Prefix) const { + return str().startswith(Prefix); + } + + /// endswith - Check if this string ends with the given \p Suffix. + bool endswith(StringRef Suffix) const { + return str().endswith(Suffix); + } + + /// @} + /// @name String Searching + /// @{ + + /// find - Search for the first character \p C in the string. + /// + /// \return - The index of the first occurrence of \p C, or npos if not + /// found. + size_t find(char C, size_t From = 0) const { + return str().find(C, From); + } + + /// Search for the first string \p Str in the string. + /// + /// \returns The index of the first occurrence of \p Str, or npos if not + /// found. + size_t find(StringRef Str, size_t From = 0) const { + return str().find(Str, From); + } + + /// Search for the last character \p C in the string. + /// + /// \returns The index of the last occurrence of \p C, or npos if not + /// found. + size_t rfind(char C, size_t From = StringRef::npos) const { + return str().rfind(C, From); + } + + /// Search for the last string \p Str in the string. + /// + /// \returns The index of the last occurrence of \p Str, or npos if not + /// found. + size_t rfind(StringRef Str) const { + return str().rfind(Str); + } + + /// Find the first character in the string that is \p C, or npos if not + /// found. Same as find. + size_t find_first_of(char C, size_t From = 0) const { + return str().find_first_of(C, From); + } + + /// Find the first character in the string that is in \p Chars, or npos if + /// not found. + /// + /// Complexity: O(size() + Chars.size()) + size_t find_first_of(StringRef Chars, size_t From = 0) const { + return str().find_first_of(Chars, From); + } + + /// Find the first character in the string that is not \p C or npos if not + /// found. + size_t find_first_not_of(char C, size_t From = 0) const { + return str().find_first_not_of(C, From); + } + + /// Find the first character in the string that is not in the string + /// \p Chars, or npos if not found. + /// + /// Complexity: O(size() + Chars.size()) + size_t find_first_not_of(StringRef Chars, size_t From = 0) const { + return str().find_first_not_of(Chars, From); + } + + /// Find the last character in the string that is \p C, or npos if not + /// found. + size_t find_last_of(char C, size_t From = StringRef::npos) const { + return str().find_last_of(C, From); + } + + /// Find the last character in the string that is in \p C, or npos if not + /// found. + /// + /// Complexity: O(size() + Chars.size()) + size_t find_last_of( + StringRef Chars, size_t From = StringRef::npos) const { + return str().find_last_of(Chars, From); + } + + /// @} + /// @name Helpful Algorithms + /// @{ + + /// Return the number of occurrences of \p C in the string. + size_t count(char C) const { + return str().count(C); + } + + /// Return the number of non-overlapped occurrences of \p Str in the + /// string. + size_t count(StringRef Str) const { + return str().count(Str); + } + + /// @} + /// @name Substring Operations + /// @{ + + /// Return a reference to the substring from [Start, Start + N). + /// + /// \param Start The index of the starting character in the substring; if + /// the index is npos or greater than the length of the string then the + /// empty substring will be returned. + /// + /// \param N The number of characters to included in the substring. If \p N + /// exceeds the number of characters remaining in the string, the string + /// suffix (starting with \p Start) will be returned. + StringRef substr(size_t Start, size_t N = StringRef::npos) const { + return str().substr(Start, N); + } + + /// Return a reference to the substring from [Start, End). + /// + /// \param Start The index of the starting character in the substring; if + /// the index is npos or greater than the length of the string then the + /// empty substring will be returned. + /// + /// \param End The index following the last character to include in the + /// substring. If this is npos, or less than \p Start, or exceeds the + /// number of characters remaining in the string, the string suffix + /// (starting with \p Start) will be returned. + StringRef slice(size_t Start, size_t End) const { + return str().slice(Start, End); + } + + // Extra methods. + + /// Explicit conversion to StringRef. + StringRef str() const { return StringRef(this->begin(), this->size()); } + + // TODO: Make this const, if it's safe... + const char* c_str() { + this->push_back(0); + this->pop_back(); + return this->data(); + } + + /// Implicit conversion to StringRef. + operator StringRef() const { return str(); } + + // Extra operators. + const SmallString &operator=(StringRef RHS) { + this->clear(); + return *this += RHS; + } + + SmallString &operator+=(StringRef RHS) { + this->append(RHS.begin(), RHS.end()); + return *this; + } + SmallString &operator+=(char C) { + this->push_back(C); + return *this; + } +}; + +} // namespace llvm + +#endif diff --git a/include/llvm/SmallVector.h b/include/llvm/SmallVector.h new file mode 100644 index 0000000000..ce8f8ce150 --- /dev/null +++ b/include/llvm/SmallVector.h @@ -0,0 +1,945 @@ +//===- llvm/ADT/SmallVector.h - 'Normally small' vectors --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the SmallVector class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_SMALLVECTOR_H +#define LLVM_ADT_SMALLVECTOR_H + +#include "llvm/iterator_range.h" +#include "llvm/AlignOf.h" +#include "llvm/Compiler.h" +#include "llvm/MathExtras.h" +#include "llvm/type_traits.h" +#include +#include +#include +#include +#include +#include +#include +#include + +namespace llvm { + +/// This is all the non-templated stuff common to all SmallVectors. +class SmallVectorBase { +protected: + void *BeginX, *EndX, *CapacityX; + +protected: + SmallVectorBase(void *FirstEl, size_t Size) + : BeginX(FirstEl), EndX(FirstEl), CapacityX((char*)FirstEl+Size) {} + + /// This is an implementation of the grow() method which only works + /// on POD-like data types and is out of line to reduce code duplication. + void grow_pod(void *FirstEl, size_t MinSizeInBytes, size_t TSize); + +public: + /// This returns size()*sizeof(T). + size_t size_in_bytes() const { + return size_t((char*)EndX - (char*)BeginX); + } + + /// capacity_in_bytes - This returns capacity()*sizeof(T). + size_t capacity_in_bytes() const { + return size_t((char*)CapacityX - (char*)BeginX); + } + + bool LLVM_ATTRIBUTE_UNUSED_RESULT empty() const { return BeginX == EndX; } +}; + +template struct SmallVectorStorage; + +/// This is the part of SmallVectorTemplateBase which does not depend on whether +/// the type T is a POD. The extra dummy template argument is used by ArrayRef +/// to avoid unnecessarily requiring T to be complete. +template +class SmallVectorTemplateCommon : public SmallVectorBase { +private: + template friend struct SmallVectorStorage; + + // Allocate raw space for N elements of type T. If T has a ctor or dtor, we + // don't want it to be automatically run, so we need to represent the space as + // something else. Use an array of char of sufficient alignment. + typedef llvm::AlignedCharArrayUnion U; + U FirstEl; + // Space after 'FirstEl' is clobbered, do not add any instance vars after it. + +protected: + SmallVectorTemplateCommon(size_t Size) : SmallVectorBase(&FirstEl, Size) {} + + void grow_pod(size_t MinSizeInBytes, size_t TSize) { + SmallVectorBase::grow_pod(&FirstEl, MinSizeInBytes, TSize); + } + + /// Return true if this is a smallvector which has not had dynamic + /// memory allocated for it. + bool isSmall() const { + return BeginX == static_cast(&FirstEl); + } + + /// Put this vector in a state of being small. + void resetToSmall() { + BeginX = EndX = CapacityX = &FirstEl; + } + + void setEnd(T *P) { this->EndX = P; } +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T *iterator; + typedef const T *const_iterator; + + typedef std::reverse_iterator const_reverse_iterator; + typedef std::reverse_iterator reverse_iterator; + + typedef T &reference; + typedef const T &const_reference; + typedef T *pointer; + typedef const T *const_pointer; + + // forward iterator creation methods. + iterator begin() { return (iterator)this->BeginX; } + const_iterator begin() const { return (const_iterator)this->BeginX; } + iterator end() { return (iterator)this->EndX; } + const_iterator end() const { return (const_iterator)this->EndX; } +protected: + iterator capacity_ptr() { return (iterator)this->CapacityX; } + const_iterator capacity_ptr() const { return (const_iterator)this->CapacityX;} +public: + + // reverse iterator creation methods. + reverse_iterator rbegin() { return reverse_iterator(end()); } + const_reverse_iterator rbegin() const{ return const_reverse_iterator(end()); } + reverse_iterator rend() { return reverse_iterator(begin()); } + const_reverse_iterator rend() const { return const_reverse_iterator(begin());} + + size_type size() const { return end()-begin(); } + size_type max_size() const { return size_type(-1) / sizeof(T); } + + /// Return the total number of elements in the currently allocated buffer. + size_t capacity() const { return capacity_ptr() - begin(); } + + /// Return a pointer to the vector's buffer, even if empty(). + pointer data() { return pointer(begin()); } + /// Return a pointer to the vector's buffer, even if empty(). + const_pointer data() const { return const_pointer(begin()); } + + reference operator[](size_type idx) { + assert(idx < size()); + return begin()[idx]; + } + const_reference operator[](size_type idx) const { + assert(idx < size()); + return begin()[idx]; + } + + reference front() { + assert(!empty()); + return begin()[0]; + } + const_reference front() const { + assert(!empty()); + return begin()[0]; + } + + reference back() { + assert(!empty()); + return end()[-1]; + } + const_reference back() const { + assert(!empty()); + return end()[-1]; + } +}; + +/// SmallVectorTemplateBase - This is where we put method +/// implementations that are designed to work with non-POD-like T's. +template +class SmallVectorTemplateBase : public SmallVectorTemplateCommon { +protected: + SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon(Size) {} + + static void destroy_range(T *S, T *E) { + while (S != E) { + --E; + E->~T(); + } + } + + /// Use move-assignment to move the range [I, E) onto the + /// objects starting with "Dest". This is just 's + /// std::move, but not all stdlibs actually provide that. + template + static It2 move(It1 I, It1 E, It2 Dest) { + for (; I != E; ++I, ++Dest) + *Dest = ::std::move(*I); + return Dest; + } + + /// Use move-assignment to move the range + /// [I, E) onto the objects ending at "Dest", moving objects + /// in reverse order. This is just 's + /// std::move_backward, but not all stdlibs actually provide that. + template + static It2 move_backward(It1 I, It1 E, It2 Dest) { + while (I != E) + *--Dest = ::std::move(*--E); + return Dest; + } + + /// Move the range [I, E) into the uninitialized memory starting with "Dest", + /// constructing elements as needed. + template + static void uninitialized_move(It1 I, It1 E, It2 Dest) { + for (; I != E; ++I, ++Dest) + ::new ((void*) &*Dest) T(::std::move(*I)); + } + + /// Copy the range [I, E) onto the uninitialized memory starting with "Dest", + /// constructing elements as needed. + template + static void uninitialized_copy(It1 I, It1 E, It2 Dest) { + std::uninitialized_copy(I, E, Dest); + } + + /// Grow the allocated memory (without initializing new elements), doubling + /// the size of the allocated memory. Guarantees space for at least one more + /// element, or MinSize more elements if specified. + void grow(size_t MinSize = 0); + +public: + void push_back(const T &Elt) { + if (LLVM_UNLIKELY(this->EndX >= this->CapacityX)) + this->grow(); + ::new ((void*) this->end()) T(Elt); + this->setEnd(this->end()+1); + } + + void push_back(T &&Elt) { + if (LLVM_UNLIKELY(this->EndX >= this->CapacityX)) + this->grow(); + ::new ((void*) this->end()) T(::std::move(Elt)); + this->setEnd(this->end()+1); + } + + void pop_back() { + this->setEnd(this->end()-1); + this->end()->~T(); + } +}; + +// Define this out-of-line to dissuade the C++ compiler from inlining it. +template +void SmallVectorTemplateBase::grow(size_t MinSize) { + size_t CurCapacity = this->capacity(); + size_t CurSize = this->size(); + // Always grow, even from zero. + size_t NewCapacity = size_t(NextPowerOf2(CurCapacity+2)); + if (NewCapacity < MinSize) + NewCapacity = MinSize; + T *NewElts = static_cast(malloc(NewCapacity*sizeof(T))); + + // Move the elements over. + this->uninitialized_move(this->begin(), this->end(), NewElts); + + // Destroy the original elements. + destroy_range(this->begin(), this->end()); + + // If this wasn't grown from the inline copy, deallocate the old space. + if (!this->isSmall()) + free(this->begin()); + + this->setEnd(NewElts+CurSize); + this->BeginX = NewElts; + this->CapacityX = this->begin()+NewCapacity; +} + + +/// SmallVectorTemplateBase - This is where we put method +/// implementations that are designed to work with POD-like T's. +template +class SmallVectorTemplateBase : public SmallVectorTemplateCommon { +protected: + SmallVectorTemplateBase(size_t Size) : SmallVectorTemplateCommon(Size) {} + + // No need to do a destroy loop for POD's. + static void destroy_range(T *, T *) {} + + /// Use move-assignment to move the range [I, E) onto the + /// objects starting with "Dest". For PODs, this is just memcpy. + template + static It2 move(It1 I, It1 E, It2 Dest) { + return ::std::copy(I, E, Dest); + } + + /// Use move-assignment to move the range [I, E) onto the objects ending at + /// "Dest", moving objects in reverse order. + template + static It2 move_backward(It1 I, It1 E, It2 Dest) { + return ::std::copy_backward(I, E, Dest); + } + + /// Move the range [I, E) onto the uninitialized memory + /// starting with "Dest", constructing elements into it as needed. + template + static void uninitialized_move(It1 I, It1 E, It2 Dest) { + // Just do a copy. + uninitialized_copy(I, E, Dest); + } + + /// Copy the range [I, E) onto the uninitialized memory + /// starting with "Dest", constructing elements into it as needed. + template + static void uninitialized_copy(It1 I, It1 E, It2 Dest) { + // Arbitrary iterator types; just use the basic implementation. + std::uninitialized_copy(I, E, Dest); + } + + /// Copy the range [I, E) onto the uninitialized memory + /// starting with "Dest", constructing elements into it as needed. + template + static void uninitialized_copy( + T1 *I, T1 *E, T2 *Dest, + typename std::enable_if::type, + T2>::value>::type * = nullptr) { + // Use memcpy for PODs iterated by pointers (which includes SmallVector + // iterators): std::uninitialized_copy optimizes to memmove, but we can + // use memcpy here. + memcpy(Dest, I, (E-I)*sizeof(T)); + } + + /// Double the size of the allocated memory, guaranteeing space for at + /// least one more element or MinSize if specified. + void grow(size_t MinSize = 0) { + this->grow_pod(MinSize*sizeof(T), sizeof(T)); + } +public: + void push_back(const T &Elt) { + if (LLVM_UNLIKELY(this->EndX >= this->CapacityX)) + this->grow(); + memcpy(this->end(), &Elt, sizeof(T)); + this->setEnd(this->end()+1); + } + + void pop_back() { + this->setEnd(this->end()-1); + } +}; + + +/// This class consists of common code factored out of the SmallVector class to +/// reduce code duplication based on the SmallVector 'N' template parameter. +template +class SmallVectorImpl : public SmallVectorTemplateBase::value> { + typedef SmallVectorTemplateBase::value > SuperClass; + + SmallVectorImpl(const SmallVectorImpl&) = delete; +public: + typedef typename SuperClass::iterator iterator; + typedef typename SuperClass::size_type size_type; + +protected: + // Default ctor - Initialize to empty. + explicit SmallVectorImpl(unsigned N) + : SmallVectorTemplateBase::value>(N*sizeof(T)) { + } + +public: + ~SmallVectorImpl() { + // Destroy the constructed elements in the vector. + this->destroy_range(this->begin(), this->end()); + + // If this wasn't grown from the inline copy, deallocate the old space. + if (!this->isSmall()) + free(this->begin()); + } + + + void clear() { + this->destroy_range(this->begin(), this->end()); + this->EndX = this->BeginX; + } + + void resize(size_type N) { + if (N < this->size()) { + this->destroy_range(this->begin()+N, this->end()); + this->setEnd(this->begin()+N); + } else if (N > this->size()) { + if (this->capacity() < N) + this->grow(N); + for (auto I = this->end(), E = this->begin() + N; I != E; ++I) + new (&*I) T(); + this->setEnd(this->begin()+N); + } + } + + void resize(size_type N, const T &NV) { + if (N < this->size()) { + this->destroy_range(this->begin()+N, this->end()); + this->setEnd(this->begin()+N); + } else if (N > this->size()) { + if (this->capacity() < N) + this->grow(N); + std::uninitialized_fill(this->end(), this->begin()+N, NV); + this->setEnd(this->begin()+N); + } + } + + void reserve(size_type N) { + if (this->capacity() < N) + this->grow(N); + } + + T LLVM_ATTRIBUTE_UNUSED_RESULT pop_back_val() { + T Result = ::std::move(this->back()); + this->pop_back(); + return Result; + } + + void swap(SmallVectorImpl &RHS); + + /// Add the specified range to the end of the SmallVector. + template + void append(in_iter in_start, in_iter in_end) { + size_type NumInputs = std::distance(in_start, in_end); + // Grow allocated space if needed. + if (NumInputs > size_type(this->capacity_ptr()-this->end())) + this->grow(this->size()+NumInputs); + + // Copy the new elements over. + this->uninitialized_copy(in_start, in_end, this->end()); + this->setEnd(this->end() + NumInputs); + } + + /// Add the specified range to the end of the SmallVector. + void append(size_type NumInputs, const T &Elt) { + // Grow allocated space if needed. + if (NumInputs > size_type(this->capacity_ptr()-this->end())) + this->grow(this->size()+NumInputs); + + // Copy the new elements over. + std::uninitialized_fill_n(this->end(), NumInputs, Elt); + this->setEnd(this->end() + NumInputs); + } + + void append(std::initializer_list IL) { + append(IL.begin(), IL.end()); + } + + void assign(size_type NumElts, const T &Elt) { + clear(); + if (this->capacity() < NumElts) + this->grow(NumElts); + this->setEnd(this->begin()+NumElts); + std::uninitialized_fill(this->begin(), this->end(), Elt); + } + + void assign(std::initializer_list IL) { + clear(); + append(IL); + } + + iterator erase(iterator I) { + assert(I >= this->begin() && "Iterator to erase is out of bounds."); + assert(I < this->end() && "Erasing at past-the-end iterator."); + + iterator N = I; + // Shift all elts down one. + this->move(I+1, this->end(), I); + // Drop the last elt. + this->pop_back(); + return(N); + } + + iterator erase(iterator S, iterator E) { + assert(S >= this->begin() && "Range to erase is out of bounds."); + assert(S <= E && "Trying to erase invalid range."); + assert(E <= this->end() && "Trying to erase past the end."); + + iterator N = S; + // Shift all elts down. + iterator I = this->move(E, this->end(), S); + // Drop the last elts. + this->destroy_range(I, this->end()); + this->setEnd(I); + return(N); + } + + iterator insert(iterator I, T &&Elt) { + if (I == this->end()) { // Important special case for empty vector. + this->push_back(::std::move(Elt)); + return this->end()-1; + } + + assert(I >= this->begin() && "Insertion iterator is out of bounds."); + assert(I <= this->end() && "Inserting past the end of the vector."); + + if (this->EndX >= this->CapacityX) { + size_t EltNo = I-this->begin(); + this->grow(); + I = this->begin()+EltNo; + } + + ::new ((void*) this->end()) T(::std::move(this->back())); + // Push everything else over. + this->move_backward(I, this->end()-1, this->end()); + this->setEnd(this->end()+1); + + // If we just moved the element we're inserting, be sure to update + // the reference. + T *EltPtr = &Elt; + if (I <= EltPtr && EltPtr < this->EndX) + ++EltPtr; + + *I = ::std::move(*EltPtr); + return I; + } + + iterator insert(iterator I, const T &Elt) { + if (I == this->end()) { // Important special case for empty vector. + this->push_back(Elt); + return this->end()-1; + } + + assert(I >= this->begin() && "Insertion iterator is out of bounds."); + assert(I <= this->end() && "Inserting past the end of the vector."); + + if (this->EndX >= this->CapacityX) { + size_t EltNo = I-this->begin(); + this->grow(); + I = this->begin()+EltNo; + } + ::new ((void*) this->end()) T(std::move(this->back())); + // Push everything else over. + this->move_backward(I, this->end()-1, this->end()); + this->setEnd(this->end()+1); + + // If we just moved the element we're inserting, be sure to update + // the reference. + const T *EltPtr = &Elt; + if (I <= EltPtr && EltPtr < this->EndX) + ++EltPtr; + + *I = *EltPtr; + return I; + } + + iterator insert(iterator I, size_type NumToInsert, const T &Elt) { + // Convert iterator to elt# to avoid invalidating iterator when we reserve() + size_t InsertElt = I - this->begin(); + + if (I == this->end()) { // Important special case for empty vector. + append(NumToInsert, Elt); + return this->begin()+InsertElt; + } + + assert(I >= this->begin() && "Insertion iterator is out of bounds."); + assert(I <= this->end() && "Inserting past the end of the vector."); + + // Ensure there is enough space. + reserve(this->size() + NumToInsert); + + // Uninvalidate the iterator. + I = this->begin()+InsertElt; + + // If there are more elements between the insertion point and the end of the + // range than there are being inserted, we can use a simple approach to + // insertion. Since we already reserved space, we know that this won't + // reallocate the vector. + if (size_t(this->end()-I) >= NumToInsert) { + T *OldEnd = this->end(); + append(std::move_iterator(this->end() - NumToInsert), + std::move_iterator(this->end())); + + // Copy the existing elements that get replaced. + this->move_backward(I, OldEnd-NumToInsert, OldEnd); + + std::fill_n(I, NumToInsert, Elt); + return I; + } + + // Otherwise, we're inserting more elements than exist already, and we're + // not inserting at the end. + + // Move over the elements that we're about to overwrite. + T *OldEnd = this->end(); + this->setEnd(this->end() + NumToInsert); + size_t NumOverwritten = OldEnd-I; + this->uninitialized_move(I, OldEnd, this->end()-NumOverwritten); + + // Replace the overwritten part. + std::fill_n(I, NumOverwritten, Elt); + + // Insert the non-overwritten middle part. + std::uninitialized_fill_n(OldEnd, NumToInsert-NumOverwritten, Elt); + return I; + } + + template + iterator insert(iterator I, ItTy From, ItTy To) { + // Convert iterator to elt# to avoid invalidating iterator when we reserve() + size_t InsertElt = I - this->begin(); + + if (I == this->end()) { // Important special case for empty vector. + append(From, To); + return this->begin()+InsertElt; + } + + assert(I >= this->begin() && "Insertion iterator is out of bounds."); + assert(I <= this->end() && "Inserting past the end of the vector."); + + size_t NumToInsert = std::distance(From, To); + + // Ensure there is enough space. + reserve(this->size() + NumToInsert); + + // Uninvalidate the iterator. + I = this->begin()+InsertElt; + + // If there are more elements between the insertion point and the end of the + // range than there are being inserted, we can use a simple approach to + // insertion. Since we already reserved space, we know that this won't + // reallocate the vector. + if (size_t(this->end()-I) >= NumToInsert) { + T *OldEnd = this->end(); + append(std::move_iterator(this->end() - NumToInsert), + std::move_iterator(this->end())); + + // Copy the existing elements that get replaced. + this->move_backward(I, OldEnd-NumToInsert, OldEnd); + + std::copy(From, To, I); + return I; + } + + // Otherwise, we're inserting more elements than exist already, and we're + // not inserting at the end. + + // Move over the elements that we're about to overwrite. + T *OldEnd = this->end(); + this->setEnd(this->end() + NumToInsert); + size_t NumOverwritten = OldEnd-I; + this->uninitialized_move(I, OldEnd, this->end()-NumOverwritten); + + // Replace the overwritten part. + for (T *J = I; NumOverwritten > 0; --NumOverwritten) { + *J = *From; + ++J; ++From; + } + + // Insert the non-overwritten middle part. + this->uninitialized_copy(From, To, OldEnd); + return I; + } + + void insert(iterator I, std::initializer_list IL) { + insert(I, IL.begin(), IL.end()); + } + + template void emplace_back(ArgTypes &&... Args) { + if (LLVM_UNLIKELY(this->EndX >= this->CapacityX)) + this->grow(); + ::new ((void *)this->end()) T(std::forward(Args)...); + this->setEnd(this->end() + 1); + } + + SmallVectorImpl &operator=(const SmallVectorImpl &RHS); + + SmallVectorImpl &operator=(SmallVectorImpl &&RHS); + + bool operator==(const SmallVectorImpl &RHS) const { + if (this->size() != RHS.size()) return false; + return std::equal(this->begin(), this->end(), RHS.begin()); + } + bool operator!=(const SmallVectorImpl &RHS) const { + return !(*this == RHS); + } + + bool operator<(const SmallVectorImpl &RHS) const { + return std::lexicographical_compare(this->begin(), this->end(), + RHS.begin(), RHS.end()); + } + + /// Set the array size to \p N, which the current array must have enough + /// capacity for. + /// + /// This does not construct or destroy any elements in the vector. + /// + /// Clients can use this in conjunction with capacity() to write past the end + /// of the buffer when they know that more elements are available, and only + /// update the size later. This avoids the cost of value initializing elements + /// which will only be overwritten. + void set_size(size_type N) { + assert(N <= this->capacity()); + this->setEnd(this->begin() + N); + } +}; + + +template +void SmallVectorImpl::swap(SmallVectorImpl &RHS) { + if (this == &RHS) return; + + // We can only avoid copying elements if neither vector is small. + if (!this->isSmall() && !RHS.isSmall()) { + std::swap(this->BeginX, RHS.BeginX); + std::swap(this->EndX, RHS.EndX); + std::swap(this->CapacityX, RHS.CapacityX); + return; + } + if (RHS.size() > this->capacity()) + this->grow(RHS.size()); + if (this->size() > RHS.capacity()) + RHS.grow(this->size()); + + // Swap the shared elements. + size_t NumShared = this->size(); + if (NumShared > RHS.size()) NumShared = RHS.size(); + for (size_type i = 0; i != NumShared; ++i) + std::swap((*this)[i], RHS[i]); + + // Copy over the extra elts. + if (this->size() > RHS.size()) { + size_t EltDiff = this->size() - RHS.size(); + this->uninitialized_copy(this->begin()+NumShared, this->end(), RHS.end()); + RHS.setEnd(RHS.end()+EltDiff); + this->destroy_range(this->begin()+NumShared, this->end()); + this->setEnd(this->begin()+NumShared); + } else if (RHS.size() > this->size()) { + size_t EltDiff = RHS.size() - this->size(); + this->uninitialized_copy(RHS.begin()+NumShared, RHS.end(), this->end()); + this->setEnd(this->end() + EltDiff); + this->destroy_range(RHS.begin()+NumShared, RHS.end()); + RHS.setEnd(RHS.begin()+NumShared); + } +} + +template +SmallVectorImpl &SmallVectorImpl:: + operator=(const SmallVectorImpl &RHS) { + // Avoid self-assignment. + if (this == &RHS) return *this; + + // If we already have sufficient space, assign the common elements, then + // destroy any excess. + size_t RHSSize = RHS.size(); + size_t CurSize = this->size(); + if (CurSize >= RHSSize) { + // Assign common elements. + iterator NewEnd; + if (RHSSize) + NewEnd = std::copy(RHS.begin(), RHS.begin()+RHSSize, this->begin()); + else + NewEnd = this->begin(); + + // Destroy excess elements. + this->destroy_range(NewEnd, this->end()); + + // Trim. + this->setEnd(NewEnd); + return *this; + } + + // If we have to grow to have enough elements, destroy the current elements. + // This allows us to avoid copying them during the grow. + // FIXME: don't do this if they're efficiently moveable. + if (this->capacity() < RHSSize) { + // Destroy current elements. + this->destroy_range(this->begin(), this->end()); + this->setEnd(this->begin()); + CurSize = 0; + this->grow(RHSSize); + } else if (CurSize) { + // Otherwise, use assignment for the already-constructed elements. + std::copy(RHS.begin(), RHS.begin()+CurSize, this->begin()); + } + + // Copy construct the new elements in place. + this->uninitialized_copy(RHS.begin()+CurSize, RHS.end(), + this->begin()+CurSize); + + // Set end. + this->setEnd(this->begin()+RHSSize); + return *this; +} + +template +SmallVectorImpl &SmallVectorImpl::operator=(SmallVectorImpl &&RHS) { + // Avoid self-assignment. + if (this == &RHS) return *this; + + // If the RHS isn't small, clear this vector and then steal its buffer. + if (!RHS.isSmall()) { + this->destroy_range(this->begin(), this->end()); + if (!this->isSmall()) free(this->begin()); + this->BeginX = RHS.BeginX; + this->EndX = RHS.EndX; + this->CapacityX = RHS.CapacityX; + RHS.resetToSmall(); + return *this; + } + + // If we already have sufficient space, assign the common elements, then + // destroy any excess. + size_t RHSSize = RHS.size(); + size_t CurSize = this->size(); + if (CurSize >= RHSSize) { + // Assign common elements. + iterator NewEnd = this->begin(); + if (RHSSize) + NewEnd = this->move(RHS.begin(), RHS.end(), NewEnd); + + // Destroy excess elements and trim the bounds. + this->destroy_range(NewEnd, this->end()); + this->setEnd(NewEnd); + + // Clear the RHS. + RHS.clear(); + + return *this; + } + + // If we have to grow to have enough elements, destroy the current elements. + // This allows us to avoid copying them during the grow. + // FIXME: this may not actually make any sense if we can efficiently move + // elements. + if (this->capacity() < RHSSize) { + // Destroy current elements. + this->destroy_range(this->begin(), this->end()); + this->setEnd(this->begin()); + CurSize = 0; + this->grow(RHSSize); + } else if (CurSize) { + // Otherwise, use assignment for the already-constructed elements. + this->move(RHS.begin(), RHS.begin()+CurSize, this->begin()); + } + + // Move-construct the new elements in place. + this->uninitialized_move(RHS.begin()+CurSize, RHS.end(), + this->begin()+CurSize); + + // Set end. + this->setEnd(this->begin()+RHSSize); + + RHS.clear(); + return *this; +} + +/// Storage for the SmallVector elements which aren't contained in +/// SmallVectorTemplateCommon. There are 'N-1' elements here. The remaining '1' +/// element is in the base class. This is specialized for the N=1 and N=0 cases +/// to avoid allocating unnecessary storage. +template +struct SmallVectorStorage { + typename SmallVectorTemplateCommon::U InlineElts[N - 1]; +}; +template struct SmallVectorStorage {}; +template struct SmallVectorStorage {}; + +/// This is a 'vector' (really, a variable-sized array), optimized +/// for the case when the array is small. It contains some number of elements +/// in-place, which allows it to avoid heap allocation when the actual number of +/// elements is below that threshold. This allows normal "small" cases to be +/// fast without losing generality for large inputs. +/// +/// Note that this does not attempt to be exception safe. +/// +template +class SmallVector : public SmallVectorImpl { + /// Inline space for elements which aren't stored in the base class. + SmallVectorStorage Storage; +public: + SmallVector() : SmallVectorImpl(N) { + } + + explicit SmallVector(size_t Size, const T &Value = T()) + : SmallVectorImpl(N) { + this->assign(Size, Value); + } + + template + SmallVector(ItTy S, ItTy E) : SmallVectorImpl(N) { + this->append(S, E); + } + + template + explicit SmallVector(const llvm::iterator_range R) + : SmallVectorImpl(N) { + this->append(R.begin(), R.end()); + } + + SmallVector(std::initializer_list IL) : SmallVectorImpl(N) { + this->assign(IL); + } + + SmallVector(const SmallVector &RHS) : SmallVectorImpl(N) { + if (!RHS.empty()) + SmallVectorImpl::operator=(RHS); + } + + const SmallVector &operator=(const SmallVector &RHS) { + SmallVectorImpl::operator=(RHS); + return *this; + } + + SmallVector(SmallVector &&RHS) : SmallVectorImpl(N) { + if (!RHS.empty()) + SmallVectorImpl::operator=(::std::move(RHS)); + } + + const SmallVector &operator=(SmallVector &&RHS) { + SmallVectorImpl::operator=(::std::move(RHS)); + return *this; + } + + SmallVector(SmallVectorImpl &&RHS) : SmallVectorImpl(N) { + if (!RHS.empty()) + SmallVectorImpl::operator=(::std::move(RHS)); + } + + const SmallVector &operator=(SmallVectorImpl &&RHS) { + SmallVectorImpl::operator=(::std::move(RHS)); + return *this; + } + + const SmallVector &operator=(std::initializer_list IL) { + this->assign(IL); + return *this; + } +}; + +template +static inline size_t capacity_in_bytes(const SmallVector &X) { + return X.capacity_in_bytes(); +} + +} // namespace llvm + +namespace std { + /// Implement std::swap in terms of SmallVector swap. + template + inline void + swap(llvm::SmallVectorImpl &LHS, llvm::SmallVectorImpl &RHS) { + LHS.swap(RHS); + } + + /// Implement std::swap in terms of SmallVector swap. + template + inline void + swap(llvm::SmallVector &LHS, llvm::SmallVector &RHS) { + LHS.swap(RHS); + } +} // namespace std + +#endif diff --git a/include/llvm/StringExtras.h b/include/llvm/StringExtras.h new file mode 100644 index 0000000000..d5a8debe19 --- /dev/null +++ b/include/llvm/StringExtras.h @@ -0,0 +1,212 @@ +//===-- llvm/ADT/StringExtras.h - Useful string functions -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file contains some functions that are useful when dealing with strings. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_STRINGEXTRAS_H +#define LLVM_ADT_STRINGEXTRAS_H + +#include "llvm/StringRef.h" +#include +#include + +namespace llvm { +template class SmallVectorImpl; + +/// hexdigit - Return the hexadecimal character for the +/// given number \p X (which should be less than 16). +static inline char hexdigit(unsigned X, bool LowerCase = false) { + const char HexChar = LowerCase ? 'a' : 'A'; + return X < 10 ? '0' + X : HexChar + X - 10; +} + +/// Construct a string ref from a boolean. +static inline StringRef toStringRef(bool B) { + return StringRef(B ? "true" : "false"); +} + +/// Interpret the given character \p C as a hexadecimal digit and return its +/// value. +/// +/// If \p C is not a valid hex digit, -1U is returned. +static inline unsigned hexDigitValue(char C) { + if (C >= '0' && C <= '9') return C-'0'; + if (C >= 'a' && C <= 'f') return C-'a'+10U; + if (C >= 'A' && C <= 'F') return C-'A'+10U; + return -1U; +} + +/// utohex_buffer - Emit the specified number into the buffer specified by +/// BufferEnd, returning a pointer to the start of the string. This can be used +/// like this: (note that the buffer must be large enough to handle any number): +/// char Buffer[40]; +/// printf("0x%s", utohex_buffer(X, Buffer+40)); +/// +/// This should only be used with unsigned types. +/// +template +static inline char *utohex_buffer(IntTy X, char *BufferEnd, bool LowerCase = false) { + char *BufPtr = BufferEnd; + *--BufPtr = 0; // Null terminate buffer. + if (X == 0) { + *--BufPtr = '0'; // Handle special case. + return BufPtr; + } + + while (X) { + unsigned char Mod = static_cast(X) & 15; + *--BufPtr = hexdigit(Mod, LowerCase); + X >>= 4; + } + return BufPtr; +} + +static inline std::string utohexstr(uint64_t X, bool LowerCase = false) { + char Buffer[17]; + return utohex_buffer(X, Buffer+17, LowerCase); +} + +static inline std::string utostr_32(uint32_t X, bool isNeg = false) { + char Buffer[11]; + char *BufPtr = Buffer+11; + + if (X == 0) *--BufPtr = '0'; // Handle special case... + + while (X) { + *--BufPtr = '0' + char(X % 10); + X /= 10; + } + + if (isNeg) *--BufPtr = '-'; // Add negative sign... + + return std::string(BufPtr, Buffer+11); +} + +static inline std::string utostr(uint64_t X, bool isNeg = false) { + char Buffer[21]; + char *BufPtr = Buffer+21; + + if (X == 0) *--BufPtr = '0'; // Handle special case... + + while (X) { + *--BufPtr = '0' + char(X % 10); + X /= 10; + } + + if (isNeg) *--BufPtr = '-'; // Add negative sign... + return std::string(BufPtr, Buffer+21); +} + + +static inline std::string itostr(int64_t X) { + if (X < 0) + return utostr(static_cast(-X), true); + else + return utostr(static_cast(X)); +} + +/// StrInStrNoCase - Portable version of strcasestr. Locates the first +/// occurrence of string 's1' in string 's2', ignoring case. Returns +/// the offset of s2 in s1 or npos if s2 cannot be found. +StringRef::size_type StrInStrNoCase(StringRef s1, StringRef s2); + +/// getToken - This function extracts one token from source, ignoring any +/// leading characters that appear in the Delimiters string, and ending the +/// token at any of the characters that appear in the Delimiters string. If +/// there are no tokens in the source string, an empty string is returned. +/// The function returns a pair containing the extracted token and the +/// remaining tail string. +std::pair getToken(StringRef Source, + StringRef Delimiters = " \t\n\v\f\r"); + +/// SplitString - Split up the specified string according to the specified +/// delimiters, appending the result fragments to the output list. +void SplitString(StringRef Source, + SmallVectorImpl &OutFragments, + StringRef Delimiters = " \t\n\v\f\r"); + +/// HashString - Hash function for strings. +/// +/// This is the Bernstein hash function. +// +// FIXME: Investigate whether a modified bernstein hash function performs +// better: http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx +// X*33+c -> X*33^c +static inline unsigned HashString(StringRef Str, unsigned Result = 0) { + for (StringRef::size_type i = 0, e = Str.size(); i != e; ++i) + Result = Result * 33 + (unsigned char)Str[i]; + return Result; +} + +/// Returns the English suffix for an ordinal integer (-st, -nd, -rd, -th). +static inline StringRef getOrdinalSuffix(unsigned Val) { + // It is critically important that we do this perfectly for + // user-written sequences with over 100 elements. + switch (Val % 100) { + case 11: + case 12: + case 13: + return "th"; + default: + switch (Val % 10) { + case 1: return "st"; + case 2: return "nd"; + case 3: return "rd"; + default: return "th"; + } + } +} + +template +inline std::string join_impl(IteratorT Begin, IteratorT End, + StringRef Separator, std::input_iterator_tag) { + std::string S; + if (Begin == End) + return S; + + S += (*Begin); + while (++Begin != End) { + S += Separator; + S += (*Begin); + } + return S; +} + +template +inline std::string join_impl(IteratorT Begin, IteratorT End, + StringRef Separator, std::forward_iterator_tag) { + std::string S; + if (Begin == End) + return S; + + size_t Len = (std::distance(Begin, End) - 1) * Separator.size(); + for (IteratorT I = Begin; I != End; ++I) + Len += (*Begin).size(); + S.reserve(Len); + S += (*Begin); + while (++Begin != End) { + S += Separator; + S += (*Begin); + } + return S; +} + +/// Joins the strings in the range [Begin, End), adding Separator between +/// the elements. +template +inline std::string join(IteratorT Begin, IteratorT End, StringRef Separator) { + typedef typename std::iterator_traits::iterator_category tag; + return join_impl(Begin, End, Separator, tag()); +} + +} // namespace llvm + +#endif diff --git a/include/llvm/StringMap.h b/include/llvm/StringMap.h new file mode 100644 index 0000000000..3bac33f4b6 --- /dev/null +++ b/include/llvm/StringMap.h @@ -0,0 +1,417 @@ +//===--- StringMap.h - String Hash table map interface ----------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the StringMap class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_STRINGMAP_H +#define LLVM_ADT_STRINGMAP_H + +#include "llvm/StringRef.h" +#include +#include +#include + +namespace llvm { + template + class StringMapConstIterator; + template + class StringMapIterator; + template + class StringMapEntry; + +/// StringMapEntryBase - Shared base class of StringMapEntry instances. +class StringMapEntryBase { + unsigned StrLen; +public: + explicit StringMapEntryBase(unsigned Len) : StrLen(Len) {} + + unsigned getKeyLength() const { return StrLen; } +}; + +/// StringMapImpl - This is the base class of StringMap that is shared among +/// all of its instantiations. +class StringMapImpl { +protected: + // Array of NumBuckets pointers to entries, null pointers are holes. + // TheTable[NumBuckets] contains a sentinel value for easy iteration. Followed + // by an array of the actual hash values as unsigned integers. + StringMapEntryBase **TheTable; + unsigned NumBuckets; + unsigned NumItems; + unsigned NumTombstones; + unsigned ItemSize; +protected: + explicit StringMapImpl(unsigned itemSize) + : TheTable(nullptr), + // Initialize the map with zero buckets to allocation. + NumBuckets(0), NumItems(0), NumTombstones(0), ItemSize(itemSize) {} + StringMapImpl(StringMapImpl &&RHS) + : TheTable(RHS.TheTable), NumBuckets(RHS.NumBuckets), + NumItems(RHS.NumItems), NumTombstones(RHS.NumTombstones), + ItemSize(RHS.ItemSize) { + RHS.TheTable = nullptr; + RHS.NumBuckets = 0; + RHS.NumItems = 0; + RHS.NumTombstones = 0; + } + + StringMapImpl(unsigned InitSize, unsigned ItemSize); + unsigned RehashTable(unsigned BucketNo = 0); + + /// LookupBucketFor - Look up the bucket that the specified string should end + /// up in. If it already exists as a key in the map, the Item pointer for the + /// specified bucket will be non-null. Otherwise, it will be null. In either + /// case, the FullHashValue field of the bucket will be set to the hash value + /// of the string. + unsigned LookupBucketFor(StringRef Key); + + /// FindKey - Look up the bucket that contains the specified key. If it exists + /// in the map, return the bucket number of the key. Otherwise return -1. + /// This does not modify the map. + int FindKey(StringRef Key) const; + + /// RemoveKey - Remove the specified StringMapEntry from the table, but do not + /// delete it. This aborts if the value isn't in the table. + void RemoveKey(StringMapEntryBase *V); + + /// RemoveKey - Remove the StringMapEntry for the specified key from the + /// table, returning it. If the key is not in the table, this returns null. + StringMapEntryBase *RemoveKey(StringRef Key); +private: + void init(unsigned Size); +public: + static StringMapEntryBase *getTombstoneVal() { + return (StringMapEntryBase*)-1; + } + + unsigned getNumBuckets() const { return NumBuckets; } + unsigned getNumItems() const { return NumItems; } + + bool empty() const { return NumItems == 0; } + unsigned size() const { return NumItems; } + + void swap(StringMapImpl &Other) { + std::swap(TheTable, Other.TheTable); + std::swap(NumBuckets, Other.NumBuckets); + std::swap(NumItems, Other.NumItems); + std::swap(NumTombstones, Other.NumTombstones); + } +}; + +/// StringMapEntry - This is used to represent one value that is inserted into +/// a StringMap. It contains the Value itself and the key: the string length +/// and data. +template +class StringMapEntry : public StringMapEntryBase { + StringMapEntry(StringMapEntry &E) = delete; +public: + ValueTy second; + + explicit StringMapEntry(unsigned strLen) + : StringMapEntryBase(strLen), second() {} + template + StringMapEntry(unsigned strLen, InitTy &&V) + : StringMapEntryBase(strLen), second(std::forward(V)) {} + + StringRef getKey() const { + return StringRef(getKeyData(), getKeyLength()); + } + + const ValueTy &getValue() const { return second; } + ValueTy &getValue() { return second; } + + void setValue(const ValueTy &V) { second = V; } + + /// getKeyData - Return the start of the string data that is the key for this + /// value. The string data is always stored immediately after the + /// StringMapEntry object. + const char *getKeyData() const {return reinterpret_cast(this+1);} + + StringRef first() const { return StringRef(getKeyData(), getKeyLength()); } + + /// Create - Create a StringMapEntry for the specified key and default + /// construct the value. + template + static StringMapEntry *Create(StringRef Key, InitType &&InitVal) { + unsigned KeyLength = Key.size(); + + // Allocate a new item with space for the string at the end and a null + // terminator. + unsigned AllocSize = static_cast(sizeof(StringMapEntry))+ + KeyLength+1; + + StringMapEntry *NewItem = + static_cast(std::malloc(AllocSize)); + + // Default construct the value. + new (NewItem) StringMapEntry(KeyLength, std::forward(InitVal)); + + // Copy the string information. + char *StrBuffer = const_cast(NewItem->getKeyData()); + memcpy(StrBuffer, Key.data(), KeyLength); + StrBuffer[KeyLength] = 0; // Null terminate for convenience of clients. + return NewItem; + } + + static StringMapEntry *Create(StringRef Key) { + return Create(Key, ValueTy()); + } + + /// GetStringMapEntryFromKeyData - Given key data that is known to be embedded + /// into a StringMapEntry, return the StringMapEntry itself. + static StringMapEntry &GetStringMapEntryFromKeyData(const char *KeyData) { + char *Ptr = const_cast(KeyData) - sizeof(StringMapEntry); + return *reinterpret_cast(Ptr); + } + + /// Destroy - Destroy this StringMapEntry, releasing memory back to the + /// specified allocator. + void Destroy() { + // Free memory referenced by the item. + this->~StringMapEntry(); + std::free(static_cast(this)); + } +}; + + +/// StringMap - This is an unconventional map that is specialized for handling +/// keys that are "strings", which are basically ranges of bytes. This does some +/// funky memory allocation and hashing things to make it extremely efficient, +/// storing the string data *after* the value in the map. +template +class StringMap : public StringMapImpl { +public: + typedef StringMapEntry MapEntryTy; + + StringMap() : StringMapImpl(static_cast(sizeof(MapEntryTy))) {} + explicit StringMap(unsigned InitialSize) + : StringMapImpl(InitialSize, static_cast(sizeof(MapEntryTy))) {} + + StringMap(StringMap &&RHS) + : StringMapImpl(std::move(RHS)) {} + + StringMap &operator=(StringMap RHS) { + StringMapImpl::swap(RHS); + return *this; + } + + // FIXME: Implement copy operations if/when they're needed. + + typedef const char* key_type; + typedef ValueTy mapped_type; + typedef StringMapEntry value_type; + typedef size_t size_type; + + typedef StringMapConstIterator const_iterator; + typedef StringMapIterator iterator; + + iterator begin() { + return iterator(TheTable, NumBuckets == 0); + } + iterator end() { + return iterator(TheTable+NumBuckets, true); + } + const_iterator begin() const { + return const_iterator(TheTable, NumBuckets == 0); + } + const_iterator end() const { + return const_iterator(TheTable+NumBuckets, true); + } + + iterator find(StringRef Key) { + int Bucket = FindKey(Key); + if (Bucket == -1) return end(); + return iterator(TheTable+Bucket, true); + } + + const_iterator find(StringRef Key) const { + int Bucket = FindKey(Key); + if (Bucket == -1) return end(); + return const_iterator(TheTable+Bucket, true); + } + + /// lookup - Return the entry for the specified key, or a default + /// constructed value if no such entry exists. + ValueTy lookup(StringRef Key) const { + const_iterator it = find(Key); + if (it != end()) + return it->second; + return ValueTy(); + } + + ValueTy &operator[](StringRef Key) { + return insert(std::make_pair(Key, ValueTy())).first->second; + } + + /// count - Return 1 if the element is in the map, 0 otherwise. + size_type count(StringRef Key) const { + return find(Key) == end() ? 0 : 1; + } + + /// insert - Insert the specified key/value pair into the map. If the key + /// already exists in the map, return false and ignore the request, otherwise + /// insert it and return true. + bool insert(MapEntryTy *KeyValue) { + unsigned BucketNo = LookupBucketFor(KeyValue->getKey()); + StringMapEntryBase *&Bucket = TheTable[BucketNo]; + if (Bucket && Bucket != getTombstoneVal()) + return false; // Already exists in map. + + if (Bucket == getTombstoneVal()) + --NumTombstones; + Bucket = KeyValue; + ++NumItems; + assert(NumItems + NumTombstones <= NumBuckets); + + RehashTable(); + return true; + } + + /// insert - Inserts the specified key/value pair into the map if the key + /// isn't already in the map. The bool component of the returned pair is true + /// if and only if the insertion takes place, and the iterator component of + /// the pair points to the element with key equivalent to the key of the pair. + std::pair insert(std::pair KV) { + unsigned BucketNo = LookupBucketFor(KV.first); + StringMapEntryBase *&Bucket = TheTable[BucketNo]; + if (Bucket && Bucket != getTombstoneVal()) + return std::make_pair(iterator(TheTable + BucketNo, false), + false); // Already exists in map. + + if (Bucket == getTombstoneVal()) + --NumTombstones; + Bucket = + MapEntryTy::Create(KV.first, std::move(KV.second)); + ++NumItems; + assert(NumItems + NumTombstones <= NumBuckets); + + BucketNo = RehashTable(BucketNo); + return std::make_pair(iterator(TheTable + BucketNo, false), true); + } + + // clear - Empties out the StringMap + void clear() { + if (empty()) return; + + // Zap all values, resetting the keys back to non-present (not tombstone), + // which is safe because we're removing all elements. + for (unsigned I = 0, E = NumBuckets; I != E; ++I) { + StringMapEntryBase *&Bucket = TheTable[I]; + if (Bucket && Bucket != getTombstoneVal()) { + static_cast(Bucket)->Destroy(); + } + Bucket = nullptr; + } + + NumItems = 0; + NumTombstones = 0; + } + + /// remove - Remove the specified key/value pair from the map, but do not + /// erase it. This aborts if the key is not in the map. + void remove(MapEntryTy *KeyValue) { + RemoveKey(KeyValue); + } + + void erase(iterator I) { + MapEntryTy &V = *I; + remove(&V); + V.Destroy(); + } + + bool erase(StringRef Key) { + iterator I = find(Key); + if (I == end()) return false; + erase(I); + return true; + } + + ~StringMap() { + // Delete all the elements in the map, but don't reset the elements + // to default values. This is a copy of clear(), but avoids unnecessary + // work not required in the destructor. + if (!empty()) { + for (unsigned I = 0, E = NumBuckets; I != E; ++I) { + StringMapEntryBase *Bucket = TheTable[I]; + if (Bucket && Bucket != getTombstoneVal()) { + static_cast(Bucket)->Destroy(); + } + } + } + free(TheTable); + } +}; + + +template +class StringMapConstIterator { +protected: + StringMapEntryBase **Ptr; +public: + typedef StringMapEntry value_type; + + StringMapConstIterator() : Ptr(nullptr) { } + + explicit StringMapConstIterator(StringMapEntryBase **Bucket, + bool NoAdvance = false) + : Ptr(Bucket) { + if (!NoAdvance) AdvancePastEmptyBuckets(); + } + + const value_type &operator*() const { + return *static_cast*>(*Ptr); + } + const value_type *operator->() const { + return static_cast*>(*Ptr); + } + + bool operator==(const StringMapConstIterator &RHS) const { + return Ptr == RHS.Ptr; + } + bool operator!=(const StringMapConstIterator &RHS) const { + return Ptr != RHS.Ptr; + } + + inline StringMapConstIterator& operator++() { // Preincrement + ++Ptr; + AdvancePastEmptyBuckets(); + return *this; + } + StringMapConstIterator operator++(int) { // Postincrement + StringMapConstIterator tmp = *this; ++*this; return tmp; + } + +private: + void AdvancePastEmptyBuckets() { + while (*Ptr == nullptr || *Ptr == StringMapImpl::getTombstoneVal()) + ++Ptr; + } +}; + +template +class StringMapIterator : public StringMapConstIterator { +public: + StringMapIterator() {} + explicit StringMapIterator(StringMapEntryBase **Bucket, + bool NoAdvance = false) + : StringMapConstIterator(Bucket, NoAdvance) { + } + StringMapEntry &operator*() const { + return *static_cast*>(*this->Ptr); + } + StringMapEntry *operator->() const { + return static_cast*>(*this->Ptr); + } +}; + +} // namespace llvm + +#endif diff --git a/include/llvm/StringRef.h b/include/llvm/StringRef.h new file mode 100644 index 0000000000..1ffe29fe60 --- /dev/null +++ b/include/llvm/StringRef.h @@ -0,0 +1,539 @@ +//===--- StringRef.h - Constant String Reference Wrapper --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_STRINGREF_H +#define LLVM_ADT_STRINGREF_H + +#include +#include +#include +#include +#include +#include +#include + +namespace llvm { + template + class SmallVectorImpl; + class StringRef; + + /// Helper functions for StringRef::getAsInteger. + bool getAsUnsignedInteger(StringRef Str, unsigned Radix, + unsigned long long &Result); + + bool getAsSignedInteger(StringRef Str, unsigned Radix, long long &Result); + + /// StringRef - Represent a constant reference to a string, i.e. a character + /// array and a length, which need not be null terminated. + /// + /// This class does not own the string data, it is expected to be used in + /// situations where the character data resides in some other buffer, whose + /// lifetime extends past that of the StringRef. For this reason, it is not in + /// general safe to store a StringRef. + class StringRef { + public: + typedef const char *iterator; + typedef const char *const_iterator; + static const size_t npos = ~size_t(0); + typedef size_t size_type; + + private: + /// The start of the string, in an external buffer. + const char *Data; + + /// The length of the string. + size_t Length; + + // Workaround memcmp issue with null pointers (undefined behavior) + // by providing a specialized version + static int compareMemory(const char *Lhs, const char *Rhs, size_t Length) { + if (Length == 0) { return 0; } + return ::memcmp(Lhs,Rhs,Length); + } + + public: + /// @name Constructors + /// @{ + + /// Construct an empty string ref. + /*implicit*/ StringRef() : Data(nullptr), Length(0) {} + + /// Construct a string ref from a cstring. + /*implicit*/ StringRef(const char *Str) + : Data(Str) { + assert(Str && "StringRef cannot be built from a NULL argument"); + Length = ::strlen(Str); // invoking strlen(NULL) is undefined behavior + } + + /// Construct a string ref from a pointer and length. + /*implicit*/ StringRef(const char *data, size_t length) + : Data(data), Length(length) { + assert((data || length == 0) && + "StringRef cannot be built from a NULL argument with non-null length"); + } + + /// Construct a string ref from an std::string. + /*implicit*/ StringRef(const std::string &Str) + : Data(Str.data()), Length(Str.length()) {} + + /// @} + /// @name Iterators + /// @{ + + iterator begin() const { return Data; } + + iterator end() const { return Data + Length; } + + const unsigned char *bytes_begin() const { + return reinterpret_cast(begin()); + } + const unsigned char *bytes_end() const { + return reinterpret_cast(end()); + } + + /// @} + /// @name String Operations + /// @{ + + /// data - Get a pointer to the start of the string (which may not be null + /// terminated). + const char *data() const { return Data; } + + /// empty - Check if the string is empty. + bool empty() const { return Length == 0; } + + /// size - Get the string size. + size_t size() const { return Length; } + + /// front - Get the first character in the string. + char front() const { + assert(!empty()); + return Data[0]; + } + + /// back - Get the last character in the string. + char back() const { + assert(!empty()); + return Data[Length-1]; + } + + // copy - Allocate copy in Allocator and return StringRef to it. + template StringRef copy(Allocator &A) const { + char *S = A.template Allocate(Length); + std::copy(begin(), end(), S); + return StringRef(S, Length); + } + + /// equals - Check for string equality, this is more efficient than + /// compare() when the relative ordering of inequal strings isn't needed. + bool equals(StringRef RHS) const { + return (Length == RHS.Length && + compareMemory(Data, RHS.Data, RHS.Length) == 0); + } + + /// equals_lower - Check for string equality, ignoring case. + bool equals_lower(StringRef RHS) const { + return Length == RHS.Length && compare_lower(RHS) == 0; + } + + /// compare - Compare two strings; the result is -1, 0, or 1 if this string + /// is lexicographically less than, equal to, or greater than the \p RHS. + int compare(StringRef RHS) const { + // Check the prefix for a mismatch. + if (int Res = compareMemory(Data, RHS.Data, std::min(Length, RHS.Length))) + return Res < 0 ? -1 : 1; + + // Otherwise the prefixes match, so we only need to check the lengths. + if (Length == RHS.Length) + return 0; + return Length < RHS.Length ? -1 : 1; + } + + /// compare_lower - Compare two strings, ignoring case. + int compare_lower(StringRef RHS) const; + + /// compare_numeric - Compare two strings, treating sequences of digits as + /// numbers. + int compare_numeric(StringRef RHS) const; + + /// str - Get the contents as an std::string. + std::string str() const { + if (!Data) return std::string(); + return std::string(Data, Length); + } + + /// @} + /// @name Operator Overloads + /// @{ + + char operator[](size_t Index) const { + assert(Index < Length && "Invalid index!"); + return Data[Index]; + } + + /// @} + /// @name Type Conversions + /// @{ + + operator std::string() const { + return str(); + } + + /// @} + /// @name String Predicates + /// @{ + + /// Check if this string starts with the given \p Prefix. + bool startswith(StringRef Prefix) const { + return Length >= Prefix.Length && + compareMemory(Data, Prefix.Data, Prefix.Length) == 0; + } + + /// Check if this string starts with the given \p Prefix, ignoring case. + bool startswith_lower(StringRef Prefix) const; + + /// Check if this string ends with the given \p Suffix. + bool endswith(StringRef Suffix) const { + return Length >= Suffix.Length && + compareMemory(end() - Suffix.Length, Suffix.Data, Suffix.Length) == 0; + } + + /// Check if this string ends with the given \p Suffix, ignoring case. + bool endswith_lower(StringRef Suffix) const; + + /// @} + /// @name String Searching + /// @{ + + /// Search for the first character \p C in the string. + /// + /// \returns The index of the first occurrence of \p C, or npos if not + /// found. + size_t find(char C, size_t From = 0) const { + size_t FindBegin = std::min(From, Length); + if (FindBegin < Length) { // Avoid calling memchr with nullptr. + // Just forward to memchr, which is faster than a hand-rolled loop. + if (const void *P = ::memchr(Data + FindBegin, C, Length - FindBegin)) + return static_cast(P) - Data; + } + return npos; + } + + /// Search for the first string \p Str in the string. + /// + /// \returns The index of the first occurrence of \p Str, or npos if not + /// found. + size_t find(StringRef Str, size_t From = 0) const; + + /// Search for the last character \p C in the string. + /// + /// \returns The index of the last occurrence of \p C, or npos if not + /// found. + size_t rfind(char C, size_t From = npos) const { + From = std::min(From, Length); + size_t i = From; + while (i != 0) { + --i; + if (Data[i] == C) + return i; + } + return npos; + } + + /// Search for the last string \p Str in the string. + /// + /// \returns The index of the last occurrence of \p Str, or npos if not + /// found. + size_t rfind(StringRef Str) const; + + /// Find the first character in the string that is \p C, or npos if not + /// found. Same as find. + size_t find_first_of(char C, size_t From = 0) const { + return find(C, From); + } + + /// Find the first character in the string that is in \p Chars, or npos if + /// not found. + /// + /// Complexity: O(size() + Chars.size()) + size_t find_first_of(StringRef Chars, size_t From = 0) const; + + /// Find the first character in the string that is not \p C or npos if not + /// found. + size_t find_first_not_of(char C, size_t From = 0) const; + + /// Find the first character in the string that is not in the string + /// \p Chars, or npos if not found. + /// + /// Complexity: O(size() + Chars.size()) + size_t find_first_not_of(StringRef Chars, size_t From = 0) const; + + /// Find the last character in the string that is \p C, or npos if not + /// found. + size_t find_last_of(char C, size_t From = npos) const { + return rfind(C, From); + } + + /// Find the last character in the string that is in \p C, or npos if not + /// found. + /// + /// Complexity: O(size() + Chars.size()) + size_t find_last_of(StringRef Chars, size_t From = npos) const; + + /// Find the last character in the string that is not \p C, or npos if not + /// found. + size_t find_last_not_of(char C, size_t From = npos) const; + + /// Find the last character in the string that is not in \p Chars, or + /// npos if not found. + /// + /// Complexity: O(size() + Chars.size()) + size_t find_last_not_of(StringRef Chars, size_t From = npos) const; + + /// @} + /// @name Helpful Algorithms + /// @{ + + /// Return the number of occurrences of \p C in the string. + size_t count(char C) const { + size_t Count = 0; + for (size_t i = 0, e = Length; i != e; ++i) + if (Data[i] == C) + ++Count; + return Count; + } + + /// Return the number of non-overlapped occurrences of \p Str in + /// the string. + size_t count(StringRef Str) const; + + /// Parse the current string as an integer of the specified radix. If + /// \p Radix is specified as zero, this does radix autosensing using + /// extended C rules: 0 is octal, 0x is hex, 0b is binary. + /// + /// If the string is invalid or if only a subset of the string is valid, + /// this returns true to signify the error. The string is considered + /// erroneous if empty or if it overflows T. + template + typename std::enable_if::is_signed, bool>::type + getAsInteger(unsigned Radix, T &Result) const { + long long LLVal; + if (getAsSignedInteger(*this, Radix, LLVal) || + static_cast(LLVal) != LLVal) + return true; + Result = LLVal; + return false; + } + + template + typename std::enable_if::is_signed, bool>::type + getAsInteger(unsigned Radix, T &Result) const { + unsigned long long ULLVal; + // The additional cast to unsigned long long is required to avoid the + // Visual C++ warning C4805: '!=' : unsafe mix of type 'bool' and type + // 'unsigned __int64' when instantiating getAsInteger with T = bool. + if (getAsUnsignedInteger(*this, Radix, ULLVal) || + static_cast(static_cast(ULLVal)) != ULLVal) + return true; + Result = ULLVal; + return false; + } + + /// @} + /// @name String Operations + /// @{ + + // Convert the given ASCII string to lowercase. + std::string lower() const; + + /// Convert the given ASCII string to uppercase. + std::string upper() const; + + /// @} + /// @name Substring Operations + /// @{ + + /// Return a reference to the substring from [Start, Start + N). + /// + /// \param Start The index of the starting character in the substring; if + /// the index is npos or greater than the length of the string then the + /// empty substring will be returned. + /// + /// \param N The number of characters to included in the substring. If N + /// exceeds the number of characters remaining in the string, the string + /// suffix (starting with \p Start) will be returned. + StringRef substr(size_t Start, size_t N = npos) const { + Start = std::min(Start, Length); + return StringRef(Data + Start, std::min(N, Length - Start)); + } + + /// Return a StringRef equal to 'this' but with the first \p N elements + /// dropped. + StringRef drop_front(size_t N = 1) const { + assert(size() >= N && "Dropping more elements than exist"); + return substr(N); + } + + /// Return a StringRef equal to 'this' but with the last \p N elements + /// dropped. + StringRef drop_back(size_t N = 1) const { + assert(size() >= N && "Dropping more elements than exist"); + return substr(0, size()-N); + } + + /// Return a reference to the substring from [Start, End). + /// + /// \param Start The index of the starting character in the substring; if + /// the index is npos or greater than the length of the string then the + /// empty substring will be returned. + /// + /// \param End The index following the last character to include in the + /// substring. If this is npos, or less than \p Start, or exceeds the + /// number of characters remaining in the string, the string suffix + /// (starting with \p Start) will be returned. + StringRef slice(size_t Start, size_t End) const { + Start = std::min(Start, Length); + End = std::min(std::max(Start, End), Length); + return StringRef(Data + Start, End - Start); + } + + /// Split into two substrings around the first occurrence of a separator + /// character. + /// + /// If \p Separator is in the string, then the result is a pair (LHS, RHS) + /// such that (*this == LHS + Separator + RHS) is true and RHS is + /// maximal. If \p Separator is not in the string, then the result is a + /// pair (LHS, RHS) where (*this == LHS) and (RHS == ""). + /// + /// \param Separator The character to split on. + /// \returns The split substrings. + std::pair split(char Separator) const { + size_t Idx = find(Separator); + if (Idx == npos) + return std::make_pair(*this, StringRef()); + return std::make_pair(slice(0, Idx), slice(Idx+1, npos)); + } + + /// Split into two substrings around the first occurrence of a separator + /// string. + /// + /// If \p Separator is in the string, then the result is a pair (LHS, RHS) + /// such that (*this == LHS + Separator + RHS) is true and RHS is + /// maximal. If \p Separator is not in the string, then the result is a + /// pair (LHS, RHS) where (*this == LHS) and (RHS == ""). + /// + /// \param Separator - The string to split on. + /// \return - The split substrings. + std::pair split(StringRef Separator) const { + size_t Idx = find(Separator); + if (Idx == npos) + return std::make_pair(*this, StringRef()); + return std::make_pair(slice(0, Idx), slice(Idx + Separator.size(), npos)); + } + + /// Split into substrings around the occurrences of a separator string. + /// + /// Each substring is stored in \p A. If \p MaxSplit is >= 0, at most + /// \p MaxSplit splits are done and consequently <= \p MaxSplit + /// elements are added to A. + /// If \p KeepEmpty is false, empty strings are not added to \p A. They + /// still count when considering \p MaxSplit + /// An useful invariant is that + /// Separator.join(A) == *this if MaxSplit == -1 and KeepEmpty == true + /// + /// \param A - Where to put the substrings. + /// \param Separator - The string to split on. + /// \param MaxSplit - The maximum number of times the string is split. + /// \param KeepEmpty - True if empty substring should be added. + void split(SmallVectorImpl &A, + StringRef Separator, int MaxSplit = -1, + bool KeepEmpty = true) const; + + /// Split into two substrings around the last occurrence of a separator + /// character. + /// + /// If \p Separator is in the string, then the result is a pair (LHS, RHS) + /// such that (*this == LHS + Separator + RHS) is true and RHS is + /// minimal. If \p Separator is not in the string, then the result is a + /// pair (LHS, RHS) where (*this == LHS) and (RHS == ""). + /// + /// \param Separator - The character to split on. + /// \return - The split substrings. + std::pair rsplit(char Separator) const { + size_t Idx = rfind(Separator); + if (Idx == npos) + return std::make_pair(*this, StringRef()); + return std::make_pair(slice(0, Idx), slice(Idx+1, npos)); + } + + /// Return string with consecutive characters in \p Chars starting from + /// the left removed. + StringRef ltrim(StringRef Chars = " \t\n\v\f\r") const { + return drop_front(std::min(Length, find_first_not_of(Chars))); + } + + /// Return string with consecutive characters in \p Chars starting from + /// the right removed. + StringRef rtrim(StringRef Chars = " \t\n\v\f\r") const { + return drop_back(Length - std::min(Length, find_last_not_of(Chars) + 1)); + } + + /// Return string with consecutive characters in \p Chars starting from + /// the left and right removed. + StringRef trim(StringRef Chars = " \t\n\v\f\r") const { + return ltrim(Chars).rtrim(Chars); + } + + /// @} + }; + + /// @name StringRef Comparison Operators + /// @{ + + inline bool operator==(StringRef LHS, StringRef RHS) { + return LHS.equals(RHS); + } + + inline bool operator!=(StringRef LHS, StringRef RHS) { + return !(LHS == RHS); + } + + inline bool operator<(StringRef LHS, StringRef RHS) { + return LHS.compare(RHS) == -1; + } + + inline bool operator<=(StringRef LHS, StringRef RHS) { + return LHS.compare(RHS) != 1; + } + + inline bool operator>(StringRef LHS, StringRef RHS) { + return LHS.compare(RHS) == 1; + } + + inline bool operator>=(StringRef LHS, StringRef RHS) { + return LHS.compare(RHS) != -1; + } + + inline std::string &operator+=(std::string &buffer, StringRef string) { + return buffer.append(string.data(), string.size()); + } + + inline std::ostream &operator<<(std::ostream &os, StringRef string) { + os.write(string.data(), string.size()); + return os; + } + + /// @} + + // StringRefs can be treated like a POD type. + template struct isPodLike; + template <> struct isPodLike { static const bool value = true; }; +} // namespace llvm + +#endif diff --git a/include/llvm/iterator_range.h b/include/llvm/iterator_range.h new file mode 100644 index 0000000000..009b7161aa --- /dev/null +++ b/include/llvm/iterator_range.h @@ -0,0 +1,56 @@ +//===- iterator_range.h - A range adaptor for iterators ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// \file +/// This provides a very simple, boring adaptor for a begin and end iterator +/// into a range type. This should be used to build range views that work well +/// with range based for loops and range based constructors. +/// +/// Note that code here follows more standards-based coding conventions as it +/// is mirroring proposed interfaces for standardization. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_ADT_ITERATOR_RANGE_H +#define LLVM_ADT_ITERATOR_RANGE_H + +#include + +namespace llvm { + +/// \brief A range adaptor for a pair of iterators. +/// +/// This just wraps two iterators into a range-compatible interface. Nothing +/// fancy at all. +template +class iterator_range { + IteratorT begin_iterator, end_iterator; + +public: + iterator_range(IteratorT begin_iterator, IteratorT end_iterator) + : begin_iterator(std::move(begin_iterator)), + end_iterator(std::move(end_iterator)) {} + + IteratorT begin() const { return begin_iterator; } + IteratorT end() const { return end_iterator; } +}; + +/// \brief Convenience function for iterating over sub-ranges. +/// +/// This provides a bit of syntactic sugar to make using sub-ranges +/// in for loops a bit easier. Analogous to std::make_pair(). +template iterator_range make_range(T x, T y) { + return iterator_range(std::move(x), std::move(y)); +} + +template iterator_range make_range(std::pair p) { + return iterator_range(std::move(p.first), std::move(p.second)); +} +} // namespace llvm + +#endif diff --git a/include/llvm/type_traits.h b/include/llvm/type_traits.h new file mode 100644 index 0000000000..6e2e202b0f --- /dev/null +++ b/include/llvm/type_traits.h @@ -0,0 +1,100 @@ +//===- llvm/Support/type_traits.h - Simplfied type traits -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file provides useful additions to the standard type_traits library. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_SUPPORT_TYPE_TRAITS_H +#define LLVM_SUPPORT_TYPE_TRAITS_H + +#include +#include + +#ifndef __has_feature +#define LLVM_DEFINED_HAS_FEATURE +#define __has_feature(x) 0 +#endif + +namespace llvm { + +/// isPodLike - This is a type trait that is used to determine whether a given +/// type can be copied around with memcpy instead of running ctors etc. +template +struct isPodLike { + // std::is_trivially_copyable is available in libc++ with clang, libstdc++ + // that comes with GCC 5. +#if (__has_feature(is_trivially_copyable) && defined(_LIBCPP_VERSION)) || \ + (defined(__GNUC__) && __GNUC__ >= 5) + // If the compiler supports the is_trivially_copyable trait use it, as it + // matches the definition of isPodLike closely. + static const bool value = std::is_trivially_copyable::value; +#elif __has_feature(is_trivially_copyable) + // Use the internal name if the compiler supports is_trivially_copyable but we + // don't know if the standard library does. This is the case for clang in + // conjunction with libstdc++ from GCC 4.x. + static const bool value = __is_trivially_copyable(T); +#else + // If we don't know anything else, we can (at least) assume that all non-class + // types are PODs. + static const bool value = !std::is_class::value; +#endif +}; + +// std::pair's are pod-like if their elements are. +template +struct isPodLike > { + static const bool value = isPodLike::value && isPodLike::value; +}; + +/// \brief Metafunction that determines whether the given type is either an +/// integral type or an enumeration type. +/// +/// Note that this accepts potentially more integral types than is_integral +/// because it is based on merely being convertible implicitly to an integral +/// type. +template class is_integral_or_enum { + typedef typename std::remove_reference::type UnderlyingT; + +public: + static const bool value = + !std::is_class::value && // Filter conversion operators. + !std::is_pointer::value && + !std::is_floating_point::value && + std::is_convertible::value; +}; + +/// \brief If T is a pointer, just return it. If it is not, return T&. +template +struct add_lvalue_reference_if_not_pointer { typedef T &type; }; + +template +struct add_lvalue_reference_if_not_pointer< + T, typename std::enable_if::value>::type> { + typedef T type; +}; + +/// \brief If T is a pointer to X, return a pointer to const X. If it is not, +/// return const T. +template +struct add_const_past_pointer { typedef const T type; }; + +template +struct add_const_past_pointer< + T, typename std::enable_if::value>::type> { + typedef const typename std::remove_pointer::type *type; +}; + +} // namespace llvm + +#ifdef LLVM_DEFINED_HAS_FEATURE +#undef __has_feature +#endif + +#endif diff --git a/include/support/Base64.h b/include/support/Base64.h new file mode 100644 index 0000000000..40cb2528f0 --- /dev/null +++ b/include/support/Base64.h @@ -0,0 +1,23 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#ifndef WPIUTIL_SUPPORT_BASE64_H_ +#define WPIUTIL_SUPPORT_BASE64_H_ + +#include +#include + +#include "llvm/StringRef.h" + +namespace wpi { + +std::size_t Base64Decode(llvm::StringRef encoded, std::string* plain); +void Base64Encode(llvm::StringRef plain, std::string* encoded); + +} // namespace wpi + +#endif // WPIUTIL_SUPPORT_BASE64_H_ diff --git a/include/support/ConcurrentQueue.h b/include/support/ConcurrentQueue.h new file mode 100644 index 0000000000..abe9580f7f --- /dev/null +++ b/include/support/ConcurrentQueue.h @@ -0,0 +1,83 @@ +// +// Copyright (c) 2013 Juan Palacios juan.palacios.puyana@gmail.com +// Subject to the BSD 2-Clause License +// - see < http://opensource.org/licenses/BSD-2-Clause> +// + +#ifndef WPIUTIL_SUPPORT_CONCURRENT_QUEUE_H_ +#define WPIUTIL_SUPPORT_CONCURRENT_QUEUE_H_ + +#include +#include +#include +#include + +namespace wpi { + +template +class ConcurrentQueue { + public: + bool empty() const { + std::unique_lock mlock(mutex_); + return queue_.empty(); + } + + typename std::queue::size_type size() const { + std::unique_lock mlock(mutex_); + return queue_.size(); + } + + T pop() { + std::unique_lock mlock(mutex_); + while (queue_.empty()) { + cond_.wait(mlock); + } + auto item = std::move(queue_.front()); + queue_.pop(); + return item; + } + + void pop(T& item) { + std::unique_lock mlock(mutex_); + while (queue_.empty()) { + cond_.wait(mlock); + } + item = queue_.front(); + queue_.pop(); + } + + void push(const T& item) { + std::unique_lock mlock(mutex_); + queue_.push(item); + mlock.unlock(); + cond_.notify_one(); + } + + void push(T&& item) { + std::unique_lock mlock(mutex_); + queue_.push(std::forward(item)); + mlock.unlock(); + cond_.notify_one(); + } + + template + void emplace(Args&&... args) { + std::unique_lock mlock(mutex_); + queue_.emplace(std::forward(args)...); + mlock.unlock(); + cond_.notify_one(); + } + + ConcurrentQueue() = default; + ConcurrentQueue(const ConcurrentQueue&) = delete; + ConcurrentQueue& operator=(const ConcurrentQueue&) = delete; + + private: + std::queue queue_; + mutable std::mutex mutex_; + std::condition_variable cond_; +}; + +} // namespace wpi + +#endif // WPIUTIL_SUPPORT_CONCURRENT_QUEUE_H_ diff --git a/include/support/Logger.h b/include/support/Logger.h new file mode 100644 index 0000000000..44436c70b3 --- /dev/null +++ b/include/support/Logger.h @@ -0,0 +1,82 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#ifndef WPIUTIL_SUPPORT_LOGGER_H_ +#define WPIUTIL_SUPPORT_LOGGER_H_ + +#include +#include +#include + +namespace wpi { + +enum LogLevel { + WPI_LOG_CRITICAL = 50, + WPI_LOG_ERROR = 40, + WPI_LOG_WARNING = 30, + WPI_LOG_INFO = 20, + WPI_LOG_DEBUG = 10, + WPI_LOG_DEBUG1 = 9, + WPI_LOG_DEBUG2 = 8, + WPI_LOG_DEBUG3 = 7, + WPI_LOG_DEBUG4 = 6 +}; + +class Logger { + public: + typedef std::function LogFunc; + + void SetLogger(LogFunc func) { m_func = func; } + + void set_min_level(unsigned int level) { m_min_level = level; } + unsigned int min_level() const { return m_min_level; } + + void Log(unsigned int level, const char* file, unsigned int line, + const char* msg) { + if (!m_func || level < m_min_level) return; + m_func(level, file, line, msg); + } + + bool HasLogger() const { return m_func != nullptr; } + + private: + LogFunc m_func; + unsigned int m_min_level = 20; +}; + +#define WPI_LOG(logger_inst, level, x) \ + do { \ + ::wpi::Logger& WPI_logger_ = logger_inst; \ + if (WPI_logger_.min_level() <= level && WPI_logger_.HasLogger()) { \ + std::ostringstream oss; \ + oss << x; \ + WPI_logger_.Log(level, __FILE__, __LINE__, oss.str().c_str()); \ + } \ + } while (0) + +#define WPI_ERROR(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_ERROR, x) +#define WPI_WARNING(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_WARNING, x) +#define WPI_INFO(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_INFO, x) + +#ifdef NDEBUG +#define WPI_DEBUG(inst, x) do {} while (0) +#define WPI_DEBUG1(inst, x) do {} while (0) +#define WPI_DEBUG2(inst, x) do {} while (0) +#define WPI_DEBUG3(inst, x) do {} while (0) +#define WPI_DEBUG4(inst, x) do {} while (0) +#else +#define WPI_DEBUG(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG, x) +#define WPI_DEBUG1(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG1, x) +#define WPI_DEBUG2(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG2, x) +#define WPI_DEBUG3(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG3, x) +#define WPI_DEBUG4(inst, x) WPI_LOG(inst, ::wpi::WPI_LOG_DEBUG4, x) +#endif + +} // namespace wpi + +#endif // WPIUTIL_SUPPORT_LOGGER_H_ diff --git a/include/support/SafeThread.h b/include/support/SafeThread.h new file mode 100644 index 0000000000..2edbe7ae3c --- /dev/null +++ b/include/support/SafeThread.h @@ -0,0 +1,93 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#ifndef WPIUTIL_SUPPORT_SAFETHREAD_H_ +#define WPIUTIL_SUPPORT_SAFETHREAD_H_ + +#include +#include +#include +#include + +namespace wpi { + +// Base class for SafeThreadOwner threads. +class SafeThread { + public: + virtual ~SafeThread() = default; + virtual void Main() = 0; + + std::mutex m_mutex; + bool m_active = true; + std::condition_variable m_cond; +}; + +namespace detail { + +// Non-template proxy base class for common proxy code. +class SafeThreadProxyBase { + public: + SafeThreadProxyBase(SafeThread* thr) : m_thread(thr) { + if (!m_thread) return; + std::unique_lock(m_thread->m_mutex).swap(m_lock); + if (!m_thread->m_active) { + m_lock.unlock(); + m_thread = nullptr; + return; + } + } + explicit operator bool() const { return m_thread != nullptr; } + std::unique_lock& GetLock() { return m_lock; } + + protected: + SafeThread* m_thread; + std::unique_lock m_lock; +}; + +// A proxy for SafeThread. +// Also serves as a scoped lock on SafeThread::m_mutex. +template +class SafeThreadProxy : public SafeThreadProxyBase { + public: + SafeThreadProxy(SafeThread* thr) : SafeThreadProxyBase(thr) {} + T& operator*() const { return *static_cast(m_thread); } + T* operator->() const { return static_cast(m_thread); } +}; + +// Non-template owner base class for common owner code. +class SafeThreadOwnerBase { + public: + void Stop(); + + protected: + SafeThreadOwnerBase() { m_thread = nullptr; } + SafeThreadOwnerBase(const SafeThreadOwnerBase&) = delete; + SafeThreadOwnerBase& operator=(const SafeThreadOwnerBase&) = delete; + ~SafeThreadOwnerBase() { Stop(); } + + void Start(SafeThread* thr); + SafeThread* GetThread() { return m_thread.load(); } + + private: + std::atomic m_thread; +}; + +} // namespace detail + +template +class SafeThreadOwner : public detail::SafeThreadOwnerBase { + public: + void Start() { Start(new T); } + void Start(T* thr) { detail::SafeThreadOwnerBase::Start(thr); } + + using Proxy = typename detail::SafeThreadProxy; + Proxy GetThread() { return Proxy(detail::SafeThreadOwnerBase::GetThread()); } +}; + +} // namespace wpi + +#endif // WPIUTIL_SUPPORT_SAFETHREAD_H_ diff --git a/include/support/atomic_static.h b/include/support/atomic_static.h new file mode 100644 index 0000000000..146a1de478 --- /dev/null +++ b/include/support/atomic_static.h @@ -0,0 +1,49 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#ifndef WPIUTIL_SUPPORT_ATOMIC_STATIC_H_ +#define WPIUTIL_SUPPORT_ATOMIC_STATIC_H_ + +#if !defined(_MSC_VER) || (_MSC_VER >= 1900) + +// Just use a local static. This is thread-safe per +// http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/ + +// Per https://msdn.microsoft.com/en-us/library/Hh567368.aspx "Magic Statics" +// are supported in Visual Studio 2015 but not in earlier versions. +#define ATOMIC_STATIC(cls, inst) static cls inst +#define ATOMIC_STATIC_DECL(cls) +#define ATOMIC_STATIC_INIT(cls) + +#else +// From http://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/ +#include +#include + +#define ATOMIC_STATIC(cls, inst) \ + cls* inst##tmp = m_instance.load(std::memory_order_acquire); \ + if (inst##tmp == nullptr) { \ + std::lock_guard lock(m_instance_mutex); \ + inst##tmp = m_instance.load(std::memory_order_relaxed); \ + if (inst##tmp == nullptr) { \ + inst##tmp = new cls; \ + m_instance.store(inst##tmp, std::memory_order_release); \ + } \ + } \ + cls& inst = *inst##tmp + +#define ATOMIC_STATIC_DECL(cls) \ + static std::atomic m_instance; \ + static std::mutex m_instance_mutex; + +#define ATOMIC_STATIC_INIT(cls) \ + std::atomic cls::m_instance; \ + std::mutex cls::m_instance_mutex; + +#endif + +#endif // WPIUTIL_SUPPORT_ATOMIC_STATIC_H_ diff --git a/include/support/leb128.h b/include/support/leb128.h new file mode 100644 index 0000000000..de08a23a32 --- /dev/null +++ b/include/support/leb128.h @@ -0,0 +1,26 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#ifndef WPIUTIL_SUPPORT_LEB128_H_ +#define WPIUTIL_SUPPORT_LEB128_H_ + +#include + +#include "llvm/SmallVector.h" + +namespace wpi { + +class raw_istream; + +std::size_t SizeUleb128(unsigned long val); +std::size_t WriteUleb128(llvm::SmallVectorImpl& dest, unsigned long val); +std::size_t ReadUleb128(const char* addr, unsigned long* ret); +bool ReadUleb128(raw_istream& is, unsigned long* ret); + +} // namespace wpi + +#endif // WPIUTIL_SUPPORT_LEB128_H_ diff --git a/include/support/raw_istream.h b/include/support/raw_istream.h new file mode 100644 index 0000000000..aeca34fe88 --- /dev/null +++ b/include/support/raw_istream.h @@ -0,0 +1,40 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#ifndef WPIUTIL_SUPPORT_RAW_ISTREAM_H_ +#define WPIUTIL_SUPPORT_RAW_ISTREAM_H_ + +#include + +namespace wpi { + +class raw_istream { + public: + raw_istream() = default; + virtual ~raw_istream() = default; + virtual bool read(void* data, std::size_t len) = 0; + virtual void close() = 0; + + raw_istream(const raw_istream&) = delete; + raw_istream& operator=(const raw_istream&) = delete; +}; + +class raw_mem_istream : public raw_istream { + public: + raw_mem_istream(const char* mem, std::size_t len) : m_cur(mem), m_left(len) {} + virtual ~raw_mem_istream() = default; + virtual bool read(void* data, std::size_t len); + virtual void close() {} + + private: + const char* m_cur; + std::size_t m_left; +}; + +} // namespace wpi + +#endif // WPIUTIL_SUPPORT_RAW_ISTREAM_H_ diff --git a/include/support/raw_socket_istream.h b/include/support/raw_socket_istream.h new file mode 100644 index 0000000000..78b0517325 --- /dev/null +++ b/include/support/raw_socket_istream.h @@ -0,0 +1,31 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#ifndef WPIUTIL_SUPPORT_RAW_SOCKET_ISTREAM_H_ +#define WPIUTIL_SUPPORT_RAW_SOCKET_ISTREAM_H_ + +#include "support/raw_istream.h" +#include "tcpsockets/NetworkStream.h" + +namespace wpi { + +class raw_socket_istream : public raw_istream { + public: + raw_socket_istream(NetworkStream& stream, int timeout = 0) + : m_stream(stream), m_timeout(timeout) {} + virtual ~raw_socket_istream() = default; + virtual bool read(void* data, std::size_t len); + virtual void close(); + + private: + NetworkStream& m_stream; + int m_timeout; +}; + +} // namespace wpi + +#endif // WPIUTIL_SUPPORT_RAW_SOCKET_ISTREAM_H_ diff --git a/include/support/timestamp.h b/include/support/timestamp.h new file mode 100644 index 0000000000..526d6e5dcd --- /dev/null +++ b/include/support/timestamp.h @@ -0,0 +1,28 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ +#ifndef WPIUTIL_SUPPORT_TIMESTAMP_H_ +#define WPIUTIL_SUPPORT_TIMESTAMP_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +unsigned long long WPI_Now(void); + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +namespace wpi { + +unsigned long long Now(); + +} // namespace wpi +#endif + +#endif // WPIUTIL_SUPPORT_TIMESTAMP_H_ diff --git a/include/tcpsockets/NetworkAcceptor.h b/include/tcpsockets/NetworkAcceptor.h new file mode 100644 index 0000000000..f4d91204b3 --- /dev/null +++ b/include/tcpsockets/NetworkAcceptor.h @@ -0,0 +1,30 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#ifndef WPIUTIL_TCPSOCKETS_NETWORKACCEPTOR_H_ +#define WPIUTIL_TCPSOCKETS_NETWORKACCEPTOR_H_ + +#include "tcpsockets/NetworkStream.h" + +namespace wpi { + +class NetworkAcceptor { + public: + NetworkAcceptor() = default; + virtual ~NetworkAcceptor() = default; + + virtual int start() = 0; + virtual void shutdown() = 0; + virtual std::unique_ptr accept() = 0; + + NetworkAcceptor(const NetworkAcceptor&) = delete; + NetworkAcceptor& operator=(const NetworkAcceptor&) = delete; +}; + +} // namespace wpi + +#endif // WPIUTIL_TCPSOCKETS_NETWORKACCEPTOR_H_ diff --git a/include/tcpsockets/NetworkStream.h b/include/tcpsockets/NetworkStream.h new file mode 100644 index 0000000000..f7dfe4533e --- /dev/null +++ b/include/tcpsockets/NetworkStream.h @@ -0,0 +1,43 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#ifndef WPIUTIL_TCPSOCKETS_NETWORKSTREAM_H_ +#define WPIUTIL_TCPSOCKETS_NETWORKSTREAM_H_ + +#include + +#include "llvm/StringRef.h" + +namespace wpi { + +class NetworkStream { + public: + NetworkStream() = default; + virtual ~NetworkStream() = default; + + enum Error { + kConnectionClosed = 0, + kConnectionReset = -1, + kConnectionTimedOut = -2 + }; + + virtual std::size_t send(const char* buffer, std::size_t len, Error* err) = 0; + virtual std::size_t receive(char* buffer, std::size_t len, Error* err, + int timeout = 0) = 0; + virtual void close() = 0; + + virtual llvm::StringRef getPeerIP() const = 0; + virtual int getPeerPort() const = 0; + virtual void setNoDelay() = 0; + + NetworkStream(const NetworkStream&) = delete; + NetworkStream& operator=(const NetworkStream&) = delete; +}; + +} // namespace wpi + +#endif // WPIUTIL_TCPSOCKETS_NETWORKSTREAM_H_ diff --git a/include/tcpsockets/SocketError.h b/include/tcpsockets/SocketError.h new file mode 100644 index 0000000000..3d87b2d5c9 --- /dev/null +++ b/include/tcpsockets/SocketError.h @@ -0,0 +1,37 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#ifndef WPIUTIL_TCPSOCKETS_SOCKETERROR_H_ +#define WPIUTIL_TCPSOCKETS_SOCKETERROR_H_ + +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +namespace wpi { + +static inline int SocketErrno() { +#ifdef _WIN32 + return WSAGetLastError(); +#else + return errno; +#endif +} + +std::string SocketStrerror(int code); + +static inline std::string SocketStrerror() { + return SocketStrerror(SocketErrno()); +} + +} // namespace wpi + +#endif // WPIUTIL_TCPSOCKETS_SOCKETERROR_H_ diff --git a/include/tcpsockets/TCPAcceptor.h b/include/tcpsockets/TCPAcceptor.h new file mode 100644 index 0000000000..99403a3aca --- /dev/null +++ b/include/tcpsockets/TCPAcceptor.h @@ -0,0 +1,57 @@ +/* + TCPAcceptor.h + + TCPAcceptor class interface. TCPAcceptor provides methods to passively + establish TCP/IP connections with clients. + + ------------------------------------------ + + Copyright © 2013 [Vic Hargrave - http://vichargrave.com] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef WPIUTIL_TCPSOCKETS_TCPACCEPTOR_H_ +#define WPIUTIL_TCPSOCKETS_TCPACCEPTOR_H_ + +#include +#include +#include + +#include "tcpsockets/NetworkAcceptor.h" +#include "tcpsockets/TCPStream.h" + +namespace wpi { + +class Logger; + +class TCPAcceptor : public NetworkAcceptor { + int m_lsd; + int m_port; + std::string m_address; + bool m_listening; + std::atomic_bool m_shutdown; + Logger& m_logger; + + public: + TCPAcceptor(int port, const char* address, Logger& logger); + ~TCPAcceptor(); + + int start() override; + void shutdown() override; + std::unique_ptr accept() override; +}; + +} // namespace wpi + +#endif // WPIUTIL_TCPSOCKETS_TCPACCEPTOR_H_ diff --git a/include/tcpsockets/TCPConnector.h b/include/tcpsockets/TCPConnector.h new file mode 100644 index 0000000000..7afb0446af --- /dev/null +++ b/include/tcpsockets/TCPConnector.h @@ -0,0 +1,44 @@ +/* + TCPConnector.h + + TCPConnector class interface. TCPConnector provides methods to actively + establish TCP/IP connections with a server. + + ------------------------------------------ + + Copyright © 2013 [Vic Hargrave - http://vichargrave.com] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License +*/ + +#ifndef WPIUTIL_TCPSOCKETS_TCPCONNECTOR_H_ +#define WPIUTIL_TCPSOCKETS_TCPCONNECTOR_H_ + +#include + +#include "tcpsockets/NetworkStream.h" + +namespace wpi { + +class Logger; + +class TCPConnector { + public: + static std::unique_ptr connect(const char* server, int port, + Logger& logger, + int timeout = 0); +}; + +} // namespace wpi + +#endif // WPIUTIL_TCPSOCKETS_TCPCONNECTOR_H_ diff --git a/include/tcpsockets/TCPStream.h b/include/tcpsockets/TCPStream.h new file mode 100644 index 0000000000..e7bb2f0d1a --- /dev/null +++ b/include/tcpsockets/TCPStream.h @@ -0,0 +1,73 @@ +/* + TCPStream.h + + TCPStream class interface. TCPStream provides methods to trasnfer + data between peers over a TCP/IP connection. + + ------------------------------------------ + + Copyright © 2013 [Vic Hargrave - http://vichargrave.com] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef WPIUTIL_TCPSOCKETS_TCPSTREAM_H_ +#define WPIUTIL_TCPSOCKETS_TCPSTREAM_H_ + +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +#include "tcpsockets/NetworkStream.h" + +struct sockaddr_in; + +namespace wpi { + +class TCPStream : public NetworkStream { + int m_sd; + std::string m_peerIP; + int m_peerPort; + + public: + friend class TCPAcceptor; + friend class TCPConnector; + + ~TCPStream(); + + std::size_t send(const char* buffer, std::size_t len, Error* err) override; + std::size_t receive(char* buffer, std::size_t len, Error* err, + int timeout = 0) override; + void close() override; + + llvm::StringRef getPeerIP() const override; + int getPeerPort() const override; + void setNoDelay() override; + + TCPStream(const TCPStream& stream) = delete; + TCPStream& operator=(const TCPStream&) = delete; + private: + bool WaitForReadEvent(int timeout); + + TCPStream(int sd, sockaddr_in* address); + TCPStream() = delete; +}; + +} // namespace wpi + +#endif diff --git a/src/dummy.cpp b/src/dummy.cpp deleted file mode 100644 index 3d12903c98..0000000000 --- a/src/dummy.cpp +++ /dev/null @@ -1,3 +0,0 @@ -namespace wpi { -void DummyFunction() {} -} diff --git a/src/llvm/ConvertUTF.cpp b/src/llvm/ConvertUTF.cpp new file mode 100644 index 0000000000..73f66d12f9 --- /dev/null +++ b/src/llvm/ConvertUTF.cpp @@ -0,0 +1,708 @@ +/*===--- ConvertUTF.c - Universal Character Names conversions ---------------=== + * + * The LLVM Compiler Infrastructure + * + * This file is distributed under the University of Illinois Open Source + * License. See LICENSE.TXT for details. + * + *===------------------------------------------------------------------------=*/ +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* --------------------------------------------------------------------- + + Conversions between UTF32, UTF-16, and UTF-8. Source code file. + Author: Mark E. Davis, 1994. + Rev History: Rick McGowan, fixes & updates May 2001. + Sept 2001: fixed const & error conditions per + mods suggested by S. Parent & A. Lillich. + June 2002: Tim Dodd added detection and handling of incomplete + source sequences, enhanced error detection, added casts + to eliminate compiler warnings. + July 2003: slight mods to back out aggressive FFFE detection. + Jan 2004: updated switches in from-UTF8 conversions. + Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions. + + See the header file "ConvertUTF.h" for complete documentation. + +------------------------------------------------------------------------ */ + + +#include "llvm/ConvertUTF.h" +#ifdef CVTUTF_DEBUG +#include +#endif +#include + +static const int halfShift = 10; /* used for shifting by 10 bits */ + +static const UTF32 halfBase = 0x0010000UL; +static const UTF32 halfMask = 0x3FFUL; + +#define UNI_SUR_HIGH_START (UTF32)0xD800 +#define UNI_SUR_HIGH_END (UTF32)0xDBFF +#define UNI_SUR_LOW_START (UTF32)0xDC00 +#define UNI_SUR_LOW_END (UTF32)0xDFFF + +/* --------------------------------------------------------------------- */ + +/* + * Index into the table below with the first byte of a UTF-8 sequence to + * get the number of trailing bytes that are supposed to follow it. + * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is + * left as-is for anyone who may want to do such conversion, which was + * allowed in earlier algorithms. + */ +static const char trailingBytesForUTF8[256] = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5 +}; + +/* + * Magic values subtracted from a buffer value during UTF8 conversion. + * This table contains as many values as there might be trailing bytes + * in a UTF-8 sequence. + */ +static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, + 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; + +/* + * Once the bits are split out into bytes of UTF-8, this is a mask OR-ed + * into the first byte, depending on how many bytes follow. There are + * as many entries in this table as there are UTF-8 sequence types. + * (I.e., one byte sequence, two byte... etc.). Remember that sequencs + * for *legal* UTF-8 will be 4 or fewer bytes total. + */ +static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +/* --------------------------------------------------------------------- */ + +/* The interface converts a whole buffer to avoid function-call overhead. + * Constants have been gathered. Loops & conditionals have been removed as + * much as possible for efficiency, in favor of drop-through switches. + * (See "Note A" at the bottom of the file for equivalent code.) + * If your compiler supports it, the "isLegalUTF8" call can be turned + * into an inline function. + */ + +extern "C" { +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF16 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + if (target >= targetEnd) { + result = targetExhausted; break; + } + ch = *source++; + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_LEGAL_UTF32) { + if (flags == strictConversion) { + result = sourceIllegal; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + --source; /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF16toUTF32 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF32* target = *targetStart; + UTF32 ch, ch2; + while (source < sourceEnd) { + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + if (target >= targetEnd) { + source = oldSource; /* Back up source pointer! */ + result = targetExhausted; break; + } + *target++ = ch; + } + *sourceStart = source; + *targetStart = target; +#ifdef CVTUTF_DEBUG +if (result == sourceIllegal) { + fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2); + fflush(stderr); +} +#endif + return result; +} +ConversionResult ConvertUTF16toUTF8 ( + const UTF16** sourceStart, const UTF16* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF16* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */ + ch = *source++; + /* If we have a surrogate pair, convert to UTF32 first. */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) { + /* If the 16 bits following the high surrogate are in the source buffer... */ + if (source < sourceEnd) { + UTF32 ch2 = *source; + /* If it's a low surrogate, convert to UTF32. */ + if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) { + ch = ((ch - UNI_SUR_HIGH_START) << halfShift) + + (ch2 - UNI_SUR_LOW_START) + halfBase; + ++source; + } else if (flags == strictConversion) { /* it's an unpaired high surrogate */ + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } else { /* We don't have the 16 bits following the high surrogate. */ + --source; /* return to the high surrogate */ + result = sourceExhausted; + break; + } + } else if (flags == strictConversion) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* Figure out how many bytes the result will require */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch < (UTF32)0x110000) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + } + + target += bytesToWrite; + if (target > targetEnd) { + source = oldSource; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF32toUTF8 ( + const UTF32** sourceStart, const UTF32* sourceEnd, + UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF32* source = *sourceStart; + UTF8* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch; + unsigned short bytesToWrite = 0; + const UTF32 byteMask = 0xBF; + const UTF32 byteMark = 0x80; + ch = *source++; + if (flags == strictConversion ) { + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + --source; /* return to the illegal value itself */ + result = sourceIllegal; + break; + } + } + /* + * Figure out how many bytes the result will require. Turn any + * illegally large UTF32 things (> Plane 17) into replacement chars. + */ + if (ch < (UTF32)0x80) { bytesToWrite = 1; + } else if (ch < (UTF32)0x800) { bytesToWrite = 2; + } else if (ch < (UTF32)0x10000) { bytesToWrite = 3; + } else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4; + } else { bytesToWrite = 3; + ch = UNI_REPLACEMENT_CHAR; + result = sourceIllegal; + } + + target += bytesToWrite; + if (target > targetEnd) { + --source; /* Back up source pointer! */ + target -= bytesToWrite; result = targetExhausted; break; + } + switch (bytesToWrite) { /* note: everything falls through. */ + case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6; + case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]); + } + target += bytesToWrite; + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +/* + * Utility routine to tell whether a sequence of bytes is legal UTF-8. + * This must be called with the length pre-determined by the first byte. + * If not calling this from ConvertUTF8to*, then the length can be set by: + * length = trailingBytesForUTF8[*source]+1; + * and the sequence is illegal right away if there aren't that many bytes + * available. + * If presented with a length > 4, this returns false. The Unicode + * definition of UTF-8 goes up to 4-byte sequences. + */ + +static Boolean isLegalUTF8(const UTF8 *source, int length) { + UTF8 a; + const UTF8 *srcptr = source+length; + switch (length) { + default: return false; + /* Everything else falls through when "true"... */ + case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + case 2: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false; + + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: if (a < 0xA0) return false; break; + case 0xED: if (a > 0x9F) return false; break; + case 0xF0: if (a < 0x90) return false; break; + case 0xF4: if (a > 0x8F) return false; break; + default: if (a < 0x80) return false; + } + + case 1: if (*source >= 0x80 && *source < 0xC2) return false; + } + if (*source > 0xF4) return false; + return true; +} + +/* --------------------------------------------------------------------- */ + +/* + * Exported function to return whether a UTF-8 sequence is legal or not. + * This is not used here; it's just exported. + */ +Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) { + int length = trailingBytesForUTF8[*source]+1; + if (length > sourceEnd - source) { + return false; + } + return isLegalUTF8(source, length); +} + +/* --------------------------------------------------------------------- */ + +static unsigned +findMaximalSubpartOfIllFormedUTF8Sequence(const UTF8 *source, + const UTF8 *sourceEnd) { + UTF8 b1, b2, b3; + + assert(!isLegalUTF8Sequence(source, sourceEnd)); + + /* + * Unicode 6.3.0, D93b: + * + * Maximal subpart of an ill-formed subsequence: The longest code unit + * subsequence starting at an unconvertible offset that is either: + * a. the initial subsequence of a well-formed code unit sequence, or + * b. a subsequence of length one. + */ + + if (source == sourceEnd) + return 0; + + /* + * Perform case analysis. See Unicode 6.3.0, Table 3-7. Well-Formed UTF-8 + * Byte Sequences. + */ + + b1 = *source; + ++source; + if (b1 >= 0xC2 && b1 <= 0xDF) { + /* + * First byte is valid, but we know that this code unit sequence is + * invalid, so the maximal subpart has to end after the first byte. + */ + return 1; + } + + if (source == sourceEnd) + return 1; + + b2 = *source; + ++source; + + if (b1 == 0xE0) { + return (b2 >= 0xA0 && b2 <= 0xBF) ? 2 : 1; + } + if (b1 >= 0xE1 && b1 <= 0xEC) { + return (b2 >= 0x80 && b2 <= 0xBF) ? 2 : 1; + } + if (b1 == 0xED) { + return (b2 >= 0x80 && b2 <= 0x9F) ? 2 : 1; + } + if (b1 >= 0xEE && b1 <= 0xEF) { + return (b2 >= 0x80 && b2 <= 0xBF) ? 2 : 1; + } + if (b1 == 0xF0) { + if (b2 >= 0x90 && b2 <= 0xBF) { + if (source == sourceEnd) + return 2; + + b3 = *source; + return (b3 >= 0x80 && b3 <= 0xBF) ? 3 : 2; + } + return 1; + } + if (b1 >= 0xF1 && b1 <= 0xF3) { + if (b2 >= 0x80 && b2 <= 0xBF) { + if (source == sourceEnd) + return 2; + + b3 = *source; + return (b3 >= 0x80 && b3 <= 0xBF) ? 3 : 2; + } + return 1; + } + if (b1 == 0xF4) { + if (b2 >= 0x80 && b2 <= 0x8F) { + if (source == sourceEnd) + return 2; + + b3 = *source; + return (b3 >= 0x80 && b3 <= 0xBF) ? 3 : 2; + } + return 1; + } + + assert((b1 >= 0x80 && b1 <= 0xC1) || b1 >= 0xF5); + /* + * There are no valid sequences that start with these bytes. Maximal subpart + * is defined to have length 1 in these cases. + */ + return 1; +} + +/* --------------------------------------------------------------------- */ + +/* + * Exported function to return the total number of bytes in a codepoint + * represented in UTF-8, given the value of the first byte. + */ +unsigned getNumBytesForUTF8(UTF8 first) { + return trailingBytesForUTF8[first] + 1; +} + +/* --------------------------------------------------------------------- */ + +/* + * Exported function to return whether a UTF-8 string is legal or not. + * This is not used here; it's just exported. + */ +Boolean isLegalUTF8String(const UTF8 **source, const UTF8 *sourceEnd) { + while (*source != sourceEnd) { + int length = trailingBytesForUTF8[**source] + 1; + if (length > sourceEnd - *source || !isLegalUTF8(*source, length)) + return false; + *source += length; + } + return true; +} + +/* --------------------------------------------------------------------- */ + +ConversionResult ConvertUTF8toUTF16 ( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF16* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (extraBytesToRead >= sourceEnd - source) { + result = sourceExhausted; break; + } + /* Do this check whether lenient or strict */ + if (!isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + break; + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */ + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (target >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */ + /* UTF-16 surrogate values are illegal in UTF-32 */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = (UTF16)ch; /* normal case */ + } + } else if (ch > UNI_MAX_UTF16) { + if (flags == strictConversion) { + result = sourceIllegal; + source -= (extraBytesToRead+1); /* return to the start */ + break; /* Bail out; shouldn't continue */ + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + /* target is a character in range 0xFFFF - 0x10FFFF. */ + if (target + 1 >= targetEnd) { + source -= (extraBytesToRead+1); /* Back up source pointer! */ + result = targetExhausted; break; + } + ch -= halfBase; + *target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START); + *target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START); + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +/* --------------------------------------------------------------------- */ + +static ConversionResult ConvertUTF8toUTF32Impl( + const UTF8** sourceStart, const UTF8* sourceEnd, + UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags, + Boolean InputIsPartial) { + ConversionResult result = conversionOK; + const UTF8* source = *sourceStart; + UTF32* target = *targetStart; + while (source < sourceEnd) { + UTF32 ch = 0; + unsigned short extraBytesToRead = trailingBytesForUTF8[*source]; + if (extraBytesToRead >= sourceEnd - source) { + if (flags == strictConversion || InputIsPartial) { + result = sourceExhausted; + break; + } else { + result = sourceIllegal; + + /* + * Replace the maximal subpart of ill-formed sequence with + * replacement character. + */ + source += findMaximalSubpartOfIllFormedUTF8Sequence(source, + sourceEnd); + *target++ = UNI_REPLACEMENT_CHAR; + continue; + } + } + if (target >= targetEnd) { + result = targetExhausted; break; + } + + /* Do this check whether lenient or strict */ + if (!isLegalUTF8(source, extraBytesToRead+1)) { + result = sourceIllegal; + if (flags == strictConversion) { + /* Abort conversion. */ + break; + } else { + /* + * Replace the maximal subpart of ill-formed sequence with + * replacement character. + */ + source += findMaximalSubpartOfIllFormedUTF8Sequence(source, + sourceEnd); + *target++ = UNI_REPLACEMENT_CHAR; + continue; + } + } + /* + * The cases all fall through. See "Note A" below. + */ + switch (extraBytesToRead) { + case 5: ch += *source++; ch <<= 6; + case 4: ch += *source++; ch <<= 6; + case 3: ch += *source++; ch <<= 6; + case 2: ch += *source++; ch <<= 6; + case 1: ch += *source++; ch <<= 6; + case 0: ch += *source++; + } + ch -= offsetsFromUTF8[extraBytesToRead]; + + if (ch <= UNI_MAX_LEGAL_UTF32) { + /* + * UTF-16 surrogate values are illegal in UTF-32, and anything + * over Plane 17 (> 0x10FFFF) is illegal. + */ + if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) { + if (flags == strictConversion) { + source -= (extraBytesToRead+1); /* return to the illegal value itself */ + result = sourceIllegal; + break; + } else { + *target++ = UNI_REPLACEMENT_CHAR; + } + } else { + *target++ = ch; + } + } else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */ + result = sourceIllegal; + *target++ = UNI_REPLACEMENT_CHAR; + } + } + *sourceStart = source; + *targetStart = target; + return result; +} + +ConversionResult ConvertUTF8toUTF32Partial(const UTF8 **sourceStart, + const UTF8 *sourceEnd, + UTF32 **targetStart, + UTF32 *targetEnd, + ConversionFlags flags) { + return ConvertUTF8toUTF32Impl(sourceStart, sourceEnd, targetStart, targetEnd, + flags, /*InputIsPartial=*/true); +} + +ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart, + const UTF8 *sourceEnd, UTF32 **targetStart, + UTF32 *targetEnd, ConversionFlags flags) { + return ConvertUTF8toUTF32Impl(sourceStart, sourceEnd, targetStart, targetEnd, + flags, /*InputIsPartial=*/false); +} + +} + +/* --------------------------------------------------------------------- + + Note A. + The fall-through switches in UTF-8 reading code save a + temp variable, some decrements & conditionals. The switches + are equivalent to the following loop: + { + int tmpBytesToRead = extraBytesToRead+1; + do { + ch += *source++; + --tmpBytesToRead; + if (tmpBytesToRead) ch <<= 6; + } while (tmpBytesToRead > 0); + } + In UTF-8 writing code, the switches on "bytesToWrite" are + similarly unrolled loops. + + --------------------------------------------------------------------- */ diff --git a/src/llvm/ConvertUTFWrapper.cpp b/src/llvm/ConvertUTFWrapper.cpp new file mode 100644 index 0000000000..810c135166 --- /dev/null +++ b/src/llvm/ConvertUTFWrapper.cpp @@ -0,0 +1,122 @@ +//===-- ConvertUTFWrapper.cpp - Wrap ConvertUTF.h with clang data types -----=== +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ConvertUTF.h" +#include +#include + +namespace llvm { + +bool ConvertCodePointToUTF8(unsigned Source, char *&ResultPtr) { + const UTF32 *SourceStart = &Source; + const UTF32 *SourceEnd = SourceStart + 1; + UTF8 *TargetStart = reinterpret_cast(ResultPtr); + UTF8 *TargetEnd = TargetStart + 4; + ConversionResult CR = ConvertUTF32toUTF8(&SourceStart, SourceEnd, + &TargetStart, TargetEnd, + strictConversion); + if (CR != conversionOK) + return false; + + ResultPtr = reinterpret_cast(TargetStart); + return true; +} + +bool hasUTF16ByteOrderMark(ArrayRef S) { + return (S.size() >= 2 && + ((S[0] == '\xff' && S[1] == '\xfe') || + (S[0] == '\xfe' && S[1] == '\xff'))); +} + +bool convertUTF16ToUTF8String(ArrayRef SrcUTF16, + SmallVectorImpl &DstUTF8) { + assert(DstUTF8.empty()); + + // Avoid OOB by returning early on empty input. + if (SrcUTF16.empty()) + return true; + + const UTF16 *Src = SrcUTF16.begin(); + const UTF16 *SrcEnd = SrcUTF16.end(); + + // Byteswap if necessary. + std::vector ByteSwapped; + if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_SWAPPED) { + ByteSwapped.insert(ByteSwapped.end(), Src, SrcEnd); + for (unsigned I = 0, E = ByteSwapped.size(); I != E; ++I) + ByteSwapped[I] = (ByteSwapped[I] << 8) | (ByteSwapped[I] >> 8); + Src = &ByteSwapped[0]; + SrcEnd = &ByteSwapped[ByteSwapped.size() - 1] + 1; + } + + // Skip the BOM for conversion. + if (Src[0] == UNI_UTF16_BYTE_ORDER_MARK_NATIVE) + Src++; + + // Just allocate enough space up front. We'll shrink it later. Allocate + // enough that we can fit a null terminator without reallocating. + DstUTF8.resize(SrcUTF16.size() * UNI_MAX_UTF8_BYTES_PER_CODE_POINT + 1); + UTF8 *Dst = reinterpret_cast(&DstUTF8[0]); + UTF8 *DstEnd = Dst + DstUTF8.size(); + + ConversionResult CR = + ConvertUTF16toUTF8(&Src, SrcEnd, &Dst, DstEnd, strictConversion); + assert(CR != targetExhausted); + + if (CR != conversionOK) { + DstUTF8.clear(); + return false; + } + + DstUTF8.resize(reinterpret_cast(Dst) - &DstUTF8[0]); + DstUTF8.push_back(0); + DstUTF8.pop_back(); + return true; +} + +bool convertUTF8ToUTF16String(StringRef SrcUTF8, + SmallVectorImpl &DstUTF16) { + assert(DstUTF16.empty()); + + // Avoid OOB by returning early on empty input. + if (SrcUTF8.empty()) { + DstUTF16.push_back(0); + DstUTF16.pop_back(); + return true; + } + + const UTF8 *Src = reinterpret_cast(SrcUTF8.begin()); + const UTF8 *SrcEnd = reinterpret_cast(SrcUTF8.end()); + + // Allocate the same number of UTF-16 code units as UTF-8 code units. Encoding + // as UTF-16 should always require the same amount or less code units than the + // UTF-8 encoding. Allocate one extra byte for the null terminator though, + // so that someone calling DstUTF16.data() gets a null terminated string. + // We resize down later so we don't have to worry that this over allocates. + DstUTF16.resize(SrcUTF8.size()+1); + UTF16 *Dst = &DstUTF16[0]; + UTF16 *DstEnd = Dst + DstUTF16.size(); + + ConversionResult CR = + ConvertUTF8toUTF16(&Src, SrcEnd, &Dst, DstEnd, strictConversion); + assert(CR != targetExhausted); + + if (CR != conversionOK) { + DstUTF16.clear(); + return false; + } + + DstUTF16.resize(Dst - &DstUTF16[0]); + DstUTF16.push_back(0); + DstUTF16.pop_back(); + return true; +} + +} // end namespace llvm + diff --git a/src/llvm/SmallPtrSet.cpp b/src/llvm/SmallPtrSet.cpp new file mode 100644 index 0000000000..d23599adcc --- /dev/null +++ b/src/llvm/SmallPtrSet.cpp @@ -0,0 +1,338 @@ +//===- llvm/ADT/SmallPtrSet.cpp - 'Normally small' pointer set ------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the SmallPtrSet class. See SmallPtrSet.h for an +// overview of the algorithm. +// +//===----------------------------------------------------------------------===// + +#include "llvm/SmallPtrSet.h" +#include "llvm/DenseMapInfo.h" +#include "llvm/MathExtras.h" +#include +#include + +using namespace llvm; + +void SmallPtrSetImplBase::shrink_and_clear() { + assert(!isSmall() && "Can't shrink a small set!"); + free(CurArray); + + // Reduce the number of buckets. + CurArraySize = NumElements > 16 ? 1 << (Log2_32_Ceil(NumElements) + 1) : 32; + NumElements = NumTombstones = 0; + + // Install the new array. Clear all the buckets to empty. + CurArray = (const void**)malloc(sizeof(void*) * CurArraySize); + assert(CurArray && "Failed to allocate memory?"); + memset(CurArray, -1, CurArraySize*sizeof(void*)); +} + +std::pair +SmallPtrSetImplBase::insert_imp(const void *Ptr) { + if (isSmall()) { + // Check to see if it is already in the set. + for (const void **APtr = SmallArray, **E = SmallArray+NumElements; + APtr != E; ++APtr) + if (*APtr == Ptr) + return std::make_pair(APtr, false); + + // Nope, there isn't. If we stay small, just 'pushback' now. + if (NumElements < CurArraySize) { + SmallArray[NumElements++] = Ptr; + return std::make_pair(SmallArray + (NumElements - 1), true); + } + // Otherwise, hit the big set case, which will call grow. + } + + if (LLVM_UNLIKELY(NumElements * 4 >= CurArraySize * 3)) { + // If more than 3/4 of the array is full, grow. + Grow(CurArraySize < 64 ? 128 : CurArraySize*2); + } else if (LLVM_UNLIKELY(CurArraySize - (NumElements + NumTombstones) < + CurArraySize / 8)) { + // If fewer of 1/8 of the array is empty (meaning that many are filled with + // tombstones), rehash. + Grow(CurArraySize); + } + + // Okay, we know we have space. Find a hash bucket. + const void **Bucket = const_cast(FindBucketFor(Ptr)); + if (*Bucket == Ptr) + return std::make_pair(Bucket, false); // Already inserted, good. + + // Otherwise, insert it! + if (*Bucket == getTombstoneMarker()) + --NumTombstones; + *Bucket = Ptr; + ++NumElements; // Track density. + return std::make_pair(Bucket, true); +} + +bool SmallPtrSetImplBase::erase_imp(const void * Ptr) { + if (isSmall()) { + // Check to see if it is in the set. + for (const void **APtr = SmallArray, **E = SmallArray+NumElements; + APtr != E; ++APtr) + if (*APtr == Ptr) { + // If it is in the set, replace this element. + *APtr = E[-1]; + E[-1] = getEmptyMarker(); + --NumElements; + return true; + } + + return false; + } + + // Okay, we know we have space. Find a hash bucket. + void **Bucket = const_cast(FindBucketFor(Ptr)); + if (*Bucket != Ptr) return false; // Not in the set? + + // Set this as a tombstone. + *Bucket = getTombstoneMarker(); + --NumElements; + ++NumTombstones; + return true; +} + +const void * const *SmallPtrSetImplBase::FindBucketFor(const void *Ptr) const { + unsigned Bucket = DenseMapInfo::getHashValue(Ptr) & (CurArraySize-1); + unsigned ArraySize = CurArraySize; + unsigned ProbeAmt = 1; + const void *const *Array = CurArray; + const void *const *Tombstone = nullptr; + while (1) { + // If we found an empty bucket, the pointer doesn't exist in the set. + // Return a tombstone if we've seen one so far, or the empty bucket if + // not. + if (LLVM_LIKELY(Array[Bucket] == getEmptyMarker())) + return Tombstone ? Tombstone : Array+Bucket; + + // Found Ptr's bucket? + if (LLVM_LIKELY(Array[Bucket] == Ptr)) + return Array+Bucket; + + // If this is a tombstone, remember it. If Ptr ends up not in the set, we + // prefer to return it than something that would require more probing. + if (Array[Bucket] == getTombstoneMarker() && !Tombstone) + Tombstone = Array+Bucket; // Remember the first tombstone found. + + // It's a hash collision or a tombstone. Reprobe. + Bucket = (Bucket + ProbeAmt++) & (ArraySize-1); + } +} + +/// Grow - Allocate a larger backing store for the buckets and move it over. +/// +void SmallPtrSetImplBase::Grow(unsigned NewSize) { + // Allocate at twice as many buckets, but at least 128. + unsigned OldSize = CurArraySize; + + const void **OldBuckets = CurArray; + bool WasSmall = isSmall(); + + // Install the new array. Clear all the buckets to empty. + CurArray = (const void**)malloc(sizeof(void*) * NewSize); + assert(CurArray && "Failed to allocate memory?"); + CurArraySize = NewSize; + memset(CurArray, -1, NewSize*sizeof(void*)); + + // Copy over all the elements. + if (WasSmall) { + // Small sets store their elements in order. + for (const void **BucketPtr = OldBuckets, **E = OldBuckets+NumElements; + BucketPtr != E; ++BucketPtr) { + const void *Elt = *BucketPtr; + *const_cast(FindBucketFor(Elt)) = const_cast(Elt); + } + } else { + // Copy over all valid entries. + for (const void **BucketPtr = OldBuckets, **E = OldBuckets+OldSize; + BucketPtr != E; ++BucketPtr) { + // Copy over the element if it is valid. + const void *Elt = *BucketPtr; + if (Elt != getTombstoneMarker() && Elt != getEmptyMarker()) + *const_cast(FindBucketFor(Elt)) = const_cast(Elt); + } + + free(OldBuckets); + NumTombstones = 0; + } +} + +SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage, + const SmallPtrSetImplBase& that) { + SmallArray = SmallStorage; + + // If we're becoming small, prepare to insert into our stack space + if (that.isSmall()) { + CurArray = SmallArray; + // Otherwise, allocate new heap space (unless we were the same size) + } else { + CurArray = (const void**)malloc(sizeof(void*) * that.CurArraySize); + assert(CurArray && "Failed to allocate memory?"); + } + + // Copy over the new array size + CurArraySize = that.CurArraySize; + + // Copy over the contents from the other set + memcpy(CurArray, that.CurArray, sizeof(void*)*CurArraySize); + + NumElements = that.NumElements; + NumTombstones = that.NumTombstones; +} + +SmallPtrSetImplBase::SmallPtrSetImplBase(const void **SmallStorage, + unsigned SmallSize, + SmallPtrSetImplBase &&that) { + SmallArray = SmallStorage; + + // Copy over the basic members. + CurArraySize = that.CurArraySize; + NumElements = that.NumElements; + NumTombstones = that.NumTombstones; + + // When small, just copy into our small buffer. + if (that.isSmall()) { + CurArray = SmallArray; + memcpy(CurArray, that.CurArray, sizeof(void *) * CurArraySize); + } else { + // Otherwise, we steal the large memory allocation and no copy is needed. + CurArray = that.CurArray; + that.CurArray = that.SmallArray; + } + + // Make the "that" object small and empty. + that.CurArraySize = SmallSize; + assert(that.CurArray == that.SmallArray); + that.NumElements = 0; + that.NumTombstones = 0; +} + +/// CopyFrom - implement operator= from a smallptrset that has the same pointer +/// type, but may have a different small size. +void SmallPtrSetImplBase::CopyFrom(const SmallPtrSetImplBase &RHS) { + assert(&RHS != this && "Self-copy should be handled by the caller."); + + if (isSmall() && RHS.isSmall()) + assert(CurArraySize == RHS.CurArraySize && + "Cannot assign sets with different small sizes"); + + // If we're becoming small, prepare to insert into our stack space + if (RHS.isSmall()) { + if (!isSmall()) + free(CurArray); + CurArray = SmallArray; + // Otherwise, allocate new heap space (unless we were the same size) + } else if (CurArraySize != RHS.CurArraySize) { + if (isSmall()) + CurArray = (const void**)malloc(sizeof(void*) * RHS.CurArraySize); + else { + const void **T = (const void**)realloc(CurArray, + sizeof(void*) * RHS.CurArraySize); + if (!T) + free(CurArray); + CurArray = T; + } + assert(CurArray && "Failed to allocate memory?"); + } + + // Copy over the new array size + CurArraySize = RHS.CurArraySize; + + // Copy over the contents from the other set + memcpy(CurArray, RHS.CurArray, sizeof(void*)*CurArraySize); + + NumElements = RHS.NumElements; + NumTombstones = RHS.NumTombstones; +} + +void SmallPtrSetImplBase::MoveFrom(unsigned SmallSize, + SmallPtrSetImplBase &&RHS) { + assert(&RHS != this && "Self-move should be handled by the caller."); + + if (!isSmall()) + free(CurArray); + + if (RHS.isSmall()) { + // Copy a small RHS rather than moving. + CurArray = SmallArray; + memcpy(CurArray, RHS.CurArray, sizeof(void*)*RHS.CurArraySize); + } else { + CurArray = RHS.CurArray; + RHS.CurArray = RHS.SmallArray; + } + + // Copy the rest of the trivial members. + CurArraySize = RHS.CurArraySize; + NumElements = RHS.NumElements; + NumTombstones = RHS.NumTombstones; + + // Make the RHS small and empty. + RHS.CurArraySize = SmallSize; + assert(RHS.CurArray == RHS.SmallArray); + RHS.NumElements = 0; + RHS.NumTombstones = 0; +} + +void SmallPtrSetImplBase::swap(SmallPtrSetImplBase &RHS) { + if (this == &RHS) return; + + // We can only avoid copying elements if neither set is small. + if (!this->isSmall() && !RHS.isSmall()) { + std::swap(this->CurArray, RHS.CurArray); + std::swap(this->CurArraySize, RHS.CurArraySize); + std::swap(this->NumElements, RHS.NumElements); + std::swap(this->NumTombstones, RHS.NumTombstones); + return; + } + + // FIXME: From here on we assume that both sets have the same small size. + + // If only RHS is small, copy the small elements into LHS and move the pointer + // from LHS to RHS. + if (!this->isSmall() && RHS.isSmall()) { + std::copy(RHS.SmallArray, RHS.SmallArray+RHS.CurArraySize, + this->SmallArray); + std::swap(this->NumElements, RHS.NumElements); + std::swap(this->CurArraySize, RHS.CurArraySize); + RHS.CurArray = this->CurArray; + RHS.NumTombstones = this->NumTombstones; + this->CurArray = this->SmallArray; + this->NumTombstones = 0; + return; + } + + // If only LHS is small, copy the small elements into RHS and move the pointer + // from RHS to LHS. + if (this->isSmall() && !RHS.isSmall()) { + std::copy(this->SmallArray, this->SmallArray+this->CurArraySize, + RHS.SmallArray); + std::swap(RHS.NumElements, this->NumElements); + std::swap(RHS.CurArraySize, this->CurArraySize); + this->CurArray = RHS.CurArray; + this->NumTombstones = RHS.NumTombstones; + RHS.CurArray = RHS.SmallArray; + RHS.NumTombstones = 0; + return; + } + + // Both a small, just swap the small elements. + assert(this->isSmall() && RHS.isSmall()); + assert(this->CurArraySize == RHS.CurArraySize); + std::swap_ranges(this->SmallArray, this->SmallArray+this->CurArraySize, + RHS.SmallArray); + std::swap(this->NumElements, RHS.NumElements); +} + +SmallPtrSetImplBase::~SmallPtrSetImplBase() { + if (!isSmall()) + free(CurArray); +} diff --git a/src/llvm/SmallVector.cpp b/src/llvm/SmallVector.cpp new file mode 100644 index 0000000000..6aa709e821 --- /dev/null +++ b/src/llvm/SmallVector.cpp @@ -0,0 +1,41 @@ +//===- llvm/ADT/SmallVector.cpp - 'Normally small' vectors ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the SmallVector class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/SmallVector.h" +using namespace llvm; + +/// grow_pod - This is an implementation of the grow() method which only works +/// on POD-like datatypes and is out of line to reduce code duplication. +void SmallVectorBase::grow_pod(void *FirstEl, size_t MinSizeInBytes, + size_t TSize) { + size_t CurSizeBytes = size_in_bytes(); + size_t NewCapacityInBytes = 2 * capacity_in_bytes() + TSize; // Always grow. + if (NewCapacityInBytes < MinSizeInBytes) + NewCapacityInBytes = MinSizeInBytes; + + void *NewElts; + if (BeginX == FirstEl) { + NewElts = malloc(NewCapacityInBytes); + + // Copy the elements over. No need to run dtors on PODs. + memcpy(NewElts, this->BeginX, CurSizeBytes); + } else { + // If this wasn't grown from the inline copy, grow the allocated space. + NewElts = realloc(this->BeginX, NewCapacityInBytes); + } + assert(NewElts && "Out of memory"); + + this->EndX = (char*)NewElts+CurSizeBytes; + this->BeginX = NewElts; + this->CapacityX = (char*)this->BeginX + NewCapacityInBytes; +} diff --git a/src/llvm/StringExtras.cpp b/src/llvm/StringExtras.cpp new file mode 100644 index 0000000000..74b47a5c36 --- /dev/null +++ b/src/llvm/StringExtras.cpp @@ -0,0 +1,58 @@ +//===-- StringExtras.cpp - Implement the StringExtras header --------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the StringExtras.h header +// +//===----------------------------------------------------------------------===// + +#include "llvm/StringExtras.h" +#include "llvm/SmallVector.h" +using namespace llvm; + +/// StrInStrNoCase - Portable version of strcasestr. Locates the first +/// occurrence of string 's1' in string 's2', ignoring case. Returns +/// the offset of s2 in s1 or npos if s2 cannot be found. +StringRef::size_type llvm::StrInStrNoCase(StringRef s1, StringRef s2) { + size_t N = s2.size(), M = s1.size(); + if (N > M) + return StringRef::npos; + for (size_t i = 0, e = M - N + 1; i != e; ++i) + if (s1.substr(i, N).equals_lower(s2)) + return i; + return StringRef::npos; +} + +/// getToken - This function extracts one token from source, ignoring any +/// leading characters that appear in the Delimiters string, and ending the +/// token at any of the characters that appear in the Delimiters string. If +/// there are no tokens in the source string, an empty string is returned. +/// The function returns a pair containing the extracted token and the +/// remaining tail string. +std::pair llvm::getToken(StringRef Source, + StringRef Delimiters) { + // Figure out where the token starts. + StringRef::size_type Start = Source.find_first_not_of(Delimiters); + + // Find the next occurrence of the delimiter. + StringRef::size_type End = Source.find_first_of(Delimiters, Start); + + return std::make_pair(Source.slice(Start, End), Source.substr(End)); +} + +/// SplitString - Split up the specified string according to the specified +/// delimiters, appending the result fragments to the output list. +void llvm::SplitString(StringRef Source, + SmallVectorImpl &OutFragments, + StringRef Delimiters) { + std::pair S = getToken(Source, Delimiters); + while (!S.first.empty()) { + OutFragments.push_back(S.first); + S = getToken(S.second, Delimiters); + } +} diff --git a/src/llvm/StringMap.cpp b/src/llvm/StringMap.cpp new file mode 100644 index 0000000000..56498346be --- /dev/null +++ b/src/llvm/StringMap.cpp @@ -0,0 +1,244 @@ +//===--- StringMap.cpp - String Hash table map implementation -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the StringMap class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/StringMap.h" +#include "llvm/StringExtras.h" +//#include "llvm/Support/Compiler.h" +#include +using namespace llvm; + +StringMapImpl::StringMapImpl(unsigned InitSize, unsigned itemSize) { + ItemSize = itemSize; + + // If a size is specified, initialize the table with that many buckets. + if (InitSize) { + init(InitSize); + return; + } + + // Otherwise, initialize it with zero buckets to avoid the allocation. + TheTable = nullptr; + NumBuckets = 0; + NumItems = 0; + NumTombstones = 0; +} + +void StringMapImpl::init(unsigned InitSize) { + assert((InitSize & (InitSize-1)) == 0 && + "Init Size must be a power of 2 or zero!"); + NumBuckets = InitSize ? InitSize : 16; + NumItems = 0; + NumTombstones = 0; + + TheTable = (StringMapEntryBase **)calloc(NumBuckets+1, + sizeof(StringMapEntryBase **) + + sizeof(unsigned)); + + // Allocate one extra bucket, set it to look filled so the iterators stop at + // end. + TheTable[NumBuckets] = (StringMapEntryBase*)2; +} + + +/// LookupBucketFor - Look up the bucket that the specified string should end +/// up in. If it already exists as a key in the map, the Item pointer for the +/// specified bucket will be non-null. Otherwise, it will be null. In either +/// case, the FullHashValue field of the bucket will be set to the hash value +/// of the string. +unsigned StringMapImpl::LookupBucketFor(StringRef Name) { + unsigned HTSize = NumBuckets; + if (HTSize == 0) { // Hash table unallocated so far? + init(16); + HTSize = NumBuckets; + } + unsigned FullHashValue = HashString(Name); + unsigned BucketNo = FullHashValue & (HTSize-1); + unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1); + + unsigned ProbeAmt = 1; + int FirstTombstone = -1; + while (1) { + StringMapEntryBase *BucketItem = TheTable[BucketNo]; + // If we found an empty bucket, this key isn't in the table yet, return it. + if (!BucketItem) { + // If we found a tombstone, we want to reuse the tombstone instead of an + // empty bucket. This reduces probing. + if (FirstTombstone != -1) { + HashTable[FirstTombstone] = FullHashValue; + return FirstTombstone; + } + + HashTable[BucketNo] = FullHashValue; + return BucketNo; + } + + if (BucketItem == getTombstoneVal()) { + // Skip over tombstones. However, remember the first one we see. + if (FirstTombstone == -1) FirstTombstone = BucketNo; + } else if (HashTable[BucketNo] == FullHashValue) { + // If the full hash value matches, check deeply for a match. The common + // case here is that we are only looking at the buckets (for item info + // being non-null and for the full hash value) not at the items. This + // is important for cache locality. + + // Do the comparison like this because Name isn't necessarily + // null-terminated! + char *ItemStr = (char*)BucketItem+ItemSize; + if (Name == StringRef(ItemStr, BucketItem->getKeyLength())) { + // We found a match! + return BucketNo; + } + } + + // Okay, we didn't find the item. Probe to the next bucket. + BucketNo = (BucketNo+ProbeAmt) & (HTSize-1); + + // Use quadratic probing, it has fewer clumping artifacts than linear + // probing and has good cache behavior in the common case. + ++ProbeAmt; + } +} + + +/// FindKey - Look up the bucket that contains the specified key. If it exists +/// in the map, return the bucket number of the key. Otherwise return -1. +/// This does not modify the map. +int StringMapImpl::FindKey(StringRef Key) const { + unsigned HTSize = NumBuckets; + if (HTSize == 0) return -1; // Really empty table? + unsigned FullHashValue = HashString(Key); + unsigned BucketNo = FullHashValue & (HTSize-1); + unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1); + + unsigned ProbeAmt = 1; + while (1) { + StringMapEntryBase *BucketItem = TheTable[BucketNo]; + // If we found an empty bucket, this key isn't in the table yet, return. + if (!BucketItem) + return -1; + + if (BucketItem == getTombstoneVal()) { + // Ignore tombstones. + } else if (HashTable[BucketNo] == FullHashValue) { + // If the full hash value matches, check deeply for a match. The common + // case here is that we are only looking at the buckets (for item info + // being non-null and for the full hash value) not at the items. This + // is important for cache locality. + + // Do the comparison like this because NameStart isn't necessarily + // null-terminated! + char *ItemStr = (char*)BucketItem+ItemSize; + if (Key == StringRef(ItemStr, BucketItem->getKeyLength())) { + // We found a match! + return BucketNo; + } + } + + // Okay, we didn't find the item. Probe to the next bucket. + BucketNo = (BucketNo+ProbeAmt) & (HTSize-1); + + // Use quadratic probing, it has fewer clumping artifacts than linear + // probing and has good cache behavior in the common case. + ++ProbeAmt; + } +} + +/// RemoveKey - Remove the specified StringMapEntry from the table, but do not +/// delete it. This aborts if the value isn't in the table. +void StringMapImpl::RemoveKey(StringMapEntryBase *V) { + const char *VStr = (char*)V + ItemSize; + StringMapEntryBase *V2 = RemoveKey(StringRef(VStr, V->getKeyLength())); + (void)V2; + assert(V == V2 && "Didn't find key?"); +} + +/// RemoveKey - Remove the StringMapEntry for the specified key from the +/// table, returning it. If the key is not in the table, this returns null. +StringMapEntryBase *StringMapImpl::RemoveKey(StringRef Key) { + int Bucket = FindKey(Key); + if (Bucket == -1) return nullptr; + + StringMapEntryBase *Result = TheTable[Bucket]; + TheTable[Bucket] = getTombstoneVal(); + --NumItems; + ++NumTombstones; + assert(NumItems + NumTombstones <= NumBuckets); + + return Result; +} + + + +/// RehashTable - Grow the table, redistributing values into the buckets with +/// the appropriate mod-of-hashtable-size. +unsigned StringMapImpl::RehashTable(unsigned BucketNo) { + unsigned NewSize; + unsigned *HashTable = (unsigned *)(TheTable + NumBuckets + 1); + + // If the hash table is now more than 3/4 full, or if fewer than 1/8 of + // the buckets are empty (meaning that many are filled with tombstones), + // grow/rehash the table. + if (NumItems * 4 > NumBuckets * 3) { + NewSize = NumBuckets*2; + } else if (NumBuckets - (NumItems + NumTombstones) <= NumBuckets / 8) { + NewSize = NumBuckets; + } else { + return BucketNo; + } + + unsigned NewBucketNo = BucketNo; + // Allocate one extra bucket which will always be non-empty. This allows the + // iterators to stop at end. + StringMapEntryBase **NewTableArray = + (StringMapEntryBase **)calloc(NewSize+1, sizeof(StringMapEntryBase *) + + sizeof(unsigned)); + unsigned *NewHashArray = (unsigned *)(NewTableArray + NewSize + 1); + NewTableArray[NewSize] = (StringMapEntryBase*)2; + + // Rehash all the items into their new buckets. Luckily :) we already have + // the hash values available, so we don't have to rehash any strings. + for (unsigned I = 0, E = NumBuckets; I != E; ++I) { + StringMapEntryBase *Bucket = TheTable[I]; + if (Bucket && Bucket != getTombstoneVal()) { + // Fast case, bucket available. + unsigned FullHash = HashTable[I]; + unsigned NewBucket = FullHash & (NewSize-1); + if (!NewTableArray[NewBucket]) { + NewTableArray[FullHash & (NewSize-1)] = Bucket; + NewHashArray[FullHash & (NewSize-1)] = FullHash; + if (I == BucketNo) + NewBucketNo = NewBucket; + continue; + } + + // Otherwise probe for a spot. + unsigned ProbeSize = 1; + do { + NewBucket = (NewBucket + ProbeSize++) & (NewSize-1); + } while (NewTableArray[NewBucket]); + + // Finally found a slot. Fill it in. + NewTableArray[NewBucket] = Bucket; + NewHashArray[NewBucket] = FullHash; + if (I == BucketNo) + NewBucketNo = NewBucket; + } + } + + free(TheTable); + + TheTable = NewTableArray; + NumBuckets = NewSize; + NumTombstones = 0; + return NewBucketNo; +} diff --git a/src/llvm/StringRef.cpp b/src/llvm/StringRef.cpp new file mode 100644 index 0000000000..f12318c162 --- /dev/null +++ b/src/llvm/StringRef.cpp @@ -0,0 +1,393 @@ +//===-- StringRef.cpp - Lightweight String References ---------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/StringRef.h" +#include "llvm/SmallVector.h" +#include +#include + +using namespace llvm; + +// MSVC emits references to this into the translation units which reference it. +#ifndef _MSC_VER +const size_t StringRef::npos; +#endif + +static char ascii_tolower(char x) { + if (x >= 'A' && x <= 'Z') + return x - 'A' + 'a'; + return x; +} + +static char ascii_toupper(char x) { + if (x >= 'a' && x <= 'z') + return x - 'a' + 'A'; + return x; +} + +static bool ascii_isdigit(char x) { + return x >= '0' && x <= '9'; +} + +// strncasecmp() is not available on non-POSIX systems, so define an +// alternative function here. +static int ascii_strncasecmp(const char *LHS, const char *RHS, size_t Length) { + for (size_t I = 0; I < Length; ++I) { + unsigned char LHC = ascii_tolower(LHS[I]); + unsigned char RHC = ascii_tolower(RHS[I]); + if (LHC != RHC) + return LHC < RHC ? -1 : 1; + } + return 0; +} + +/// compare_lower - Compare strings, ignoring case. +int StringRef::compare_lower(StringRef RHS) const { + if (int Res = ascii_strncasecmp(Data, RHS.Data, std::min(Length, RHS.Length))) + return Res; + if (Length == RHS.Length) + return 0; + return Length < RHS.Length ? -1 : 1; +} + +/// Check if this string starts with the given \p Prefix, ignoring case. +bool StringRef::startswith_lower(StringRef Prefix) const { + return Length >= Prefix.Length && + ascii_strncasecmp(Data, Prefix.Data, Prefix.Length) == 0; +} + +/// Check if this string ends with the given \p Suffix, ignoring case. +bool StringRef::endswith_lower(StringRef Suffix) const { + return Length >= Suffix.Length && + ascii_strncasecmp(end() - Suffix.Length, Suffix.Data, Suffix.Length) == 0; +} + +/// compare_numeric - Compare strings, handle embedded numbers. +int StringRef::compare_numeric(StringRef RHS) const { + for (size_t I = 0, E = std::min(Length, RHS.Length); I != E; ++I) { + // Check for sequences of digits. + if (ascii_isdigit(Data[I]) && ascii_isdigit(RHS.Data[I])) { + // The longer sequence of numbers is considered larger. + // This doesn't really handle prefixed zeros well. + size_t J; + for (J = I + 1; J != E + 1; ++J) { + bool ld = J < Length && ascii_isdigit(Data[J]); + bool rd = J < RHS.Length && ascii_isdigit(RHS.Data[J]); + if (ld != rd) + return rd ? -1 : 1; + if (!rd) + break; + } + // The two number sequences have the same length (J-I), just memcmp them. + if (int Res = compareMemory(Data + I, RHS.Data + I, J - I)) + return Res < 0 ? -1 : 1; + // Identical number sequences, continue search after the numbers. + I = J - 1; + continue; + } + if (Data[I] != RHS.Data[I]) + return (unsigned char)Data[I] < (unsigned char)RHS.Data[I] ? -1 : 1; + } + if (Length == RHS.Length) + return 0; + return Length < RHS.Length ? -1 : 1; +} + +//===----------------------------------------------------------------------===// +// String Operations +//===----------------------------------------------------------------------===// + +std::string StringRef::lower() const { + std::string Result(size(), char()); + for (size_type i = 0, e = size(); i != e; ++i) { + Result[i] = ascii_tolower(Data[i]); + } + return Result; +} + +std::string StringRef::upper() const { + std::string Result(size(), char()); + for (size_type i = 0, e = size(); i != e; ++i) { + Result[i] = ascii_toupper(Data[i]); + } + return Result; +} + +//===----------------------------------------------------------------------===// +// String Searching +//===----------------------------------------------------------------------===// + + +/// find - Search for the first string \arg Str in the string. +/// +/// \return - The index of the first occurrence of \arg Str, or npos if not +/// found. +size_t StringRef::find(StringRef Str, size_t From) const { + size_t N = Str.size(); + if (N > Length) + return npos; + + // For short haystacks or unsupported needles fall back to the naive algorithm + if (Length < 16 || N > 255 || N == 0) { + for (size_t e = Length - N + 1, i = std::min(From, e); i != e; ++i) + if (substr(i, N).equals(Str)) + return i; + return npos; + } + + if (From >= Length) + return npos; + + // Build the bad char heuristic table, with uint8_t to reduce cache thrashing. + uint8_t BadCharSkip[256]; + std::memset(BadCharSkip, N, 256); + for (unsigned i = 0; i != N-1; ++i) + BadCharSkip[(uint8_t)Str[i]] = N-1-i; + + unsigned Len = Length-From, Pos = From; + while (Len >= N) { + if (substr(Pos, N).equals(Str)) // See if this is the correct substring. + return Pos; + + // Otherwise skip the appropriate number of bytes. + uint8_t Skip = BadCharSkip[(uint8_t)(*this)[Pos+N-1]]; + Len -= Skip; + Pos += Skip; + } + + return npos; +} + +/// rfind - Search for the last string \arg Str in the string. +/// +/// \return - The index of the last occurrence of \arg Str, or npos if not +/// found. +size_t StringRef::rfind(StringRef Str) const { + size_t N = Str.size(); + if (N > Length) + return npos; + for (size_t i = Length - N + 1, e = 0; i != e;) { + --i; + if (substr(i, N).equals(Str)) + return i; + } + return npos; +} + +/// find_first_of - Find the first character in the string that is in \arg +/// Chars, or npos if not found. +/// +/// Note: O(size() + Chars.size()) +StringRef::size_type StringRef::find_first_of(StringRef Chars, + size_t From) const { + std::bitset<1 << CHAR_BIT> CharBits; + for (size_type i = 0; i != Chars.size(); ++i) + CharBits.set((unsigned char)Chars[i]); + + for (size_type i = std::min(From, Length), e = Length; i != e; ++i) + if (CharBits.test((unsigned char)Data[i])) + return i; + return npos; +} + +/// find_first_not_of - Find the first character in the string that is not +/// \arg C or npos if not found. +StringRef::size_type StringRef::find_first_not_of(char C, size_t From) const { + for (size_type i = std::min(From, Length), e = Length; i != e; ++i) + if (Data[i] != C) + return i; + return npos; +} + +/// find_first_not_of - Find the first character in the string that is not +/// in the string \arg Chars, or npos if not found. +/// +/// Note: O(size() + Chars.size()) +StringRef::size_type StringRef::find_first_not_of(StringRef Chars, + size_t From) const { + std::bitset<1 << CHAR_BIT> CharBits; + for (size_type i = 0; i != Chars.size(); ++i) + CharBits.set((unsigned char)Chars[i]); + + for (size_type i = std::min(From, Length), e = Length; i != e; ++i) + if (!CharBits.test((unsigned char)Data[i])) + return i; + return npos; +} + +/// find_last_of - Find the last character in the string that is in \arg C, +/// or npos if not found. +/// +/// Note: O(size() + Chars.size()) +StringRef::size_type StringRef::find_last_of(StringRef Chars, + size_t From) const { + std::bitset<1 << CHAR_BIT> CharBits; + for (size_type i = 0; i != Chars.size(); ++i) + CharBits.set((unsigned char)Chars[i]); + + for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i) + if (CharBits.test((unsigned char)Data[i])) + return i; + return npos; +} + +/// find_last_not_of - Find the last character in the string that is not +/// \arg C, or npos if not found. +StringRef::size_type StringRef::find_last_not_of(char C, size_t From) const { + for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i) + if (Data[i] != C) + return i; + return npos; +} + +/// find_last_not_of - Find the last character in the string that is not in +/// \arg Chars, or npos if not found. +/// +/// Note: O(size() + Chars.size()) +StringRef::size_type StringRef::find_last_not_of(StringRef Chars, + size_t From) const { + std::bitset<1 << CHAR_BIT> CharBits; + for (size_type i = 0, e = Chars.size(); i != e; ++i) + CharBits.set((unsigned char)Chars[i]); + + for (size_type i = std::min(From, Length) - 1, e = -1; i != e; --i) + if (!CharBits.test((unsigned char)Data[i])) + return i; + return npos; +} + +void StringRef::split(SmallVectorImpl &A, + StringRef Separators, int MaxSplit, + bool KeepEmpty) const { + StringRef rest = *this; + + // rest.data() is used to distinguish cases like "a," that splits into + // "a" + "" and "a" that splits into "a" + 0. + for (int splits = 0; + rest.data() != nullptr && (MaxSplit < 0 || splits < MaxSplit); + ++splits) { + std::pair p = rest.split(Separators); + + if (KeepEmpty || p.first.size() != 0) + A.push_back(p.first); + rest = p.second; + } + // If we have a tail left, add it. + if (rest.data() != nullptr && (rest.size() != 0 || KeepEmpty)) + A.push_back(rest); +} + +//===----------------------------------------------------------------------===// +// Helpful Algorithms +//===----------------------------------------------------------------------===// + +/// count - Return the number of non-overlapped occurrences of \arg Str in +/// the string. +size_t StringRef::count(StringRef Str) const { + size_t Count = 0; + size_t N = Str.size(); + if (N > Length) + return 0; + for (size_t i = 0, e = Length - N + 1; i != e; ++i) + if (substr(i, N).equals(Str)) + ++Count; + return Count; +} + +static unsigned GetAutoSenseRadix(StringRef &Str) { + if (Str.startswith("0x")) { + Str = Str.substr(2); + return 16; + } + + if (Str.startswith("0b")) { + Str = Str.substr(2); + return 2; + } + + if (Str.startswith("0o")) { + Str = Str.substr(2); + return 8; + } + + if (Str.startswith("0")) + return 8; + + return 10; +} + + +/// GetAsUnsignedInteger - Workhorse method that converts a integer character +/// sequence of radix up to 36 to an unsigned long long value. +bool llvm::getAsUnsignedInteger(StringRef Str, unsigned Radix, + unsigned long long &Result) { + // Autosense radix if not specified. + if (Radix == 0) + Radix = GetAutoSenseRadix(Str); + + // Empty strings (after the radix autosense) are invalid. + if (Str.empty()) return true; + + // Parse all the bytes of the string given this radix. Watch for overflow. + Result = 0; + while (!Str.empty()) { + unsigned CharVal; + if (Str[0] >= '0' && Str[0] <= '9') + CharVal = Str[0]-'0'; + else if (Str[0] >= 'a' && Str[0] <= 'z') + CharVal = Str[0]-'a'+10; + else if (Str[0] >= 'A' && Str[0] <= 'Z') + CharVal = Str[0]-'A'+10; + else + return true; + + // If the parsed value is larger than the integer radix, the string is + // invalid. + if (CharVal >= Radix) + return true; + + // Add in this character. + unsigned long long PrevResult = Result; + Result = Result*Radix+CharVal; + + // Check for overflow by shifting back and seeing if bits were lost. + if (Result/Radix < PrevResult) + return true; + + Str = Str.substr(1); + } + + return false; +} + +bool llvm::getAsSignedInteger(StringRef Str, unsigned Radix, + long long &Result) { + unsigned long long ULLVal; + + // Handle positive strings first. + if (Str.empty() || Str.front() != '-') { + if (getAsUnsignedInteger(Str, Radix, ULLVal) || + // Check for value so large it overflows a signed value. + (long long)ULLVal < 0) + return true; + Result = ULLVal; + return false; + } + + // Get the positive part of the value. + if (getAsUnsignedInteger(Str.substr(1), Radix, ULLVal) || + // Reject values so large they'd overflow as negative signed, but allow + // "-0". This negates the unsigned so that the negative isn't undefined + // on signed overflow. + (long long)-ULLVal > 0) + return true; + + Result = -ULLVal; + return false; +} diff --git a/src/support/Base64.cpp b/src/support/Base64.cpp new file mode 100644 index 0000000000..88fe28a47b --- /dev/null +++ b/src/support/Base64.cpp @@ -0,0 +1,152 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +/* ==================================================================== + * Copyright (c) 1995-1999 The Apache Group. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * 4. The names "Apache Server" and "Apache Group" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the Apache Group + * for use in the Apache HTTP server project (http://www.apache.org/)." + * + * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Group and was originally based + * on public domain software written at the National Center for + * Supercomputing Applications, University of Illinois, Urbana-Champaign. + * For more information on the Apache Group and the Apache HTTP server + * project, please see . + * + */ + +#include "support/Base64.h" + +namespace wpi { + +// aaaack but it's fast and const should make it shared text page. +static const unsigned char pr2six[256] = +{ + // ASCII table + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, + 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, + 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 +}; + +std::size_t Base64Decode(llvm::StringRef encoded, std::string* plain) { + const unsigned char *end = encoded.bytes_begin(); + while (pr2six[*end] <= 63 && end != encoded.bytes_end()) ++end; + std::size_t nprbytes = end - encoded.bytes_begin(); + + plain->clear(); + if (nprbytes == 0) + return 0; + plain->reserve(((nprbytes + 3) / 4) * 3); + + const unsigned char *cur = encoded.bytes_begin(); + + while (nprbytes > 4) { + (*plain) += (pr2six[cur[0]] << 2 | pr2six[cur[1]] >> 4); + (*plain) += (pr2six[cur[1]] << 4 | pr2six[cur[2]] >> 2); + (*plain) += (pr2six[cur[2]] << 6 | pr2six[cur[3]]); + cur += 4; + nprbytes -= 4; + } + + // Note: (nprbytes == 1) would be an error, so just ignore that case + if (nprbytes > 1) (*plain) += (pr2six[cur[0]] << 2 | pr2six[cur[1]] >> 4); + if (nprbytes > 2) (*plain) += (pr2six[cur[1]] << 4 | pr2six[cur[2]] >> 2); + if (nprbytes > 3) (*plain) += (pr2six[cur[2]] << 6 | pr2six[cur[3]]); + + return (end - encoded.bytes_begin()) + ((4 - nprbytes) & 3); +} + +static const char basis_64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +void Base64Encode(llvm::StringRef plain, std::string* encoded) { + encoded->clear(); + if (plain.empty()) + return; + std::size_t len = plain.size(); + encoded->reserve(((len + 2) / 3 * 4) + 1); + + std::size_t i; + for (i = 0; (i + 2) < len; i += 3) { + (*encoded) += basis_64[(plain[i] >> 2) & 0x3F]; + (*encoded) += + basis_64[((plain[i] & 0x3) << 4) | ((int)(plain[i + 1] & 0xF0) >> 4)]; + (*encoded) += basis_64[((plain[i + 1] & 0xF) << 2) | + ((int)(plain[i + 2] & 0xC0) >> 6)]; + (*encoded) += basis_64[plain[i + 2] & 0x3F]; + } + if (i < len) { + (*encoded) += basis_64[(plain[i] >> 2) & 0x3F]; + if (i == (len - 1)) { + (*encoded) += basis_64[((plain[i] & 0x3) << 4)]; + (*encoded) += '='; + } else { + (*encoded) += + basis_64[((plain[i] & 0x3) << 4) | ((int)(plain[i + 1] & 0xF0) >> 4)]; + (*encoded) += basis_64[((plain[i + 1] & 0xF) << 2)]; + } + (*encoded) += '='; + } +} + +} // namespace wpi diff --git a/src/support/SafeThread.cpp b/src/support/SafeThread.cpp new file mode 100644 index 0000000000..434d933b8b --- /dev/null +++ b/src/support/SafeThread.cpp @@ -0,0 +1,31 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#include "support/SafeThread.h" + +using namespace wpi; + +void detail::SafeThreadOwnerBase::Start(SafeThread* thr) { + SafeThread* curthr = nullptr; + SafeThread* newthr = thr; + if (!m_thread.compare_exchange_strong(curthr, newthr)) { + delete newthr; + return; + } + std::thread([=]() { + newthr->Main(); + delete newthr; + }).detach(); +} + +void detail::SafeThreadOwnerBase::Stop() { + SafeThread* thr = m_thread.exchange(nullptr); + if (!thr) return; + std::lock_guard lock(thr->m_mutex); + thr->m_active = false; + thr->m_cond.notify_one(); +} diff --git a/src/support/leb128.cpp b/src/support/leb128.cpp new file mode 100644 index 0000000000..002ee43673 --- /dev/null +++ b/src/support/leb128.cpp @@ -0,0 +1,119 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#include "support/leb128.h" + +#include "support/raw_istream.h" + +namespace wpi { + +/** + * Get size of unsigned LEB128 data + * @val: value + * + * Determine the number of bytes required to encode an unsigned LEB128 datum. + * The algorithm is taken from Appendix C of the DWARF 3 spec. For information + * on the encodings refer to section "7.6 - Variable Length Data". Return + * the number of bytes required. + */ +std::size_t SizeUleb128(unsigned long val) { + std::size_t count = 0; + do { + val >>= 7; + ++count; + } while (val != 0); + return count; +} + +/** + * Write unsigned LEB128 data + * @addr: the address where the ULEB128 data is to be stored + * @val: value to be stored + * + * Encode an unsigned LEB128 encoded datum. The algorithm is taken + * from Appendix C of the DWARF 3 spec. For information on the + * encodings refer to section "7.6 - Variable Length Data". Return + * the number of bytes written. + */ +std::size_t WriteUleb128(llvm::SmallVectorImpl& dest, unsigned long val) { + std::size_t count = 0; + + do { + unsigned char byte = val & 0x7f; + val >>= 7; + + if (val != 0) + byte |= 0x80; // mark this byte to show that more bytes will follow + + dest.push_back(byte); + count++; + } while (val != 0); + + return count; +} + +/** + * Read unsigned LEB128 data + * @addr: the address where the ULEB128 data is stored + * @ret: address to store the result + * + * Decode an unsigned LEB128 encoded datum. The algorithm is taken + * from Appendix C of the DWARF 3 spec. For information on the + * encodings refer to section "7.6 - Variable Length Data". Return + * the number of bytes read. + */ +std::size_t ReadUleb128(const char* addr, unsigned long* ret) { + unsigned long result = 0; + int shift = 0; + std::size_t count = 0; + + while (1) { + unsigned char byte = *reinterpret_cast(addr); + addr++; + count++; + + result |= (byte & 0x7f) << shift; + shift += 7; + + if (!(byte & 0x80)) break; + } + + *ret = result; + + return count; +} + +/** + * Read unsigned LEB128 data from a stream + * @is: the input stream where the ULEB128 data is to be read from + * @ret: address to store the result + * + * Decode an unsigned LEB128 encoded datum. The algorithm is taken + * from Appendix C of the DWARF 3 spec. For information on the + * encodings refer to section "7.6 - Variable Length Data". Return + * false on stream error, true on success. + */ +bool ReadUleb128(raw_istream& is, unsigned long* ret) { + unsigned long result = 0; + int shift = 0; + + while (1) { + unsigned char byte; + if (!is.read((char*)&byte, 1)) return false; + + result |= (byte & 0x7f) << shift; + shift += 7; + + if (!(byte & 0x80)) break; + } + + *ret = result; + + return true; +} + +} // namespace wpi diff --git a/src/support/raw_istream.cpp b/src/support/raw_istream.cpp new file mode 100644 index 0000000000..13af6b97a8 --- /dev/null +++ b/src/support/raw_istream.cpp @@ -0,0 +1,20 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#include "support/raw_istream.h" + +#include + +using namespace wpi; + +bool raw_mem_istream::read(void* data, std::size_t len) { + if (len > m_left) return false; + std::memcpy(data, m_cur, len); + m_cur += len; + m_left -= len; + return true; +} diff --git a/src/support/raw_socket_istream.cpp b/src/support/raw_socket_istream.cpp new file mode 100644 index 0000000000..a4dd1e4d5a --- /dev/null +++ b/src/support/raw_socket_istream.cpp @@ -0,0 +1,26 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#include "support/raw_socket_istream.h" + +using namespace wpi; + +bool raw_socket_istream::read(void* data, std::size_t len) { + char* cdata = static_cast(data); + std::size_t pos = 0; + + while (pos < len) { + NetworkStream::Error err; + std::size_t count = + m_stream.receive(&cdata[pos], len - pos, &err, m_timeout); + if (count == 0) return false; + pos += count; + } + return true; +} + +void raw_socket_istream::close() { m_stream.close(); } diff --git a/src/support/timestamp.cpp b/src/support/timestamp.cpp new file mode 100644 index 0000000000..9b21e5e2d7 --- /dev/null +++ b/src/support/timestamp.cpp @@ -0,0 +1,89 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ +#include "support/timestamp.h" + +#ifdef _WIN32 +#include +#include +#include +#else +#include +#endif + +// offset in microseconds +static unsigned long long zerotime() { +#ifdef _WIN32 + FILETIME ft; + unsigned long long tmpres = 0; + // 100-nanosecond intervals since January 1, 1601 (UTC) + // which means 0.1 us + GetSystemTimeAsFileTime(&ft); + tmpres |= ft.dwHighDateTime; + tmpres <<= 32; + tmpres |= ft.dwLowDateTime; + // January 1st, 1970 - January 1st, 1601 UTC ~ 369 years + // or 116444736000000000 us + static const unsigned long long deltaepoch = 116444736000000000ull; + tmpres -= deltaepoch; + return tmpres; +#else + // 100-ns intervals + using namespace std::chrono; + return duration_cast( + high_resolution_clock::now().time_since_epoch()).count() / 100u; +#endif +} + +static unsigned long long timestamp() { +#ifdef _WIN32 + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + // there is an imprecision with the initial value, + // but what matters is that timestamps are monotonic and consistent + return static_cast(li.QuadPart); +#else + // 100-ns intervals + using namespace std::chrono; + return duration_cast( + steady_clock::now().time_since_epoch()).count() / 100u; +#endif +} + +#ifdef _WIN32 +static unsigned long long update_frequency() { + LARGE_INTEGER li; + if (!QueryPerformanceFrequency(&li) || !li.QuadPart) { + // log something + std::terminate(); + } + return static_cast(li.QuadPart); +} +#endif + +static const unsigned long long zerotime_val = zerotime(); +static const unsigned long long offset_val = timestamp(); +#ifdef _WIN32 +static const unsigned long long frequency_val = update_frequency(); +#endif + +unsigned long long wpi::Now() { +#ifdef _WIN32 + assert(offset_val > 0u); + assert(frequency_val > 0u); + unsigned long long delta = timestamp() - offset_val; + // because the frequency is in update per seconds, we have to multiply the + // delta by 10,000,000 + unsigned long long delta_in_us = delta * 10000000ull / frequency_val; + return delta_in_us + zerotime_val; +#else + return zerotime_val + timestamp() - offset_val; +#endif +} + +unsigned long long WPI_Now() { + return wpi::Now(); +} diff --git a/src/tcpsockets/SocketError.cpp b/src/tcpsockets/SocketError.cpp new file mode 100644 index 0000000000..a2628fdd2b --- /dev/null +++ b/src/tcpsockets/SocketError.cpp @@ -0,0 +1,31 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#include "tcpsockets/SocketError.h" + +#ifdef _WIN32 +#include +#else +#include +#endif + +namespace wpi { + +std::string SocketStrerror(int code) { +#ifdef _WIN32 + LPSTR errstr = nullptr; + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + 0, code, 0, (LPSTR)&errstr, 0, 0); + std::string rv(errstr); + LocalFree(errstr); + return rv; +#else + return strerror(code); +#endif +} + +} // namespace wpi diff --git a/src/tcpsockets/TCPAcceptor.cpp b/src/tcpsockets/TCPAcceptor.cpp new file mode 100644 index 0000000000..9d8039ccab --- /dev/null +++ b/src/tcpsockets/TCPAcceptor.cpp @@ -0,0 +1,189 @@ +/* + TCPAcceptor.cpp + + TCPAcceptor class definition. TCPAcceptor provides methods to passively + establish TCP/IP connections with clients. + + ------------------------------------------ + + Copyright © 2013 [Vic Hargrave - http://vichargrave.com] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "tcpsockets/TCPAcceptor.h" + +#include +#include +#ifdef _WIN32 +#include +#pragma comment(lib, "Ws2_32.lib") +#else +#include +#include +#include +#include +#endif + +#include "llvm/SmallString.h" +#include "support/Logger.h" +#include "tcpsockets/SocketError.h" + +using namespace wpi; + +TCPAcceptor::TCPAcceptor(int port, const char* address, Logger& logger) + : m_lsd(0), + m_port(port), + m_address(address), + m_listening(false), + m_logger(logger) { + m_shutdown = false; +#ifdef _WIN32 + WSAData wsaData; + WORD wVersionRequested = MAKEWORD(2, 2); + WSAStartup(wVersionRequested, &wsaData); +#endif +} + +TCPAcceptor::~TCPAcceptor() { + if (m_lsd > 0) { + shutdown(); +#ifdef _WIN32 + closesocket(m_lsd); +#else + close(m_lsd); +#endif + } +#ifdef _WIN32 + WSACleanup(); +#endif +} + +int TCPAcceptor::start() { + if (m_listening) return 0; + + m_lsd = socket(PF_INET, SOCK_STREAM, 0); + if (m_lsd < 0) { + WPI_ERROR(m_logger, "could not create socket"); + return -1; + } + struct sockaddr_in address; + + std::memset(&address, 0, sizeof(address)); + address.sin_family = PF_INET; + if (m_address.size() > 0) { +#ifdef _WIN32 + llvm::SmallString<128> addr_copy(m_address); + addr_copy.push_back('\0'); + int size = sizeof(address); + WSAStringToAddress(addr_copy.data(), PF_INET, nullptr, (struct sockaddr*)&address, &size); +#else + inet_pton(PF_INET, m_address.c_str(), &(address.sin_addr)); +#endif + } else { + address.sin_addr.s_addr = INADDR_ANY; + } + address.sin_port = htons(m_port); + + int optval = 1; + setsockopt(m_lsd, SOL_SOCKET, SO_REUSEADDR, (char*)&optval, sizeof optval); + + int result = bind(m_lsd, (struct sockaddr*)&address, sizeof(address)); + if (result != 0) { + WPI_ERROR(m_logger, "bind() failed: " << SocketStrerror()); + return result; + } + + result = listen(m_lsd, 5); + if (result != 0) { + WPI_ERROR(m_logger, "listen() failed: " << SocketStrerror()); + return result; + } + m_listening = true; + return result; +} + +void TCPAcceptor::shutdown() { + m_shutdown = true; +#ifdef _WIN32 + ::shutdown(m_lsd, SD_BOTH); + + // this is ugly, but the easiest way to do this + // force wakeup of accept() with a non-blocking connect to ourselves + struct sockaddr_in address; + + std::memset(&address, 0, sizeof(address)); + address.sin_family = PF_INET; + llvm::SmallString<128> addr_copy; + if (m_address.size() > 0) + addr_copy = m_address; + else + addr_copy = "127.0.0.1"; + addr_copy.push_back('\0'); + int size = sizeof(address); + if (WSAStringToAddress(addr_copy.data(), PF_INET, nullptr, + (struct sockaddr*)&address, &size) != 0) + return; + address.sin_port = htons(m_port); + + fd_set sdset; + struct timeval tv; + int result = -1, valopt, sd = socket(AF_INET, SOCK_STREAM, 0); + if (sd < 0) return; + + // Set socket to non-blocking + u_long mode = 1; + ioctlsocket(sd, FIONBIO, &mode); + + // Try to connect + ::connect(sd, (struct sockaddr*)&address, sizeof(address)); + + // Close + ::closesocket(sd); + +#else + ::shutdown(m_lsd, SHUT_RDWR); + int nullfd = ::open("/dev/null", O_RDONLY); + if (nullfd >= 0) { + ::dup2(nullfd, m_lsd); + ::close(nullfd); + } +#endif +} + +std::unique_ptr TCPAcceptor::accept() { + if (!m_listening || m_shutdown) return nullptr; + + struct sockaddr_in address; +#ifdef _WIN32 + int len = sizeof(address); +#else + socklen_t len = sizeof(address); +#endif + std::memset(&address, 0, sizeof(address)); + int sd = ::accept(m_lsd, (struct sockaddr*)&address, &len); + if (sd < 0) { + if (!m_shutdown) + WPI_ERROR(m_logger, "accept() failed: " << SocketStrerror()); + return nullptr; + } + if (m_shutdown) { +#ifdef _WIN32 + closesocket(sd); +#else + close(sd); +#endif + return nullptr; + } + return std::unique_ptr(new TCPStream(sd, &address)); +} diff --git a/src/tcpsockets/TCPConnector.cpp b/src/tcpsockets/TCPConnector.cpp new file mode 100644 index 0000000000..8800acd7dd --- /dev/null +++ b/src/tcpsockets/TCPConnector.cpp @@ -0,0 +1,189 @@ +/* + TCPConnector.h + + TCPConnector class definition. TCPConnector provides methods to actively + establish TCP/IP connections with a server. + + ------------------------------------------ + + Copyright © 2013 [Vic Hargrave - http://vichargrave.com] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License +*/ + +#include "tcpsockets/TCPConnector.h" + +#include +#include +#include +#include +#ifdef _WIN32 +#include +#include +#else +#include +#include +#include +#include +#include +#endif + +#include "tcpsockets/TCPStream.h" + +#include "llvm/SmallString.h" +#include "support/Logger.h" +#include "tcpsockets/SocketError.h" + +using namespace wpi; + +static int ResolveHostName(const char* hostname, struct in_addr* addr) { + struct addrinfo hints; + struct addrinfo* res; + + hints.ai_flags = 0; + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = 0; + hints.ai_addrlen = 0; + hints.ai_addr = nullptr; + hints.ai_canonname = nullptr; + hints.ai_next = nullptr; + int result = getaddrinfo(hostname, nullptr, &hints, &res); + if (result == 0) { + std::memcpy(addr, &((struct sockaddr_in*)res->ai_addr)->sin_addr, + sizeof(struct in_addr)); + freeaddrinfo(res); + } + return result; +} + +std::unique_ptr TCPConnector::connect(const char* server, + int port, Logger& logger, + int timeout) { +#ifdef _WIN32 + struct WSAHelper { + WSAHelper() { + WSAData wsaData; + WORD wVersionRequested = MAKEWORD(2, 2); + WSAStartup(wVersionRequested, &wsaData); + } + ~WSAHelper() { WSACleanup(); } + }; + static WSAHelper helper; +#endif + struct sockaddr_in address; + + std::memset(&address, 0, sizeof(address)); + address.sin_family = AF_INET; + if (ResolveHostName(server, &(address.sin_addr)) != 0) { +#ifdef _WIN32 + llvm::SmallString<128> addr_copy(server); + addr_copy.push_back('\0'); + int size = sizeof(address); + if (WSAStringToAddress(addr_copy.data(), PF_INET, nullptr, (struct sockaddr*)&address, &size) != 0) { + WPI_ERROR(logger, "could not resolve " << server << " address"); + return nullptr; + } +#else + inet_pton(PF_INET, server, &(address.sin_addr)); +#endif + } + address.sin_port = htons(port); + + if (timeout == 0) { + int sd = socket(AF_INET, SOCK_STREAM, 0); + if (sd < 0) { + WPI_ERROR(logger, "could not create socket"); + return nullptr; + } + if (::connect(sd, (struct sockaddr*)&address, sizeof(address)) != 0) { + WPI_ERROR(logger, "connect() to " << server << " port " << port << " failed: " << SocketStrerror()); +#ifdef _WIN32 + closesocket(sd); +#else + ::close(sd); +#endif + return nullptr; + } + return std::unique_ptr(new TCPStream(sd, &address)); + } + + fd_set sdset; + struct timeval tv; + socklen_t len; + int result = -1, valopt, sd = socket(AF_INET, SOCK_STREAM, 0); + if (sd < 0) { + WPI_ERROR(logger, "could not create socket"); + return nullptr; + } + + // Set socket to non-blocking +#ifdef _WIN32 + u_long mode = 1; + ioctlsocket(sd, FIONBIO, &mode); +#else + long arg; + arg = fcntl(sd, F_GETFL, nullptr); + arg |= O_NONBLOCK; + fcntl(sd, F_SETFL, arg); +#endif + + // Connect with time limit + if ((result = ::connect(sd, (struct sockaddr*)&address, sizeof(address))) < + 0) { + int my_errno = SocketErrno(); +#ifdef _WIN32 + if (my_errno == WSAEWOULDBLOCK || my_errno == WSAEINPROGRESS) { +#else + if (my_errno == EWOULDBLOCK || my_errno == EINPROGRESS) { +#endif + tv.tv_sec = timeout; + tv.tv_usec = 0; + FD_ZERO(&sdset); + FD_SET(sd, &sdset); + if (select(sd + 1, nullptr, &sdset, nullptr, &tv) > 0) { + len = sizeof(int); + getsockopt(sd, SOL_SOCKET, SO_ERROR, (char*)(&valopt), &len); + if (valopt) { + WPI_ERROR(logger, "select() to " << server << " port " << port << " error " << valopt << " - " << SocketStrerror(valopt)); + } + // connection established + else + result = 0; + } else + WPI_INFO(logger, "connect() to " << server << " port " << port << " timed out"); + } else + WPI_ERROR(logger, "connect() to " << server << " port " << port << " error " << SocketErrno() << " - " << SocketStrerror()); + } + + // Return socket to blocking mode +#ifdef _WIN32 + mode = 0; + ioctlsocket(sd, FIONBIO, &mode); +#else + arg = fcntl(sd, F_GETFL, nullptr); + arg &= (~O_NONBLOCK); + fcntl(sd, F_SETFL, arg); +#endif + + // Create stream object if connected, close if not. + if (result == -1) { +#ifdef _WIN32 + closesocket(sd); +#else + ::close(sd); +#endif + return nullptr; + } + return std::unique_ptr(new TCPStream(sd, &address)); +} diff --git a/src/tcpsockets/TCPStream.cpp b/src/tcpsockets/TCPStream.cpp new file mode 100644 index 0000000000..c87aeabb52 --- /dev/null +++ b/src/tcpsockets/TCPStream.cpp @@ -0,0 +1,159 @@ +/* + TCPStream.h + + TCPStream class definition. TCPStream provides methods to trasnfer + data between peers over a TCP/IP connection. + + ------------------------------------------ + + Copyright © 2013 [Vic Hargrave - http://vichargrave.com] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include "tcpsockets/TCPStream.h" + +#ifdef _WIN32 +#include +#else +#include +#include +#include +#endif + +using namespace wpi; + +TCPStream::TCPStream(int sd, sockaddr_in* address) : m_sd(sd) { + char ip[50]; +#ifdef _WIN32 + unsigned long size = sizeof(ip) - 1; + WSAAddressToString((sockaddr*)address, sizeof sockaddr_in, nullptr, ip, &size); +#else + inet_ntop(PF_INET, (in_addr*)&(address->sin_addr.s_addr), ip, + sizeof(ip) - 1); +#endif + m_peerIP = ip; + m_peerPort = ntohs(address->sin_port); +} + +TCPStream::~TCPStream() { close(); } + +std::size_t TCPStream::send(const char* buffer, std::size_t len, Error* err) { + if (m_sd < 0) { + *err = kConnectionClosed; + return 0; + } +#ifdef _WIN32 + WSABUF wsaBuf; + wsaBuf.buf = const_cast(buffer); + wsaBuf.len = (ULONG)len; + DWORD rv; + bool result = true; + while (WSASend(m_sd, &wsaBuf, 1, &rv, 0, nullptr, nullptr) == SOCKET_ERROR) { + if (WSAGetLastError() != WSAEWOULDBLOCK) { + result = false; + break; + } + Sleep(1); + } + if (!result) { + char Buffer[128]; +#ifdef _MSC_VER + sprintf_s(Buffer, "Send() failed: WSA error=%d\n", WSAGetLastError()); +#else + std::snprintf(Buffer, 128, "Send() failed: WSA error=%d\n", WSAGetLastError()); +#endif + OutputDebugStringA(Buffer); + *err = kConnectionReset; + return 0; + } +#else + ssize_t rv = write(m_sd, buffer, len); + if (rv < 0) { + *err = kConnectionReset; + return 0; + } +#endif + return static_cast(rv); +} + +std::size_t TCPStream::receive(char* buffer, std::size_t len, Error* err, + int timeout) { + if (m_sd < 0) { + *err = kConnectionClosed; + return 0; + } +#ifdef _WIN32 + int rv; +#else + ssize_t rv; +#endif + if (timeout <= 0) { +#ifdef _WIN32 + rv = recv(m_sd, buffer, len, 0); +#else + rv = read(m_sd, buffer, len); +#endif + } + else if (WaitForReadEvent(timeout)) { +#ifdef _WIN32 + rv = recv(m_sd, buffer, len, 0); +#else + rv = read(m_sd, buffer, len); +#endif + } else { + *err = kConnectionTimedOut; + return 0; + } + if (rv < 0) { + *err = kConnectionReset; + return 0; + } + return static_cast(rv); +} + +void TCPStream::close() { + if (m_sd >= 0) { +#ifdef _WIN32 + ::shutdown(m_sd, SD_BOTH); + closesocket(m_sd); +#else + ::shutdown(m_sd, SHUT_RDWR); + ::close(m_sd); +#endif + } + m_sd = -1; +} + +llvm::StringRef TCPStream::getPeerIP() const { return m_peerIP; } + +int TCPStream::getPeerPort() const { return m_peerPort; } + +void TCPStream::setNoDelay() { + int optval = 1; + setsockopt(m_sd, IPPROTO_TCP, TCP_NODELAY, (char*)&optval, sizeof optval); +} + +bool TCPStream::WaitForReadEvent(int timeout) { + fd_set sdset; + struct timeval tv; + + tv.tv_sec = timeout; + tv.tv_usec = 0; + FD_ZERO(&sdset); + FD_SET(m_sd, &sdset); + if (select(m_sd + 1, &sdset, NULL, NULL, &tv) > 0) { + return true; + } + return false; +} diff --git a/unittest/Base64Test.cpp b/unittest/Base64Test.cpp new file mode 100644 index 0000000000..972ca487ad --- /dev/null +++ b/unittest/Base64Test.cpp @@ -0,0 +1,76 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +#include "support/Base64.h" + +#include "gtest/gtest.h" + +namespace wpi { + +struct Base64TestParam { + int plain_len; + const char* plain; + const char* encoded; +}; + +std::ostream& operator<<(std::ostream& os, const Base64TestParam& param) { + os << "Base64TestParam(Len: " << param.plain_len << ", " + << "Plain: \"" << param.plain << "\", " + << "Encoded: \"" << param.encoded << "\")"; + return os; +} + +class Base64Test : public ::testing::TestWithParam { + protected: + llvm::StringRef GetPlain() { + if (GetParam().plain_len < 0) + return llvm::StringRef(GetParam().plain); + else + return llvm::StringRef(GetParam().plain, GetParam().plain_len); + } +}; + +TEST_P(Base64Test, Encode) { + std::string s; + Base64Encode(GetPlain(), &s); + ASSERT_EQ(GetParam().encoded, s); +} + +TEST_P(Base64Test, Decode) { + std::string s; + llvm::StringRef encoded = GetParam().encoded; + EXPECT_EQ(encoded.size(), Base64Decode(encoded, &s)); + ASSERT_EQ(GetPlain(), s); +} + +static Base64TestParam sample[] = { + {-1, "Send reinforcements", "U2VuZCByZWluZm9yY2VtZW50cw=="}, + {-1, "Now is the time for all good coders\n to learn C++", + "Tm93IGlzIHRoZSB0aW1lIGZvciBhbGwgZ29vZCBjb2RlcnMKIHRvIGxlYXJuIEMrKw=="}, + {-1, + "This is line one\nThis is line two\nThis is line three\nAnd so on...\n", + "VGhpcyBpcyBsaW5lIG9uZQpUaGlzIGlzIGxpbmUgdHdvClRoaXMgaXMgbGluZSB0aHJlZQpBb" + "mQgc28gb24uLi4K"}, +}; + +INSTANTIATE_TEST_CASE_P(Base64Sample, Base64Test, ::testing::ValuesIn(sample)); + +static Base64TestParam standard[] = { + {0, "", ""}, + {1, "\0", "AA=="}, + {2, "\0\0", "AAA="}, + {3, "\0\0\0", "AAAA"}, + {1, "\377", "/w=="}, + {2, "\377\377", "//8="}, + {3, "\377\377\377", "////"}, + {2, "\xff\xef", "/+8="}, +}; + +INSTANTIATE_TEST_CASE_P(Base64Standard, Base64Test, + ::testing::ValuesIn(standard)); + +} // namespace wpi diff --git a/unittest/leb128Test.cpp b/unittest/leb128Test.cpp new file mode 100644 index 0000000000..00a79eebd2 --- /dev/null +++ b/unittest/leb128Test.cpp @@ -0,0 +1,114 @@ +/*----------------------------------------------------------------------------*/ +/* Copyright (c) FIRST 2015. All Rights Reserved. */ +/* Open Source Software - may be modified and shared by FRC teams. The code */ +/* must be accompanied by the FIRST BSD license file in the root directory of */ +/* the project. */ +/*----------------------------------------------------------------------------*/ + +//===- llvm/unittest/Support/LEB128Test.cpp - LEB128 function tests -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "support/leb128.h" + +#include "gtest/gtest.h" + +#include +#include + +#include "llvm/SmallString.h" +#include "llvm/StringRef.h" + +#include "support/raw_istream.h" + +namespace wpi { + +TEST(LEB128Test, WriteUleb128) { +#define EXPECT_ULEB128_EQ(EXPECTED, VALUE, PAD) \ + do { \ + llvm::StringRef expected(EXPECTED, sizeof(EXPECTED)-1); \ + llvm::SmallString<32> buf; \ + std::size_t size = WriteUleb128(buf, VALUE); \ + EXPECT_EQ(size, buf.size()); \ + EXPECT_EQ(expected, buf.str()); \ + } while (0) + + // Write ULEB128 + EXPECT_ULEB128_EQ("\x00", 0, 0); + EXPECT_ULEB128_EQ("\x01", 1, 0); + EXPECT_ULEB128_EQ("\x3f", 63, 0); + EXPECT_ULEB128_EQ("\x40", 64, 0); + EXPECT_ULEB128_EQ("\x7f", 0x7f, 0); + EXPECT_ULEB128_EQ("\x80\x01", 0x80, 0); + EXPECT_ULEB128_EQ("\x81\x01", 0x81, 0); + EXPECT_ULEB128_EQ("\x90\x01", 0x90, 0); + EXPECT_ULEB128_EQ("\xff\x01", 0xff, 0); + EXPECT_ULEB128_EQ("\x80\x02", 0x100, 0); + EXPECT_ULEB128_EQ("\x81\x02", 0x101, 0); + +#undef EXPECT_ULEB128_EQ +} + +TEST(LEB128Test, ReadUleb128) { +#define EXPECT_READ_ULEB128_EQ(EXPECTED, VALUE) \ + do { \ + unsigned long val = 0; \ + std::size_t size = ReadUleb128(VALUE, &val); \ + EXPECT_EQ(sizeof(VALUE) - 1, size); \ + EXPECT_EQ(EXPECTED, val); \ + } while (0) + + // Read ULEB128 + EXPECT_READ_ULEB128_EQ(0u, "\x00"); + EXPECT_READ_ULEB128_EQ(1u, "\x01"); + EXPECT_READ_ULEB128_EQ(63u, "\x3f"); + EXPECT_READ_ULEB128_EQ(64u, "\x40"); + EXPECT_READ_ULEB128_EQ(0x7fu, "\x7f"); + EXPECT_READ_ULEB128_EQ(0x80u, "\x80\x01"); + EXPECT_READ_ULEB128_EQ(0x81u, "\x81\x01"); + EXPECT_READ_ULEB128_EQ(0x90u, "\x90\x01"); + EXPECT_READ_ULEB128_EQ(0xffu, "\xff\x01"); + EXPECT_READ_ULEB128_EQ(0x100u, "\x80\x02"); + EXPECT_READ_ULEB128_EQ(0x101u, "\x81\x02"); + EXPECT_READ_ULEB128_EQ(8320u, "\x80\xc1\x80\x80\x10"); + +#undef EXPECT_READ_ULEB128_EQ +} + +TEST(LEB128Test, SizeUleb128) { + // Testing Plan: + // (1) 128 ^ n ............ need (n+1) bytes + // (2) 128 ^ n * 64 ....... need (n+1) bytes + // (3) 128 ^ (n+1) - 1 .... need (n+1) bytes + + EXPECT_EQ(1u, SizeUleb128(0)); // special case + + EXPECT_EQ(1u, SizeUleb128(0x1UL)); + EXPECT_EQ(1u, SizeUleb128(0x40UL)); + EXPECT_EQ(1u, SizeUleb128(0x7fUL)); + + EXPECT_EQ(2u, SizeUleb128(0x80UL)); + EXPECT_EQ(2u, SizeUleb128(0x2000UL)); + EXPECT_EQ(2u, SizeUleb128(0x3fffUL)); + + EXPECT_EQ(3u, SizeUleb128(0x4000UL)); + EXPECT_EQ(3u, SizeUleb128(0x100000UL)); + EXPECT_EQ(3u, SizeUleb128(0x1fffffUL)); + + EXPECT_EQ(4u, SizeUleb128(0x200000UL)); + EXPECT_EQ(4u, SizeUleb128(0x8000000UL)); + EXPECT_EQ(4u, SizeUleb128(0xfffffffUL)); + + EXPECT_EQ(5u, SizeUleb128(0x10000000UL)); + EXPECT_EQ(5u, SizeUleb128(0x40000000UL)); + EXPECT_EQ(5u, SizeUleb128(0x7fffffffUL)); + + EXPECT_EQ(5u, SizeUleb128(UINT32_MAX)); +} + +} // namespace wpi