Loading...
Searching...
No Matches
listProxy.h
Go to the documentation of this file.
1//
2// Copyright 2016 Pixar
3//
4// Licensed under the Apache License, Version 2.0 (the "Apache License")
5// with the following modification; you may not use this file except in
6// compliance with the Apache License and the following modification to it:
7// Section 6. Trademarks. is deleted and replaced with:
8//
9// 6. Trademarks. This License does not grant permission to use the trade
10// names, trademarks, service marks, or product names of the Licensor
11// and its affiliates, except as required to comply with Section 4(c) of
12// the License and to reproduce the content of the NOTICE file.
13//
14// You may obtain a copy of the Apache License at
15//
16// http://www.apache.org/licenses/LICENSE-2.0
17//
18// Unless required by applicable law or agreed to in writing, software
19// distributed under the Apache License with the above modification is
20// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21// KIND, either express or implied. See the Apache License for the specific
22// language governing permissions and limitations under the Apache License.
23//
24#ifndef PXR_USD_SDF_LIST_PROXY_H
25#define PXR_USD_SDF_LIST_PROXY_H
26
28
29#include "pxr/pxr.h"
30#include "pxr/usd/sdf/allowed.h"
31#include "pxr/usd/sdf/listEditor.h"
32#include "pxr/usd/sdf/listOp.h"
33#include "pxr/usd/sdf/path.h"
34
38
39#include <memory>
40#include <optional>
41#include <type_traits>
42
43PXR_NAMESPACE_OPEN_SCOPE
44
53template <class _TypePolicy>
55public:
56 typedef _TypePolicy TypePolicy;
58 typedef typename TypePolicy::value_type value_type;
59 typedef std::vector<value_type> value_vector_type;
60
61private:
62 // Proxies an item in a list editor list.
63 class _ItemProxy {
64 public:
65 explicit _ItemProxy(This* owner, size_t index) :
66 _owner(owner), _index(index)
67 {
68 // Do nothing
69 }
70
71 _ItemProxy& operator=(const _ItemProxy& x) {
72 _owner->_Edit(_index, 1, value_vector_type(1, x));
73 return *this;
74 }
75
76 _ItemProxy& operator=(const value_type& x) {
77 _owner->_Edit(_index, 1, value_vector_type(1, x));
78 return *this;
79 }
80
81 operator value_type() const {
82 return _owner->_Get(_index);
83 }
84
85 // Operators rely on implicit conversion to value_type
86 // for comparing two _ItemProxy instances
87 bool operator==(const value_type& x) const {
88 return _owner->_Get(_index) == x;
89 }
90
91 bool operator!=(const value_type& x) const {
92 return !(*this == x);
93 }
94
95 bool operator<(const value_type& x) const {
96 return _owner->_Get(_index) < x;
97 }
98
99 bool operator>(const value_type& x) const {
100 return x < value_type(*this);
101 }
102
103 bool operator>=(const value_type& x) const {
104 return !(*this < x);
105 }
106
107 bool operator<=(const value_type& x) const {
108 return !(x < value_type(*this));
109 }
110
111 private:
112 This* _owner;
113 size_t _index;
114 };
115 friend class _ItemProxy;
116
117 class _GetHelper {
118 public:
119 typedef _ItemProxy result_type;
120
121 result_type operator()(This* owner, size_t index) const {
122 return _ItemProxy(owner, index);
123 }
124 };
125 class _ConstGetHelper {
126 public:
127 typedef value_type result_type;
128
129 result_type operator()(const This* owner, size_t index) const {
130 return owner->_Get(index);
131 }
132 };
133 friend class _GetHelper;
134 friend class _ConstGetHelper;
135
136 template <class Owner, class GetItem>
137 class _Iterator {
138 class _PtrProxy {
139 public:
140 std::add_pointer_t<typename GetItem::result_type> operator->() {
141 return std::addressof(_result);
142 }
143 private:
144 friend class _Iterator;
145 explicit _PtrProxy(
146 std::add_const_t<
147 std::add_lvalue_reference_t<
148 typename GetItem::result_type>
149 > result) : _result(result) {}
150 typename GetItem::result_type _result;
151 };
152 public:
153 using This = _Iterator<Owner, GetItem>;
154 using iterator_category = std::random_access_iterator_tag;
155 using value_type = std::remove_cv_t<
156 std::remove_reference_t<
157 typename GetItem::result_type
158 >
159 >;
160 using reference = typename GetItem::result_type;
161 using pointer = _PtrProxy;
162 using difference_type = std::ptrdiff_t;
163
164 static_assert(!std::is_lvalue_reference<reference>::value,
165 "reference is an lvalue_reference and usage of "
166 "this class unnecessarily instantiates a _PtrProxy.");
167
168 _Iterator() = default;
169
170 _Iterator(Owner owner, size_t index) : _owner(owner), _index(index)
171 {
172 // Do nothing
173 }
174
175 reference operator*() const { return dereference(); }
176 pointer operator->() const { return pointer(dereference()); }
177 reference operator[](const difference_type index) const {
178 This advanced(*this);
179 advanced.advance(index);
180 return advanced.dereference();
181 }
182
183 difference_type operator-(const This& other) const {
184 return -distance_to(other);
185 }
186
187 This& operator++() {
188 increment();
189 return *this;
190 }
191
192 This& operator--() {
193 decrement();
194 return *this;
195 }
196
197 This operator++(int) {
198 This result(*this);
199 increment();
200 return result;
201 }
202
203 This operator--(int) {
204 This result(*this);
205 decrement();
206 return result;
207 }
208
209 This operator+(const difference_type increment) const {
210 This result(*this);
211 result.advance(increment);
212 return result;
213 }
214
215 This operator-(const difference_type decrement) const {
216 This result(*this);
217 result.advance(-decrement);
218 return result;
219 }
220
221 This& operator+=(const difference_type increment) {
222 advance(increment);
223 return *this;
224 }
225
226 This& operator-=(const difference_type decrement) {
227 advance(-decrement);
228 return *this;
229 }
230
231 bool operator==(const This& other) const {
232 return equal(other);
233 }
234
235 bool operator!=(const This& other) const {
236 return !equal(other);
237 }
238
239 bool operator<(const This& other) const {
240 TF_DEV_AXIOM(_owner == other._owner);
241 return _index < other._index;
242 }
243
244 bool operator<=(const This& other) const {
245 TF_DEV_AXIOM(_owner == other._owner);
246 return _index <= other._index;
247 }
248
249 bool operator>(const This& other) const {
250 TF_DEV_AXIOM(_owner == other._owner);
251 return _index > other._index;
252 }
253
254 bool operator>=(const This& other) const {
255 TF_DEV_AXIOM(_owner == other._owner);
256 return _index >= other._index;
257 }
258
259 private:
260
261 reference dereference() const {
262 return _getItem(_owner, _index);
263 }
264
265 bool equal(const This& other) const {
266 if (_owner != other._owner) {
267 TF_CODING_ERROR("Comparing SdfListProxy iterators from "
268 "different proxies!");
269 return false;
270 }
271 return _index == other._index;
272 }
273
274 void increment() {
275 ++_index;
276 }
277
278 void decrement() {
279 --_index;
280 }
281
282 void advance(difference_type n) {
283 _index += n;
284 }
285
286 difference_type distance_to(const This& other) const {
287 return other._index - _index;
288 }
289
290 private:
291 GetItem _getItem;
292 Owner _owner = nullptr;
293 size_t _index = 0;
294 };
295
296public:
297 typedef _ItemProxy reference;
298 typedef _Iterator<This*, _GetHelper> iterator;
299 typedef _Iterator<const This*, _ConstGetHelper> const_iterator;
300 typedef Tf_ProxyReferenceReverseIterator<iterator> reverse_iterator;
301 typedef Tf_ProxyReferenceReverseIterator<const_iterator> const_reverse_iterator;
302
306 SdfListProxy(SdfListOpType op) :
307 _op(op)
308 {
309 }
310
313 SdfListProxy(const std::shared_ptr<Sdf_ListEditor<TypePolicy> >& editor,
314 SdfListOpType op) :
315 _listEditor(editor),
316 _op(op)
317 {
318 }
319
321 iterator begin() {
322 return iterator(_GetThis(), 0);
323 }
325 iterator end() {
326 return iterator(_GetThis(), _GetSize());
327 }
328
330 reverse_iterator rbegin() {
331 return reverse_iterator(end());
332 }
334 reverse_iterator rend() {
335 return reverse_iterator(begin());
336 }
337
339 const_iterator begin() const {
340 return const_iterator(_GetThis(), 0);
341 }
343 const_iterator end() const {
344 return const_iterator(_GetThis(), _GetSize());
345 }
346
348 const_reverse_iterator rbegin() const {
349 return const_reverse_iterator(end());
350 }
353 const_reverse_iterator rend() const {
354 return const_reverse_iterator(begin());
355 }
356
358 size_t size() const {
359 return _Validate() ? _GetSize() : 0;
360 }
361
363 bool empty() const {
364 return size() == 0;
365 }
366
368 reference operator[](size_t n) {
369 return reference(_GetThis(), n);
370 }
371
373 value_type operator[](size_t n) const {
374 return _Get(n);
375 }
376
378 reference front() {
379 return reference(_GetThis(), 0);
380 }
381
383 reference back() {
384 return reference(_GetThis(), _GetSize() - 1);
385 }
386
388 value_type front() const {
389 return _Get(0);
390 }
391
393 value_type back() const {
394 return _Get(_GetSize() - 1);
395 }
396
398 void push_back(const value_type& elem) {
399 _Edit(_GetSize(), 0, value_vector_type(1, elem));
400 }
401
403 void pop_back() {
404 _Edit(_GetSize() - 1, 1, value_vector_type());
405 }
406
408 iterator insert(iterator pos, const value_type& x) {
409 _Edit(pos - iterator(this, 0), 0, value_vector_type(1, x));
410 return pos;
411 }
412
415 template <class InputIterator>
416 void insert(iterator pos, InputIterator f, InputIterator l) {
417 _Edit(pos - iterator(this, 0), 0, value_vector_type(f, l));
418 }
419
421 void erase(iterator pos) {
422 _Edit(pos - iterator(this, 0), 1, value_vector_type());
423 }
424
426 void erase(iterator f, iterator l) {
427 _Edit(f - iterator(this, 0), l - f, value_vector_type());
428 }
429
431 void clear() {
432 _Edit(0, _GetSize(), value_vector_type());
433 }
434
439 void resize(size_t n, const value_type& t = value_type()) {
440 size_t s = _GetSize();
441 if (n > s) {
442 _Edit(s, 0, value_vector_type(n - s, t));
443 }
444 else if (n < s) {
445 _Edit(n, s - n, value_vector_type());
446 }
447 }
448
450 operator value_vector_type() const {
451 return _listEditor ? _listEditor->GetVector(_op) : value_vector_type();
452 }
453
456 template <class T2>
458 _Edit(0, _GetSize(), static_cast<value_vector_type>(other));
459 return *this;
460 }
461
463 This& operator=(const value_vector_type& other) {
464 _Edit(0, _GetSize(), other);
465 return *this;
466 }
467
469 template <class Y>
470 This& operator=(const std::vector<Y>& v) {
471 _Edit(0, _GetSize(), value_vector_type(v.begin(), v.end()));
472 return *this;
473 }
474
476 template <class T2>
477 bool operator==(const SdfListProxy<T2>& y) const {
478 return value_vector_type(*this) == value_vector_type(y);
479 }
480
482 template <class T2>
483 bool operator!=(const SdfListProxy<T2>& y) const {
484 return !(*this == y);
485 }
486
488 template <class T2>
489 bool operator<(const SdfListProxy<T2>& y) const {
490 return value_vector_type(*this) < value_vector_type(y);
491 }
492
494 template <class T2>
495 bool operator<=(const SdfListProxy<T2>& y) const {
496 return value_vector_type(*this) <= value_vector_type(y);
497 }
498
500 template <class T2>
501 bool operator>(const SdfListProxy<T2>& y) const {
502 return !(*this <= y);
503 }
504
506 template <class T2>
507 bool operator>=(const SdfListProxy<T2>& y) const {
508 return !(*this < y);
509 }
510
512 bool operator==(const value_vector_type& y) const {
513 return value_vector_type(*this) == y;
514 }
515
517 friend bool operator==(const value_vector_type& x, const SdfListProxy& y) {
518 return y == x;
519 }
520
522 bool operator!=(const value_vector_type& y) const {
523 return !(*this == y);
524 }
525
527 friend bool operator!=(const value_vector_type& x, const SdfListProxy& y) {
528 return y != x;
529 }
530
532 bool operator<(const value_vector_type& y) const {
533 return value_vector_type(*this) < y;
534 }
535
537 friend bool operator<(const value_vector_type& x, const SdfListProxy& y) {
538 return x < value_vector_type(y);
539 }
540
542 bool operator>(const value_vector_type& y) const {
543 return value_vector_type(*this) > y;
544 }
545
547 friend bool operator>(const value_vector_type& x, const SdfListProxy& y) {
548 return x > value_vector_type(y);
549 }
550
552 bool operator<=(const value_vector_type& y) const {
553 return !(*this > y);
554 }
555
557 friend bool operator<=(const value_vector_type& x, const SdfListProxy& y) {
558 return x <= value_vector_type(y);
559 }
560
562 bool operator>=(const value_vector_type& y) const {
563 return !(*this < y);
564 }
565
567 friend bool operator>=(const value_vector_type& x, const SdfListProxy& y) {
568 return x >= value_vector_type(y);
569 }
570
573 explicit operator bool() const
574 {
575 return _listEditor && _listEditor->IsValid() && _IsRelevant();
576 }
577
578 // Extensions
579
581 SdfLayerHandle GetLayer() const
582 {
583 return _listEditor ? _listEditor->GetLayer() : SdfLayerHandle();
584 }
585
588 {
589 return _listEditor ? _listEditor->GetPath() : SdfPath();
590 }
591
593 bool IsExpired() const
594 {
595 return _listEditor && _listEditor->IsExpired();
596 }
597
598 size_t Count(const value_type& value) const
599 {
600 return (_Validate() ? _listEditor->Count(_op, value) : 0);
601 }
602
603 size_t Find(const value_type& value) const
604 {
605 return (_Validate() ? _listEditor->Find(_op, value) : size_t(-1));
606 }
607
608 void Insert(int index, const value_type& value)
609 {
610 if (index == -1) {
611 index = static_cast<int>(_GetSize());
612 }
613 _Edit(index, 0, value_vector_type(1, value));
614 }
615
616 void Remove(const value_type& value)
617 {
618 size_t index = Find(value);
619 if (index != size_t(-1)) {
620 Erase(index);
621 }
622 else {
623 // Allow policy to raise an error even though we're not
624 // doing anything.
625 _Edit(_GetSize(), 0, value_vector_type());
626 }
627 }
628
629 void Replace(const value_type& oldValue, const value_type& newValue)
630 {
631 size_t index = Find(oldValue);
632 if (index != size_t(-1)) {
633 _Edit(index, 1, value_vector_type(1, newValue));
634 }
635 else {
636 // Allow policy to raise an error even though we're not
637 // doing anything.
638 _Edit(_GetSize(), 0, value_vector_type());
639 }
640 }
641
642 void Erase(size_t index)
643 {
644 _Edit(index, 1, value_vector_type());
645 }
646
648 void ApplyList(const SdfListProxy &list)
649 {
650 if (_Validate() && list._Validate()) {
651 _listEditor->ApplyList(_op, *list._listEditor);
652 }
653 }
654
656 void ApplyEditsToList(value_vector_type* vec)
657 {
658 if (_Validate()) {
659 _listEditor->ApplyEditsToList(vec);
660 }
661 }
662
673 template <class CB>
674 void ModifyItemEdits(CB callback)
675 {
676 if (_Validate()) {
677 _listEditor->ModifyItemEdits(std::forward<CB>(callback));
678 }
679 }
680
681private:
682 bool _Validate()
683 {
684 if (!_listEditor) {
685 return false;
686 }
687
688 if (IsExpired()) {
689 TF_CODING_ERROR("Accessing expired list editor");
690 return false;
691 }
692 return true;
693 }
694
695 bool _Validate() const
696 {
697 if (!_listEditor) {
698 return false;
699 }
700
701 if (IsExpired()) {
702 TF_CODING_ERROR("Accessing expired list editor");
703 return false;
704 }
705 return true;
706 }
707
708 This* _GetThis()
709 {
710 return _Validate() ? this : NULL;
711 }
712
713 const This* _GetThis() const
714 {
715 return _Validate() ? this : NULL;
716 }
717
718 bool _IsRelevant() const
719 {
720 if (_listEditor->IsExplicit()) {
721 return _op == SdfListOpTypeExplicit;
722 }
723 else if (_listEditor->IsOrderedOnly()) {
724 return _op == SdfListOpTypeOrdered;
725 }
726 else {
727 return _op != SdfListOpTypeExplicit;
728 }
729 }
730
731 size_t _GetSize() const
732 {
733 return _listEditor ? _listEditor->GetSize(_op) : 0;
734 }
735
736 value_type _Get(size_t n) const
737 {
738 return _Validate() ? _listEditor->Get(_op, n) : value_type();
739 }
740
741 void _Edit(size_t index, size_t n, const value_vector_type& elems)
742 {
743 if (_Validate()) {
744 // Allow policy to raise an error even if we're not
745 // doing anything.
746 if (n == 0 && elems.empty()) {
747 SdfAllowed canEdit = _listEditor->PermissionToEdit(_op);
748 if (!canEdit) {
749 TF_CODING_ERROR("Editing list: %s",
750 canEdit.GetWhyNot().c_str());
751 }
752 return;
753 }
754
755 bool valid =
756 _listEditor->ReplaceEdits(_op, index, n, elems);
757 if (!valid) {
758 TF_CODING_ERROR("Inserting invalid value into list editor");
759 }
760 }
761 }
762
763private:
764 std::shared_ptr<Sdf_ListEditor<TypePolicy> > _listEditor;
765 SdfListOpType _op;
766
767 template <class> friend class SdfPyWrapListProxy;
768};
769
770// Allow TfIteration over list proxies.
771template <typename T>
772struct Tf_ShouldIterateOverCopy<SdfListProxy<T> > : std::true_type
773{
774};
775
776PXR_NAMESPACE_CLOSE_SCOPE
777
778#endif // PXR_USD_SDF_LIST_PROXY_H
Low-level utilities for informing users of various internal and external diagnostic conditions.
A simple iterator adapter for STL containers.
Indicates if an operation is allowed and, if not, why not.
Definition: allowed.h:46
SDF_API const std::string & GetWhyNot() const
Returns the reason why the operation is not allowed.
Represents a single list of list editing operations.
Definition: listProxy.h:54
void pop_back()
Remove the last element from this sequence.
Definition: listProxy.h:403
value_type operator[](size_t n) const
Return a copy of the item at index n.
Definition: listProxy.h:373
const_reverse_iterator rend() const
Return a const reverse iterator past the start item of the sequence.
Definition: listProxy.h:353
void push_back(const value_type &elem)
Append elem to this sequence.
Definition: listProxy.h:398
friend bool operator<=(const value_vector_type &x, const SdfListProxy &y)
Less-than or equal to comparison.
Definition: listProxy.h:557
void ApplyList(const SdfListProxy &list)
Applies the edits in the given list to this one.
Definition: listProxy.h:648
value_type front() const
Return a copy of the item at the front of the sequence.
Definition: listProxy.h:388
bool operator<=(const value_vector_type &y) const
Less-than or equal to comparison.
Definition: listProxy.h:552
friend bool operator<(const value_vector_type &x, const SdfListProxy &y)
Less-than comparison.
Definition: listProxy.h:537
void ApplyEditsToList(value_vector_type *vec)
Apply the edits in this list to the given vec.
Definition: listProxy.h:656
size_t size() const
Return the size of the sequence.
Definition: listProxy.h:358
const_iterator begin() const
Return a const iterator to the start of the sequence.
Definition: listProxy.h:339
void resize(size_t n, const value_type &t=value_type())
Resize the contents of the sequence.
Definition: listProxy.h:439
void insert(iterator pos, InputIterator f, InputIterator l)
Insert copies of the elements in [f, l) into this sequence starting at position pos.
Definition: listProxy.h:416
bool operator>(const SdfListProxy< T2 > &y) const
Greater-than comparison.
Definition: listProxy.h:501
bool operator<=(const SdfListProxy< T2 > &y) const
Less-than-or-equal comparison.
Definition: listProxy.h:495
bool operator<(const SdfListProxy< T2 > &y) const
Less-than comparison.
Definition: listProxy.h:489
SdfListProxy(const std::shared_ptr< Sdf_ListEditor< TypePolicy > > &editor, SdfListOpType op)
Create a new proxy wrapping the list operation vector specified by op in the underlying listEditor.
Definition: listProxy.h:313
bool operator!=(const SdfListProxy< T2 > &y) const
Inequality comparison.
Definition: listProxy.h:483
bool empty() const
Return true if size() == 0.
Definition: listProxy.h:363
friend bool operator!=(const value_vector_type &x, const SdfListProxy &y)
Inequality comparision.
Definition: listProxy.h:527
reverse_iterator rend()
Return a reverse iterator past the start item of the sequence.
Definition: listProxy.h:334
reference front()
Return a reference to the item at the front of the sequence.
Definition: listProxy.h:378
SdfLayerHandle GetLayer() const
Returns the layer that this list editor belongs to.
Definition: listProxy.h:581
bool operator>=(const SdfListProxy< T2 > &y) const
Greater-than-or-equal comparison.
Definition: listProxy.h:507
value_type back() const
Return a copy of the item at the back of the sequence.
Definition: listProxy.h:393
friend bool operator>(const value_vector_type &x, const SdfListProxy &y)
Greater-than comparison.
Definition: listProxy.h:547
bool operator>(const value_vector_type &y) const
Greater-than comparison.
Definition: listProxy.h:542
reference operator[](size_t n)
Return a reference to the item at index n.
Definition: listProxy.h:368
SdfListProxy(SdfListOpType op)
Creates a default list proxy object for list operation vector specified op.
Definition: listProxy.h:306
This & operator=(const std::vector< Y > &v)
Replace all elements in this sequence with the given vector.
Definition: listProxy.h:470
void ModifyItemEdits(CB callback)
Modify all edits in this list.
Definition: listProxy.h:674
void erase(iterator f, iterator l)
Erase all the elements in the range [f, l).
Definition: listProxy.h:426
SdfPath GetPath() const
Returns the path to this list editor's value.
Definition: listProxy.h:587
friend bool operator==(const value_vector_type &x, const SdfListProxy &y)
Equality comparision.
Definition: listProxy.h:517
bool operator<(const value_vector_type &y) const
Less-than comparison.
Definition: listProxy.h:532
bool operator==(const value_vector_type &y) const
Equality comparison.
Definition: listProxy.h:512
iterator insert(iterator pos, const value_type &x)
Insert x into this sequence at position pos.
Definition: listProxy.h:408
bool IsExpired() const
Returns true if the list editor is expired.
Definition: listProxy.h:593
bool operator!=(const value_vector_type &y) const
Inequality comparison.
Definition: listProxy.h:522
bool operator>=(const value_vector_type &y) const
Greater-than or equal to comparison.
Definition: listProxy.h:562
void clear()
Clear the contents of the sequence.
Definition: listProxy.h:431
iterator end()
Return an iterator to the end of the sequence.
Definition: listProxy.h:325
const_iterator end() const
Return a const iterator to the end of the sequence.
Definition: listProxy.h:343
void erase(iterator pos)
Erase the element at pos.
Definition: listProxy.h:421
reverse_iterator rbegin()
Return a reverse iterator to the last item of the sequence.
Definition: listProxy.h:330
iterator begin()
Return an iterator to the start of the sequence.
Definition: listProxy.h:321
This & operator=(const SdfListProxy< T2 > &other)
Replace all elements in this sequence with the elements in the other sequence.
Definition: listProxy.h:457
const_reverse_iterator rbegin() const
Return a const reverse iterator to the last item of the sequence.
Definition: listProxy.h:348
reference back()
Return a reference to the item at the back of the sequence.
Definition: listProxy.h:383
This & operator=(const value_vector_type &other)
Replace all elements in this sequence with the given vector.
Definition: listProxy.h:463
bool operator==(const SdfListProxy< T2 > &y) const
Equality comparison.
Definition: listProxy.h:477
friend bool operator>=(const value_vector_type &x, const SdfListProxy &y)
Greater-than or equal to comparison.
Definition: listProxy.h:567
A path value used to locate objects in layers or scenegraphs.
Definition: path.h:290
#define TF_DEV_AXIOM(cond)
The same as TF_AXIOM, but compiled only in dev builds.
Definition: diagnostic.h:222
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition: diagnostic.h:85