Package com.slytechs.jnetstream.packet

Source Code of com.slytechs.jnetstream.packet.FastHeaderCache

/**
* Copyright (C) 2007 Sly Technologies, Inc. This library is free software; you
* can redistribute it and/or modify it under the terms of the GNU Lesser
* General Public License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version. This
* library is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details. You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.slytechs.jnetstream.packet;

import java.util.Arrays;
import java.util.Iterator;

import org.jnetstream.packet.Header;
import org.jnetstream.packet.HeaderCache;
import org.jnetstream.protocol.ProtocolEntry;
import org.jnetstream.protocol.ProtocolInfo;
import org.jnetstream.protocol.ProtocolRegistry;
import org.jnetstream.protocol.codec.HeaderRuntime;

/**
* @author Mark Bednarczyk
* @author Sly Technologies, Inc.
*/
@SuppressWarnings("unchecked")
public class FastHeaderCache implements HeaderCache {

  private static final int BIT_SHIFT = 20;

  private static final int COUNT = 10;

  private static final int INDEX_MASK = 0xFFF00000;

  private static final int VALUE_MASK = ~INDEX_MASK;

  private long bits = 0;

  private int last = -1; // Index of last entry into offsets

  private int[] offsets = new int[FastHeaderCache.COUNT];

  private Header[] refs = new Header[FastHeaderCache.COUNT];

  /*
   * (non-Javadoc)
   *
   * @see org.jnetstream.packet.FastHeaderCache#add(org.jnetstream.protocol.codec.HeaderRuntime)
   */
  public void add(final Header header) {
    final int index = ProtocolRegistry.lookup(header.getProtocol()).getIndex();
    final int offset = header.getOffset();

    add(index, offset, header);
  }

  /*
   * (non-Javadoc)
   *
   * @see com.slytechs.packet.FastHeaderCache#add(int, int)
   */
  public void add(final int index, final int offset) {
    final int mask = index << BIT_SHIFT;

    bits |= (1L << index);

    last++;

    if (last == offsets.length) {
      this.reallocate();
    }

    offsets[last] = mask | offset;
  }

  /*
   * (non-Javadoc)
   *
   * @see com.slytechs.packet.FastHeaderCache#add(int, int,
   *      org.jnetstream.protocol.codec.HeaderRuntime)
   */
  public void add(final int index, final int offset, final Header header) {
    final int mask = index << BIT_SHIFT;
    bits |= (1L << index);

    last++;

    if (last == offsets.length) {
      this.reallocate();
    }

    offsets[last] = mask | offset;
    refs[last] = header;
  }

