• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

evolvedbinary / j8cu / 92

25 Feb 2025 12:59AM UTC coverage: 95.844% (-4.2%) from 100.0%
92

push

circleci

adamretter
Add reverse to string to doubly linked list for debugging

0 of 9 new or added lines in 1 file covered. (0.0%)

2 existing lines in 1 file now uncovered.

369 of 385 relevant lines covered (95.84%)

0.96 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.67
/src/main/java/com/evolvedbinary/j8cu/list/linked/AbstractLinkedList.java
1
/*
2
 * Copyright © 2025, Evolved Binary Ltd. <tech@evolvedbinary.com>
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *     * Redistributions of source code must retain the above copyright
8
 *       notice, this list of conditions and the following disclaimer.
9
 *     * Redistributions in binary form must reproduce the above copyright
10
 *       notice, this list of conditions and the following disclaimer in the
11
 *       documentation and/or other materials provided with the distribution.
12
 *     * Neither the name of the <organization> nor the
13
 *       names of its contributors may be used to endorse or promote products
14
 *       derived from this software without specific prior written permission.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
 */
27
package com.evolvedbinary.j8cu.list.linked;
28

29
import org.jspecify.annotations.Nullable;
30

31
import java.util.Collections;
32
import java.util.Iterator;
33
import java.util.Objects;
34

35
/**
36
 * Base class for a Linked List.
37
 *
38
 * @author <a href="mailto:adam@evolvedbinary.com">Adam Retter</a>
39
 */
40
public abstract class AbstractLinkedList<T, N extends AbstractNode<T, N>> implements LinkedList<T> {
41

42
    @Nullable N head = null;
1✔
43

44
    /**
45
     * Points at the last item in the Linked List; an optimisation to allow faster appends!
46
     */
47
    @Nullable N last = null;
1✔
48

49
    /**
50
     * Simple cache that holds previously
51
     * removed nodes so that they may be reused
52
     * when adding new nodes.
53
     */
54
    @Nullable final AbstractNode<T, N>[] reusableNodesCache;
55
    int reusableNodes = 0;
1✔
56

57
    protected AbstractLinkedList() {
58
        // no cache
UNCOV
59
        this(0);
×
UNCOV
60
    }
×
61

62
    /**
63
     * @param nodeCacheSize the size of the cache to use for reusing nodes that are removed.
64
     */
65
    @SuppressWarnings("unchecked")
66
    public AbstractLinkedList(final int nodeCacheSize) {
1✔
67
        if (nodeCacheSize <= 0) {
1✔
68
            // no cache
69
            this.reusableNodesCache = null;
1✔
70
        } else {
71
            this.reusableNodesCache = (N[]) new AbstractNode[nodeCacheSize];
1✔
72
        }
73
    }
1✔
74

75
    /**
76
     * Create a node for this list.
77
     * May create a new node, or reuse a previously removed one from the cache.
78
     *
79
     * @param element the element to store in the node.
80
     *
81
     * @return the node for the list.
82
     */
83
    @SuppressWarnings("unchecked")
84
    protected N createNode(final T element) {
85
        if (reusableNodesCache != null && reusableNodes > 0) {
1✔
86
            // get node from cache
87
            final N cachedNode = (N) reusableNodesCache[--reusableNodes];
1✔
88
            reusableNodesCache[reusableNodes] = null;
1✔
89
            cachedNode.data = element;
1✔
90
            return cachedNode;
1✔
91
        }
92

93
        return newNode(element);
1✔
94
    }
95

96
    /**
97
     * Create a new node object for this list.
98
     *
99
     * @param element the element to store in the node.
100
     *
101
     * @return the new node.
102
     */
103
    abstract N newNode(final T element);
104

105
    /**
106
     * Discard a node that is no longer used in this list.
107
     * May add the node to a cache for later reuse.
108
     *
109
     * @param node the node that is no longer used in this cache.
110
     */
111
    protected void discardNode(final N node) {
112
        if (reusableNodesCache != null && reusableNodes < reusableNodesCache.length) {
1✔
113
            node.data = null;
1✔
114
            node.next = null;
1✔
115
            reusableNodesCache[reusableNodes++] = node;
1✔
116
        }
117
    }
1✔
118

119
    @Override
120
    public boolean isEmpty() {
121
        return head == null;
1✔
122
    }
123

124
    @Override
125
    public @Nullable T head() {
126
        if (head == null) {
1✔
127
            throw new IllegalStateException("The list is empty");
1✔
128
        }
129
        return head.data;
1✔
130
    }
131

132
    @Override
133
    public @Nullable T last() {
134
        if (last == null) {
1✔
135
            throw new IllegalStateException("The list is empty");
1✔
136
        }
137
        return last.data;
1✔
138
    }
139

140
    @Override
141
    public Iterator<T> iterator() {
142
        if (head == null) {
1✔
143
            // is empty
144
            return Collections.emptyIterator();
1✔
145
        }
146
        return new LinkedListIterator<>(head);
1✔
147
    }
148

149
    @Override
150
    public boolean containsIdentity(@Nullable T element) {
151
        for (final T listElement : this) {
1✔
152
            if (listElement == element) {
1✔
153
                return true;
1✔
154
            }
155
        }
1✔
156
        return false;
1✔
157
    }
158

159
    @Override
160
    public boolean containsEquivalent(@Nullable T element) {
161
        for (final T listElement : this) {
1✔
162
            if (Objects.equals(listElement, element)) {
1✔
163
                return true;
1✔
164
            }
165
        }
1✔
166
        return false;
1✔
167
    }
168

169
    @Override
170
    public boolean removeFirst(@Nullable final T element) {
171
        return remove(element, RemovalMode.REMOVE_FIRST) == 1;
1✔
172
    }
173

174
    @Override
175
    public boolean removeOne(@Nullable final T element) {
176
        return remove(element, RemovalMode.REMOVE_ONE) == 1;
1✔
177
    }
178

179
    @Override
180
    public long removeAll(@Nullable final T element) {
181
        return remove(element, RemovalMode.REMOVE_ALL);
1✔
182
    }
183

184
    protected enum RemovalMode {
1✔
185
        /**
186
         * Remove the first matching element.
187
         */
188
        REMOVE_FIRST,
1✔
189

190
        /**
191
         * Remove any one matching element.
192
         */
193
        REMOVE_ONE,
1✔
194

195
        /**
196
         * Remove all matching elements
197
         */
198
        REMOVE_ALL
1✔
199
    }
200

201
    protected abstract long remove(@Nullable final T element, final RemovalMode removalMode);
202

203
    @Override
204
    public void clear() {
205
        this.head = null;
1✔
206
        this.last = null;
1✔
207
    }
1✔
208

209
    @Override
210
    public String toString() {
211
        final StringBuilder builder = new StringBuilder();
1✔
212
        builder.append('[');
1✔
213
        final Iterator<T> iterator = iterator();
1✔
214
        while (iterator.hasNext()) {
1✔
215
            builder.append(iterator.next());
1✔
216
            if (iterator.hasNext()) {
1✔
217
                builder.append(", ");
1✔
218
            }
219
        }
220
        builder.append(']');
1✔
221
        return builder.toString();
1✔
222
    }
223
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc