blob: 52de9160dc9fa4ea921361fda9f61d7f957a3bb2 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CRAZY_LINKER_UTIL_H
#define CRAZY_LINKER_UTIL_H
#include <fcntl.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
#include <cstdlib>
#include <cstring>
#include <type_traits>
#include <utility>
namespace crazy {
// Helper macro to loop around EINTR errors in syscalls.
#define HANDLE_EINTR(expr) TEMP_FAILURE_RETRY(expr)
// Helper macro to tag unused variables. Use in the declaration, between
// the type and name, as in:
// int CRAZY_UNUSED my_var = 0;
#define CRAZY_UNUSED __attribute__((unused))
// Offset in a file indicating a failure.
#define CRAZY_OFFSET_FAILED (-1)
// Helper scoped pointer class.
template <class T>
class ScopedPtr {
public:
ScopedPtr() : ptr_(NULL) {}
explicit ScopedPtr(T* ptr) : ptr_(ptr) {}
~ScopedPtr() { Reset(NULL); }
ScopedPtr(ScopedPtr&& other) noexcept : ptr_(other.ptr_) {
other.ptr_ = nullptr;
}
ScopedPtr& operator=(ScopedPtr&& other) noexcept {
if (this != &other) {
delete ptr_;
ptr_ = other.ptr_;
other.ptr_ = nullptr;
}
return *this;
}
T* Release() {
T* ret = ptr_;
ptr_ = NULL;
return ret;
}
void Reset(T* ptr) {
delete ptr_;
ptr_ = ptr;
}
T* Get() { return ptr_; }
T& operator*() { return *ptr_; }
T* operator->() { return ptr_; }
private:
T* ptr_;
};
// Return the base name from a file path. Important: this is a pointer
// into the original string.
const char* GetBaseNamePtr(const char* path);
// Helper class used to implement a string. Similar to std::string
// without all the crazy iterator / iostream stuff.
//
// Required because crazy linker should only link against the system
// libstdc++ that only provides new/delete.
//
class String {
public:
String();
String(const char* str, size_t len);
String(const String& other);
String(String&& other) noexcept;
explicit String(const char* str);
explicit String(char ch);
~String();
const char* c_str() const { return ptr_; }
char* ptr() { return ptr_; }
size_t size() const { return size_; }
size_t capacity() const { return capacity_; }
const char* begin() const { return ptr_; }
const char* end() const { return ptr_ + size_; }
char* begin() { return ptr_; }
char* end() { return ptr_ + size_; }
const char* cbegin() const { return ptr_; }
const char* cend() const { return ptr_ + size_; }
bool IsEmpty() const { return size_ == 0; }
char& operator[](size_t index) { return ptr_[index]; }
String& operator=(const String& other) {
Assign(other.ptr_, other.size_);
return *this;
}
String& operator=(String&& other) noexcept;
String& operator=(const char* str) {
Assign(str, strlen(str));
return *this;
}
String& operator=(char ch) {
Assign(&ch, 1);
return *this;
}
String& operator+=(const String& other) {
Append(other);
return *this;
}
String& operator+=(const char* str) {
Append(str, strlen(str));
return *this;
}
String& operator+=(char ch) {
Append(&ch, 1);
return *this;
}
void Resize(size_t new_size);
void Reserve(size_t new_capacity);
void Assign(const char* str, size_t len);
void Assign(const String& other) { Assign(other.ptr_, other.size_); }
void Assign(const char* str) { Assign(str, strlen(str)); }
void Append(const char* str, size_t len);
void Append(const String& other) { Append(other.ptr_, other.size_); }
void Append(const char* str) { Append(str, strlen(str)); }
// Comparison operators.
bool operator==(const String& other) const;
bool operator==(const char* str) const;
inline bool operator!=(const String& other) const {
return !(*this == other);
}
inline bool operator!=(const char* str) const { return !(*this == str); }
private:
inline void Init() {
ptr_ = const_cast<char*>(kEmpty);
size_ = 0;
capacity_ = 0;
}
inline bool HasValidPointer() const {
return ptr_ != const_cast<char*>(kEmpty);
}
void InitFrom(const char* str, size_t len);
static const char kEmpty[];
char* ptr_;
size_t size_;
size_t capacity_;
};
// Base vector class used by all instantiations of Vector<> to reduce
// generated code size.
class VectorBase {
public:
VectorBase() = default;
~VectorBase();
// Disallow copy operations.
VectorBase(const VectorBase&) = delete;
VectorBase& operator=(const VectorBase&) = delete;
// Allow move operations.
VectorBase(VectorBase&& other) noexcept;
VectorBase& operator=(VectorBase&& other) noexcept;
// Return true iff vector is empty.
constexpr bool IsEmpty() const { return count_ == 0U; }
// Return number of items in container.
constexpr size_t GetCount() const { return count_; }
protected:
// Reset container state.
void DoReset() {
data_ = nullptr;
count_ = 0;
capacity_ = 0;
}
// Perform various operations on the array.
void DoResize(size_t new_count, size_t item_size);
void DoReserve(size_t new_capacity, size_t item_size);
void* DoInsert(size_t pos, size_t item_size);
void* DoInsert(size_t pos, size_t count, size_t item_size);
void DoRemove(size_t pos, size_t item_size);
void DoRemove(size_t pos, size_t count, size_t item_size);
char* data_ = nullptr;
size_t count_ = 0;
size_t capacity_ = 0;
};
// Result type for a linear or binary search function.
// The packing generates smaller and faster machine code on ARM and x86.
struct SearchResult {
bool found : 1;
size_t pos : sizeof(size_t) * CHAR_BIT - 1;
};
// Helper template used to implement a simple vector of POD-struct items.
// I.e. this uses memmove() to move items during insertion / removal.
//
// Required because crazy linker should only link against the system
// libstdc++ which only provides new/delete.
//
template <class T>
class Vector : public VectorBase {
public:
Vector() { static_assert(std::is_pod<T>::value, "type T should be POD"); }
~Vector() = default;
// Move operations are allowed.
Vector(Vector&& other) : VectorBase(std::move(other)) {}
Vector& operator=(Vector&& other) {
if (this != &other) {
this->VectorBase::operator=(std::move(other));
}
return *this;
}
// Support for-range loops.
constexpr const T* cbegin() const {
return reinterpret_cast<const T*>(data_);
}
constexpr const T* cend() const { return cbegin() + count_; }
constexpr const T* begin() const { return cbegin(); }
constexpr const T* end() const { return cend(); }
T* begin() { return const_cast<T*>(cbegin()); }
T* end() { return const_cast<T*>(cend()); }
// Array access operator.
constexpr const T& operator[](size_t index) const { return cbegin()[index]; }
T& operator[](size_t index) { return begin()[index]; }
// Append one item at the end of the vector.
void PushBack(T item) { InsertAt(count_, item); }
// Remove the first item from the vector and return it.
// Undefined behaviour if it is empty.
T PopFirst() {
T result = cbegin()[0];
RemoveAt(0);
return result;
}
// Remove the last item from the vector and return it.
// Undefined behaviour if the vector is empty.
T PopLast() {
T result = cend()[-1];
DoResize(count_ - 1, sizeof(T));
return result;
}
// Remove a specific item from the vector, if it contains it.
void Remove(T item) {
SearchResult result = Find(item);
if (result.found)
RemoveAt(result.pos);
}
// Insert a new |item| into a specific position |index|.
void InsertAt(size_t index, T item) {
auto* slot = reinterpret_cast<T*>(DoInsert(index, sizeof(T)));
*slot = item;
}
// Remove the item at position |index|.
void RemoveAt(size_t index) { DoRemove(index, sizeof(T)); }
// Try to find |item| in the vector.
SearchResult Find(T wanted) const {
for (size_t pos = 0; pos < count_; ++pos) {
if (cbegin()[pos] == wanted)
return {true, pos};
}
return {false, 0};
}
// Returns true if vector contains |item|.
bool Has(T item) const { return Find(item).found; }
// Resize vector.
void Resize(size_t new_count) { DoResize(new_count, sizeof(T)); }
// Reset the vector's capacity to a new value. Truncate size if needed.
void Reserve(size_t new_capacity) { DoReserve(new_capacity, sizeof(T)); }
};
} // namespace crazy
#endif // CRAZY_LINKER_UTIL_H