Coverage Report - com.allanbank.mongodb.bson.io.SizeOfVisitor
 
Classes in this File Line Coverage Branch Coverage Complexity
SizeOfVisitor
96%
106/110
87%
7/8
1.207
 
 1  
 /*
 2  
  * #%L
 3  
  * SizeOfVisitor.java - mongodb-async-driver - Allanbank Consulting, Inc.
 4  
  * %%
 5  
  * Copyright (C) 2011 - 2014 Allanbank Consulting, Inc.
 6  
  * %%
 7  
  * Licensed under the Apache License, Version 2.0 (the "License");
 8  
  * you may not use this file except in compliance with the License.
 9  
  * You may obtain a copy of the License at
 10  
  * 
 11  
  *      http://www.apache.org/licenses/LICENSE-2.0
 12  
  * 
 13  
  * Unless required by applicable law or agreed to in writing, software
 14  
  * distributed under the License is distributed on an "AS IS" BASIS,
 15  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16  
  * See the License for the specific language governing permissions and
 17  
  * limitations under the License.
 18  
  * #L%
 19  
  */
 20  
 package com.allanbank.mongodb.bson.io;
 21  
 
 22  
 import java.nio.charset.Charset;
 23  
 import java.util.List;
 24  
 
 25  
 import com.allanbank.mongodb.bson.Document;
 26  
 import com.allanbank.mongodb.bson.Element;
 27  
 import com.allanbank.mongodb.bson.ElementType;
 28  
 import com.allanbank.mongodb.bson.Visitor;
 29  
 import com.allanbank.mongodb.bson.element.BinaryElement;
 30  
 import com.allanbank.mongodb.bson.element.ObjectId;
 31  
 
 32  
 /**
 33  
  * A visitor to determine the size of the documents it visits.
 34  
  * 
 35  
  * @api.no This class is <b>NOT</b> part of the drivers API. This class may be
 36  
  *         mutated in incompatible ways between any two releases of the driver.
 37  
  * @copyright 2011-2013, Allanbank Consulting, Inc., All Rights Reserved
 38  
  */
 39  
 public class SizeOfVisitor implements Visitor {
 40  
     /** UTF-8 Character set for encoding strings. */
 41  1
     public final static Charset UTF8 = StringDecoder.UTF8;
 42  
 
 43  
     /** The computed size. */
 44  
     private int mySize;
 45  
 
 46  
     /** The encoder for strings. */
 47  
     private final StringEncoder myStringEncoder;
 48  
 
 49  
     /**
 50  
      * Creates a new SizeOfVisitor.
 51  
      */
 52  
     public SizeOfVisitor() {
 53  1
         this(null);
 54  1
     }
 55  
 
 56  
     /**
 57  
      * Creates a new SizeOfVisitor.
 58  
      * 
 59  
      * @param encoder
 60  
      *            The encoder for strings.
 61  
      */
 62  
     public SizeOfVisitor(final StringEncoder encoder) {
 63  1
         super();
 64  1
         mySize = 0;
 65  1
         myStringEncoder = encoder;
 66  1
     }
 67  
 
 68  
     /**
 69  
      * Returns the visitor's output buffer.
 70  
      * 
 71  
      * @param string
 72  
      *            The 'C' string to determine the size of.
 73  
      * @return The visitor's output buffer.
 74  
      */
 75  
     public int computeCStringSize(final String string) {
 76  195
         return utf8Size(string) + 1;
 77  
     }
 78  
 
 79  
     /**
 80  
      * Returns the visitor's output buffer.
 81  
      * 
 82  
      * @param string
 83  
      *            The 'UTF8' string to determine the size of.
 84  
      * @return The visitor's output buffer.
 85  
      */
 86  
     public int computeStringSize(final String string) {
 87  30
         return 4 + utf8Size(string) + 1;
 88  
     }
 89  
 
 90  
     /**
 91  
      * Return the current Size of the written document.
 92  
      * 
 93  
      * @return The current size of the encoded document.
 94  
      */
 95  
     public int getSize() {
 96  5
         return mySize;
 97  
     }
 98  
 
 99  
     /**
 100  
      * Resets the size to zero and clears the cached documents. Use
 101  
      * {@link #rewind()} to just set the size to zero and not clear the cached
 102  
      * documents.
 103  
      */
 104  
     public void reset() {
 105  1
         mySize = 0;
 106  1
     }
 107  
 
 108  
     /**
 109  
      * Resets the size to zero but does not clear the cached documents. Use
 110  
      * {@link #reset()} to set the size to zero and clear the cached documents.
 111  
      */
 112  
     public void rewind() {
 113  1
         mySize = 0;
 114  1
     }
 115  
 
 116  
     /**
 117  
      * Computes the size of the encoded UTF8 String based on the table below.
 118  
      * 
 119  
      * <pre>
 120  
      * #    Code Points      Bytes
 121  
      * 1    U+0000..U+007F   1
 122  
      * 
 123  
      * 2    U+0080..U+07FF   2
 124  
      * 
 125  
      * 3    U+0800..U+0FFF   3
 126  
      *      U+1000..U+FFFF
 127  
      * 
 128  
      * 4   U+10000..U+3FFFF  4
 129  
      *     U+40000..U+FFFFF  4
 130  
      *    U+100000..U10FFFF  4
 131  
      * </pre>
 132  
      * 
 133  
      * @param string
 134  
      *            The string to determine the length of.
 135  
      * @return The length of the string encoded as UTF8.
 136  
      */
 137  
     public int utf8Size(final String string) {
 138  225
         if (myStringEncoder != null) {
 139  0
             return myStringEncoder.encodeSize(string);
 140  
         }
 141  225
         return StringEncoder.utf8Size(string);
 142  
     }
 143  
 
 144  
     /**
 145  
      * {@inheritDoc}
 146  
      */
 147  
     @Override
 148  
     public void visit(final List<Element> elements) {
 149  24
         mySize += 4;
 150  24
         for (final Element element : elements) {
 151  
             // Optimization to avoid the array copy.
 152  165
             if (element.getType() == ElementType.BINARY) {
 153  12
                 final BinaryElement be = (BinaryElement) element;
 154  12
                 doVisitBinary(be.getName(), be.getSubType(), be.length());
 155  12
             }
 156  
             else {
 157  153
                 element.accept(this);
 158  
             }
 159  165
         }
 160  24
         mySize += 1;
 161  24
     }
 162  
 
 163  
     /**
 164  
      * {@inheritDoc}
 165  
      */
 166  
     @Override
 167  
     public void visitArray(final String name, final List<Element> elements) {
 168  
 
 169  3
         mySize += 1;
 170  3
         mySize += computeCStringSize(name);
 171  3
         visit(elements);
 172  3
     }
 173  
 
 174  
     /**
 175  
      * {@inheritDoc}
 176  
      */
 177  
     @Override
 178  
     public void visitBinary(final String name, final byte subType,
 179  
             final byte[] data) {
 180  
 
 181  0
         final int dataLength = data.length;
 182  
 
 183  0
         doVisitBinary(name, subType, dataLength);
 184  0
     }
 185  
 
 186  
     /**
 187  
      * {@inheritDoc}
 188  
      */
 189  
     @Override
 190  
     public void visitBoolean(final String name, final boolean value) {
 191  
 
 192  33
         mySize += 1;
 193  33
         mySize += computeCStringSize(name);
 194  33
         mySize += 1;
 195  33
     }
 196  
 
 197  
     /**
 198  
      * {@inheritDoc}
 199  
      */
 200  
     @Override
 201  
     public void visitDBPointer(final String name, final String databaseName,
 202  
             final String collectionName, final ObjectId id) {
 203  6
         mySize += 1;
 204  6
         mySize += computeCStringSize(name);
 205  6
         mySize += computeStringSize(databaseName + "." + collectionName);
 206  6
         mySize += (4 + 8);
 207  6
     }
 208  
 
 209  
     /**
 210  
      * {@inheritDoc}
 211  
      */
 212  
     @Override
 213  
     public void visitDocument(final String name, final List<Element> elements) {
 214  12
         mySize += 1;
 215  12
         mySize += computeCStringSize(name);
 216  12
         visit(elements);
 217  12
     }
 218  
 
 219  
     /**
 220  
      * {@inheritDoc}
 221  
      */
 222  
     @Override
 223  
     public void visitDouble(final String name, final double value) {
 224  6
         mySize += 1;
 225  6
         mySize += computeCStringSize(name);
 226  6
         mySize += 8;
 227  6
     }
 228  
 
 229  
     /**
 230  
      * {@inheritDoc}
 231  
      */
 232  
     @Override
 233  
     public void visitInteger(final String name, final int value) {
 234  6
         mySize += 1;
 235  6
         mySize += computeCStringSize(name);
 236  6
         mySize += 4;
 237  6
     }
 238  
 
 239  
     /**
 240  
      * {@inheritDoc}
 241  
      */
 242  
     @Override
 243  
     public void visitJavaScript(final String name, final String code) {
 244  6
         mySize += 1;
 245  6
         mySize += computeCStringSize(name);
 246  6
         mySize += computeStringSize(code);
 247  6
     }
 248  
 
 249  
     /**
 250  
      * {@inheritDoc}
 251  
      */
 252  
     @Override
 253  
     public void visitJavaScript(final String name, final String code,
 254  
             final Document scope) {
 255  6
         mySize += 1;
 256  6
         mySize += computeCStringSize(name);
 257  
 
 258  6
         mySize += 4;
 259  6
         mySize += computeStringSize(code);
 260  
 
 261  6
         scope.accept(this);
 262  6
     }
 263  
 
 264  
     /**
 265  
      * {@inheritDoc}
 266  
      */
 267  
     @Override
 268  
     public void visitLong(final String name, final long value) {
 269  6
         mySize += 1;
 270  6
         mySize += computeCStringSize(name);
 271  6
         mySize += 8;
 272  6
     }
 273  
 
 274  
     /**
 275  
      * {@inheritDoc}
 276  
      */
 277  
     @Override
 278  
     public void visitMaxKey(final String name) {
 279  6
         mySize += 1;
 280  6
         mySize += computeCStringSize(name);
 281  6
     }
 282  
 
 283  
     /**
 284  
      * {@inheritDoc}
 285  
      */
 286  
     @Override
 287  
     public void visitMinKey(final String name) {
 288  6
         mySize += 1;
 289  6
         mySize += computeCStringSize(name);
 290  6
     }
 291  
 
 292  
     /**
 293  
      * {@inheritDoc}
 294  
      */
 295  
     @Override
 296  
     public void visitMongoTimestamp(final String name, final long value) {
 297  6
         mySize += 1;
 298  6
         mySize += computeCStringSize(name);
 299  6
         mySize += 8;
 300  6
     }
 301  
 
 302  
     /**
 303  
      * {@inheritDoc}
 304  
      */
 305  
     @Override
 306  
     public void visitNull(final String name) {
 307  6
         mySize += 1;
 308  6
         mySize += computeCStringSize(name);
 309  6
     }
 310  
 
 311  
     /**
 312  
      * {@inheritDoc}
 313  
      */
 314  
     @Override
 315  
     public void visitObjectId(final String name, final ObjectId id) {
 316  6
         mySize += 1;
 317  6
         mySize += computeCStringSize(name);
 318  6
         mySize += (4 + 8);
 319  6
     }
 320  
 
 321  
     /**
 322  
      * {@inheritDoc}
 323  
      */
 324  
     @Override
 325  
     public void visitRegularExpression(final String name, final String pattern,
 326  
             final String options) {
 327  15
         mySize += 1;
 328  15
         mySize += computeCStringSize(name);
 329  15
         mySize += computeCStringSize(pattern);
 330  15
         mySize += computeCStringSize(options);
 331  15
     }
 332  
 
 333  
     /**
 334  
      * {@inheritDoc}
 335  
      */
 336  
     @Override
 337  
     public void visitString(final String name, final String value) {
 338  6
         mySize += 1;
 339  6
         mySize += computeCStringSize(name);
 340  6
         mySize += computeStringSize(value);
 341  6
     }
 342  
 
 343  
     /**
 344  
      * {@inheritDoc}
 345  
      */
 346  
     @Override
 347  
     public void visitSymbol(final String name, final String symbol) {
 348  6
         mySize += 1;
 349  6
         mySize += computeCStringSize(name);
 350  6
         mySize += computeStringSize(symbol);
 351  6
     }
 352  
 
 353  
     /**
 354  
      * {@inheritDoc}
 355  
      */
 356  
     @Override
 357  
     public void visitTimestamp(final String name, final long timestamp) {
 358  12
         mySize += 1;
 359  12
         mySize += computeCStringSize(name);
 360  12
         mySize += 8;
 361  12
     }
 362  
 
 363  
     /**
 364  
      * Computes the size of the binary based on the name, type and length of the
 365  
      * data.
 366  
      * 
 367  
      * @param name
 368  
      *            The name of the element.
 369  
      * @param subType
 370  
      *            The sub-type of the binary element.
 371  
      * @param dataLength
 372  
      *            The length of data contained in the element.
 373  
      */
 374  
     private void doVisitBinary(final String name, final byte subType,
 375  
             final int dataLength) {
 376  12
         mySize += 1;
 377  12
         mySize += computeCStringSize(name);
 378  
 
 379  12
         switch (subType) {
 380  
         case 2: {
 381  6
             mySize += (4 + 1 + 4 + dataLength);
 382  6
             break;
 383  
 
 384  
         }
 385  
         case 0:
 386  
         default:
 387  6
             mySize += (4 + 1 + dataLength);
 388  
             break;
 389  
         }
 390  12
     }
 391  
 }