Ruby  2.0.0p481(2014-05-08revision45883)
ext/json/fbuffer/fbuffer.h
Go to the documentation of this file.
00001 
00002 #ifndef _FBUFFER_H_
00003 #define _FBUFFER_H_
00004 
00005 #include "ruby.h"
00006 
00007 #ifndef RHASH_SIZE
00008 #define RHASH_SIZE(hsh) (RHASH(hsh)->tbl->num_entries)
00009 #endif
00010 
00011 #ifndef RFLOAT_VALUE
00012 #define RFLOAT_VALUE(val) (RFLOAT(val)->value)
00013 #endif
00014 
00015 #ifndef RARRAY_PTR
00016 #define RARRAY_PTR(ARRAY) RARRAY(ARRAY)->ptr
00017 #endif
00018 #ifndef RARRAY_LEN
00019 #define RARRAY_LEN(ARRAY) RARRAY(ARRAY)->len
00020 #endif
00021 #ifndef RSTRING_PTR
00022 #define RSTRING_PTR(string) RSTRING(string)->ptr
00023 #endif
00024 #ifndef RSTRING_LEN
00025 #define RSTRING_LEN(string) RSTRING(string)->len
00026 #endif
00027 
00028 #ifdef PRIsVALUE
00029 # define RB_OBJ_CLASSNAME(obj) rb_obj_class(obj)
00030 # define RB_OBJ_STRING(obj) (obj)
00031 #else
00032 # define PRIsVALUE "s"
00033 # define RB_OBJ_CLASSNAME(obj) rb_obj_classname(obj)
00034 # define RB_OBJ_STRING(obj) StringValueCStr(obj)
00035 #endif
00036 
00037 #ifdef HAVE_RUBY_ENCODING_H
00038 #include "ruby/encoding.h"
00039 #define FORCE_UTF8(obj) rb_enc_associate((obj), rb_utf8_encoding())
00040 #else
00041 #define FORCE_UTF8(obj)
00042 #endif
00043 
00044 /* We don't need to guard objects for rbx, so let's do nothing at all. */
00045 #ifndef RB_GC_GUARD
00046 #define RB_GC_GUARD(object)
00047 #endif
00048 
00049 typedef struct FBufferStruct {
00050     unsigned long initial_length;
00051     char *ptr;
00052     unsigned long len;
00053     unsigned long capa;
00054 } FBuffer;
00055 
00056 #define FBUFFER_INITIAL_LENGTH_DEFAULT 1024
00057 
00058 #define FBUFFER_PTR(fb) (fb->ptr)
00059 #define FBUFFER_LEN(fb) (fb->len)
00060 #define FBUFFER_CAPA(fb) (fb->capa)
00061 #define FBUFFER_PAIR(fb) FBUFFER_PTR(fb), FBUFFER_LEN(fb)
00062 
00063 static FBuffer *fbuffer_alloc(unsigned long initial_length);
00064 static void fbuffer_free(FBuffer *fb);
00065 static void fbuffer_clear(FBuffer *fb);
00066 static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len);
00067 #ifdef JSON_GENERATOR
00068 static void fbuffer_append_long(FBuffer *fb, long number);
00069 #endif
00070 static void fbuffer_append_char(FBuffer *fb, char newchr);
00071 #ifdef JSON_GENERATOR
00072 static FBuffer *fbuffer_dup(FBuffer *fb);
00073 static VALUE fbuffer_to_s(FBuffer *fb);
00074 #endif
00075 
00076 static FBuffer *fbuffer_alloc(unsigned long initial_length)
00077 {
00078     FBuffer *fb;
00079     if (initial_length <= 0) initial_length = FBUFFER_INITIAL_LENGTH_DEFAULT;
00080     fb = ALLOC(FBuffer);
00081     memset((void *) fb, 0, sizeof(FBuffer));
00082     fb->initial_length = initial_length;
00083     return fb;
00084 }
00085 
00086 static void fbuffer_free(FBuffer *fb)
00087 {
00088     if (fb->ptr) ruby_xfree(fb->ptr);
00089     ruby_xfree(fb);
00090 }
00091 
00092 static void fbuffer_clear(FBuffer *fb)
00093 {
00094     fb->len = 0;
00095 }
00096 
00097 static void fbuffer_inc_capa(FBuffer *fb, unsigned long requested)
00098 {
00099     unsigned long required;
00100 
00101     if (!fb->ptr) {
00102         fb->ptr = ALLOC_N(char, fb->initial_length);
00103         fb->capa = fb->initial_length;
00104     }
00105 
00106     for (required = fb->capa; requested > required - fb->len; required <<= 1);
00107 
00108     if (required > fb->capa) {
00109         REALLOC_N(fb->ptr, char, required);
00110         fb->capa = required;
00111     }
00112 }
00113 
00114 static void fbuffer_append(FBuffer *fb, const char *newstr, unsigned long len)
00115 {
00116     if (len > 0) {
00117         fbuffer_inc_capa(fb, len);
00118         MEMCPY(fb->ptr + fb->len, newstr, char, len);
00119         fb->len += len;
00120     }
00121 }
00122 
00123 #ifdef JSON_GENERATOR
00124 static void fbuffer_append_str(FBuffer *fb, VALUE str)
00125 {
00126     const char *newstr = StringValuePtr(str);
00127     unsigned long len = RSTRING_LEN(str);
00128 
00129     RB_GC_GUARD(str);
00130 
00131     fbuffer_append(fb, newstr, len);
00132 }
00133 #endif
00134 
00135 static void fbuffer_append_char(FBuffer *fb, char newchr)
00136 {
00137     fbuffer_inc_capa(fb, 1);
00138     *(fb->ptr + fb->len) = newchr;
00139     fb->len++;
00140 }
00141 
00142 #ifdef JSON_GENERATOR
00143 static void freverse(char *start, char *end)
00144 {
00145     char c;
00146 
00147     while (end > start) {
00148         c = *end, *end-- = *start, *start++ = c;
00149     }
00150 }
00151 
00152 static long fltoa(long number, char *buf)
00153 {
00154     static char digits[] = "0123456789";
00155     long sign = number;
00156     char* tmp = buf;
00157 
00158     if (sign < 0) number = -number;
00159     do *tmp++ = digits[number % 10]; while (number /= 10);
00160     if (sign < 0) *tmp++ = '-';
00161     freverse(buf, tmp - 1);
00162     return tmp - buf;
00163 }
00164 
00165 static void fbuffer_append_long(FBuffer *fb, long number)
00166 {
00167     char buf[20];
00168     unsigned long len = fltoa(number, buf);
00169     fbuffer_append(fb, buf, len);
00170 }
00171 
00172 static FBuffer *fbuffer_dup(FBuffer *fb)
00173 {
00174     unsigned long len = fb->len;
00175     FBuffer *result;
00176 
00177     result = fbuffer_alloc(len);
00178     fbuffer_append(result, FBUFFER_PAIR(fb));
00179     return result;
00180 }
00181 
00182 static VALUE fbuffer_to_s(FBuffer *fb)
00183 {
00184     VALUE result = rb_str_new(FBUFFER_PAIR(fb));
00185     fbuffer_free(fb);
00186     FORCE_UTF8(result);
00187     return result;
00188 }
00189 #endif
00190 #endif
00191