1 | \chapter{Linked List}
|
---|
2 |
|
---|
3 | I wrote a linked-list library for \CFA. This chapter describes it.
|
---|
4 |
|
---|
5 | The library provides a doubly-linked list that
|
---|
6 | attaches links intrusively,
|
---|
7 | supports multiple link directions,
|
---|
8 | integrates with user code via the type system,
|
---|
9 | treats its ends uniformly, and
|
---|
10 | identifies a list using an explicit head.
|
---|
11 |
|
---|
12 | TODO: more summary
|
---|
13 |
|
---|
14 |
|
---|
15 |
|
---|
16 | \section{Features}
|
---|
17 |
|
---|
18 | \subsection{Core Design Issues}
|
---|
19 |
|
---|
20 | This section reviews how a user experiences my \CFA list library's position on the issues of Section~\ref{toc:lst:issue}.
|
---|
21 | The library provides a doubly-linked list that
|
---|
22 | attaches links intrusively,
|
---|
23 | supports multiple link directions,
|
---|
24 | integrates with user code via the type system,
|
---|
25 | treats its ends uniformly, and
|
---|
26 | identifies a list using an explicit head.
|
---|
27 |
|
---|
28 | The \CFA list library's version of the running @req@ example is in Figure~\ref{fig:lst-features-intro}.
|
---|
29 | Its link attachment is intrusive and the resulting memory layout is pure-stack, just as for the LQ version of Figure~\ref{f:Intrusive}.
|
---|
30 | The framework-provided type @dlink(...)@ provides the links.
|
---|
31 | The user inserts the links into the @req@ structure by using \CFA inline-inheritance (TODO: reference introduction).
|
---|
32 | Inline inheritance means the type of the field is @dlink(req)@, the field is unnamed, a reference to a @req@ is implicitly convertible to @dlink@.\footnote{
|
---|
33 | The \CFA list examples elide the \lstinline{P9_EMBEDDED} annotations that (TODO: xref P9E future work) proposes to obviate.
|
---|
34 | Thus, these examples illustrate a to-be state, free of what is to be historic clutter.
|
---|
35 | The elided portions are immaterial to the discussion and the examples work with the annotations provided.
|
---|
36 | The \CFA test suite (TODO:cite?) includes equivalent demonstrations, with the annotations included.}
|
---|
37 | These links have a nontrivial, user-specified location within the @req@ structure;
|
---|
38 | this convention encapsulates the implied pointer arithmetic safely.
|
---|
39 |
|
---|
40 | \begin{figure}
|
---|
41 | \lstinput{20-32}{lst-features-intro.run.cfa}
|
---|
42 | \caption[Multiple link directions in \CFA list library]{
|
---|
43 | Demonstration of the running \lstinline{req} example, done using the \CFA list library.
|
---|
44 | This example does the same job that Figure~\ref{fig:lst-issues-attach} shows three ways.
|
---|
45 | }
|
---|
46 | \label{fig:lst-features-intro}
|
---|
47 | \end{figure}
|
---|
48 |
|
---|
49 | \begin{figure}
|
---|
50 | \centering
|
---|
51 | \begin{tabular}{@{}ll@{}}
|
---|
52 | \begin{tabular}{@{}l@{}}
|
---|
53 | \lstinput{20-25}{lst-features-multidir.run.cfa} \\
|
---|
54 | \lstinput{40-67}{lst-features-multidir.run.cfa}
|
---|
55 | \end{tabular}
|
---|
56 | &
|
---|
57 | \lstinput[language=C++]{20-60}{lst-issues-multi-static.run.c}
|
---|
58 | \end{tabular}
|
---|
59 |
|
---|
60 | \caption{
|
---|
61 | Demonstration of multiple static link directions done in the \CFA list library.
|
---|
62 | This example does the same job as Figure~\ref{fig:lst-issues-multi-static}.
|
---|
63 | }
|
---|
64 | \label{fig:lst-features-multidir}
|
---|
65 | \end{figure}
|
---|
66 |
|
---|
67 | Figure~\ref{fig:lst-features-multidir} shows how the \CFA library supports multi-static link directionality.
|
---|
68 | The declaration of @req@ now has two inline-inheriting @dlink@ occurrences.
|
---|
69 | The first of these lines gives a type named @req.by_pri@, @req@ inherits from it, and it inherits from @dlink@.
|
---|
70 | The second line @req.by_rqr@ is similar to @req.by_pri@.
|
---|
71 | Thus, there is a diamond, non-virtual, inheritance from @req@ to @dlink@, with @by_pri@ and @by_rqr@ being the mid-level types.
|
---|
72 | Disambiguation occurs in the declarations of the list-head objects.
|
---|
73 | The type of the variable @reqs_pri_global@ is @dlist(req, req.by_pri)@,
|
---|
74 | meaning operations called on @reqs_pri_global@ are implicitly disambiguated.
|
---|
75 | In the example, the calls @insert_first(reqs_pri_global, ...)@ imply, ``here, we are working by priority.''
|
---|
76 |
|
---|
77 | The \CFA library also supports the common case, of single directionality, more naturally than LQ.
|
---|
78 | Figure~\ref{fig:lst-features-intro} shows a single-direction list done with no contrived name for the link direction,
|
---|
79 | where Figure~\ref{f:Intrusive} adds the unnecessary name, @x@.
|
---|
80 | In \CFA, a user doing a single direction (Figure~\ref{fig:lst-features-intro})
|
---|
81 | sets up a simple inheritance with @dlink@, and declares a list head to have the simpler type @dlist(...)@.
|
---|
82 | While a user doing multiple link directions (Figure~\ref{fig:lst-features-multidir})
|
---|
83 | sets up a diamond inheritance with @dlink@, and declares a list head to have the more-informed type @dlist(..., DIR)@.
|
---|
84 |
|
---|
85 | The directionality issue also has an advanced corner-case that needs treatment.
|
---|
86 | When working with multiple directions, while calls like @insert_first@ benefit from implicit direction disambiguation, other calls like @insert_after@ still require explicit disambiguation.
|
---|
87 | It happens because the call
|
---|
88 | \begin{cfa}
|
---|
89 | insert_after(r1, r2);
|
---|
90 | \end{cfa}
|
---|
91 | does not have enough information to clarify which of a request's simultaneous list directions is intended.
|
---|
92 | Is @r2@ supposed to be the next-priority request after @r1@, or is @r2@ supposed to join the same-requestor list of @r1@?
|
---|
93 | As such, the \CFA compiler gives an ambiguity error for this call.
|
---|
94 | To let the programmer resolve the ambiguity, the list library provides a hook for applying the \CFA language's scoping and priority rules.
|
---|
95 | It applies as:
|
---|
96 | \begin{cfa}
|
---|
97 | with ( DLINK_VIA(req, req.pri) ) insert_after(r1, r2);
|
---|
98 | \end{cfa}
|
---|
99 | Here, importing (using the @with@ syntax on) the @DLINK_VIA@ result causes one of the list directions to become a more attrictive candidate to \CFA's overload resolution.
|
---|
100 | This boost applies within the scope of the the import, which is a single line in the example just given, but could also be a custom block or an entire function body.
|
---|
101 |
|
---|
102 | \noindent
|
---|
103 | \begin{tabular}{ll}
|
---|
104 | \begin{cfa}
|
---|
105 | void f() with ( DLINK_VIA(req, req.pri) ) {
|
---|
106 | ...
|
---|
107 |
|
---|
108 | insert_after(r1, r2);
|
---|
109 |
|
---|
110 | ...
|
---|
111 | }
|
---|
112 | \end{cfa}
|
---|
113 | &
|
---|
114 | \begin{cfa}
|
---|
115 | void f() {
|
---|
116 | ...
|
---|
117 | with ( DLINK_VIA(req, req.pri) ) {
|
---|
118 | ...
|
---|
119 | }
|
---|
120 | ...
|
---|
121 | }
|
---|
122 | \end{cfa}
|
---|
123 | \end{tabular}
|
---|
124 |
|
---|
125 | \noindent
|
---|
126 | By doing in on a larger scope, a user can put code within that acts as if there is only one list direction.
|
---|
127 | This boost is needed only when operating on a list with several directions, using operations that do not take list heads.
|
---|
128 | Otherwise, the sole applicable list direction ``just works.''
|
---|
129 |
|
---|
130 | The \CFA library offers a type-system mediated integration with user code.
|
---|
131 | The examples presented do not use preprocessor macros.
|
---|
132 | The touchpoints @dlink@ and @dlist@ are ordinary types.
|
---|
133 | Even though they are delivered as header-included static-inline implementations,
|
---|
134 | the \CFA compiler typechecks the list library code separately from user code.
|
---|
135 | Errors in user code are reported only with mention of the library's declarations.
|
---|
136 |
|
---|
137 | The \CFA library works in headed and headless modes. TODO: elaborate.
|
---|
138 |
|
---|
139 |
|
---|
140 |
|
---|
141 | \subsection{Iteration}
|
---|
142 |
|
---|
143 | Many languages offer an iterator interface for collections to implement, and a corresponding for-each loop syntax for consuming the items through implicit interface calls.
|
---|
144 | \CFA does not yet have a general-purpose form of such a feature, though it has a form that addresses some use cases.
|
---|
145 | This section shows why the incumbemt \CFA pattern does not work for linked lists and gives the alternative now offered by the linked-list libary.
|
---|
146 | Chapter 5 [TODO: deal with optimism here] presents a design that satisfies both uses and accommodates even more complex collections.
|
---|
147 |
|
---|
148 | The incumbent \CFA extensible loop syntax is:
|
---|
149 | \begin{cfa}
|
---|
150 | for( elem; begin ~ end )
|
---|
151 | for( elem; end )
|
---|
152 | \end{cfa}
|
---|
153 | Many derived forms of @begin ~ end@ exist, but they of primaty interest to defining numeric ranges, so they are excluded from the linked-list discussion.
|
---|
154 | This ``two-place for'' syntax abbreviates, respectively:
|
---|
155 | \begin{cfa}
|
---|
156 | for( typeof(end) elem = begin; elem < end; elem += 1 )
|
---|
157 | for( typeof(end) elem = 0; elem < end; elem += 1 )
|
---|
158 | \end{cfa}
|
---|
159 | From these calls, letting @E@ be @typeof(end)@, the implied interface is:
|
---|
160 | \begin{itemize}
|
---|
161 | \item
|
---|
162 | case-appropriate construction: one of @void ?{}( E &, typeof(begin) )@, or @void ?{}( E &, zero_t )@, depending on the specific loop form
|
---|
163 | \item
|
---|
164 | comparison, for termination testing: @int ?<?( const E &, const E & )@
|
---|
165 | \item
|
---|
166 | increment, for ``next item'': @E & ?+=?( E &, one_t )@
|
---|
167 | \end{itemize}
|
---|
168 | The shortened loop works well for using a numeric range to step through an array:
|
---|
169 | \begin{cfa}
|
---|
170 | for ( i; n ) total += a[i];
|
---|
171 | \end{cfa}
|
---|
172 |
|
---|
173 | When used for array-stepping, the loop is acting like JavaScript's @for...in@ construct,
|
---|
174 | \begin{cfa}
|
---|
175 | for ( i in a ) total += a[i];
|
---|
176 | \end{cfa}
|
---|
177 | albeit with different mechanisms for expressing the array's length.
|
---|
178 | But the similarity is that the loop binds the declared identifier (@i@) to the array's \emph{indeces}, not its contained values.
|
---|
179 | A linked list has only values, no keys.
|
---|
180 | So, to seek iteration of a linked list via the existing loop syntax is to ask whether this syntax can also do double-duty for iterating values.
|
---|
181 | That is, to be an analog of JavaScript's @for..of@ syntax:
|
---|
182 | \begin{cfa}
|
---|
183 | for ( e of a ) total += e;
|
---|
184 | \end{cfa}
|
---|
185 |
|
---|
186 | The \CFA team will likely implement an extension of this functionality that moves the @~@ syntax from being part of the loop, to being a first-class operator (with associated multi-pace operators for the elided derived forms).
|
---|
187 | With this change, both @begin ~ end@ and @end@ (in context of the latter ``two-place for'' expression) parse as \emph{ranges}, and the loop syntax becomes, simply:
|
---|
188 | \begin{cfa}
|
---|
189 | for( elem; rangeExpr )
|
---|
190 | \end{cfa}
|
---|
191 | The expansion and underlying API are under discussion.
|
---|
192 | TODO: explain pivot from ``is at done?'' to ``has more?''
|
---|
193 | Advantages of this change include being able to pass ranges to functions, for example, projecting a numerically regular subsequence of array entries, and being able to use the loop syntax to cover more collection types, such as looping over the keys of a hashtable.
|
---|
194 |
|
---|
195 |
|
---|
196 |
|
---|
197 |
|
---|
198 | When iteratig an empty list, the question, ``Is there a further element?'' needs to be posed once, receiving the answer, ``no.''
|
---|
199 | When iterating an $n$-item list, the same question gets $n$ ``yes'' answers (one for each element), plus one ``no'' answer, once there are no more elements; the question is posed $n+1$ times.
|
---|
200 |
|
---|
201 | When iteratig an empty list, the question, ``What is the value of the current element?'' is never posed, nor is the command, ``Move to the next element,'' issued. When iterating an $n$-item list, each happens $n$ times.
|
---|
202 |
|
---|
203 | So, asking about the existence of an element happens once more than retrieving an element's value and advancing the position.
|
---|
204 |
|
---|
205 | Many iteration APIs deal with this fact by splitting these steps across different functions, and relying on the user's knowledge of iterator state to know when to call each. In Java, the function @hasNext@ should be called $n+1$ times and @next@ should be called $n$ times (doing the double duty of advancing the iteration and returning a value). In \CC, the jobs are split among the three actions, @it != end@, @it++@ and @*it@, the latter two being called one time more than the first.
|
---|
206 |
|
---|
207 | TODO: deal with simultaneous axes: @DLINK_VIA@ just works
|
---|
208 |
|
---|
209 | TODO: deal with spontaneous simultaneity, like a single-axis req, put into an array: which ``axis'' is @&req++@ navigating: array-adjacency vs link dereference. It should sick according to how you got it in the first place: navigating dlist(req, req.pri) vs navigating array(req, 42). (prob. future work)
|
---|
210 |
|
---|
211 | \section{Implementation}
|
---|
212 |
|
---|
213 | \subsection{Links}
|
---|
214 |
|
---|
215 | \VRef[Figure]{fig:lst-impl-links} continues the running @req@ example, now showing the \CFA list library's internal representation.
|
---|
216 |
|
---|
217 | \begin{figure}
|
---|
218 | \centering
|
---|
219 | \includegraphics{lst-impl-links.pdf}
|
---|
220 | \caption{
|
---|
221 | \CFA list library representations for the cases under discussion.
|
---|
222 | }
|
---|
223 | \label{fig:lst-impl-links}
|
---|
224 | \end{figure}
|
---|
225 |
|
---|
226 | The @dlink@ structure contains exactly two pointers: @next@ and @prev@. This @dlink@ content is opaque to the user.
|
---|
227 |
|
---|
228 | Even though the user-facing list model is ordered (linear), the CFA library implements all listing as circular.
|
---|
229 | This choice helps achieve uniform end treatment and TODO finish summarizing benefit.
|
---|
230 |
|
---|
231 | A link pointer targets a neighbouring @dlink@ structure, rather than a neighbouring @req@.
|
---|
232 | (Recall, the running example has the user putting a @dlink@ within a @req@.)
|
---|
233 |
|
---|
234 | Link pointers are tagged according to whether the link is user-visible.
|
---|
235 | Links among user-requested neighbours are left natural, with the tag bit not set.
|
---|
236 | System-added links, which produce the circular implementation, have the tag bit set.
|
---|
237 | Iteration reports ``has more elements'' when crossing natural links, and ``no more elements'' upon reaching a tagged link.
|
---|
238 |
|
---|
239 | In a headed list, the list head (@dlist(req)@) acts as an extra element in the implementation-level circularly-linked list.
|
---|
240 | The content of a @dlist@ is a (private) @dlink@, with the @next@ pointer purposed for the first element, and the @prev@ pointer purposed for the last element.
|
---|
241 | Since the head wraps a @dlink@, since a @req@ does too, and since a link-pointer targets a @dlink@, the resulting cycle is among @dlink@ strucures, situated inside of other things.
|
---|
242 | The tags on the links say what the wrapper is: untagged (user link) means the targeted @dlink@ is within a @req@, while tagged (system link) means the targeted @dlink@ is within a list head.
|
---|
243 |
|
---|
244 | In a headless list, the cicular backing list is only among @dlink@s within @req@s. The tags are set on the links that a user cannot navigate.
|
---|
245 |
|
---|
246 | No distinction is made between an unlisted item under a headed model and a singleton list under a headless model. Both are represented as an item referring to itself, with both tags set.
|
---|
247 |
|
---|
248 |
|
---|
249 |
|
---|
250 | \section{Future Work}
|
---|
251 | \label{toc:lst:futwork}
|
---|
252 |
|
---|
253 |
|
---|
254 | TODO: deal with: A doubly linked list is being designed.
|
---|
255 |
|
---|
256 | TODO: deal with: Link fields are system-managed.
|
---|
257 | Links in GDB.
|
---|
258 |
|
---|