  /*
   * (non-Javadoc)
   *
   * @see com.slytechs.packet.FastHeaderCache#clear()
   */
  public void clear() {
    bits = 0;
    Arrays.fill(offsets, 0);
    Arrays.fill(refs, null);
    last = -1;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.jnetstream.packet.FastHeaderCache#contains(java.lang.Class)
   */
  public boolean contains(Class<? extends Header> c) {

    final ProtocolEntry protocol = ProtocolRegistry.lookup(c);

    if (protocol == null) {
      return false;
    }

    final int index = protocol.getIndex();

    if (index == ProtocolInfo.NO_BIT_INDEX) {
      for (int i = 0; i < refs.length; i++) {
        final Header rt = refs[i];
        if (rt == protocol) {
          return true;
        }
      }

      return false;

    } else {
      return contains(index);
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see com.slytechs.packet.FastHeaderCache#contains(int)
   */
  public boolean contains(final int index) {
    return (bits & (1L << index)) != 0;
  }

  /*
   * (non-Javadoc)
   *
   * @see com.slytechs.packet.FastHeaderCache#contains(int, int)
   */
  public boolean contains(final int index, final int instance) {
    if ((bits & (1L << index)) == 0) {
      return false;
    }

    final int mask = index << BIT_SHIFT;
    int inst = instance;
    for (int i = 0; i < offsets.length; i++) {
      final int o = offsets[i];

      if ((o & INDEX_MASK) == mask) {
        if (inst-- == 0) {
          return true;
        }
      }
    }

    return false;

  }

  /*
   * (non-Javadoc)
   *
   * @see com.slytechs.packet.FastHeaderCache#contains(org.jnetstream.protocol.Protocol)
   */
  public boolean contains(final ProtocolEntry protocol) {
    final int index = protocol.getIndex();

    if (index == 0) {

      for (int i = 0; i < refs.length; i++) {
        if (refs[i].getProtocol() == protocol.getProtocol()) {
          return true;
        }
      }

      return false;

    } else {
      return contains(index);
    }
  }

  private int[] copyOf(int[] src, int size) {

    int[] dst = new int[size];
    if (size < src.length) {
      System.arraycopy(src, 0, dst, 0, size);

    } else {
      System.arraycopy(src, 0, dst, 0, src.length);
    }

    return (int[]) dst;

  }

  private <S extends Header> S[] copyOf(S[] src, int size) {

    Header[] dst = new Header[size];
    if (size < src.length) {
      System.arraycopy(src, 0, dst, 0, size);

    } else {
      System.arraycopy(src, 0, dst, 0, src.length);
    }

    return (S[]) dst;

  }

  /*
   * (non-Javadoc)
   *
   * @see org.jnetstream.packet.FastHeaderCache#getHeader(java.lang.Class)
   */
  public Header getHeader(Class<? extends Header> c) {

    final ProtocolEntry protocol = ProtocolRegistry.lookup(c);

    if (protocol == null) {
      return null;
    }

    return getHeader(protocol);
  }

  /*
   * (non-Javadoc)
   *
   * @see java.util.Map#get(java.lang.Object)
   */
  /*
   * (non-Javadoc)
   *
   * @see com.slytechs.packet.FastHeaderCache#getHeader(int)
   */
  public Header getHeader(final int index) {
    final int mask = index << BIT_SHIFT;

    for (int i = 0; i < offsets.length; i++) {
      final int o = offsets[i];

      if ((o & FastHeaderCache.INDEX_MASK) == mask) {
        return refs[i];
      }

    }

    throw new IndexOutOfBoundsException(
        "Header information not found for index " + index
            + ". You must use hasHeader first.");
  }

  /*
   * (non-Javadoc)
   *
   * @see java.util.Map#get(java.lang.Object)
   */
  /*
   * (non-Javadoc)
   *
   * @see com.slytechs.packet.FastHeaderCache#getHeader(int, int)
   */
  public Header getHeader(final int index, final int instance) {
    final int mask = index << BIT_SHIFT;
    int inst = instance;

    for (int i = 0; i < offsets.length; i++) {
      final int o = offsets[i];

      if ((o & FastHeaderCache.INDEX_MASK) == mask) {
        if (inst-- == 0) {
          return refs[i];
        }
      }

    }

    throw new IndexOutOfBoundsException(
        "Header information not found for index " + index + "." + instance
            + ". You must use hasHeader first.");
  }

  public Header getHeader(final ProtocolEntry protocol) {
    final int index = protocol.getIndex();

    if (index != ProtocolInfo.NO_BIT_INDEX) {
      return getHeader(index);
    }

    for (int i = 0; i < refs.length; i++) {
      final Header rt = refs[i];
      if (rt == protocol) {
        return rt;
      }

    }

    throw new IndexOutOfBoundsException(
        "Header information not found for protocol " + protocol
            + ". You must use hasHeader first.");
  }

  /*
   * (non-Javadoc)
   *
   * @see java.util.Map#get(java.lang.Object)
   */
  /*
   * (non-Javadoc)
   *
   * @see com.slytechs.packet.FastHeaderCache#getOffset(int)
   */
  public int getOffset(final int index) {
    final int mask = index << BIT_SHIFT;

    for (final int o : offsets) {
      if ((o & FastHeaderCache.INDEX_MASK) == mask) {
        return o & FastHeaderCache.VALUE_MASK;
      }

    }

    throw new IndexOutOfBoundsException(
        "Offset information not found for index " + index
            + ".0. You must use hasHeader first.");
  }

  /*
   * (non-Javadoc)
   *
   * @see java.util.Map#get(java.lang.Object)
   */
  /*
   * (non-Javadoc)
   *
   * @see com.slytechs.packet.FastHeaderCache#getOffset(int, int)
   */
  public int getOffset(final int index, final int instance) {
    final int mask = index << BIT_SHIFT;
    int inst = instance;

    for (final int o : offsets) {
      if ((o & FastHeaderCache.INDEX_MASK) == mask) {
        if (inst-- == 0) {
          return o & FastHeaderCache.VALUE_MASK;
        }
      }

    }

    throw new IndexOutOfBoundsException(
        "Offset information not found for index " + index + "." + instance
            + ". You must use hasHeader first.");
  }

  /*
   * (non-Javadoc)
   *
   * @see java.util.Map#isEmpty()
   */
  /*
   * (non-Javadoc)
   *
   * @see com.slytechs.packet.FastHeaderCache#isEmpty()
   */
  public boolean isEmpty() {
    return bits == 0;
  }

  /*
   * (non-Javadoc)
   *
   * @see java.lang.Iterable#iterator()
   */
  public Iterator<Header> iterator() {
    return new Iterator<Header>() {
      private int i = 0;

      public boolean hasNext() {
        return i <= last;
      }

      public Header next() {
        return refs[i++];
      }

      public void remove() {
        throw new UnsupportedOperationException(
            "Remove operation not supported in fast header cache. "
                + "Use Packet.remove instead.");
      }

    };
  }

  /*
   * (non-Javadoc)
   *
   * @see com.slytechs.packet.FastHeaderCache#put(int, int,
   *      org.jnetstream.protocol.codec.HeaderRuntime)
   */
  public void put(final int index, final int instance, final Header header) {
    final int mask = index << BIT_SHIFT;
    bits |= (1L << index);
    int inst = instance;

    for (int i = 0; i < offsets.length; i++) {
      final int o = offsets[i];

      if ((o & FastHeaderCache.INDEX_MASK) == mask) {
        if (inst-- == 0) {
          refs[i] = header;
          return;
        }
      }
    }

    throw new IllegalArgumentException("Unable to find index " + index + "."
        + instance + ". You must use hasHeader first.");
  }

  /**
   *
   */
  private void reallocate() {
    offsets = copyOf(offsets, offsets.length + FastHeaderCache.COUNT);
    refs = copyOf(refs, refs.length + FastHeaderCache.COUNT);
  }

  /*
   * (non-Javadoc)
   *
   * @see java.util.Map#size()
   */
  /*
   * (non-Javadoc)
   *
   * @see com.slytechs.packet.FastHeaderCache#size()
   */
  public int size() {
    return last + 1;
  }

  /*
   * (non-Javadoc)
   *
   * @see org.jnetstream.packet.FastHeaderCache#toArray(org.jnetstream.packet.Header[])
   */
  public Header[] toArray(Header[] h) {
    for (int i = 0; i < last + 1; i++) {
      h[i] = refs[i];
    }

    return h;
  }

  public String toString() {
    return "" + bits + Arrays.toString(this.offsets);
  }

}
TOP

Related Classes of com.slytechs.jnetstream.packet.FastHeaderCache

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.