|
1
|
1 #pragma once
|
|
|
2
|
|
|
3 #include <functional>
|
|
|
4 #include <initializer_list>
|
|
|
5 #include <pfc/list.h>
|
|
|
6 #include "completion_notify.h"
|
|
|
7
|
|
|
8 namespace fb2k {
|
|
|
9 typedef service_ptr objRef;
|
|
|
10
|
|
|
11 template<typename interface_t> class array_typed;
|
|
|
12 template<typename interface_t> class array_soft_typed;
|
|
|
13
|
|
|
14 class NOVTABLE array : public service_base, public pfc::list_base_const_t<service_ptr> {
|
|
|
15 FB2K_MAKE_SERVICE_INTERFACE( array, service_base );
|
|
|
16 public:
|
|
|
17 virtual size_t count() const = 0;
|
|
|
18 size_t size() const {return count();}
|
|
|
19 virtual objRef itemAt( size_t index ) const = 0;
|
|
|
20
|
|
|
21 objRef firstItem( ) const;
|
|
|
22 objRef lastItem( ) const;
|
|
|
23
|
|
|
24 objRef operator[] (size_t idx) const {return itemAt(idx);}
|
|
|
25
|
|
|
26 array::ptr arrayReordered( size_t const * order, size_t count );
|
|
|
27
|
|
|
28 array::ptr copy() const;
|
|
|
29 //! If this is a mutable array, creates a const copy of it. \n
|
|
|
30 //! Otherwise returns this object.
|
|
|
31 array::ptr makeConst() const;
|
|
|
32
|
|
|
33 static array::ptr empty();
|
|
|
34 static array::ptr arrayWithArray( array::ptr source );
|
|
|
35 static array::ptr arrayWithObject( objRef source );
|
|
|
36 static array::ptr arrayWithObjects( objRef const * source, size_t count );
|
|
|
37 static array::ptr arrayWithObjects(std::initializer_list< objRef > const&);
|
|
|
38
|
|
|
39 size_t indexOfItem( objRef item );
|
|
|
40
|
|
|
41 array::ptr subset( pfc::bit_array const & mask ) const;
|
|
|
42 array::ptr subsetExcluding( pfc::bit_array const & mask ) const;
|
|
|
43 array::ptr subsetExcludingSingle( size_t index ) const;
|
|
|
44
|
|
|
45 // UNSAFE CAST HELPER
|
|
|
46 // Use only when documented as allowed
|
|
|
47 template<typename interface_t>
|
|
|
48 const pfc::list_base_const_t< service_ptr_t< interface_t > >& as_list_of() const {
|
|
|
49 const pfc::list_base_const_t<service_ptr> * temp = this;
|
|
|
50 return *reinterpret_cast<const pfc::list_base_const_t< service_ptr_t< interface_t > > * > (temp);
|
|
|
51 }
|
|
|
52
|
|
|
53 // TYPED ARRAY HELPER
|
|
|
54 // Usage: for( auto obj : myArray->typed<interface>() ) { ... }
|
|
|
55 // Expects ALL objects in the array to implement the interface - causes runtime bugcheck if they don't
|
|
|
56 template<typename interface_t>
|
|
|
57 const array_typed<interface_t>& typed() const { return *reinterpret_cast< const array_typed<interface_t> * > (this); }
|
|
|
58
|
|
|
59 // SOFT TYPED ARRAY HELPER
|
|
|
60 // Usage: for( auto obj : myArray->softTyped<interface>() ) { ... }
|
|
|
61 // Skips objects not implementing the interface.
|
|
|
62 template<typename interface_t>
|
|
|
63 const array_soft_typed<interface_t>& softTyped() const { return *reinterpret_cast<const array_soft_typed<interface_t> *> (this); }
|
|
|
64
|
|
|
65
|
|
|
66 // pfc::list_base_const_t<>
|
|
|
67 t_size get_count() const override {return this->count();}
|
|
|
68 void get_item_ex(service_ptr& p_out, t_size n) const override { p_out = this->itemAt(n); }
|
|
|
69 };
|
|
|
70
|
|
|
71 template<typename interface_t> class array_typed : public array {
|
|
|
72 public:
|
|
|
73 typedef service_ptr_t<interface_t> ptr_t;
|
|
|
74 class iterator {
|
|
|
75 public:
|
|
|
76 static iterator _make(const array* arr, size_t index) { iterator ret; ret.m_arr = arr; ret.m_index = index; return ret; }
|
|
|
77 void operator++() { ++m_index; }
|
|
|
78 bool operator==(const iterator& other) const { PFC_ASSERT(m_arr == other.m_arr); return m_index == other.m_index; }
|
|
|
79 bool operator!=(const iterator& other) const { PFC_ASSERT(m_arr == other.m_arr); return m_index != other.m_index; }
|
|
|
80
|
|
|
81 ptr_t operator*() const {
|
|
|
82 ptr_t ret;
|
|
|
83 ret ^= m_arr->itemAt(m_index);
|
|
|
84 return ret;
|
|
|
85 }
|
|
|
86 private:
|
|
|
87 const array* m_arr;
|
|
|
88 size_t m_index;
|
|
|
89 };
|
|
|
90 typedef iterator const_iterator;
|
|
|
91 iterator begin() const { return iterator::_make(this, 0); }
|
|
|
92 iterator end() const { return iterator::_make(this, this->count()); }
|
|
|
93 };
|
|
|
94
|
|
|
95 template<typename interface_t> class array_soft_typed : public array {
|
|
|
96 public:
|
|
|
97 typedef service_ptr_t<interface_t> ptr_t;
|
|
|
98 class iterator {
|
|
|
99 public:
|
|
|
100 static iterator _make(const array* arr, size_t index) {
|
|
|
101 iterator ret;
|
|
|
102 ret.m_arr = arr; ret.m_index = index;
|
|
|
103 ret.m_max = arr->count();
|
|
|
104 ret.fetch();
|
|
|
105 return ret;
|
|
|
106 }
|
|
|
107 void operator++() { ++m_index; fetch(); }
|
|
|
108 bool operator==(const iterator& other) const { PFC_ASSERT(m_arr == other.m_arr); return m_index == other.m_index; }
|
|
|
109 bool operator!=(const iterator& other) const { PFC_ASSERT(m_arr == other.m_arr); return m_index != other.m_index; }
|
|
|
110
|
|
|
111 ptr_t operator*() const {
|
|
|
112 PFC_ASSERT(m_ptr.is_valid());
|
|
|
113 return m_ptr;
|
|
|
114 }
|
|
|
115 private:
|
|
|
116 void fetch() {
|
|
|
117 m_ptr.reset();
|
|
|
118 while (m_index < m_max) {
|
|
|
119 if (m_ptr &= m_arr->itemAt(m_index)) break;
|
|
|
120 ++m_index;
|
|
|
121 }
|
|
|
122 }
|
|
|
123 const array* m_arr;
|
|
|
124 size_t m_index, m_max;
|
|
|
125 ptr_t m_ptr;
|
|
|
126 };
|
|
|
127 typedef iterator const_iterator;
|
|
|
128 iterator begin() const { return iterator::_make(this, 0); }
|
|
|
129 iterator end() const { return iterator::_make(this, this->count()); }
|
|
|
130 };
|
|
|
131
|
|
|
132 class NOVTABLE arrayMutable : public array {
|
|
|
133 FB2K_MAKE_SERVICE_INTERFACE( arrayMutable, array );
|
|
|
134 public:
|
|
|
135 virtual void remove( pfc::bit_array const & mask ) = 0;
|
|
|
136 virtual void insert( objRef obj, size_t at ) = 0;
|
|
|
137 virtual void insertFrom( array::ptr objects, size_t at ) = 0;
|
|
|
138 virtual void reorder( const size_t * order, size_t count ) = 0;
|
|
|
139
|
|
|
140 virtual void resize( size_t newSize ) = 0;
|
|
|
141 virtual void setItem( objRef obj, size_t atIndex ) = 0;
|
|
|
142
|
|
|
143 arrayMutable::ptr copy() const;
|
|
|
144 array::ptr copyConst() const;
|
|
|
145
|
|
|
146 void removeAt( size_t idx );
|
|
|
147 void add( objRef obj ) {insert( obj, (size_t)(-1) ) ; }
|
|
|
148 void addFrom( array::ptr obj ) {insertFrom( obj, (size_t)(-1) ) ; }
|
|
|
149 static arrayMutable::ptr empty();
|
|
|
150 static arrayMutable::ptr arrayWithArray( array::ptr source );
|
|
|
151 static arrayMutable::ptr arrayWithObject( objRef source );
|
|
|
152 static arrayMutable::ptr arrayWithCapacity(size_t capacity);
|
|
|
153 };
|
|
|
154
|
|
|
155 class NOVTABLE string : public service_base {
|
|
|
156 FB2K_MAKE_SERVICE_INTERFACE( string, service_base );
|
|
|
157 public:
|
|
|
158 virtual const char * c_str() const = 0;
|
|
|
159
|
|
|
160 size_t length() const { return strlen(c_str()); }
|
|
|
161 bool isEmpty() const { return *c_str() == 0; }
|
|
|
162 bool equals( const char * other ) const { return strcmp(c_str(), other) == 0; }
|
|
|
163 bool equals( string::ptr other ) const { return equals(other->c_str()); }
|
|
|
164
|
|
|
165 static string::ptr stringWithString( const char * str );
|
|
|
166 static string::ptr stringWithString( string::ptr str );
|
|
|
167 static string::ptr stringWithString( const char * str, size_t len );
|
|
|
168 static bool equalsNullSafe( string::ptr v1, string::ptr v2 );
|
|
|
169 };
|
|
|
170
|
|
|
171 class NOVTABLE memBlock : public service_base {
|
|
|
172 FB2K_MAKE_SERVICE_INTERFACE( memBlock, service_base );
|
|
|
173 public:
|
|
|
174 virtual const void * data() const = 0;
|
|
|
175 virtual size_t size() const = 0;
|
|
|
176
|
|
|
177 const uint8_t * begin() const { return (const uint8_t*) data(); }
|
|
|
178 const uint8_t * end() const { return begin() + size(); }
|
|
|
179
|
|
|
180 //! Album_art_data compatibility
|
|
|
181 size_t get_size() { return size(); }
|
|
|
182 //! Album_art_data compatibility
|
|
|
183 const void * get_ptr() { return data(); }
|
|
|
184
|
|
|
185 memBlock::ptr copy() const;
|
|
|
186
|
|
|
187 static memBlock::ptr empty();
|
|
|
188 static memBlock::ptr blockWithData( const void * inData, size_t inSize);
|
|
|
189 static memBlock::ptr blockWithBlock( memBlock::ptr block );
|
|
|
190 template<typename vec_t>
|
|
|
191 static memBlock::ptr blockWithVector(const vec_t & vec) {
|
|
|
192 auto size = vec.size();
|
|
|
193 if (size == 0) return empty();
|
|
|
194 return blockWithData(&vec[0], size * sizeof(vec[0]));
|
|
|
195 }
|
|
|
196
|
|
|
197 //! Create an object that takes ownership of this memory, without copying it; will call free() when done.
|
|
|
198 static memBlock::ptr blockWithDataTakeOwnership(void * inData, size_t inSize);
|
|
|
199 static memBlock::ptr blockWithData(pfc::mem_block const &);
|
|
|
200 static memBlock::ptr blockWithData(pfc::mem_block && );
|
|
|
201
|
|
|
202 //! Determine whether two memBlock objects store the same content.
|
|
|
203 static bool equals(memBlock const & v1, memBlock const & v2) {
|
|
|
204 const t_size s = v1.size();
|
|
|
205 if (s != v2.size()) return false;
|
|
|
206 return memcmp(v1.data(), v2.data(),s) == 0;
|
|
|
207 }
|
|
|
208 static bool equals(ptr const& v1, ptr const& v2) {
|
|
|
209 if (v1.is_valid() != v2.is_valid()) return false;
|
|
|
210 if (v1.is_empty() && v2.is_empty()) return true;
|
|
|
211 return equals(*v1, *v2);
|
|
|
212 }
|
|
|
213
|
|
|
214 bool operator==(const memBlock & other) const {return equals(*this,other);}
|
|
|
215 bool operator!=(const memBlock & other) const {return !equals(*this,other);}
|
|
|
216
|
|
|
217 };
|
|
|
218
|
|
|
219 class NOVTABLE memBlockMutable : public memBlock {
|
|
|
220 FB2K_MAKE_SERVICE_INTERFACE( memBlockMutable, memBlock );
|
|
|
221 public:
|
|
|
222 virtual void * dataMutable() = 0;
|
|
|
223
|
|
|
224 //! Resizes preserving content. When expanding, contents of newly allocated area are undefined.
|
|
|
225 virtual void resize( size_t size ) = 0;
|
|
|
226 //! Resizes without preserving content. Contents undefined afterwards.
|
|
|
227 virtual void resizeDiscard( size_t size ) { resize( size ); }
|
|
|
228
|
|
|
229 memBlockMutable::ptr copy() const;
|
|
|
230 memBlock::ptr copyConst() const;
|
|
|
231 static memBlockMutable::ptr empty();
|
|
|
232 static memBlockMutable::ptr blockWithSize( size_t initSize );
|
|
|
233 static memBlockMutable::ptr blockWithData( const void * inData, size_t inSize );
|
|
|
234 static memBlockMutable::ptr blockWithBlock( memBlock::ptr block );
|
|
|
235
|
|
|
236 bool operator==(const memBlockMutable & other) const {return equals(*this,other);}
|
|
|
237 bool operator!=(const memBlockMutable & other) const {return !equals(*this,other);}
|
|
|
238 };
|
|
|
239
|
|
|
240
|
|
|
241 //! Asynchronous object return helper. \n
|
|
|
242 //! If the operation has failed for some reason, receiveObj() will be called with null object.
|
|
|
243 class objReceiver : public service_base {
|
|
|
244 FB2K_MAKE_SERVICE_INTERFACE( objReceiver, service_base );
|
|
|
245 public:
|
|
|
246 virtual void receiveObj( objRef obj ) = 0;
|
|
|
247 };
|
|
|
248
|
|
|
249 typedef objReceiver::ptr objReceiverRef;
|
|
|
250
|
|
|
251
|
|
|
252 typedef ::completion_notify completionNotify;
|
|
|
253 typedef completionNotify::ptr completionNotifyRef;
|
|
|
254 typedef array::ptr arrayRef;
|
|
|
255 typedef arrayMutable::ptr arrayMutableRef;
|
|
|
256 typedef string::ptr stringRef;
|
|
|
257 typedef memBlock::ptr memBlockRef;
|
|
|
258 typedef memBlockMutable::ptr memBlockMutableRef;
|
|
|
259
|
|
|
260 stringRef makeString( const wchar_t * str );
|
|
|
261 stringRef makeString( const wchar_t * str, size_t len );
|
|
|
262
|
|
|
263 inline stringRef makeString( const char * str ) {
|
|
|
264 return string::stringWithString ( str );
|
|
|
265 }
|
|
|
266 inline stringRef makeString( const char * str, size_t len) {
|
|
|
267 return string::stringWithString ( str, len );
|
|
|
268 }
|
|
|
269 inline arrayRef makeArray( std::initializer_list<objRef> const & arg ) {
|
|
|
270 return array::arrayWithObjects( arg );
|
|
|
271 }
|
|
|
272 inline memBlockRef makeMemBlock( const void * data, size_t size ) {
|
|
|
273 return memBlock::blockWithData( data, size );
|
|
|
274 }
|
|
|
275
|
|
|
276 void describe( objRef obj, pfc::string_formatter & output, unsigned indent);
|
|
|
277 void describeDebug( objRef obj );
|
|
|
278
|
|
|
279
|
|
|
280 typedef std::function< void (objRef) > objReceiverFunc_t;
|
|
|
281
|
|
|
282 objReceiverRef makeObjReceiver( objReceiverFunc_t );
|
|
|
283
|
|
|
284 template<typename class_t> objReceiverRef makeObjReceiverTyped(std::function< void(service_ptr_t<class_t>) > func) {
|
|
|
285 return makeObjReceiver([=](objRef obj) {
|
|
|
286 if (obj.is_empty()) func(nullptr);
|
|
|
287 else {
|
|
|
288 service_ptr_t<class_t> temp; temp ^= obj; func(temp);
|
|
|
289 }
|
|
|
290 });
|
|
|
291 }
|
|
|
292
|
|
|
293 objRef callOnRelease( std::function< void () > );
|
|
|
294 objRef callOnReleaseInMainThread( std::function< void () > );
|
|
|
295
|
|
|
296 arrayRef makeArrayDeferred( std::function< arrayRef () > f );
|
|
|
297 }
|
|
|
298 inline pfc::string_base & operator<<(pfc::string_base & p_fmt, fb2k::stringRef str) { p_fmt.add_string(str->c_str()); return p_fmt; }
|