Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
scoped_safearray.h
Go to the documentation of this file.
1// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef BASE_WIN_SCOPED_SAFEARRAY_H_
6#define BASE_WIN_SCOPED_SAFEARRAY_H_
7
8#include <objbase.h>
9#include <optional>
10
11#include "base/base_export.h"
12#include "base/logging.h"
13#include "base/macros.h"
15
16namespace base {
17namespace win {
18
19// Manages a Windows SAFEARRAY. This is a minimal wrapper that simply provides
20// RAII semantics and does not duplicate the extensive functionality that
21// CComSafeArray offers.
23 public:
24 // LockScope<VARTYPE> class for automatically managing the lifetime of a
25 // SAFEARRAY lock, and granting easy access to the underlying data either
26 // through random access or as an iterator.
27 // It is undefined behavior if the underlying SAFEARRAY is destroyed
28 // before the LockScope.
29 // LockScope implements std::iterator_traits as a random access iterator, so
30 // that LockScope is compatible with STL methods that require these traits.
31 template <VARTYPE ElementVartype>
32 class BASE_EXPORT LockScope final {
33 public:
34 // Type declarations to support std::iterator_traits
35 using iterator_category = std::random_access_iterator_tag;
37 using difference_type = ptrdiff_t;
41 using const_pointer = const value_type*;
42
44 : safearray_(nullptr),
45 vartype_(VT_EMPTY),
46 array_(nullptr),
47 array_size_(0U) {}
48
50 : safearray_(std::exchange(other.safearray_, nullptr)),
51 vartype_(std::exchange(other.vartype_, VT_EMPTY)),
52 array_(std::exchange(other.array_, nullptr)),
53 array_size_(std::exchange(other.array_size_, 0U)) {}
54
56 BASE_DCHECK(this != &other);
57 Reset();
58 safearray_ = std::exchange(other.safearray_, nullptr);
59 vartype_ = std::exchange(other.vartype_, VT_EMPTY);
60 array_ = std::exchange(other.array_, nullptr);
61 array_size_ = std::exchange(other.array_size_, 0U);
62 return *this;
63 }
64
65 ~LockScope() { Reset(); }
66
67 VARTYPE Type() const { return vartype_; }
68
69 size_t size() const { return array_size_; }
70
71 pointer begin() { return array_; }
72 pointer end() { return array_ + array_size_; }
73 const_pointer begin() const { return array_; }
74 const_pointer end() const { return array_ + array_size_; }
75
76 pointer data() { return array_; }
77 const_pointer data() const { return array_; }
78
79 reference operator[](int index) { return at(index); }
80 const_reference operator[](int index) const { return at(index); }
81
82 reference at(size_t index) {
83 BASE_DCHECK(array_ != nullptr);
84 BASE_DCHECK(index < array_size_);
85 return array_[index];
86 }
87 const_reference at(size_t index) const {
88 return const_cast<LockScope<ElementVartype>*>(this)->at(index);
89 }
90
91 private:
92 LockScope(SAFEARRAY* safearray,
93 VARTYPE vartype,
94 pointer array,
95 size_t array_size)
96 : safearray_(safearray),
97 vartype_(vartype),
98 array_(array),
99 array_size_(array_size) {}
100
101 void Reset() {
102 if (safearray_)
103 SafeArrayUnaccessData(safearray_);
104 safearray_ = nullptr;
105 vartype_ = VT_EMPTY;
106 array_ = nullptr;
107 array_size_ = 0U;
108 }
109
110 SAFEARRAY* safearray_;
111 VARTYPE vartype_;
112 pointer array_;
113 size_t array_size_;
114
115 friend class ScopedSafearray;
117 };
118
119 explicit ScopedSafearray(SAFEARRAY* safearray = nullptr)
120 : safearray_(safearray) {}
121
122 // Move constructor
123 ScopedSafearray(ScopedSafearray&& r) noexcept : safearray_(r.safearray_) {
124 r.safearray_ = nullptr;
125 }
126
127 // Move operator=. Allows assignment from a ScopedSafearray rvalue.
129 Reset(rvalue.Release());
130 return *this;
131 }
132
133 ~ScopedSafearray() { Destroy(); }
134
135 // Creates a LockScope for accessing the contents of a
136 // single-dimensional SAFEARRAYs.
137 template <VARTYPE ElementVartype>
138 std::optional<LockScope<ElementVartype>> CreateLockScope() const {
139 if (!safearray_ || SafeArrayGetDim(safearray_) != 1)
140 return std::nullopt;
141
142 VARTYPE vartype;
143 HRESULT hr = SafeArrayGetVartype(safearray_, &vartype);
144 if (FAILED(hr) ||
146 return std::nullopt;
147 }
148
149 typename LockScope<ElementVartype>::pointer array = nullptr;
150 hr = SafeArrayAccessData(safearray_, reinterpret_cast<void**>(&array));
151 if (FAILED(hr))
152 return std::nullopt;
153
154 const size_t array_size = GetCount();
155 return LockScope<ElementVartype>(safearray_, vartype, array, array_size);
156 }
157
158 void Destroy() {
159 if (safearray_) {
160 HRESULT hr = SafeArrayDestroy(safearray_);
161 BASE_DCHECK(S_OK == hr);
162 safearray_ = nullptr;
163 }
164 }
165
166 // Give ScopedSafearray ownership over an already allocated SAFEARRAY or
167 // nullptr.
168 void Reset(SAFEARRAY* safearray = nullptr) {
169 if (safearray != safearray_) {
170 Destroy();
171 safearray_ = safearray;
172 }
173 }
174
175 // Releases ownership of the SAFEARRAY to the caller.
176 SAFEARRAY* Release() {
177 SAFEARRAY* safearray = safearray_;
178 safearray_ = nullptr;
179 return safearray;
180 }
181
182 // Retrieves the pointer address.
183 // Used to receive SAFEARRAYs as out arguments (and take ownership).
184 // This function releases any existing references because it will leak
185 // the existing ref otherwise.
186 // Usage: GetSafearray(safearray.Receive());
187 SAFEARRAY** Receive() {
188 Destroy();
189 return &safearray_;
190 }
191
192 // Returns the number of elements in a dimension of the array.
193 size_t GetCount(UINT dimension = 0) const {
194 BASE_DCHECK(safearray_);
195 // Initialize |lower| and |upper| so this method will return zero if either
196 // SafeArrayGetLBound or SafeArrayGetUBound returns failure because they
197 // only write to the output parameter when successful.
198 LONG lower = 0;
199 LONG upper = -1;
200 BASE_DCHECK(dimension < SafeArrayGetDim(safearray_));
201 HRESULT hr = SafeArrayGetLBound(safearray_, dimension + 1, &lower);
203 hr = SafeArrayGetUBound(safearray_, dimension + 1, &upper);
205 return (upper - lower + 1);
206 }
207
208 // Returns the internal pointer.
209 SAFEARRAY* Get() const { return safearray_; }
210
211 // Forbid comparison of ScopedSafearray types. You should never have the same
212 // SAFEARRAY owned by two different scoped_ptrs.
213 bool operator==(const ScopedSafearray& safearray2) const = delete;
214 bool operator!=(const ScopedSafearray& safearray2) const = delete;
215
216 private:
217 SAFEARRAY* safearray_;
219};
220
221} // namespace win
222} // namespace base
223
224#endif // BASE_WIN_SCOPED_SAFEARRAY_H_
#define BASE_EXPORT
Definition base_export.h:26
std::random_access_iterator_tag iterator_category
const_reference operator[](int index) const
LockScope< ElementVartype > & operator=(LockScope< ElementVartype > &&other)
const_reference at(size_t index) const
LockScope(LockScope< ElementVartype > &&other)
typename internal::VariantUtil< ElementVartype >::Type value_type
void Reset(SAFEARRAY *safearray=nullptr)
bool operator==(const ScopedSafearray &safearray2) const =delete
ScopedSafearray & operator=(ScopedSafearray &&rvalue)
ScopedSafearray(SAFEARRAY *safearray=nullptr)
ScopedSafearray(ScopedSafearray &&r) noexcept
size_t GetCount(UINT dimension=0) const
bool operator!=(const ScopedSafearray &safearray2) const =delete
std::optional< LockScope< ElementVartype > > CreateLockScope() const
Definition ref_ptr.h:256
typename VartypeToNativeType< ElementVartype >::Type Type
#define BASE_DCHECK(condition)
Definition logging.h:63
#define BASE_DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition macros.h:8
#define SUCCEEDED(hr)
long LONG
unsigned int UINT
#define FAILED(hr)