stringtable-atom (empty) → 0.0.1
raw patch · 6 files changed
+704/−0 lines, 6 filesdep +basedep +binarydep +bytestringsetup-changed
Dependencies added: base, binary, bytestring
Files
- LICENSE +24/−0
- Setup.lhs +5/−0
- StringTable/Atom.hsc +191/−0
- cbits/StringTable_cbits.c +441/−0
- cbits/StringTable_cbits.h +22/−0
- stringtable-atom.cabal +21/−0
+ LICENSE view
@@ -0,0 +1,24 @@+Copyright (c) 2008, John Meacham+All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:+ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.+ * Redistributions in binary form must reproduce the above copyright+ notice, this list of conditions and the following disclaimer in the+ documentation and/or other materials provided with the distribution.+ * Neither the name of the author nor the names of its contributors may be+ used to endorse or promote products derived from this software without+ specific prior written permission.++THIS SOFTWARE IS PROVIDED BY JOHN MEACHAM ``AS IS'' AND ANY+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL JOHN MEACHAM BE LIABLE FOR ANY+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.lhs view
@@ -0,0 +1,5 @@+#!/usr/bin/env runhaskell+> module Main where+> import Distribution.Simple+> main :: IO ()+> main = defaultMain
+ StringTable/Atom.hsc view
@@ -0,0 +1,191 @@+{-# OPTIONS_GHC -fffi -XTypeSynonymInstances -XDeriveDataTypeable #-}+module StringTable.Atom(+ Atom(),+ ToAtom(..),+ FromAtom(..),+ HasHash(..),+ intToAtom,+ isValidAtom,+ unsafeIntToAtom,+ atomCompare,+ unsafeByteIndex,+ dumpTable,+ dumpToFile,+ dumpStringTableStats+ ) where++#include "StringTable_cbits.h"++import qualified Data.ByteString as BS+import qualified Data.ByteString.Internal as BS+import qualified Data.ByteString.Unsafe as BS+import Control.Monad+import Data.Binary+import Data.Binary.Get+import Data.Binary.Put+import Foreign+import Foreign.Marshal+import Data.Word+import Data.Char+import Foreign.C+import Data.Monoid+import Data.Dynamic+import Data.Bits++newtype Atom = Atom (#type atom_t)+ deriving(Typeable,Eq,Ord)++class FromAtom a where+ fromAtom :: Atom -> a+ fromAtomIO :: Atom -> IO a++ fromAtomIO a = return (fromAtom a)+ fromAtom a = unsafePerformIO (fromAtomIO a)++class ToAtom a where+ toAtom :: a -> Atom+ toAtomIO :: a -> IO Atom++ toAtomIO a = return (toAtom a)+ toAtom a = unsafePerformIO (toAtomIO a)++class HasHash a where+ hash32 :: a -> Word32++instance HasHash Atom where+ hash32 a = let (x,y) = fromAtom a :: CStringLen in unsafePerformIO $ hash2 0 x (fromIntegral y)++instance HasHash BS.ByteString where+ hash32 bs = unsafePerformIO $ do+ BS.unsafeUseAsCStringLen bs $ \ (x,y) -> hash2 0 x (fromIntegral y)++instance HasHash String where+ hash32 s = unsafePerformIO $ withCStringLen s $ \ (x,y) -> hash2 0 x (fromIntegral y)++instance FromAtom (String -> String) where+ fromAtom x = shows (fromAtom x :: String)++instance ToAtom Atom where+ toAtom x = x++instance FromAtom Atom where+ fromAtom x = x++instance ToAtom Char where+ toAtom x = toAtom [x]++instance ToAtom CStringLen where+ toAtomIO (cs,len) = do+ if (len > (#const MAX_ENTRY_SIZE))+ then fail "StringTable: atom is too big"+ else stAdd cs (fromIntegral len)++++instance ToAtom CString where+ toAtomIO cs = do+ len <- BS.c_strlen cs+ toAtomIO (cs,fromIntegral len :: Int)++instance ToAtom String where+ toAtomIO s = toAtomIO (BS.pack (toUTF s))++instance FromAtom String where+ fromAtom = fromUTF . BS.unpack . fromAtom++instance ToAtom BS.ByteString where+ toAtomIO bs = BS.unsafeUseAsCStringLen bs toAtomIO++instance FromAtom CStringLen where+ fromAtom a@(Atom v) = (stPtr a,fromIntegral $ (v `shiftR` (#const ATOM_LEN_SHIFT)) .&. (#const ATOM_LEN_MASK))++instance FromAtom Word where+ fromAtom (Atom i) = fromIntegral i++instance FromAtom Int where+ fromAtom (Atom i) = fromIntegral i++instance FromAtom BS.ByteString where+ fromAtomIO a = do+ sl <- fromAtomIO a :: IO CStringLen+ BS.unsafePackCStringLen sl++instance Monoid Atom where+ mempty = toAtom BS.empty+ mappend x y = unsafePerformIO $ atomAppend x y++instance Show Atom where+ showsPrec _ atom = (fromAtom atom ++)++instance Read Atom where+ readsPrec _ s = [ (toAtom s,"") ]++intToAtom :: Monad m => Int -> m Atom+intToAtom i = if isValidAtom i then return (Atom $ fromIntegral i) else fail $ "intToAtom: " ++ show i++isValidAtom :: Int -> Bool+isValidAtom i = odd i++unsafeIntToAtom :: Int -> Atom+unsafeIntToAtom x = Atom (fromIntegral x)++unsafeByteIndex :: Atom -> Int -> Word8+unsafeByteIndex atom off = fromIntegral (unsafePerformIO $ peek (stPtr atom `advancePtr` off))++foreign import ccall unsafe "stringtable_lookup" stAdd :: CString -> CInt -> IO Atom+foreign import ccall unsafe "stringtable_ptr" stPtr :: Atom -> CString+foreign import ccall unsafe "stringtable_stats" dumpStringTableStats :: IO ()+foreign import ccall unsafe "dump_table" dumpTable :: IO ()+foreign import ccall unsafe "atom_append" atomAppend :: Atom -> Atom -> IO Atom+foreign import ccall unsafe "lexigraphic_compare" c_atomCompare :: Atom -> Atom -> CInt+foreign import ccall unsafe "dump_to_file" dumpToFile :: IO ()+foreign import ccall unsafe hash2 :: Word32 -> CString -> CInt -> IO Word32++atomCompare a b = if c == 0 then EQ else if c > 0 then GT else LT where+ c = c_atomCompare a b++++-- | Convert Unicode characters to UTF-8.+toUTF :: String -> [Word8]+toUTF [] = []+toUTF (x:xs) | ord x<=0x007F = (fromIntegral $ ord x):toUTF xs+ | ord x<=0x07FF = fromIntegral (0xC0 .|. ((ord x `shift` (-6)) .&. 0x1F)):+ fromIntegral (0x80 .|. (ord x .&. 0x3F)):+ toUTF xs+ | otherwise = fromIntegral (0xE0 .|. ((ord x `shift` (-12)) .&. 0x0F)):+ fromIntegral (0x80 .|. ((ord x `shift` (-6)) .&. 0x3F)):+ fromIntegral (0x80 .|. (ord x .&. 0x3F)):+ toUTF xs++-- | Convert UTF-8 to Unicode.++fromUTF :: [Word8] -> String+fromUTF xs = fromUTF' (map fromIntegral xs) where+ fromUTF' [] = []+ fromUTF' (all@(x:xs))+ | x<=0x7F = (chr (x)):fromUTF' xs+ | x<=0xBF = err+ | x<=0xDF = twoBytes all+ | x<=0xEF = threeBytes all+ | otherwise = err+ twoBytes (x1:x2:xs) = chr ((((x1 .&. 0x1F) `shift` 6) .|.+ (x2 .&. 0x3F))):fromUTF' xs+ twoBytes _ = error "fromUTF: illegal two byte sequence"++ threeBytes (x1:x2:x3:xs) = chr ((((x1 .&. 0x0F) `shift` 12) .|.+ ((x2 .&. 0x3F) `shift` 6) .|.+ (x3 .&. 0x3F))):fromUTF' xs+ threeBytes _ = error "fromUTF: illegal three byte sequence"++ err = error "fromUTF: illegal UTF-8 character"++instance Binary Atom where+ get = do+ x <- getWord8+ bs <- getBytes (fromIntegral x)+ return $ toAtom bs+ put a = do+ let bs = fromAtom a+ putWord8 $ fromIntegral $ BS.length bs+ putByteString bs
+ cbits/StringTable_cbits.c view
@@ -0,0 +1,441 @@+#include <stdio.h>+#include <string.h>+#include <stdlib.h>+#include <inttypes.h>+#include <ctype.h>+#include <stdbool.h>+#define NDEBUG 1+#include <assert.h>+++#define USE_THREADS 0++#if USE_THREADS++#include <pthread.h>++static pthread_mutex_t mutex_hash = PTHREAD_MUTEX_INITIALIZER;+static pthread_mutex_t mutex_string = PTHREAD_MUTEX_INITIALIZER;++#else++#define pthread_mutex_lock(x) ;+#define pthread_mutex_unlock(x) ;++#endif++#include "StringTable_cbits.h"+// 23 bits of chunk space to leave one bit for 'valid' flag.+// valid flag must be set to 1 for it to be a valid atom++static void dieif(bool,char *);+uint32_t hash2(uint32_t salt,unsigned char *key, int key_len);+static void print_quoted(FILE *file,unsigned char *s,int len);++// string allocation stuff++#define NUM_CHUNKS 256+#define CHUNK_SIZE 16384++++#define ATOM_LEN(c) (((atom_t)(c) >> ATOM_LEN_SHIFT) & ATOM_LEN_MASK)+#define CHUNK_INDEX(c) (((atom_t)(c) >> 9)&0xFF)+#define CHUNK_OFFSET(c) (((atom_t)(c) >> 17) & 0x3FFF)++#define MAKE_ATOM(ci,co,len) ((((((atom_t)len) & ATOM_LEN_MASK) << ATOM_LEN_SHIFT) | ((((atom_t)ci) & 0xff) << 9) | (((atom_t)co & 0x3FFF) << 17)) | VALID_BITMASK)++#define ATOM_PTR(c) ((unsigned char *)&(stringtable_chunks[CHUNK_INDEX(c)][CHUNK_OFFSET(c)]))++#define ATOM_VALID(a) (a)++// ((a) & VALID_BITMASK)++++static unsigned char first_chunk[CHUNK_SIZE];+static unsigned char *stringtable_chunks[NUM_CHUNKS] = { first_chunk };++static uint16_t current_chunk = 0;+static uint16_t next_free_offset = 0;++static atom_t+add_string(unsigned char *cs, int len)+{+ pthread_mutex_lock(&mutex_string);+ //printf("add_string(%c,%c,%i)\n",cs[0],cs[1],len);+ assert(len >= 0);+ assert(len < MAX_ENTRY_SIZE);+ assert(next_free_offset < CHUNK_SIZE);+ if(next_free_offset + 1 > CHUNK_SIZE - MAX_ENTRY_SIZE) {+ dieif(current_chunk >= NUM_CHUNKS - 1, "No more chunks");+ current_chunk++;+ assert(!stringtable_chunks[current_chunk]);+ stringtable_chunks[current_chunk] = malloc(CHUNK_SIZE);+ dieif(!stringtable_chunks[current_chunk], "error alocating memory");+ next_free_offset = 0;+ }+ memcpy(stringtable_chunks[current_chunk] + next_free_offset, cs, len);+ atom_t r = MAKE_ATOM(current_chunk, next_free_offset, len);+ assert(CHUNK_INDEX(r) == current_chunk);+ assert(CHUNK_OFFSET(r) == next_free_offset);+ assert(ATOM_PTR(r) == stringtable_chunks[current_chunk] + next_free_offset);+ assert(ATOM_LEN(r) == len);+ next_free_offset += len;+ assert(next_free_offset < CHUNK_SIZE);+ assert(current_chunk < NUM_CHUNKS);+ pthread_mutex_unlock(&mutex_string);+ return r;+}++// hashtable stuff++#define KEEP_HASH 2++#define CUCKOO_HASHES 2U+#define CUCKOO_BUCKETS 2U++typedef uint32_t hash_t;++struct hentry {+#if KEEP_HASH+ hash_t hashes[CUCKOO_HASHES];+#endif+ atom_t atom;+};++#define INIT_SIZE 2+static uint32_t hsize = INIT_SIZE;+static struct hentry init_htable[(1 << INIT_SIZE) * CUCKOO_HASHES];+static struct hentry *htable = init_htable;++#define HASHSIZE (1 << hsize)+#define HASHMASK (HASHSIZE - 1)++#define INDEX_HASH(i) ((i) / HASHSIZE)+#define HASH_INDEX(h,x) ((h * HASHSIZE) + (HASHMASK & ((uint32_t)x)))++#define HASH_BUCKET(x,b) ((((x) + (b)) % HASHSIZE) + (INDEX_HASH(x)*HASHSIZE))++#define DEPTH_LIMIT 512++static void hash_insert(struct hentry x);++static void+fast_insert(int t, int tb, struct hentry hb) {+ hash_insert(hb);+}++#ifndef NDEBUG++static bool+atom_exists(atom_t a) {+ for(int i = 0; i < HASHSIZE*CUCKOO_HASHES; i++) {+ if(a == htable[i].atom) return true;+ }+ return false;+}+static bool+item_exists(unsigned char *cs, int len) {+ for(int i = 0; i < HASHSIZE*CUCKOO_HASHES; i++) {+ atom_t a = htable[i].atom;+ if(ATOM_VALID(a)) {+ if(len == ATOM_LEN(a) && !memcmp(ATOM_PTR(a),cs,len))+ return true;+ }+ }+ return false;+}++#endif++void+dump_to_file(void) {+ FILE *file = fopen("atom.dump","w");+ for(int i = 0; i < HASHSIZE*CUCKOO_HASHES; i++) {+ atom_t a = htable[i].atom;+ if(ATOM_VALID(a)) {+ fprintf(file,"%u:",ATOM_LEN(a));+ print_quoted(file, ATOM_PTR(a),ATOM_LEN(a));+ fwrite("\n",1,1,file);+ }+ }+}++void+dump_table(void) {+ for(int i = 0; i < HASHSIZE*CUCKOO_HASHES; i++) {+ atom_t a = htable[i].atom;+ if(ATOM_VALID(a)) {+ printf("%p %u: ",ATOM_PTR(a),ATOM_LEN(a));+ fwrite(ATOM_PTR(a),1,ATOM_LEN(a),stdout);+ fwrite("\n",1,1,stdout);+ }+ }+}+++static void+grow_table(void) {+ // fprintf(stderr,"grow_table[[[\n");+ uint32_t os = (1 << hsize++) * CUCKOO_HASHES;+ struct hentry *ot = htable;+ htable = calloc(sizeof(struct hentry),CUCKOO_HASHES * (1 << hsize));++ for(int i = 0; i < os; i++) {+ if(ATOM_VALID(ot[i].atom))+ fast_insert(0,0,ot[i]);+ }+ if(ot != init_htable) free(ot);+// fprintf(stderr,"]]]\n");+}++#if KEEP_HASH+#define FHASH(x,i) ((x).hashes[i])+#else+#define FHASH(x,i) (hash2(i,ATOM_PTR((x).atom),ATOM_LEN((x).atom)))+#endif++static void+hash_insert(struct hentry x) {+ assert(ATOM_VALID(x.atom));+// fprintf(stderr,"hash_insert(%x,%p:%i,%x,%x,[%x,%x]", x.atom, ATOM_PTR(x.atom), ATOM_LEN(x.atom), x.hashes[0], x.hashes[1],HASH_INDEX(0,x.hashes[0]),HASH_INDEX(1,x.hashes[1]));+ assert(!atom_exists(x.atom));+ assert(!item_exists(ATOM_PTR(x.atom),ATOM_LEN(x.atom)));+ atom_t start = x.atom;+ for(int loop = 0; loop < DEPTH_LIMIT;loop++) {+ for(int i = 0; i < CUCKOO_HASHES; i++) {+// int e = HASH_INDEX(i,FHASH(x,i));+ for(int j = 0; j < CUCKOO_BUCKETS; j++) {+ //#struct hentry *b = &(htable[(e + j) & HASHJMASK ]);+ //struct hentry *b = &htable[HASH_BUCKET(e,j)];+ struct hentry *b = &htable[HASH_INDEX(i,FHASH(x,i) + j)];+ if(!ATOM_VALID(b->atom)) {+ *b = x;+// fprintf(stderr,")\n");+ return;+ }+ struct hentry tb = x;+ x = *b;+ *b = tb;+ }+ // struct hentry *b = &(htable[e]);+ }+ if(x.atom == start) {+ break;+ }+ }+ grow_table();+// fprintf(stderr,"R");+ return hash_insert(x);+}++++static void+print_quoted(FILE *file,unsigned char *s,int len)+{+ for(int i = 0;i < len; i ++) {+ switch(s[i]) {+ case '\n': fputs("\\n",file); continue;+ case '\r': fputs("\\r",file); continue;+ case '\t': fputs("\\t",file); continue;+ default: ;+ }+ if(isprint(s[i]))+ fputc(s[i],file);+ else+ fprintf(file,"\\x%2.2X", (unsigned)s[i]);+ }+}+++atom_t+stringtable_lookup(unsigned char *cs, int len)+{+// static FILE *file = NULL;+// if(!file)+// file = fopen("atom.lookup","w");+// fprintf(file,"stringtable_lookup(");+// print_quoted(file,cs,len);+// fprintf(file,")\n");+ pthread_mutex_lock(&mutex_hash);+ assert(len >= 0);+ assert(len < MAX_ENTRY_SIZE);+ hash_t h[CUCKOO_HASHES];+ for(uint32_t i = 0; i < CUCKOO_HASHES; i++) {+ h[i] = hash2(i,cs,len);+ //int e = HASH_INDEX(i,h[i]);+ for(int j = 0; j < CUCKOO_BUCKETS; j++) {+ //struct hentry *b = &htable[(e + i) & HASHJMASK ];+ //struct hentry *b = &htable[HASH_BUCKET(e,j)];+ struct hentry *b = &htable[HASH_INDEX(i,h[i] + j)];+#if KEEP_HASH+ if (ATOM_VALID(b->atom) && h[i] == b->hashes[i] && len == ATOM_LEN(b->atom) && !memcmp(ATOM_PTR(b->atom),cs,len)) {+ pthread_mutex_unlock(&mutex_hash);+ return b->atom;+ }+#else+ if (ATOM_VALID(b->atom) && len == ATOM_LEN(b->atom) && !memcmp(ATOM_PTR(b->atom),cs,len)) {+ pthread_mutex_unlock(&mutex_hash);+ return b->atom;+ }+#endif+ }+ }+ atom_t na = add_string(cs,len);+ struct hentry hb;+ hb.atom = na;+#if KEEP_HASH+ memcpy(hb.hashes,h,sizeof hb.hashes);+#endif+ hash_insert(hb);+ pthread_mutex_unlock(&mutex_hash);+ return na;+}++++int+lexigraphic_compare(atom_t x, atom_t y)+{+ int xl = ATOM_LEN(x);+ int yl = ATOM_LEN(y);+ return memcmp(ATOM_PTR(x),ATOM_PTR(y),xl < yl ? xl : yl) || xl - yl;+}+++atom_t+atom_append(atom_t x,atom_t y)+{+ unsigned char *xs,*ys;+ int xl,yl;++ xl = stringtable_find(x,&xs);+ yl = stringtable_find(y,&ys);++ unsigned char buf[MAX_ENTRY_SIZE];++ memcpy(buf,xs,xl);+ memcpy(buf + xl,ys,yl);++ return stringtable_lookup(buf,xl + yl);+}++unsigned char *+stringtable_ptr(atom_t cl)+{+ assert(ATOM_VALID(cl));+ return ATOM_PTR(cl);+}++int+stringtable_get(atom_t cl, char buf[MAX_ENTRY_SIZE])+{+ assert(ATOM_VALID(cl));+ memcpy(buf,ATOM_PTR(cl),ATOM_LEN(cl));+ return ATOM_LEN(cl);+}++int+stringtable_find(atom_t cl, unsigned char **res)+{+ assert(ATOM_VALID(cl));+ *res = ATOM_PTR(cl);+ return ATOM_LEN(cl);+}++void+stringtable_stats(void)+{+ unsigned static_memory = sizeof(stringtable_chunks);+ printf("Static Memory: %u\n", static_memory);+ unsigned dynamic_memory = (current_chunk + 1) * CHUNK_SIZE;+ unsigned data_memory = current_chunk*CHUNK_SIZE + next_free_offset;;+ printf("Used Chunks: %u/%u - %u bytes\n", current_chunk + 1, NUM_CHUNKS, data_memory);+ unsigned num_entries = 0;+ unsigned hash_types[CUCKOO_HASHES];+ memset(hash_types,0,sizeof hash_types);+ unsigned num_total = 0;+ for(int i = 0; i < HASHSIZE * CUCKOO_HASHES; i++) {+ num_total++;+ dynamic_memory += sizeof(struct hentry);+ if(ATOM_VALID(htable[i].atom)) {+ num_entries++;+ hash_types[i / HASHSIZE]++;+ }+ }++ for(int i = 0; i < CUCKOO_HASHES; i++)+ printf("Hash Table %i: %u\n", i, hash_types[i]);++ printf("Usage: %u/%u %.3f%%\n", num_entries, num_total, (double)num_entries * 100.0 / num_total);++ printf("Dynamic Memory: %u\n", dynamic_memory);+ printf("Storage Efficiency: %.3f%%\n", (double)data_memory * 100.0/ dynamic_memory);++}+++++static void+dieif(bool w,char *str)+{+ if(w) {+ fprintf(stderr, "stringlib: %s\n", str);+ exit(1);+ }+}++// hash functions+++uint32_t+hash2(uint32_t salt, unsigned char *key, int key_len)+{+ uint32_t hash = salt;+ for (int i = 0; i < key_len; i++) {+ hash += key[i];+ hash += (hash << 10);+ hash ^= (hash >> 6);+ }+ hash += (hash << 3);+ hash ^= (hash >> 11);+ hash += (hash << 15);+ return hash;+}++/*+int+main(int argc, char *argv[])+{+ unsigned char buf[MAX_ENTRY_SIZE];+ while(fgets((char *)buf,MAX_ENTRY_SIZE,stdin)) {+ buf[MAX_ENTRY_SIZE - 1] = '\0';+ unsigned len = strlen((char *)buf);+ if(!len) continue;+ if(buf[len - 1] == '\n') buf[--len] = '\0';+ stringtable_lookup(buf,len);+ //printf("%x: %s\n", a, buf);++ }++ dump_table();+ stringtable_stats();++ return 0;+}+static hash_t+hash3(uint32_t salt, unsigned char* str, size_t len)+{+ const uint32_t fnv_prime = 0x811C9DC5;+ unsigned int hash = salt;+ for(int i = 0; i < len; i++) {+ hash *= fnv_prime;+ hash ^= str[i];+ hash ^= salt;+ }+ return hash;+}+*/
+ cbits/StringTable_cbits.h view
@@ -0,0 +1,22 @@+#ifndef ST_CBITS_H+#define ST_CBITS_H++#include <stdint.h>++#define MAX_ENTRY_SIZE 256+#define VALID_BITMASK 0x1++// always shift, then mask+#define ATOM_LEN_MASK 0xff+#define ATOM_LEN_SHIFT 1++typedef uint32_t atom_t;+++atom_t stringtable_lookup(unsigned char *cs, int len);+void stringtable_stats(void);+int stringtable_find(atom_t cl, unsigned char **res);+unsigned char *stringtable_ptr(atom_t cl);+++#endif
+ stringtable-atom.cabal view
@@ -0,0 +1,21 @@+Name: stringtable-atom+Version: 0.0.1+Category: Data+Synopsis: Maps strings to Atoms for fast equality and ordering comparison+Description: Maps strings to Atoms for fast equality and ordering comparison+License: BSD3+License-File: LICENSE+Author: John Meacham+Maintainer: audreyt@audreyt.org+Copyright: John Meacham, 2008+Exposed-modules: StringTable.Atom++Build-Depends: base, bytestring>=0.9.0.1, binary+Build-Type: Simple+Tested-With: GHC==6.8.2++extensions: ForeignFunctionInterface, TypeSynonymInstances, DeriveDataTypeable, FlexibleInstances+c-sources: cbits/StringTable_cbits.c+extra-source-files: cbits/StringTable_cbits.h+include-dirs: cbits+cc-options: -O2 -std=c99