blob: 109eb003e6819d1277b435cde7a0bcc865cf27df [file] [log] [blame]
//===--- OwnedString.h - String storage -------------------------*- C++ -*-===//
// This source file is part of the open source project
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
// See for license information
// See for the list of Swift project authors
// This file defines the 'OwnedString' storage wrapper, which can hold its own
// unique copy of a string, or merely hold a reference to some point in a
// source buffer, which is assumed to live at least as long as a value of this
// type.
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/TrailingObjects.h"
using llvm::StringRef;
namespace swift {
/// Holds a string - either statically allocated or dynamically allocated
/// and owned by this type.
class OwnedString {
/// An owner that keeps the buffer of a ref counted \c OwnedString alive.
class TextOwner final : public llvm::ThreadSafeRefCountedBase<TextOwner>,
public llvm::TrailingObjects<TextOwner, char> {
TextOwner(StringRef Text) {
std::uninitialized_copy(Text.begin(), Text.end(),
static TextOwner *make(StringRef Text) {
auto size = totalSizeToAlloc<char>(Text.size());
void *data = ::operator new(size);
return new (data) TextOwner(Text);
/// Disable sized deallocation for TextOwner, because it has tail-allocated
/// data.
void operator delete(void *p) { ::operator delete(p); }
const char *getText() const { return getTrailingObjects<char>(); }
/// The text this owned string represents
StringRef Text;
/// In case of a ref counted string an owner that keeps the buffer \c Text
/// references alive.
llvm::IntrusiveRefCntPtr<TextOwner> OwnedPtr;
OwnedString(StringRef Text, llvm::IntrusiveRefCntPtr<TextOwner> OwnedPtr)
: Text(Text), OwnedPtr(OwnedPtr) {}
OwnedString() : OwnedString(/*Text=*/StringRef(), /*OwnedPtr=*/nullptr) {}
/// Create a ref counted \c OwnedString that is initialized with the text of
/// the given \c StringRef.
OwnedString(StringRef Str) : OwnedString(makeRefCounted(Str)) {}
/// Create a ref counted \c OwnedString that is initialized with the text of
/// the given buffer.
OwnedString(const char *Str) : OwnedString(StringRef(Str)) {}
/// Create an \c OwnedString that references the given string. The
/// \c OwnedString will not take ownership of that buffer and will assume that
/// the buffer outlives its lifetime.
static OwnedString makeUnowned(StringRef Str) {
return OwnedString(Str, /*OwnedPtr=*/nullptr);
/// Create an \c OwnedString that keeps its contents in a reference counted
/// buffer. The contents of \p Str will be copied initially and are allowed to
/// be disposed after the \c OwnedString has been created.
static OwnedString makeRefCounted(StringRef Str) {
if (Str.empty()) {
// Copying an empty string doesn't make sense. Just create an unowned
// string that points to the empty string.
return makeUnowned(Str);
} else {
llvm::IntrusiveRefCntPtr<TextOwner> OwnedPtr(TextOwner::make(Str));
// Allocate the StringRef on the stack first. This is to ensure that the
// order of evaluation of the arguments is specified. The specification
// does not specify the order of evaluation for the arguments. Itanium
// chose to evaluate left to right, while Windows evaluates right to left.
// As such, it is possible that the OwnedPtr has already been `std::move`d
// by the time that the StringRef is attempted to be created. In such a
// case, the offset of the field (+4) is used instead of the pointer to
// the text, resulting in invalid memory references.
StringRef S(OwnedPtr->getText(), Str.size());
return OwnedString(S, std::move(OwnedPtr));
/// Returns the length of the string in bytes.
size_t size() const { return Text.size(); }
/// Returns true if the length is 0.
bool empty() const { return size() == 0; }
/// Returns a StringRef to the underlying data. No copy is made and no
/// ownership changes take place.
StringRef str() const { return Text; }
bool operator==(const OwnedString &Right) const {
return str() == Right.str();
} // end namespace swift