View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements. See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache license, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License. You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the license for the specific language governing permissions and
15   * limitations under the license.
16   */
17  package org.apache.logging.log4j.util;
18  
19  /**
20   * Utility for preventing primitive parameter values from being auto-boxed. Auto-boxing creates temporary objects
21   * which contribute to pressure on the garbage collector. With this utility users can convert primitive values directly
22   * into text without allocating temporary objects.
23   * <p>
24   * Example usage:
25   * </p><pre>
26   * import static org.apache.logging.log4j.util.Unbox.box;
27   * ...
28   * long longValue = 123456L;
29   * double doubleValue = 3.14;
30   * // prevent primitive values from being auto-boxed
31   * logger.debug("Long value={}, double value={}", box(longValue), box(doubleValue));
32   * </pre>
33   */
34  @PerformanceSensitive("allocation")
35  public class Unbox {
36      private static final int MASK = 16 - 1;
37  
38      private static class State {
39          private final StringBuilder[] ringBuffer = new StringBuilder[16];
40          private int current;
41          State() {
42              for (int i = 0; i < ringBuffer.length; i++) {
43                  ringBuffer[i] = new StringBuilder(21);
44              }
45          }
46  
47          public StringBuilder getStringBuilder() {
48              final StringBuilder result = ringBuffer[MASK & current++];
49              result.setLength(0);
50              return result;
51          }
52  
53          public boolean isBoxedPrimitive(final StringBuilder text) {
54              for (int i = 0; i < ringBuffer.length; i++) {
55                  if (text == ringBuffer[i]) {
56                      return true;
57                  }
58              }
59              return false;
60          }
61      }
62      private static ThreadLocal<State> threadLocalState = new ThreadLocal<>();
63  
64      /**
65       * Returns a {@code StringBuilder} containing the text representation of the specified primitive value.
66       * This method will not allocate temporary objects.
67       *
68       * @param value the value whose text representation to return
69       * @return a {@code StringBuilder} containing the text representation of the specified primitive value
70       */
71      @PerformanceSensitive("allocation")
72      public static StringBuilder box(final float value) {
73          return getSB().append(value);
74      }
75  
76      /**
77       * Returns a {@code StringBuilder} containing the text representation of the specified primitive value.
78       * This method will not allocate temporary objects.
79       *
80       * @param value the value whose text representation to return
81       * @return a {@code StringBuilder} containing the text representation of the specified primitive value
82       */
83      @PerformanceSensitive("allocation")
84      public static StringBuilder box(final double value) {
85          return getSB().append(value);
86      }
87  
88      /**
89       * Returns a {@code StringBuilder} containing the text representation of the specified primitive value.
90       * This method will not allocate temporary objects.
91       *
92       * @param value the value whose text representation to return
93       * @return a {@code StringBuilder} containing the text representation of the specified primitive value
94       */
95      @PerformanceSensitive("allocation")
96      public static StringBuilder box(final short value) {
97          return getSB().append(value);
98      }
99  
100     /**
101      * Returns a {@code StringBuilder} containing the text representation of the specified primitive value.
102      * This method will not allocate temporary objects.
103      *
104      * @param value the value whose text representation to return
105      * @return a {@code StringBuilder} containing the text representation of the specified primitive value
106      */
107     @PerformanceSensitive("allocation")
108     public static StringBuilder box(final int value) {
109         return getSB().append(value);
110     }
111 
112     /**
113      * Returns a {@code StringBuilder} containing the text representation of the specified primitive value.
114      * This method will not allocate temporary objects.
115      *
116      * @param value the value whose text representation to return
117      * @return a {@code StringBuilder} containing the text representation of the specified primitive value
118      */
119     @PerformanceSensitive("allocation")
120     public static StringBuilder box(final char value) {
121         return getSB().append(value);
122     }
123 
124     /**
125      * Returns a {@code StringBuilder} containing the text representation of the specified primitive value.
126      * This method will not allocate temporary objects.
127      *
128      * @param value the value whose text representation to return
129      * @return a {@code StringBuilder} containing the text representation of the specified primitive value
130      */
131     @PerformanceSensitive("allocation")
132     public static StringBuilder box(final long value) {
133         return getSB().append(value);
134     }
135 
136     /**
137      * Returns a {@code StringBuilder} containing the text representation of the specified primitive value.
138      * This method will not allocate temporary objects.
139      *
140      * @param value the value whose text representation to return
141      * @return a {@code StringBuilder} containing the text representation of the specified primitive value
142      */
143     @PerformanceSensitive("allocation")
144     public static StringBuilder box(final byte value) {
145         return getSB().append(value);
146     }
147 
148     /**
149      * Returns a {@code StringBuilder} containing the text representation of the specified primitive value.
150      * This method will not allocate temporary objects.
151      *
152      * @param value the value whose text representation to return
153      * @return a {@code StringBuilder} containing the text representation of the specified primitive value
154      */
155     @PerformanceSensitive("allocation")
156     public static StringBuilder box(final boolean value) {
157         return getSB().append(value);
158     }
159 
160     private static State getState() {
161         State state = threadLocalState.get();
162         if (state == null) {
163             state = new State();
164             threadLocalState.set(state);
165         }
166         return state;
167     }
168 
169     private static StringBuilder getSB() {
170         return getState().getStringBuilder();
171     }
172 }