forked from pytorch/FBGEMM
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAlignedVec.h
156 lines (131 loc) · 4.29 KB
/
AlignedVec.h
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
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <cassert>
#include <cstdlib>
#include <stdexcept>
#include <vector>
/**
* Allocator for aligned data.
*
* Modified from the Mallocator from Stephan T. Lavavej.
* <http://blogs.msdn.com/b/vcblog/archive/2008/08/28/the-mallocator.aspx>
*
*/
template <typename T, std::size_t Alignment>
class aligned_allocator {
public:
// The following will be the same for virtually all allocators.
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef T value_type;
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
T* address(T& r) const {
return &r;
}
const T* address(const T& s) const {
return &s;
}
std::size_t max_size() const {
// The following has been carefully written to be independent of
// the definition of size_t and to avoid signed/unsigned warnings.
return (static_cast<std::size_t>(0) - static_cast<std::size_t>(1)) /
sizeof(T);
}
// The following must be the same for all allocators.
template <typename U>
struct rebind {
typedef aligned_allocator<U, Alignment> other;
};
bool operator!=(const aligned_allocator& other) const {
return !(*this == other);
}
void construct(T* const p, const T& t) const {
void* const pv = static_cast<void*>(p);
new (pv) T(t);
}
void destroy(T* const p) const {
p->~T();
}
// Returns true if and only if storage allocated from *this
// can be deallocated from other, and vice versa.
// Always returns true for stateless allocators.
bool operator==(const aligned_allocator& /*other*/) const {
return true;
}
// Default constructor, copy constructor, rebinding constructor, and
// destructor. Empty for stateless allocators.
aligned_allocator() {}
aligned_allocator(const aligned_allocator&) {}
template <typename U>
aligned_allocator(const aligned_allocator<U, Alignment>&) {}
~aligned_allocator() {}
// The following will be different for each allocator.
T* allocate(const std::size_t n) const {
// The return value of allocate(0) is unspecified.
// Mallocator returns NULL in order to avoid depending
// on malloc(0)'s implementation-defined behavior
// (the implementation can define malloc(0) to return NULL,
// in which case the bad_alloc check below would fire).
// All allocators can return NULL in this case.
if (n == 0) {
return nullptr;
}
// All allocators should contain an integer overflow check.
// The Standardization Committee recommends that std::length_error
// be thrown in the case of integer overflow.
if (n > max_size()) {
throw std::length_error(
"aligned_allocator<T>::allocate() - Integer overflow.");
}
// Mallocator wraps malloc().
void* pv = nullptr;
int ret;
#ifdef _MSC_VER
pv = _aligned_malloc(n * sizeof(T), Alignment);
ret = 0;
#else
ret = posix_memalign(&pv, Alignment, n * sizeof(T));
#endif
// pv = aligned_alloc(Alignment, n * sizeof(T));
// Allocators should throw std::bad_alloc in the case of memory allocation
// failure.
if (ret || pv == nullptr) {
throw std::bad_alloc();
}
return static_cast<T*>(pv);
}
void deallocate(T* const p, const std::size_t /*n*/) const {
#ifdef _MSC_VER
_aligned_free(p);
#else
free(p);
#endif
}
// The following will be the same for all allocators that ignore hints.
template <typename U>
T* allocate(const std::size_t n, const U* /* const hint */) const {
return allocate(n);
}
// Allocators are not required to be assignable, so
// all allocators should have a private unimplemented
// assignment operator. Note that this will trigger the
// off-by-default (enabled under /Wall) warning C4626
// "assignment operator could not be generated because a
// base class assignment operator is inaccessible" within
// the STL headers, but that warning is useless.
private:
aligned_allocator& operator=(const aligned_allocator&) {
assert(0);
}
};
template <typename T>
using aligned_vector = std::vector<T, aligned_allocator<T, 64>>;