package org.httpkit; import clojure.lang.ISeq; import clojure.lang.Seqable; import java.util.Arrays; import java.util.Map; import static org.httpkit.HttpUtils.*; /** * Save a few bytes of memory => No Map.Entry, and a little faster * Date: 4/23/13 * * @author feng <shenedu@gmail.com> * @since 2.0.2 */ public class HeaderMap { public boolean isEmpty() { return size == 0; } public final int INIT_SIZE = 8; private int size = 0; private Object arrays[] = new Object[INIT_SIZE * 2]; public void put(String key, Object obj) { final int total = size * 2; if (total == arrays.length) { arrays = Arrays.copyOf(arrays, arrays.length * 2); } arrays[total] = key; arrays[total + 1] = obj; size += 1; } public void putOrReplace(String key, Object obj) { final int total = size * 2; // * 2 for (int i = 0; i < total; i += 2) { if (key.equals(arrays[i])) { arrays[i + 1] = obj;// replace return; } } put(key, obj); } public Object get(String key) { final int total = size << 1; // * 2 for (int i = 0; i < total; i += 2) { if (key.equals(arrays[i])) { return arrays[i + 1]; } } return null; } public boolean containsKey(String key) { final int total = size * 2; // * 2 for (int i = 0; i < total; i += 2) { if (key.equals(arrays[i])) { return true; } } return false; } public void clear() { this.size = 0; } public static HeaderMap camelCase(Map<String, Object> map) { HeaderMap tmp = new HeaderMap(); if (map != null) { for (Map.Entry<String, Object> e : map.entrySet()) { tmp.put(HttpUtils.camelCase(e.getKey()), e.getValue()); } } return tmp; } public void encodeHeaders(DynamicBytes bytes) { final int total = size * 2; for (int i = 0; i < total; i += 2) { String k = (String) arrays[i]; Object v = arrays[i + 1]; // omit invalid headers and prevent possible exceptions (e.g., NullPointerException) if (k == null || v == null) { continue; } // ring spec says it could be a seq if (v instanceof Seqable) { ISeq seq = ((Seqable) v).seq(); while (seq != null) { bytes.append(k); bytes.append(COLON, SP); bytes.append(seq.first().toString(), HttpUtils.UTF_8); bytes.append(CR, LF); seq = seq.next(); } } else { bytes.append(k); bytes.append(COLON, SP); // supposed to be ISO-8859-1, but utf-8 is compatible. // filename in Content-Disposition can be utf8 bytes.append(v.toString(), HttpUtils.UTF_8); bytes.append(CR, LF); } } bytes.append(CR, LF); } }