/*
* JLibs: Common Utilities for Java
* Copyright (C) 2009 Santhosh Kumar T <santhosh.tekuri@gmail.com>
*
* 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.
*/
package jlibs.nio.http.msg;
import jlibs.core.lang.ImpossibleException;
import jlibs.nio.http.util.USAscii;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.util.Objects;
import java.util.TreeMap;
/**
* @author Santhosh Kumar Tekuri
*/
public class AsciiString{
public final String text;
private final byte bytes[];
private final int hashCode;
public AsciiString(CharSequence text){
this(text, USAscii.caseInsensitiveHashCode(text));
}
AsciiString(CharSequence text, int hashCode){
Objects.requireNonNull(text, "text==null");
this.text = text.toString();
this.hashCode = hashCode;
bytes = USAscii.toBytes(this.text);
}
public void putInto(ByteBuffer buffer){
buffer.put(bytes, 0, bytes.length);
}
public int putInto(ByteBuffer buffer, int offset){
int min = Math.min(bytes.length-offset, buffer.remaining());
if(min>0)
buffer.put(bytes, offset, min);
return offset + min;
}
@Override
public int hashCode(){
return hashCode;
}
@Override
public boolean equals(Object obj){
if(obj==this)
return true;
if(obj instanceof AsciiString){
AsciiString that = (AsciiString)obj;
if(this.internID!=0 && that.internID!=0)
return this.internID==that.internID;
if(this.hashCode!=that.hashCode || this.bytes.length!=that.bytes.length)
return false;
int len = bytes.length;
for(int i=0; i<len; i++){
int ch1 = bytes[i];
if(ch1>='a' && ch1<='z')
ch1 = ch1 & 0xDF;
int ch2 = that.bytes[i];
if(ch2>='a' && ch2<='z')
ch2 = ch2 & 0xDF;
if(ch1!=ch2)
return false;
}
return true;
}else
return false;
}
public boolean equals(CharSequence seq){
if(seq==null || bytes.length!=seq.length())
return false;
int len = bytes.length;
for(int i=0; i<len; i++){
int ch1 = bytes[i];
if(ch1>='a' && ch1<='z')
ch1 = ch1 & 0xDF;
int ch2 = seq.charAt(i);
if(ch2>='a' && ch2<='z')
ch2 = ch2 & 0xDF;
if(ch1!=ch2)
return false;
}
return true;
}
@Override
public String toString(){
return text;
}
private int internID;
private static final Headers INTERNED = new Headers();
protected static void initInterned(){
if(INTERNED.getFirst()!=null)
return;
TreeMap<String, AsciiString> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
try{
Class classes[] = { Request.class, Response.class };
for(Class clazz: classes){
for(Field field: clazz.getFields()){
if(field.getType()==AsciiString.class){
AsciiString string = (AsciiString)field.get(null);
INTERNED.add(string, "");
map.put(string.text, string);
}
}
}
}catch(Exception ex){
throw new ImpossibleException(ex);
}
int id = 0;
for(AsciiString string: map.values())
string.internID = ++id;
}
public static AsciiString valueOf(CharSequence seq){
int hashCode = USAscii.caseInsensitiveHashCode(seq);
Header header = INTERNED.entry(seq, hashCode, false);
if(header!=null)
return header.getName();
return new AsciiString(seq, hashCode);
}
}