Add in PreallocatedArray, PreallocatedMap data structures.

These arrays are meant to be used in situations where you want to allocate a
potentially large amount of default constructible items for a collection of
fixed size.

An example of such a use case is for data flow algorithms which need a
one to one mapping from BB -> StateObject. In such a case, if the state
object is default constructible, we can allocate all of the structures
first, initialize them for each BB, and then process as we normally
would. Thus we eliminate overhead due to memory allocation.

Since the data structures take an allocator it also enables one to use it in
cases where one allocates memory from an allocator and references it via an
ArrayRef. We do this in swift when storing data into certain instructions.

Another benefit over using DenseMaps in such cases is that a DenseMap (unless
you preallocate) can cause all sorts of invalidation issues as new states are
added.

I am planning on using this in my Enum Simplification work and changing
the Global ARC Optimizer to use this.

Swift SVN r18739
This commit is contained in:
Michael Gottesman
2014-06-08 22:52:12 +00:00
parent 218859f7c2
commit a301dbe548
2 changed files with 156 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
//===- PreallocatedArray.h - Fixed size array -------------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_BASIC_PREALLOCATEDARRAY_H_
#define SWIFT_BASIC_PREALLOCATEDARRAY_H_
#include "llvm/Support/Allocator.h"
#include <type_traits>
namespace swift {
/// An array meant for large collections of default constructible elements of
/// fixed size. It does one large allocation on construction.
template <typename EltTy, typename AllocatorTy=llvm::MallocAllocator>
class PreallocatedArray {
static_assert(std::is_default_constructible<EltTy>::value,
"EltTy must be default constructable.");
unsigned NumElts;
Optional<AllocatorTy> Allocator;
EltTy *Elt;
public:
PreallocatedArray(unsigned NumElts)
: NumElts(NumElts),
Allocator(llvm::MallocAllocator()),
Elt(new (Allocator->template Allocate<EltTy>(NumElts)) EltTy[NumElts]) {}
PreallocatedArray(unsigned NumElts, AllocatorTy &Allocator)
: NumElts(NumElts),
Elt(new (Allocator.template Allocate<EltTy>(NumElts)) EltTy[NumElts]) {}
// Call destructors of data.
~PreallocatedArray() {
for (unsigned i = 0; i < NumElts; ++i) {
Elt[i].~EltTy();
}
}
MutableArrayRef<EltTy> getArray() {
return MutableArrayRef<EltTy>(Elt, NumElts);
}
ArrayRef<EltTy> getArray() const {
return ArrayRef<EltTy>(Elt, NumElts);
}
using iterator = typename MutableArrayRef<EltTy>::iterator;
using const_iterator = typename ArrayRef<EltTy>::iterator;
iterator begin() { return getArray().begin(); }
iterator end() { return getArray().end(); }
const_iterator begin() const { return getArray().begin(); }
const_iterator end() const { return getArray().end(); }
Range<iterator> getRange() { return {begin(), end()}; }
Range<const_iterator> getRange() const { return {begin(), end()}; }
unsigned size() const { return NumElts; }
EltTy &operator[](size_t Index) {
return getArray()[Index];
}
};
} // end namespace swift
#endif

View File

@@ -0,0 +1,79 @@
//===- PreallocatedMap.h - Fixed size, sorted map ---------------*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_BASIC_PREALLOCATEDMAP_H_
#define SWIFT_BASIC_PREALLOCATEDMAP_H_
#include "swift/Basic/PreallocatedArray.h"
namespace swift {
/// A map with a fixed constant size. The way to use it is to first go through
/// as an array initializing all the data structures. Then sort call sort.
template <typename KeyTy, typename ValueTy,
typename AllocatorTy=llvm::MallocAllocator>
class PreallocatedMap {
using PairTy = std::pair<KeyTy, ValueTy>;
using ArrayTy = PreallocatedArray<PairTy, AllocatorTy>;
using SortFunTy = std::function<bool (const PairTy &, const PairTy &)>;
bool IsSorted = false;
ArrayTy Array;
SortFunTy SortFun;
public:
PreallocatedMap(unsigned NumElts, SortFunTy SortFun) : Array(NumElts),
SortFun(SortFun) {}
PreallocatedMap(unsigned NumElts, AllocatorTy &Allocator, SortFunTy SortFun)
: Array(NumElts, Allocator), SortFun(SortFun) {}
// Make the map immutable by setting the immutable flag and sorting the
// map. Only after this is called can one search for things in the map.
void sort() {
if (IsSorted)
return;
IsSorted = true;
std::sort(Array.begin(), Array.end(), SortFun);
}
// Returns whether the array is sorted.
bool isSorted() const { return IsSorted; }
PairTy &operator[](size_t Index) { return Array[Index]; }
ValueTy &operator[](KeyTy &Key) {
auto P = find(Key);
assert(P != end() && "Unknown key!");
return P->second;
}
unsigned size() const { return Array.size(); }
using iterator = typename ArrayTy::iterator;
using const_iterator = typename ArrayTy::const_iterator;
iterator begin() { return Array.begin(); }
iterator end() { return Array.end(); }
const_iterator begin() const { return Array.begin(); }
const_iterator end() const { return Array.end(); }
Range<iterator> getRange() { return Array.getRange(); }
Range<const_iterator> getRange() const { return Array.getRange(); }
iterator find(KeyTy &Key) {
std::pair<KeyTy, ValueTy> Pair;
Pair.first = Key;
return std::lower_bound(Array.begin(), Array.end(), Pair, SortFun);
}
};
} // end namespace swift
#endif