Mr Flibble <fli...@reddwarf.jmc.corp> writes:
>On Sun, 16 Oct 2022 22:02:39 +0200
>David Brown <
david...@hesbynett.no> wrote:
How about some real data, comparing std::list to a custom
class? This c_dlist example dates back to the late 1980s, before
std::list existed and was used in embedded (operating system
and hypervisor) code well into the second decade of the 21st
century.
============ Begin custom list example ============================
#include <stdint.h>
#include <stdio.h>
#include "include/dlist.h"
class c_task : public c_dlist
{
static const size_t MAX_NAMELEN = 32ul;
char task_name[MAX_NAMELEN];
void *task_address;
uint32_t task_priority;
public:
c_task(const char *name, uint32_t priority)
: task_address(0ul), task_priority(priority)
{ init(); snprintf(task_name, sizeof(task_name), "%s", name); }
const char *get_name(void) const { return task_name; }
uint32_t get_priority(void) const { return task_priority; }
};
int
main(int argc, const char **argv, const char **envp)
{
c_dlist listhead;
c_task task1("task1", 15);
c_task task2("task2", 20);
listhead.init();
listhead.append(&task1);
listhead.append(&task2);
c_dlist_iterator di(&listhead);
while (di.next()) {
c_task *tp = (c_task *)di.curr();
printf("Task %s, priority %u\n", tp->get_name(), tp->get_priority());
}
return 0;
}
============ Compiled with -O2, here's 'main'
0000000000400500 <main>:
400500: 55 push %rbp
400501: ba 32 00 00 00 mov $0x32,%edx
400506: b8 31 00 00 00 mov $0x31,%eax
40050b: 53 push %rbx
40050c: 48 81 ec 98 00 00 00 sub $0x98,%rsp
400513: 48 8d 5c 24 10 lea 0x10(%rsp),%rbx
400518: 48 8d 74 24 50 lea 0x50(%rsp),%rsi
40051d: 66 89 54 24 64 mov %dx,0x64(%rsp)
400522: 48 c7 44 24 40 00 00 movq $0x0,0x40(%rsp)
400529: 00 00
40052b: c7 44 24 48 0f 00 00 movl $0xf,0x48(%rsp)
400532: 00
400533: 48 89 e5 mov %rsp,%rbp
400536: c7 44 24 20 74 61 73 movl $0x6b736174,0x20(%rsp)
40053d: 6b
40053e: 66 89 44 24 24 mov %ax,0x24(%rsp)
400543: ba 14 00 00 00 mov $0x14,%edx
400548: 48 c7 84 24 80 00 00 movq $0x0,0x80(%rsp)
40054f: 00 00 00 00 00
400554: c7 84 24 88 00 00 00 movl $0x14,0x88(%rsp)
40055b: 14 00 00 00
40055f: c7 44 24 60 74 61 73 movl $0x6b736174,0x60(%rsp)
400566: 6b
400567: 48 89 64 24 10 mov %rsp,0x10(%rsp)
40056c: 48 89 5c 24 08 mov %rbx,0x8(%rsp)
400571: 48 89 5c 24 50 mov %rbx,0x50(%rsp)
400576: 48 89 64 24 58 mov %rsp,0x58(%rsp)
40057b: 48 89 74 24 18 mov %rsi,0x18(%rsp)
400580: 48 89 34 24 mov %rsi,(%rsp)
400584: eb 13 jmp 400599 <main+0x99>
400586: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40058d: 00 00 00
400590: 8b 53 38 mov 0x38(%rbx),%edx
400593: 48 89 de mov %rbx,%rsi
400596: 48 89 c3 mov %rax,%rbx
400599: 48 83 c6 10 add $0x10,%rsi
40059d: 31 c0 xor %eax,%eax
40059f: bf 40 07 40 00 mov $0x400740,%edi
4005a4: e8 27 ff ff ff callq 4004d0 <printf@plt>
4005a9: 48 39 eb cmp %rbp,%rbx
4005ac: 48 8b 03 mov (%rbx),%rax
4005af: 75 df jne 400590 <main+0x90>
4005b1: 48 81 c4 98 00 00 00 add $0x98,%rsp
4005b8: 31 c0 xor %eax,%eax
4005ba: 5b pop %rbx
4005bb: 5d pop %rbp
4005bc: c3 retq
4005bd: 0f 1f 00 nopl (%rax)
The only nonlocal branch is to the printf function.
=========Version using std::list
#include <stdint.h>
#include <stdio.h>
#include <list>
class c_task
{
static const size_t MAX_NAMELEN = 32ul;
char task_name[MAX_NAMELEN];
void *task_address;
uint32_t task_priority;
public:
c_task(const char *name, uint32_t priority)
: task_address(0ul), task_priority(priority)
{ snprintf(task_name, sizeof(task_name), "%s", name); }
const char *get_name(void) const { return task_name; }
uint32_t get_priority(void) const { return task_priority; }
};
int
main(int argc, const char **argv, const char **envp)
{
std::list<c_task> listhead;
c_task task1("task1", 15);
c_task task2("task2", 20);
listhead.push_back(task1);
listhead.push_back(task2);
std::list<c_task>::iterator it = listhead.begin();
for (; it != listhead.end(); ++it) {
c_task tp = *it;
printf("Task %s, priority %u\n", tp.get_name(), tp.get_priority());
}
return 0;
}
And here's main:
0000000000400740 <main>:
400740: 41 54 push %r12
400742: b8 31 00 00 00 mov $0x31,%eax
400747: ba 32 00 00 00 mov $0x32,%edx
40074c: 55 push %rbp
40074d: 53 push %rbx
40074e: 48 81 ec a0 00 00 00 sub $0xa0,%rsp
400755: 48 8d 7c 24 10 lea 0x10(%rsp),%rdi
40075a: 48 89 e5 mov %rsp,%rbp
40075d: 48 89 24 24 mov %rsp,(%rsp)
400761: 48 89 64 24 08 mov %rsp,0x8(%rsp)
400766: 48 c7 44 24 30 00 00 movq $0x0,0x30(%rsp)
40076d: 00 00
40076f: c7 44 24 38 0f 00 00 movl $0xf,0x38(%rsp)
400776: 00
400777: c7 44 24 10 74 61 73 movl $0x6b736174,0x10(%rsp)
40077e: 6b
40077f: 66 89 44 24 14 mov %ax,0x14(%rsp)
400784: 48 c7 44 24 60 00 00 movq $0x0,0x60(%rsp)
40078b: 00 00
40078d: c7 44 24 68 14 00 00 movl $0x14,0x68(%rsp)
400794: 00
400795: c7 44 24 40 74 61 73 movl $0x6b736174,0x40(%rsp)
40079c: 6b
40079d: 66 89 54 24 44 mov %dx,0x44(%rsp)
4007a2: e8 c9 01 00 00 callq 400970 <std::list<c_task, std::allocator<c_task> >::_M_create_node(c_task const&) [clone .isra.11]>
4007a7: 48 89 c7 mov %rax,%rdi
4007aa: 48 89 e6 mov %rsp,%rsi
4007ad: e8 4e ff ff ff callq 400700 <std::__detail::_List_node_base::_M_hook(std::__detail::_List_node_base*)@plt>
4007b2: 48 8d 7c 24 40 lea 0x40(%rsp),%rdi
4007b7: e8 b4 01 00 00 callq 400970 <std::list<c_task, std::allocator<c_task> >::_M_create_node(c_task const&) [clone .isra.11]>
4007bc: 48 89 e6 mov %rsp,%rsi
4007bf: 48 89 c7 mov %rax,%rdi
4007c2: e8 39 ff ff ff callq 400700 <std::__detail::_List_node_base::_M_hook(std::__detail::_List_node_base*)@plt>
4007c7: 48 8b 1c 24 mov (%rsp),%rbx
4007cb: 48 39 e3 cmp %rsp,%rbx
4007ce: 74 5b je 40082b <main+0xeb>
4007d0: 48 8b 43 10 mov 0x10(%rbx),%rax
4007d4: 48 8d 74 24 70 lea 0x70(%rsp),%rsi
4007d9: bf 50 0a 40 00 mov $0x400a50,%edi
4007de: 48 89 44 24 70 mov %rax,0x70(%rsp)
4007e3: 48 8b 43 18 mov 0x18(%rbx),%rax
4007e7: 48 89 44 24 78 mov %rax,0x78(%rsp)
4007ec: 48 8b 43 20 mov 0x20(%rbx),%rax
4007f0: 48 89 84 24 80 00 00 mov %rax,0x80(%rsp)
4007f7: 00
4007f8: 48 8b 43 28 mov 0x28(%rbx),%rax
4007fc: 48 89 84 24 88 00 00 mov %rax,0x88(%rsp)
400803: 00
400804: 48 8b 43 30 mov 0x30(%rbx),%rax
400808: 48 89 84 24 90 00 00 mov %rax,0x90(%rsp)
40080f: 00
400810: 48 8b 53 38 mov 0x38(%rbx),%rdx
400814: 31 c0 xor %eax,%eax
400816: 48 89 94 24 98 00 00 mov %rdx,0x98(%rsp)
40081d: 00
40081e: e8 9d fe ff ff callq 4006c0 <printf@plt>
400823: 48 8b 1b mov (%rbx),%rbx
400826: 48 39 eb cmp %rbp,%rbx
400829: 75 a5 jne 4007d0 <main+0x90>
40082b: 48 8b 3c 24 mov (%rsp),%rdi
40082f: 48 39 ef cmp %rbp,%rdi
400832: 75 0f jne 400843 <main+0x103>
400834: eb 1a jmp 400850 <main+0x110>
400836: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40083d: 00 00 00
400840: 48 89 df mov %rbx,%rdi
400843: 48 8b 1f mov (%rdi),%rbx
400846: e8 95 fe ff ff callq 4006e0 <operator delete(void*)@plt>
40084b: 48 39 eb cmp %rbp,%rbx
40084e: 75 f0 jne 400840 <main+0x100>
400850: 48 81 c4 a0 00 00 00 add $0xa0,%rsp
400857: 31 c0 xor %eax,%eax
400859: 5b pop %rbx
40085a: 5d pop %rbp
40085b: 41 5c pop %r12
40085d: c3 retq
40085e: 48 8b 3c 24 mov (%rsp),%rdi
400862: 49 89 c4 mov %rax,%r12
400865: 48 39 ef cmp %rbp,%rdi
400868: 74 0d je 400877 <main+0x137>
40086a: 48 8b 1f mov (%rdi),%rbx
40086d: e8 6e fe ff ff callq 4006e0 <operator delete(void*)@plt>
400872: 48 89 df mov %rbx,%rdi
400875: eb ee jmp 400865 <main+0x125>
400877: 4c 89 e7 mov %r12,%rdi
40087a: e8 b1 fe ff ff callq 400730 <_Unwind_Resume@plt>
40087f: 90 nop
Also compiled with -O2.
David's point seems pretty valid to me.
====== same version of the std::list, but using std::list<c_task*>:
0000000000400740 <main>:
400740: 41 54 push %r12
400742: b8 31 00 00 00 mov $0x31,%eax
400747: ba 32 00 00 00 mov $0x32,%edx
40074c: bf 18 00 00 00 mov $0x18,%edi
400751: 55 push %rbp
400752: 53 push %rbx
400753: 48 83 ec 70 sub $0x70,%rsp
400757: 48 89 e5 mov %rsp,%rbp
40075a: 48 89 24 24 mov %rsp,(%rsp)
40075e: 48 89 64 24 08 mov %rsp,0x8(%rsp)
400763: 48 c7 44 24 30 00 00 movq $0x0,0x30(%rsp)
40076a: 00 00
40076c: c7 44 24 38 0f 00 00 movl $0xf,0x38(%rsp)
400773: 00
400774: c7 44 24 10 74 61 73 movl $0x6b736174,0x10(%rsp)
40077b: 6b
40077c: 66 89 44 24 14 mov %ax,0x14(%rsp)
400781: 48 c7 44 24 60 00 00 movq $0x0,0x60(%rsp)
400788: 00 00
40078a: c7 44 24 68 14 00 00 movl $0x14,0x68(%rsp)
400791: 00
400792: c7 44 24 40 74 61 73 movl $0x6b736174,0x40(%rsp)
400799: 6b
40079a: 66 89 54 24 44 mov %dx,0x44(%rsp)
40079f: e8 7c ff ff ff callq 400720 <operator new(unsigned long)@plt>
4007a4: 48 83 f8 f0 cmp $0xfffffffffffffff0,%rax
4007a8: 74 09 je 4007b3 <main+0x73>
4007aa: 48 8d 54 24 10 lea 0x10(%rsp),%rdx
4007af: 48 89 50 10 mov %rdx,0x10(%rax)
4007b3: 48 89 c7 mov %rax,%rdi
4007b6: 48 89 ee mov %rbp,%rsi
4007b9: e8 42 ff ff ff callq 400700 <std::__detail::_List_node_base::_M_hook(std::__detail::_List_node_base*)@plt>
4007be: bf 18 00 00 00 mov $0x18,%edi
4007c3: e8 58 ff ff ff callq 400720 <operator new(unsigned long)@plt>
4007c8: 48 83 f8 f0 cmp $0xfffffffffffffff0,%rax
4007cc: 74 09 je 4007d7 <main+0x97>
4007ce: 48 8d 54 24 40 lea 0x40(%rsp),%rdx
4007d3: 48 89 50 10 mov %rdx,0x10(%rax)
4007d7: 48 89 ee mov %rbp,%rsi
4007da: 48 89 c7 mov %rax,%rdi
4007dd: e8 1e ff ff ff callq 400700 <std::__detail::_List_node_base::_M_hook(std::__detail::_List_node_base*)@plt>
4007e2: 48 8b 1c 24 mov (%rsp),%rbx
4007e6: 48 39 eb cmp %rbp,%rbx
4007e9: 74 20 je 40080b <main+0xcb>
4007eb: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)
4007f0: 48 8b 73 10 mov 0x10(%rbx),%rsi
4007f4: bf e0 09 40 00 mov $0x4009e0,%edi
4007f9: 31 c0 xor %eax,%eax
4007fb: 8b 56 28 mov 0x28(%rsi),%edx
4007fe: e8 bd fe ff ff callq 4006c0 <printf@plt>
400803: 48 8b 1b mov (%rbx),%rbx
400806: 48 39 eb cmp %rbp,%rbx
400809: 75 e5 jne 4007f0 <main+0xb0>
40080b: 48 8b 3c 24 mov (%rsp),%rdi
40080f: 48 39 ef cmp %rbp,%rdi
400812: 75 0f jne 400823 <main+0xe3>
400814: eb 1a jmp 400830 <main+0xf0>
400816: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40081d: 00 00 00
400820: 48 89 df mov %rbx,%rdi
400823: 48 8b 1f mov (%rdi),%rbx
400826: e8 b5 fe ff ff callq 4006e0 <operator delete(void*)@plt>
40082b: 48 39 eb cmp %rbp,%rbx
40082e: 75 f0 jne 400820 <main+0xe0>
400830: 48 83 c4 70 add $0x70,%rsp
400834: 31 c0 xor %eax,%eax
400836: 5b pop %rbx
400837: 5d pop %rbp
400838: 41 5c pop %r12
40083a: c3 retq
40083b: 48 8b 3c 24 mov (%rsp),%rdi
40083f: 49 89 c4 mov %rax,%r12
400842: 48 39 ef cmp %rbp,%rdi
400845: 74 0d je 400854 <main+0x114>
400847: 48 8b 1f mov (%rdi),%rbx
40084a: e8 91 fe ff ff callq 4006e0 <operator delete(void*)@plt>
40084f: 48 89 df mov %rbx,%rdi
400852: eb ee jmp 400842 <main+0x102>
400854: 4c 89 e7 mov %r12,%rdi
400857: e8 d4 fe ff ff callq 400730 <_Unwind_Resume@plt>
=======And the same with -fno-exceptions:
0000000000400650 <main>:
400650: 55 push %rbp
400651: b8 31 00 00 00 mov $0x31,%eax
400656: ba 32 00 00 00 mov $0x32,%edx
40065b: bf 18 00 00 00 mov $0x18,%edi
400660: 53 push %rbx
400661: 48 83 ec 78 sub $0x78,%rsp
400665: 48 89 24 24 mov %rsp,(%rsp)
400669: 48 89 64 24 08 mov %rsp,0x8(%rsp)
40066e: 48 89 e5 mov %rsp,%rbp
400671: 48 c7 44 24 30 00 00 movq $0x0,0x30(%rsp)
400678: 00 00
40067a: c7 44 24 38 0f 00 00 movl $0xf,0x38(%rsp)
400681: 00
400682: c7 44 24 10 74 61 73 movl $0x6b736174,0x10(%rsp)
400689: 6b
40068a: 66 89 44 24 14 mov %ax,0x14(%rsp)
40068f: 48 c7 44 24 60 00 00 movq $0x0,0x60(%rsp)
400696: 00 00
400698: c7 44 24 68 14 00 00 movl $0x14,0x68(%rsp)
40069f: 00
4006a0: c7 44 24 40 74 61 73 movl $0x6b736174,0x40(%rsp)
4006a7: 6b
4006a8: 66 89 54 24 44 mov %dx,0x44(%rsp)
4006ad: e8 8e ff ff ff callq 400640 <operator new(unsigned long)@plt>
4006b2: 48 83 f8 f0 cmp $0xfffffffffffffff0,%rax
4006b6: 74 09 je 4006c1 <main+0x71>
4006b8: 48 8d 4c 24 10 lea 0x10(%rsp),%rcx
4006bd: 48 89 48 10 mov %rcx,0x10(%rax)
4006c1: 48 89 c7 mov %rax,%rdi
4006c4: 48 89 ee mov %rbp,%rsi
4006c7: e8 64 ff ff ff callq 400630 <std::__detail::_List_node_base::_M_hook(std::__detail::_List_node_base*)@plt>
4006cc: bf 18 00 00 00 mov $0x18,%edi
4006d1: e8 6a ff ff ff callq 400640 <operator new(unsigned long)@plt>
4006d6: 48 83 f8 f0 cmp $0xfffffffffffffff0,%rax
4006da: 74 09 je 4006e5 <main+0x95>
4006dc: 48 8d 54 24 40 lea 0x40(%rsp),%rdx
4006e1: 48 89 50 10 mov %rdx,0x10(%rax)
4006e5: 48 89 ee mov %rbp,%rsi
4006e8: 48 89 c7 mov %rax,%rdi
4006eb: e8 40 ff ff ff callq 400630 <std::__detail::_List_node_base::_M_hook(std::__detail::_List_node_base*)@plt>
4006f0: 48 8b 1c 24 mov (%rsp),%rbx
4006f4: 48 39 eb cmp %rbp,%rbx
4006f7: 74 22 je 40071b <main+0xcb>
4006f9: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
400700: 48 8b 73 10 mov 0x10(%rbx),%rsi
400704: 31 c0 xor %eax,%eax
400706: bf d0 08 40 00 mov $0x4008d0,%edi
40070b: 8b 56 28 mov 0x28(%rsi),%edx
40070e: e8 dd fe ff ff callq 4005f0 <printf@plt>
400713: 48 8b 1b mov (%rbx),%rbx
400716: 48 39 eb cmp %rbp,%rbx
400719: 75 e5 jne 400700 <main+0xb0>
40071b: 48 8b 3c 24 mov (%rsp),%rdi
40071f: 48 39 ef cmp %rbp,%rdi
400722: 75 0f jne 400733 <main+0xe3>
400724: eb 1a jmp 400740 <main+0xf0>
400726: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1)
40072d: 00 00 00
400730: 48 89 df mov %rbx,%rdi
400733: 48 8b 1f mov (%rdi),%rbx
400736: e8 d5 fe ff ff callq 400610 <operator delete(void*)@plt>
40073b: 48 39 eb cmp %rbp,%rbx
40073e: 75 f0 jne 400730 <main+0xe0>
40073e: 75 f0 jne 400730 <main+0xe0>
400740: 48 83 c4 78 add $0x78,%rsp
400744: 31 c0 xor %eax,%eax
400746: 5b pop %rbx
400747: 5d pop %rbp
400748: c3 retq
400749: 0f 1f 00 nopl (%rax)
PS: dlist header file used above:
/*
*
* $Id: dlist.h,v 1.5 2011-07-27 23:52:17 scott Exp $
*/
#if !defined(__dlist_h_)
#define __dlist_h_
/**
* Double Linked List.
*
* Implement double linked list operations. An object that
* is included on a double-linked list derives from c_dlist.
*
* Note that locking is the responsibility of the derived class.
*
* <pre>
* class c_object: public c_dlist {
* private-data.
* public:
* public-data.
* };
* </pre>
*
* class c_object constructor or ::init function must invoked the
* c_dlist::init function to initialize the list pointers. If the
* element is not on a list, the list pointers will refer to the
* element itself. The c_dlist::is_onlist method will return <i>true</i>
* if the element is on a list, false if the element is stand-alone.
*
* The c_dlist::insert function will insert a new element before
* the object, while the c_dlist::append function will insert
* a new element after the object. This example shows an object,
* </i>object_1</i> which is already on a c_dlist listhead object
* and the code fragment will insert a new object either before or
* after the object (rather than at the beginning or end of the list).
*
* <pre>
* c_object *object_1;
* c_object *object_2;
*
* object_1.append(object_2); // Link object 2 after object 1
* object_1.insert(object_2); // Link object 2 before object 1
* </pre>
*
* The c_dlist class can also be used as a list-head object by itself,
* however, with this usage, the semantics of the c_dlist::insert and
* c_dlist::append functions change subtly; c_dlist::append will add
* the named object to the beginning of the list, while c_dlist::insert
* will add the named object to the end of the list.
*
* <pre>
* c_dlist object1_list;
* c_object *object_3;
*
* object1_list.append(object_1); // Add to start of list
* object1_list.insert(object_2); // Add to end of list
* object2.append(object_3); // Insert object 3 after object 2.
*
* Objects are removed from a list by invoking the c_dlist::remove
* function on the object being removed.
*
* <pre>
* object_1.remove(); // Remove object1 from list
* </pre>
*/
class c_dlist {
c_dlist *dl_next; ///< Forward Link
c_dlist *dl_prev; ///< Backward Link
public:
void append(c_dlist *);
void init(void);
void insert(c_dlist *);
bool is_empty(void) const;
bool is_onlist(void) const;
c_dlist *flink(void);
c_dlist *blink(void);
void remove(void);
};
/**
* Initialize a list entry. An initialized entry set so that the
* prev and next pointers refer to the element itself (e.g. this).
*/
inline void
c_dlist::init(void)
{
dl_next = dl_prev = this;
}
/**
* Get next element pointer. It is recommend that client code use
* c_dlist_iterator rather than using this function directly.
*
* @returns the next element pointer.
*/
inline c_dlist *
c_dlist::flink(void)
{
return dl_next;
}
/**
* Get previous element pointer. It is recommend that client code use
* c_dlist_iterator rather than using this function directly.
*
* @returns the previous element pointer.
*/
inline c_dlist *
c_dlist::blink(void)
{
return dl_prev;
}
/**
* Insert into double-linked list. The named element is inserted
* before the current element (e.g. <i>this</i>). If the current
* element is a c_dlist being used as a listhead, using insert will
* have the effect of adding the element to the tail of the double-linked
* list.
*
* @param dp The list element to add to the list.
*/
inline void
c_dlist::insert(c_dlist *dp)
{
dp->dl_next = this;
dp->dl_prev = dl_prev;
dl_prev->dl_next = dp;
dl_prev = dp;
}
/**
* Insert into double-linked list. The named element is inserted
* after the current element (e.g. <i>this</i>). If the current
* element is a c_dlist being used as a listhead, using append will
* have the effect of adding the element to the head of the double-linked
* list.
*
* @param dp The list element to add to the list.
*/
inline void
c_dlist::append(c_dlist *dp)
{
dp->dl_next = dl_next;
dp->dl_prev = this;
dl_next->dl_prev = dp;
dl_next = dp;
}
/**
* Remove the element from a double-linked list. This function should
* be called on the object being removed. Calling the c_dlist::remove on
* a c_dlist object being used as a listhead will result in the entire
* list becoming disconnected from the listhead, which is probably not the
* desired behavior. Thus, it is not recommended to call c_dlist::remove
* on a c_dlist being used as a listhead. Remove the objects individually
* instead.
*
* This function is safe to call during a c_dlist_iterator.
*/
inline void
c_dlist::remove(void)
{
if (dl_next == this) {
return;
}
dl_next->dl_prev = dl_prev;
dl_prev->dl_next = dl_next;
dl_prev = dl_next = this;
}
/**
* Determine if element is on a list. Return true if the element is on
* a list, false if not. When called on a c_dlist being used as a listhead,
* this function will indicate whether the list is empty or not (see
* c_dlist::is_empty()).
*
* @returns true if the element is on a list or if the listhead is non-empty
*/
inline bool
c_dlist::is_onlist(void) const
{
return dl_next != this;
}
/**
* Determine if a list is empty. Return true if the c_dlist object being
* used as a listhead has no elements.
*
* @returns true if the list is empty
*/
inline bool
c_dlist::is_empty(void) const
{
return !is_onlist();
}
/**
* Double-Linked list iterator. This class can be used to iterate over
* the members of a double-linked list as represented by a c_dlist object.
*
* The iterator allows deletion of the current element.
*
* <pre>
* c_dlist object_listhead; // List of c_objects
* c_dlist_iterator di(&object_listhead);
*
* while (di.next()) {
* c_object = (c_object *)di.curr();
*
* // operate on object.
*
* // This is safe:
* c_object->remove();
* }
* </pre>
*/
class c_dlist_iterator {
c_dlist *list;
c_dlist *current;
c_dlist *current_next;
c_dlist *current_prev;
public:
c_dlist_iterator(c_dlist *);
c_dlist *curr(void);
bool next(void);
bool prev(void);
void reset(c_dlist * = NULL);
};
/**
* Create a double linked list iterator.
*
* @param dlp The list over which to iterate
*/
inline
c_dlist_iterator::c_dlist_iterator(c_dlist *dlp)
{
list = current = dlp;
current_next = current->flink();
current_prev = current->blink();
}
/**
* Return current element. Immediately after c_dlist_iterator::reset or
* after the c_dlist_iterator::c_dlist_iterator the current element is the
* list head itself. c_dlist_iterator::next must be called to get the first
* element on the list. See example in c_dlist_iterator class documentation.
*
* @returns the current element in the iteration.
*/
inline c_dlist *
c_dlist_iterator::curr(void)
{
return current;
}
/**
* Iterate to the next element in the list. Save the next and previous
* pointers to allow the element to be deleted without perturbing the
* iteration.
*
* @returns true if the element is not the list-head
*/
inline bool
c_dlist_iterator::next(void)
{
current = current_next;
current_next = current->flink();
current_prev = current->blink();
return current != list;
}
/**
* Iterate to the previous element in the list. Save the next and previous
* pointers to allow the element to be deleted without perturbing the
* iteration.
*
* @returns true if the element is not the list-head
*/
inline bool
c_dlist_iterator::prev(void)
{
current = current_prev;
current_next = current->flink();
current_prev = current->blink();
return current != list;
}
/**
* Reset the iterator to the head of the list.
*/
inline void
c_dlist_iterator::reset(c_dlist *new_listhead)
{
if (new_listhead != NULL) {
list = new_listhead;
}
current = list;
current_next = current->flink();
current_prev = current->blink();
}
#endif /* !defined(__dlist_h_) */
/* vim: sw=4 sts=4 sta ts=8:
*/