/src/arrow/cpp/src/arrow/buffer.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | #include "arrow/buffer.h" |
19 | | |
20 | | #include <algorithm> |
21 | | #include <cstdint> |
22 | | #include <utility> |
23 | | |
24 | | #include "arrow/result.h" |
25 | | #include "arrow/status.h" |
26 | | #include "arrow/util/bit_util.h" |
27 | | #include "arrow/util/logging.h" |
28 | | #include "arrow/util/slice_util_internal.h" |
29 | | #include "arrow/util/string.h" |
30 | | |
31 | | namespace arrow { |
32 | | |
33 | | Result<std::shared_ptr<Buffer>> Buffer::CopySlice(const int64_t start, |
34 | | const int64_t nbytes, |
35 | 1 | MemoryPool* pool) const { |
36 | | // Sanity checks |
37 | 1 | ARROW_CHECK_LE(start, size_); |
38 | 1 | ARROW_CHECK_LE(nbytes, size_ - start); |
39 | 1 | DCHECK_GE(nbytes, 0); |
40 | | |
41 | 1 | ARROW_ASSIGN_OR_RAISE(auto new_buffer, AllocateResizableBuffer(nbytes, pool)); |
42 | 1 | std::memcpy(new_buffer->mutable_data(), data() + start, static_cast<size_t>(nbytes)); |
43 | 1 | return std::move(new_buffer); |
44 | 1 | } |
45 | | |
46 | | namespace { |
47 | | |
48 | 0 | Status CheckBufferSlice(const Buffer& buffer, int64_t offset, int64_t length) { |
49 | 0 | return internal::CheckSliceParams(buffer.size(), offset, length, "buffer"); |
50 | 0 | } |
51 | | |
52 | 0 | Status CheckBufferSlice(const Buffer& buffer, int64_t offset) { |
53 | 0 | if (ARROW_PREDICT_FALSE(offset < 0)) { |
54 | | // Avoid UBSAN in subtraction below |
55 | 0 | return Status::IndexError("Negative buffer slice offset"); |
56 | 0 | } |
57 | 0 | return CheckBufferSlice(buffer, offset, buffer.size() - offset); |
58 | 0 | } |
59 | | |
60 | | } // namespace |
61 | | |
62 | | Result<std::shared_ptr<Buffer>> SliceBufferSafe(const std::shared_ptr<Buffer>& buffer, |
63 | 0 | int64_t offset) { |
64 | 0 | RETURN_NOT_OK(CheckBufferSlice(*buffer, offset)); |
65 | 0 | return SliceBuffer(buffer, offset); |
66 | 0 | } |
67 | | |
68 | | Result<std::shared_ptr<Buffer>> SliceBufferSafe(const std::shared_ptr<Buffer>& buffer, |
69 | 0 | int64_t offset, int64_t length) { |
70 | 0 | RETURN_NOT_OK(CheckBufferSlice(*buffer, offset, length)); |
71 | 0 | return SliceBuffer(buffer, offset, length); |
72 | 0 | } |
73 | | |
74 | | Result<std::shared_ptr<Buffer>> SliceMutableBufferSafe( |
75 | 0 | const std::shared_ptr<Buffer>& buffer, int64_t offset) { |
76 | 0 | RETURN_NOT_OK(CheckBufferSlice(*buffer, offset)); |
77 | 0 | return SliceMutableBuffer(buffer, offset); |
78 | 0 | } |
79 | | |
80 | | Result<std::shared_ptr<Buffer>> SliceMutableBufferSafe( |
81 | 0 | const std::shared_ptr<Buffer>& buffer, int64_t offset, int64_t length) { |
82 | 0 | RETURN_NOT_OK(CheckBufferSlice(*buffer, offset, length)); |
83 | 0 | return SliceMutableBuffer(buffer, offset, length); |
84 | 0 | } |
85 | | |
86 | 0 | std::string Buffer::ToHexString() { |
87 | 0 | return HexEncode(data(), static_cast<size_t>(size())); |
88 | 0 | } |
89 | | |
90 | 0 | bool Buffer::Equals(const Buffer& other, const int64_t nbytes) const { |
91 | 0 | return this == &other || (size_ >= nbytes && other.size_ >= nbytes && |
92 | 0 | (data_ == other.data_ || |
93 | 0 | !memcmp(data_, other.data_, static_cast<size_t>(nbytes)))); |
94 | 0 | } |
95 | | |
96 | 0 | bool Buffer::Equals(const Buffer& other) const { |
97 | 0 | return this == &other || (size_ == other.size_ && |
98 | 0 | (data_ == other.data_ || |
99 | 0 | !memcmp(data_, other.data_, static_cast<size_t>(size_)))); |
100 | 0 | } |
101 | | |
102 | 0 | std::string Buffer::ToString() const { |
103 | 0 | return std::string(reinterpret_cast<const char*>(data_), static_cast<size_t>(size_)); |
104 | 0 | } |
105 | | |
106 | 0 | void Buffer::CheckMutable() const { DCHECK(is_mutable()) << "buffer not mutable"; } |
107 | | |
108 | 0 | void Buffer::CheckCPU() const { |
109 | 0 | DCHECK(is_cpu()) << "not a CPU buffer (device: " << device()->ToString() << ")"; |
110 | 0 | } |
111 | | |
112 | | Result<std::shared_ptr<io::RandomAccessFile>> Buffer::GetReader( |
113 | 0 | std::shared_ptr<Buffer> buf) { |
114 | 0 | return buf->memory_manager_->GetBufferReader(buf); |
115 | 0 | } |
116 | | |
117 | 0 | Result<std::shared_ptr<io::OutputStream>> Buffer::GetWriter(std::shared_ptr<Buffer> buf) { |
118 | 0 | if (!buf->is_mutable()) { |
119 | 0 | return Status::Invalid("Expected mutable buffer"); |
120 | 0 | } |
121 | 0 | return buf->memory_manager_->GetBufferWriter(buf); |
122 | 0 | } |
123 | | |
124 | | Result<std::shared_ptr<Buffer>> Buffer::Copy(std::shared_ptr<Buffer> source, |
125 | 0 | const std::shared_ptr<MemoryManager>& to) { |
126 | 0 | return MemoryManager::CopyBuffer(source, to); |
127 | 0 | } |
128 | | |
129 | | Result<std::unique_ptr<Buffer>> Buffer::CopyNonOwned( |
130 | 0 | const Buffer& source, const std::shared_ptr<MemoryManager>& to) { |
131 | 0 | return MemoryManager::CopyNonOwned(source, to); |
132 | 0 | } |
133 | | |
134 | | Result<std::shared_ptr<Buffer>> Buffer::View(std::shared_ptr<Buffer> source, |
135 | 0 | const std::shared_ptr<MemoryManager>& to) { |
136 | 0 | return MemoryManager::ViewBuffer(source, to); |
137 | 0 | } |
138 | | |
139 | | Result<std::shared_ptr<Buffer>> Buffer::ViewOrCopy( |
140 | 0 | std::shared_ptr<Buffer> source, const std::shared_ptr<MemoryManager>& to) { |
141 | 0 | auto maybe_buffer = MemoryManager::ViewBuffer(source, to); |
142 | 0 | if (maybe_buffer.ok()) { |
143 | 0 | return maybe_buffer; |
144 | 0 | } |
145 | 0 | return MemoryManager::CopyBuffer(source, to); |
146 | 0 | } |
147 | | |
148 | | class StlStringBuffer : public Buffer { |
149 | | public: |
150 | | explicit StlStringBuffer(std::string data) |
151 | 0 | : Buffer(nullptr, 0), input_(std::move(data)) { |
152 | 0 | data_ = reinterpret_cast<const uint8_t*>(input_.c_str()); |
153 | 0 | size_ = static_cast<int64_t>(input_.size()); |
154 | 0 | capacity_ = size_; |
155 | 0 | } |
156 | | |
157 | | private: |
158 | | std::string input_; |
159 | | }; |
160 | | |
161 | 0 | std::shared_ptr<Buffer> Buffer::FromString(std::string data) { |
162 | 0 | return std::make_shared<StlStringBuffer>(std::move(data)); |
163 | 0 | } |
164 | | |
165 | | std::shared_ptr<Buffer> SliceMutableBuffer(const std::shared_ptr<Buffer>& buffer, |
166 | 0 | const int64_t offset, const int64_t length) { |
167 | 0 | return std::make_shared<MutableBuffer>(buffer, offset, length); |
168 | 0 | } |
169 | | |
170 | | MutableBuffer::MutableBuffer(const std::shared_ptr<Buffer>& parent, const int64_t offset, |
171 | | const int64_t size) |
172 | | : MutableBuffer(reinterpret_cast<uint8_t*>(parent->mutable_address()) + offset, |
173 | 0 | size) { |
174 | 0 | DCHECK(parent->is_mutable()) << "Must pass mutable buffer"; |
175 | 0 | parent_ = parent; |
176 | 0 | } |
177 | | |
178 | 0 | Result<std::shared_ptr<Buffer>> AllocateBitmap(int64_t length, MemoryPool* pool) { |
179 | 0 | ARROW_ASSIGN_OR_RAISE(auto buf, AllocateBuffer(bit_util::BytesForBits(length), pool)); |
180 | | // Zero out any trailing bits |
181 | 0 | if (buf->size() > 0) { |
182 | 0 | buf->mutable_data()[buf->size() - 1] = 0; |
183 | 0 | } |
184 | 0 | return std::move(buf); |
185 | 0 | } |
186 | | |
187 | 0 | Result<std::shared_ptr<Buffer>> AllocateEmptyBitmap(int64_t length, MemoryPool* pool) { |
188 | 0 | return AllocateEmptyBitmap(length, kDefaultBufferAlignment, pool); |
189 | 0 | } |
190 | | |
191 | | Result<std::shared_ptr<Buffer>> AllocateEmptyBitmap(int64_t length, int64_t alignment, |
192 | 0 | MemoryPool* pool) { |
193 | 0 | ARROW_ASSIGN_OR_RAISE(auto buf, |
194 | 0 | AllocateBuffer(bit_util::BytesForBits(length), alignment, pool)); |
195 | 0 | memset(buf->mutable_data(), 0, static_cast<size_t>(buf->size())); |
196 | 0 | return std::move(buf); |
197 | 0 | } |
198 | | |
199 | 0 | Status AllocateEmptyBitmap(int64_t length, std::shared_ptr<Buffer>* out) { |
200 | 0 | return AllocateEmptyBitmap(length).Value(out); |
201 | 0 | } |
202 | | |
203 | | Result<std::shared_ptr<Buffer>> ConcatenateBuffers( |
204 | 0 | const std::vector<std::shared_ptr<Buffer>>& buffers, MemoryPool* pool) { |
205 | 0 | int64_t out_length = 0; |
206 | 0 | for (const auto& buffer : buffers) { |
207 | 0 | out_length += buffer->size(); |
208 | 0 | } |
209 | 0 | ARROW_ASSIGN_OR_RAISE(auto out, AllocateBuffer(out_length, pool)); |
210 | 0 | auto out_data = out->mutable_data(); |
211 | 0 | for (const auto& buffer : buffers) { |
212 | 0 | std::memcpy(out_data, buffer->data(), buffer->size()); |
213 | 0 | out_data += buffer->size(); |
214 | 0 | } |
215 | 0 | return std::move(out); |
216 | 0 | } |
217 | | |
218 | | } // namespace arrow |