• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2008, 2010 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 
24 /**
25  * \file list.h
26  * \brief Doubly-linked list abstract container type.
27  *
28  * Each doubly-linked list has a sentinel head and tail node.  These nodes
29  * contain no data.  The head sentinel can be identified by its \c prev
30  * pointer being \c NULL.  The tail sentinel can be identified by its
31  * \c next pointer being \c NULL.
32  *
33  * A list is empty if either the head sentinel's \c next pointer points to the
34  * tail sentinel or the tail sentinel's \c prev poiner points to the head
35  * sentinel. The head sentinel and tail sentinel nodes are allocated within the
36  * list structure.
37  *
38  * Do note that this means that the list nodes will contain pointers into the
39  * list structure itself and as a result you may not \c realloc() an  \c
40  * exec_list or any structure in which an \c exec_list is embedded.
41  */
42 
43 #pragma once
44 #ifndef LIST_CONTAINER_H
45 #define LIST_CONTAINER_H
46 
47 #ifndef __cplusplus
48 #include <stddef.h>
49 #endif
50 #include <assert.h>
51 
52 #include "util/ralloc.h"
53 
54 struct exec_node {
55    struct exec_node *next;
56    struct exec_node *prev;
57 
58 #ifdef __cplusplus
59    DECLARE_RZALLOC_CXX_OPERATORS(exec_node)
60 
exec_nodeexec_node61    exec_node() : next(NULL), prev(NULL)
62    {
63       /* empty */
64    }
65 
66    const exec_node *get_next() const;
67    exec_node *get_next();
68 
69    const exec_node *get_prev() const;
70    exec_node *get_prev();
71 
72    void remove();
73 
74    /**
75     * Link a node with itself
76     *
77     * This creates a sort of degenerate list that is occasionally useful.
78     */
79    void self_link();
80 
81    /**
82     * Insert a node in the list after the current node
83     */
84    void insert_after(exec_node *after);
85    /**
86     * Insert a node in the list before the current node
87     */
88    void insert_before(exec_node *before);
89 
90    /**
91     * Insert another list in the list before the current node
92     */
93    void insert_before(struct exec_list *before);
94 
95    /**
96     * Replace the current node with the given node.
97     */
98    void replace_with(exec_node *replacement);
99 
100    /**
101     * Is this the sentinel at the tail of the list?
102     */
103    bool is_tail_sentinel() const;
104 
105    /**
106     * Is this the sentinel at the head of the list?
107     */
108    bool is_head_sentinel() const;
109 #endif
110 };
111 
112 static inline void
exec_node_init(struct exec_node * n)113 exec_node_init(struct exec_node *n)
114 {
115    n->next = NULL;
116    n->prev = NULL;
117 }
118 
119 static inline const struct exec_node *
exec_node_get_next_const(const struct exec_node * n)120 exec_node_get_next_const(const struct exec_node *n)
121 {
122    return n->next;
123 }
124 
125 static inline struct exec_node *
exec_node_get_next(struct exec_node * n)126 exec_node_get_next(struct exec_node *n)
127 {
128    return n->next;
129 }
130 
131 static inline const struct exec_node *
exec_node_get_prev_const(const struct exec_node * n)132 exec_node_get_prev_const(const struct exec_node *n)
133 {
134    return n->prev;
135 }
136 
137 static inline struct exec_node *
exec_node_get_prev(struct exec_node * n)138 exec_node_get_prev(struct exec_node *n)
139 {
140    return n->prev;
141 }
142 
143 static inline void
exec_node_remove(struct exec_node * n)144 exec_node_remove(struct exec_node *n)
145 {
146    n->next->prev = n->prev;
147    n->prev->next = n->next;
148    n->next = NULL;
149    n->prev = NULL;
150 }
151 
152 static inline void
exec_node_self_link(struct exec_node * n)153 exec_node_self_link(struct exec_node *n)
154 {
155    n->next = n;
156    n->prev = n;
157 }
158 
159 static inline void
exec_node_insert_after(struct exec_node * n,struct exec_node * after)160 exec_node_insert_after(struct exec_node *n, struct exec_node *after)
161 {
162    after->next = n->next;
163    after->prev = n;
164 
165    n->next->prev = after;
166    n->next = after;
167 }
168 
169 static inline void
exec_node_insert_node_before(struct exec_node * n,struct exec_node * before)170 exec_node_insert_node_before(struct exec_node *n, struct exec_node *before)
171 {
172    before->next = n;
173    before->prev = n->prev;
174 
175    n->prev->next = before;
176    n->prev = before;
177 }
178 
179 static inline void
exec_node_replace_with(struct exec_node * n,struct exec_node * replacement)180 exec_node_replace_with(struct exec_node *n, struct exec_node *replacement)
181 {
182    replacement->prev = n->prev;
183    replacement->next = n->next;
184 
185    n->prev->next = replacement;
186    n->next->prev = replacement;
187 }
188 
189 static inline bool
exec_node_is_tail_sentinel(const struct exec_node * n)190 exec_node_is_tail_sentinel(const struct exec_node *n)
191 {
192    return n->next == NULL;
193 }
194 
195 static inline bool
exec_node_is_head_sentinel(const struct exec_node * n)196 exec_node_is_head_sentinel(const struct exec_node *n)
197 {
198    return n->prev == NULL;
199 }
200 
201 #ifdef __cplusplus
get_next()202 inline const exec_node *exec_node::get_next() const
203 {
204    return exec_node_get_next_const(this);
205 }
206 
get_next()207 inline exec_node *exec_node::get_next()
208 {
209    return exec_node_get_next(this);
210 }
211 
get_prev()212 inline const exec_node *exec_node::get_prev() const
213 {
214    return exec_node_get_prev_const(this);
215 }
216 
get_prev()217 inline exec_node *exec_node::get_prev()
218 {
219    return exec_node_get_prev(this);
220 }
221 
remove()222 inline void exec_node::remove()
223 {
224    exec_node_remove(this);
225 }
226 
self_link()227 inline void exec_node::self_link()
228 {
229    exec_node_self_link(this);
230 }
231 
insert_after(exec_node * after)232 inline void exec_node::insert_after(exec_node *after)
233 {
234    exec_node_insert_after(this, after);
235 }
236 
insert_before(exec_node * before)237 inline void exec_node::insert_before(exec_node *before)
238 {
239    exec_node_insert_node_before(this, before);
240 }
241 
replace_with(exec_node * replacement)242 inline void exec_node::replace_with(exec_node *replacement)
243 {
244    exec_node_replace_with(this, replacement);
245 }
246 
is_tail_sentinel()247 inline bool exec_node::is_tail_sentinel() const
248 {
249    return exec_node_is_tail_sentinel(this);
250 }
251 
is_head_sentinel()252 inline bool exec_node::is_head_sentinel() const
253 {
254    return exec_node_is_head_sentinel(this);
255 }
256 #endif
257 
258 #ifdef __cplusplus
259 /* This macro will not work correctly if `t' uses virtual inheritance.  If you
260  * are using virtual inheritance, you deserve a slow and painful death.  Enjoy!
261  */
262 #define exec_list_offsetof(t, f, p) \
263    (((char *) &((t *) p)->f) - ((char *) p))
264 #else
265 #define exec_list_offsetof(t, f, p) offsetof(t, f)
266 #endif
267 
268 /**
269  * Get a pointer to the structure containing an exec_node
270  *
271  * Given a pointer to an \c exec_node embedded in a structure, get a pointer to
272  * the containing structure.
273  *
274  * \param type  Base type of the structure containing the node
275  * \param node  Pointer to the \c exec_node
276  * \param field Name of the field in \c type that is the embedded \c exec_node
277  */
278 #define exec_node_data(type, node, field) \
279    ((type *) (((char *) node) - exec_list_offsetof(type, field, node)))
280 
281 #ifdef __cplusplus
282 struct exec_node;
283 #endif
284 
285 struct exec_list {
286    struct exec_node head_sentinel;
287    struct exec_node tail_sentinel;
288 
289 #ifdef __cplusplus
290    DECLARE_RALLOC_CXX_OPERATORS(exec_list)
291 
exec_listexec_list292    exec_list()
293    {
294       make_empty();
295    }
296 
297    void make_empty();
298 
299    bool is_empty() const;
300 
301    const exec_node *get_head() const;
302    exec_node *get_head();
303    const exec_node *get_head_raw() const;
304    exec_node *get_head_raw();
305 
306    const exec_node *get_tail() const;
307    exec_node *get_tail();
308    const exec_node *get_tail_raw() const;
309    exec_node *get_tail_raw();
310 
311    unsigned length() const;
312 
313    void push_head(exec_node *n);
314    void push_tail(exec_node *n);
315    void push_degenerate_list_at_head(exec_node *n);
316 
317    /**
318     * Remove the first node from a list and return it
319     *
320     * \return
321     * The first node in the list or \c NULL if the list is empty.
322     *
323     * \sa exec_list::get_head
324     */
325    exec_node *pop_head();
326 
327    /**
328     * Move all of the nodes from this list to the target list
329     */
330    void move_nodes_to(exec_list *target);
331 
332    /**
333     * Append all nodes from the source list to the end of the target list
334     */
335    void append_list(exec_list *source);
336 
337    /**
338     * Prepend all nodes from the source list to the beginning of the target
339     * list
340     */
341    void prepend_list(exec_list *source);
342 #endif
343 };
344 
345 static inline void
exec_list_make_empty(struct exec_list * list)346 exec_list_make_empty(struct exec_list *list)
347 {
348    list->head_sentinel.next = &list->tail_sentinel;
349    list->head_sentinel.prev = NULL;
350    list->tail_sentinel.next = NULL;
351    list->tail_sentinel.prev = &list->head_sentinel;
352 }
353 
354 static inline bool
exec_list_is_empty(const struct exec_list * list)355 exec_list_is_empty(const struct exec_list *list)
356 {
357    /* There are three ways to test whether a list is empty or not.
358     *
359     * - Check to see if the head sentinel's \c next is the tail sentinel.
360     * - Check to see if the tail sentinel's \c prev is the head sentinel.
361     * - Check to see if the head is the sentinel node by test whether its
362     *   \c next pointer is \c NULL.
363     *
364     * The first two methods tend to generate better code on modern systems
365     * because they save a pointer dereference.
366     */
367    return list->head_sentinel.next == &list->tail_sentinel;
368 }
369 
370 static inline const struct exec_node *
exec_list_get_head_const(const struct exec_list * list)371 exec_list_get_head_const(const struct exec_list *list)
372 {
373    return !exec_list_is_empty(list) ? list->head_sentinel.next : NULL;
374 }
375 
376 static inline struct exec_node *
exec_list_get_head(struct exec_list * list)377 exec_list_get_head(struct exec_list *list)
378 {
379    return !exec_list_is_empty(list) ? list->head_sentinel.next : NULL;
380 }
381 
382 static inline const struct exec_node *
exec_list_get_head_raw_const(const struct exec_list * list)383 exec_list_get_head_raw_const(const struct exec_list *list)
384 {
385    return list->head_sentinel.next;
386 }
387 
388 static inline struct exec_node *
exec_list_get_head_raw(struct exec_list * list)389 exec_list_get_head_raw(struct exec_list *list)
390 {
391    return list->head_sentinel.next;
392 }
393 
394 static inline const struct exec_node *
exec_list_get_tail_const(const struct exec_list * list)395 exec_list_get_tail_const(const struct exec_list *list)
396 {
397    return !exec_list_is_empty(list) ? list->tail_sentinel.prev : NULL;
398 }
399 
400 static inline struct exec_node *
exec_list_get_tail(struct exec_list * list)401 exec_list_get_tail(struct exec_list *list)
402 {
403    return !exec_list_is_empty(list) ? list->tail_sentinel.prev : NULL;
404 }
405 
406 static inline const struct exec_node *
exec_list_get_tail_raw_const(const struct exec_list * list)407 exec_list_get_tail_raw_const(const struct exec_list *list)
408 {
409    return list->tail_sentinel.prev;
410 }
411 
412 static inline struct exec_node *
exec_list_get_tail_raw(struct exec_list * list)413 exec_list_get_tail_raw(struct exec_list *list)
414 {
415    return list->tail_sentinel.prev;
416 }
417 
418 static inline unsigned
exec_list_length(const struct exec_list * list)419 exec_list_length(const struct exec_list *list)
420 {
421    unsigned size = 0;
422    struct exec_node *node;
423 
424    for (node = list->head_sentinel.next; node->next != NULL; node = node->next) {
425       size++;
426    }
427 
428    return size;
429 }
430 
431 static inline void
exec_list_push_head(struct exec_list * list,struct exec_node * n)432 exec_list_push_head(struct exec_list *list, struct exec_node *n)
433 {
434    n->next = list->head_sentinel.next;
435    n->prev = &list->head_sentinel;
436 
437    n->next->prev = n;
438    list->head_sentinel.next = n;
439 }
440 
441 static inline void
exec_list_push_tail(struct exec_list * list,struct exec_node * n)442 exec_list_push_tail(struct exec_list *list, struct exec_node *n)
443 {
444    n->next = &list->tail_sentinel;
445    n->prev = list->tail_sentinel.prev;
446 
447    n->prev->next = n;
448    list->tail_sentinel.prev = n;
449 }
450 
451 static inline void
exec_list_push_degenerate_list_at_head(struct exec_list * list,struct exec_node * n)452 exec_list_push_degenerate_list_at_head(struct exec_list *list, struct exec_node *n)
453 {
454    assert(n->prev->next == n);
455 
456    n->prev->next = list->head_sentinel.next;
457    list->head_sentinel.next->prev = n->prev;
458    n->prev = &list->head_sentinel;
459    list->head_sentinel.next = n;
460 }
461 
462 static inline struct exec_node *
exec_list_pop_head(struct exec_list * list)463 exec_list_pop_head(struct exec_list *list)
464 {
465    struct exec_node *const n = exec_list_get_head(list);
466    if (n != NULL)
467       exec_node_remove(n);
468 
469    return n;
470 }
471 
472 static inline void
exec_list_move_nodes_to(struct exec_list * list,struct exec_list * target)473 exec_list_move_nodes_to(struct exec_list *list, struct exec_list *target)
474 {
475    if (exec_list_is_empty(list)) {
476       exec_list_make_empty(target);
477    } else {
478       target->head_sentinel.next = list->head_sentinel.next;
479       target->head_sentinel.prev = NULL;
480       target->tail_sentinel.next = NULL;
481       target->tail_sentinel.prev = list->tail_sentinel.prev;
482 
483       target->head_sentinel.next->prev = &target->head_sentinel;
484       target->tail_sentinel.prev->next = &target->tail_sentinel;
485 
486       exec_list_make_empty(list);
487    }
488 }
489 
490 static inline void
exec_list_append(struct exec_list * list,struct exec_list * source)491 exec_list_append(struct exec_list *list, struct exec_list *source)
492 {
493    if (exec_list_is_empty(source))
494       return;
495 
496    /* Link the first node of the source with the last node of the target list.
497     */
498    list->tail_sentinel.prev->next = source->head_sentinel.next;
499    source->head_sentinel.next->prev = list->tail_sentinel.prev;
500 
501    /* Make the tail of the source list be the tail of the target list.
502     */
503    list->tail_sentinel.prev = source->tail_sentinel.prev;
504    list->tail_sentinel.prev->next = &list->tail_sentinel;
505 
506    /* Make the source list empty for good measure.
507     */
508    exec_list_make_empty(source);
509 }
510 
511 static inline void
exec_list_prepend(struct exec_list * list,struct exec_list * source)512 exec_list_prepend(struct exec_list *list, struct exec_list *source)
513 {
514    exec_list_append(source, list);
515    exec_list_move_nodes_to(source, list);
516 }
517 
518 static inline void
exec_node_insert_list_before(struct exec_node * n,struct exec_list * before)519 exec_node_insert_list_before(struct exec_node *n, struct exec_list *before)
520 {
521    if (exec_list_is_empty(before))
522       return;
523 
524    before->tail_sentinel.prev->next = n;
525    before->head_sentinel.next->prev = n->prev;
526 
527    n->prev->next = before->head_sentinel.next;
528    n->prev = before->tail_sentinel.prev;
529 
530    exec_list_make_empty(before);
531 }
532 
533 static inline void
exec_list_validate(const struct exec_list * list)534 exec_list_validate(const struct exec_list *list)
535 {
536    const struct exec_node *node;
537 
538    assert(list->head_sentinel.next->prev == &list->head_sentinel);
539    assert(list->head_sentinel.prev == NULL);
540    assert(list->tail_sentinel.next == NULL);
541    assert(list->tail_sentinel.prev->next == &list->tail_sentinel);
542 
543    /* We could try to use one of the interators below for this but they all
544     * either require C++ or assume the exec_node is embedded in a structure
545     * which is not the case for this function.
546     */
547    for (node = list->head_sentinel.next; node->next != NULL; node = node->next) {
548       assert(node->next->prev == node);
549       assert(node->prev->next == node);
550    }
551 }
552 
553 #ifdef __cplusplus
make_empty()554 inline void exec_list::make_empty()
555 {
556    exec_list_make_empty(this);
557 }
558 
is_empty()559 inline bool exec_list::is_empty() const
560 {
561    return exec_list_is_empty(this);
562 }
563 
get_head()564 inline const exec_node *exec_list::get_head() const
565 {
566    return exec_list_get_head_const(this);
567 }
568 
get_head()569 inline exec_node *exec_list::get_head()
570 {
571    return exec_list_get_head(this);
572 }
573 
get_head_raw()574 inline const exec_node *exec_list::get_head_raw() const
575 {
576    return exec_list_get_head_raw_const(this);
577 }
578 
get_head_raw()579 inline exec_node *exec_list::get_head_raw()
580 {
581    return exec_list_get_head_raw(this);
582 }
583 
get_tail()584 inline const exec_node *exec_list::get_tail() const
585 {
586    return exec_list_get_tail_const(this);
587 }
588 
get_tail()589 inline exec_node *exec_list::get_tail()
590 {
591    return exec_list_get_tail(this);
592 }
593 
get_tail_raw()594 inline const exec_node *exec_list::get_tail_raw() const
595 {
596    return exec_list_get_tail_raw_const(this);
597 }
598 
get_tail_raw()599 inline exec_node *exec_list::get_tail_raw()
600 {
601    return exec_list_get_tail_raw(this);
602 }
603 
length()604 inline unsigned exec_list::length() const
605 {
606    return exec_list_length(this);
607 }
608 
push_head(exec_node * n)609 inline void exec_list::push_head(exec_node *n)
610 {
611    exec_list_push_head(this, n);
612 }
613 
push_tail(exec_node * n)614 inline void exec_list::push_tail(exec_node *n)
615 {
616    exec_list_push_tail(this, n);
617 }
618 
push_degenerate_list_at_head(exec_node * n)619 inline void exec_list::push_degenerate_list_at_head(exec_node *n)
620 {
621    exec_list_push_degenerate_list_at_head(this, n);
622 }
623 
pop_head()624 inline exec_node *exec_list::pop_head()
625 {
626    return exec_list_pop_head(this);
627 }
628 
move_nodes_to(exec_list * target)629 inline void exec_list::move_nodes_to(exec_list *target)
630 {
631    exec_list_move_nodes_to(this, target);
632 }
633 
append_list(exec_list * source)634 inline void exec_list::append_list(exec_list *source)
635 {
636    exec_list_append(this, source);
637 }
638 
prepend_list(exec_list * source)639 inline void exec_list::prepend_list(exec_list *source)
640 {
641    exec_list_prepend(this, source);
642 }
643 
insert_before(exec_list * before)644 inline void exec_node::insert_before(exec_list *before)
645 {
646    exec_node_insert_list_before(this, before);
647 }
648 #endif
649 
650 #define foreach_in_list(__type, __inst, __list)      \
651    for (__type *(__inst) = (__type *)(__list)->head_sentinel.next; \
652         !(__inst)->is_tail_sentinel();               \
653         (__inst) = (__type *)(__inst)->next)
654 
655 #define foreach_in_list_reverse(__type, __inst, __list)   \
656    for (__type *(__inst) = (__type *)(__list)->tail_sentinel.prev; \
657         !(__inst)->is_head_sentinel();                    \
658         (__inst) = (__type *)(__inst)->prev)
659 
660 /**
661  * This version is safe even if the current node is removed.
662  */
663 #define foreach_in_list_safe(__type, __node, __list) \
664    for (__type *__node = (__type *)(__list)->head_sentinel.next,   \
665                *__next = (__type *)__node->next;     \
666         __next != NULL;                              \
667         __node = __next, __next = (__type *)__next->next)
668 
669 #define foreach_in_list_reverse_safe(__type, __node, __list) \
670    for (__type *__node = (__type *)(__list)->tail_sentinel.prev,      \
671                *__prev = (__type *)__node->prev;             \
672         __prev != NULL;                                      \
673         __node = __prev, __prev = (__type *)__prev->prev)
674 
675 #define foreach_in_list_use_after(__type, __inst, __list) \
676    __type *(__inst);                                      \
677    for ((__inst) = (__type *)(__list)->head_sentinel.next; \
678         !(__inst)->is_tail_sentinel();                    \
679         (__inst) = (__type *)(__inst)->next)
680 /**
681  * Iterate through two lists at once.  Stops at the end of the shorter list.
682  *
683  * This is safe against either current node being removed or replaced.
684  */
685 #define foreach_two_lists(__node1, __list1, __node2, __list2) \
686    for (struct exec_node * __node1 = (__list1)->head_sentinel.next, \
687                          * __node2 = (__list2)->head_sentinel.next, \
688                          * __next1 = __node1->next,           \
689                          * __next2 = __node2->next            \
690 	; __next1 != NULL && __next2 != NULL                  \
691 	; __node1 = __next1,                                  \
692           __node2 = __next2,                                  \
693           __next1 = __next1->next,                            \
694           __next2 = __next2->next)
695 
696 #define foreach_list_typed(__type, __node, __field, __list)		\
697    for (__type * __node =						\
698          exec_node_data(__type, (__list)->head_sentinel.next, __field); \
699 	(__node)->__field.next != NULL; 				\
700 	(__node) = exec_node_data(__type, (__node)->__field.next, __field))
701 
702 #define foreach_list_typed_reverse(__type, __node, __field, __list)        \
703    for (__type * __node =                                                \
704            exec_node_data(__type, (__list)->tail_sentinel.prev, __field);  \
705         (__node)->__field.prev != NULL;                                 \
706         (__node) = exec_node_data(__type, (__node)->__field.prev, __field))
707 
708 #define foreach_list_typed_safe(__type, __node, __field, __list)           \
709    for (__type * __node =                                                  \
710            exec_node_data(__type, (__list)->head_sentinel.next, __field),  \
711                * __next =                                                  \
712            exec_node_data(__type, (__node)->__field.next, __field);        \
713         (__node)->__field.next != NULL;                                    \
714         __node = __next, __next =                                          \
715            exec_node_data(__type, (__next)->__field.next, __field))
716 
717 #define foreach_list_typed_reverse_safe(__type, __node, __field, __list)   \
718    for (__type * __node =                                                  \
719            exec_node_data(__type, (__list)->tail_sentinel.prev, __field),  \
720                * __prev =                                                  \
721            exec_node_data(__type, (__node)->__field.prev, __field);        \
722         (__node)->__field.prev != NULL;                                    \
723         __node = __prev, __prev =                                          \
724            exec_node_data(__type, (__prev)->__field.prev, __field))
725 
726 #endif /* LIST_CONTAINER_H */
727