View Javadoc
1   /*
2    * Copyright 2021 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty5.buffer.api.internal;
17  
18  import io.netty5.buffer.api.Drop;
19  
20  import java.lang.invoke.MethodHandles;
21  import java.lang.invoke.VarHandle;
22  
23  public final class ArcDrop<T> implements Drop<T> {
24      private static final VarHandle COUNT;
25      static {
26          try {
27              COUNT = MethodHandles.lookup().findVarHandle(ArcDrop.class, "count", int.class);
28          } catch (Exception e) {
29              throw new ExceptionInInitializerError(e);
30          }
31      }
32  
33      private final Drop<T> delegate;
34      @SuppressWarnings("FieldMayBeFinal")
35      private volatile int count;
36  
37      public ArcDrop(Drop<T> delegate) {
38          this.delegate = delegate;
39      }
40  
41      public static <X> Drop<X> wrap(Drop<X> drop) {
42          if (drop.getClass() == ArcDrop.class) {
43              return drop;
44          }
45          return new ArcDrop<>(drop);
46      }
47  
48      public static <X> Drop<X> acquire(Drop<X> drop) {
49          if (drop.getClass() == ArcDrop.class) {
50              ((ArcDrop<X>) drop).increment();
51              return drop;
52          }
53          return new ArcDrop<>(drop);
54      }
55  
56      public ArcDrop<T> increment() {
57          int c;
58          do {
59              c = count;
60              checkValidState(c);
61          } while (!COUNT.compareAndSet(this, c, c + 1));
62          return this;
63      }
64  
65      @Override
66      public void drop(T obj) {
67          int c;
68          int n;
69          do {
70              c = count;
71              n = c - 1;
72              checkValidState(c);
73          } while (!COUNT.compareAndSet(this, c, n));
74          if (n == -1) {
75              delegate.drop(obj);
76          }
77      }
78  
79      @Override
80      public Drop<T> fork() {
81          return increment();
82      }
83  
84      @Override
85      public void attach(T obj) {
86          delegate.attach(obj);
87      }
88  
89      public Drop<T> unwrap() {
90          return delegate;
91      }
92  
93      @Override
94      public String toString() {
95          StringBuilder builder = new StringBuilder()
96                  .append("ArcDrop@")
97                  .append(Integer.toHexString(System.identityHashCode(this)))
98                  .append('(').append(count).append(", ");
99          Drop<T> drop = this;
100         while ((drop = ((ArcDrop<T>) drop).unwrap()) instanceof ArcDrop) {
101             builder.append(((ArcDrop<T>) drop).count).append(", ");
102         }
103         return builder.append(drop).append(')').toString();
104     }
105 
106     private static void checkValidState(int count) {
107         if (count == -1) {
108             throw new IllegalStateException("Underlying resources have already been freed.");
109         }
110     }
111 }