Changeset 6673

Show
Ignore:
Timestamp:
31/05/10 14:07:01 (2 years ago)
Author:
westram
Message:
  • GBS_strstruct
    • made a class
    • added unit tests
Location:
trunk/ARBDB
Files:
3 modified

Legend:

Unmodified
Added
Removed
  • trunk/ARBDB/Makefile

    r6654 r6673  
    712712adstring.o: $(ARBHOME)/INCLUDE/SigHandler.h 
    713713adstring.o: $(ARBHOME)/INCLUDE/smartptr.h 
     714adstring.o: $(ARBHOME)/INCLUDE/test_unit.h 
    714715adstring.o: $(ARBHOME)/INCLUDE/valgrind.h 
    715716 
  • trunk/ARBDB/ad_prot.h

    r6665 r6673  
    168168GB_BUFFER GBS_mempntr(GBS_strstruct *strstr); 
    169169long GBS_memoffset(GBS_strstruct *strstr); 
    170 void GBS_str_cut_tail(GBS_strstruct *strstr, int byte_count); 
     170void GBS_str_cut_tail(GBS_strstruct *strstr, size_t byte_count); 
    171171void GBS_strncat(GBS_strstruct *strstr, const char *ptr, size_t len); 
    172172void GBS_strcat(GBS_strstruct *strstr, const char *ptr); 
  • trunk/ARBDB/adstring.cxx

    r6659 r6673  
    679679//      String streams 
    680680 
    681 #if defined(DEBUG) 
    682 // # define DUMP_STRSTRUCT_MEMUSE 
    683 #endif // DEBUG 
    684  
    685  
    686 struct GBS_strstruct { 
    687     char *GBS_strcat_data; 
    688     long  GBS_strcat_data_size; 
    689     long  GBS_strcat_pos; 
     681class GBS_strstruct : Noncopyable { 
     682    char   *data; 
     683    size_t  buffer_size; 
     684    size_t  pos; 
     685 
     686    void set_pos(size_t toPos) { 
     687        pos       = toPos; 
     688        data[pos] = 0; 
     689    } 
     690    void inc_pos(size_t inc) { set_pos(pos+inc); } 
     691 
     692public: 
     693 
     694    GBS_strstruct() 
     695        : data(NULL) 
     696        , buffer_size(0) 
     697        , pos(0) 
     698    {} 
     699    ~GBS_strstruct() { free(data); } 
     700 
     701    size_t get_buffer_size() const { return buffer_size; } 
     702    size_t get_position() const { return pos; } 
     703     
     704    const char *get_data() const { return data; } 
     705 
     706    char *release_mem(size_t& size) { 
     707        char *result = data; 
     708        size         = buffer_size; 
     709        buffer_size  = 0; 
     710        data         = 0; 
     711        return result; 
     712    } 
     713 
     714    void reset_pos() { set_pos(0); } 
     715 
     716    void assign_mem(char *block, size_t blocksize) { 
     717        free(data); 
     718 
     719        gb_assert(block && blocksize>0); 
     720 
     721        data      = block; 
     722        buffer_size = blocksize; 
     723 
     724        reset_pos(); 
     725    } 
     726    void reassign_mem(GBS_strstruct& from) { 
     727        size_t  size; 
     728        char   *block = from.release_mem(size); 
     729 
     730        assign_mem(block, size); 
     731    } 
     732 
     733 
     734    void alloc_mem(size_t blocksize) { 
     735        gb_assert(blocksize>0); 
     736        gb_assert(!data); 
     737 
     738        assign_mem((char*)malloc(blocksize), blocksize); 
     739    } 
     740    void realloc_mem(size_t newsize) { 
     741        if (!data) alloc_mem(newsize); 
     742        else { 
     743            data      = (char*)realloc(data, newsize); 
     744            buffer_size = newsize; 
     745 
     746            gb_assert(pos<newsize); 
     747        } 
     748    } 
     749 
     750    void ensure_mem(size_t needed_size) { 
     751        // ensures insertion of 'needed_size' bytes is ok 
     752        size_t whole_needed_size = pos+needed_size+1; 
     753        if (buffer_size<whole_needed_size) { 
     754            size_t next_size = (whole_needed_size * 3) >> 1; 
     755            realloc_mem(next_size); 
     756        } 
     757    } 
     758 
     759    // -------------------- 
     760 
     761    void cut_tail(size_t byte_count) { 
     762        set_pos(pos<byte_count ? 0 : pos-byte_count); 
     763    } 
     764     
     765    void put(char c) { 
     766        ensure_mem(1); 
     767        data[pos] = c; 
     768        inc_pos(1); 
     769    } 
     770    void nput(char c, size_t count) { 
     771        ensure_mem(count); 
     772        memset(data+pos, c, count); 
     773        inc_pos(count); 
     774    } 
     775 
     776    void ncat(const char *from, size_t count) { 
     777        if (count) { 
     778            ensure_mem(count); 
     779            memcpy(data+pos, from, count); 
     780            inc_pos(count); 
     781        } 
     782    } 
     783    void cat(const char *from) { ncat(from, strlen(from)); } 
     784 
     785    void vprintf(size_t maxlen, const char *templat, va_list& parg) { 
     786        ensure_mem(maxlen); 
     787 
     788        char *buffer = data+pos; 
     789        int   printed; 
     790 
     791#ifdef LINUX 
     792        printed = vsnprintf(buffer, maxlen, templat, parg); 
     793#else 
     794        printed = vsprintf(buffer, templat, parg); 
     795#endif 
     796 
     797        assert_or_exit(printed >= 0 && (size_t)printed <= maxlen); 
     798        inc_pos(printed); 
     799    } 
    690800}; 
    691801 
    692 static GBS_strstruct *last_used = 0; 
    693  
    694 GBS_strstruct *GBS_stropen(long init_size) {   // opens a memory file 
    695     GBS_strstruct *strstr; 
    696  
    697     if (last_used && last_used->GBS_strcat_data_size >= init_size) { 
    698         strstr    = last_used; 
    699         last_used = 0; 
     802static GBS_strstruct last_used; 
     803 
     804GBS_strstruct *GBS_stropen(long init_size) {  
     805    /*! create a new memory file 
     806     * @param init_size  estimated used size 
     807     */ 
     808     
     809    GBS_strstruct *strstr = new GBS_strstruct; 
     810 
     811    gb_assert(init_size>0); 
     812 
     813    if (last_used.get_buffer_size() >= (size_t)init_size) { 
     814        strstr->reassign_mem(last_used); 
     815 
     816        static short oversized_counter = 0; 
     817 
     818        if ((size_t)init_size*10 < strstr->get_buffer_size()) oversized_counter++; 
     819        else oversized_counter = 0; 
     820 
     821        if (oversized_counter>10) {                 // was oversized more than 10 times -> realloc 
     822            size_t dummy; 
     823            free(strstr->release_mem(dummy)); 
     824            strstr->alloc_mem(init_size); 
     825        } 
    700826    } 
    701827    else { 
    702 #if defined(DUMP_STRSTRUCT_MEMUSE) 
    703         printf("allocating new GBS_strstruct (size = %li)\n", init_size); 
    704 #endif // DUMP_STRSTRUCT_MEMUSE 
    705         strstr                       = (GBS_strstruct *)malloc(sizeof(GBS_strstruct)); 
    706         strstr->GBS_strcat_data_size = init_size; 
    707         strstr->GBS_strcat_data      = (char *)malloc((size_t)strstr->GBS_strcat_data_size); 
    708     } 
    709  
    710     strstr->GBS_strcat_pos     = 0; 
    711     strstr->GBS_strcat_data[0] = 0; 
     828        strstr->alloc_mem(init_size); 
     829    } 
    712830 
    713831    return strstr; 
     
    717835    // returns a char* copy of the memory file 
    718836 
    719     long  length = strstr->GBS_strcat_pos; 
    720     char *str    = (char*)malloc(length+1); 
    721  
    722     gb_assert(str); 
    723  
    724     memcpy(str, strstr->GBS_strcat_data, length+1); // copy with 0 
     837    size_t  length = strstr->get_position(); 
     838    char   *str    = (char*)malloc(length+1); 
     839 
     840    memcpy(str, strstr->get_data(), length+1); // copy with 0 
    725841    GBS_strforget(strstr); 
    726842 
     
    729845 
    730846void GBS_strforget(GBS_strstruct *strstr) { 
    731     if (last_used) { 
    732         if (last_used->GBS_strcat_data_size < strstr->GBS_strcat_data_size) { // last_used is smaller -> keep this 
    733             GBS_strstruct *tmp = last_used; 
    734             last_used          = strstr; 
    735             strstr             = tmp; 
    736         } 
    737     } 
    738     else { 
    739         static short oversized_counter = 0; 
    740  
    741         if (strstr->GBS_strcat_pos*10 < strstr->GBS_strcat_data_size) oversized_counter++; 
    742         else oversized_counter = 0; 
    743  
    744         if (oversized_counter<10) { 
    745             // keep strstruct for next call 
    746             last_used = strstr; 
    747             strstr    = 0; 
    748         } 
    749         // otherwise the current strstruct was oversized 10 times -> free it 
    750     } 
    751  
    752     if (strstr) { 
    753 #if defined(DUMP_STRSTRUCT_MEMUSE) 
    754         printf("freeing GBS_strstruct (size = %li)\n", strstr->GBS_strcat_data_size); 
    755 #endif // DUMP_STRSTRUCT_MEMUSE 
    756         free(strstr->GBS_strcat_data); 
    757         free(strstr); 
    758     } 
     847    size_t last_bsize = last_used.get_buffer_size(); 
     848    size_t curr_bsize = strstr->get_buffer_size(); 
     849 
     850    if (last_bsize < curr_bsize) { // last_used is smaller -> keep this 
     851        last_used.reassign_mem(*strstr); 
     852    } 
     853    delete strstr; 
    759854} 
    760855 
    761856GB_BUFFER GBS_mempntr(GBS_strstruct *strstr) { 
    762     // returns the memory file 
    763     return strstr->GBS_strcat_data; 
     857    // returns the memory file (with write access) 
     858    return (GB_BUFFER)strstr->get_data();  
    764859} 
    765860 
    766861long GBS_memoffset(GBS_strstruct *strstr) { 
    767862    // returns the offset into the memory file 
    768     return strstr->GBS_strcat_pos; 
    769 } 
    770  
    771 void GBS_str_cut_tail(GBS_strstruct *strstr, int byte_count) { 
     863    return strstr->get_position(); 
     864} 
     865 
     866void GBS_str_cut_tail(GBS_strstruct *strstr, size_t byte_count) { 
    772867    // Removes byte_count characters at the tail of a memfile 
    773     strstr->GBS_strcat_pos -= byte_count; 
    774     if (strstr->GBS_strcat_pos < 0) strstr->GBS_strcat_pos = 0; 
    775     strstr->GBS_strcat_data[strstr->GBS_strcat_pos] = 0; 
    776 } 
    777  
    778 static void gbs_strensure_mem(GBS_strstruct *strstr, long len) { 
    779     if (strstr->GBS_strcat_pos + len + 2 >= strstr->GBS_strcat_data_size) { 
    780         strstr->GBS_strcat_data_size = (strstr->GBS_strcat_pos+len+2)*3/2; 
    781         strstr->GBS_strcat_data      = (char *)realloc(strstr->GBS_strcat_data, strstr->GBS_strcat_data_size); 
    782 #if defined(DUMP_STRSTRUCT_MEMUSE) 
    783         printf("re-allocated GBS_strstruct to size = %li\n", strstr->GBS_strcat_data_size); 
    784 #endif // DUMP_STRSTRUCT_MEMUSE 
    785     } 
     868    strstr->cut_tail(byte_count); 
    786869} 
    787870 
     
    790873     * (caution : copies zero byte and mem behind if used with wrong len!) 
    791874     */ 
    792     if (len>0) { 
    793         gbs_strensure_mem(strstr, len+2); 
    794         memcpy(strstr->GBS_strcat_data+strstr->GBS_strcat_pos, ptr, len); 
    795         strstr->GBS_strcat_pos += len; 
    796         strstr->GBS_strcat_data[strstr->GBS_strcat_pos] = 0; 
    797     } 
     875    strstr->ncat(ptr, len); 
    798876} 
    799877 
    800878void GBS_strcat(GBS_strstruct *strstr, const char *ptr) { 
    801879    // append string to strstruct 
    802     GBS_strncat(strstr, ptr, strlen(ptr)); 
    803 } 
    804  
    805  
     880    strstr->cat(ptr); 
     881} 
    806882 
    807883void GBS_strnprintf(GBS_strstruct *strstr, long len, const char *templat, ...) { 
    808884    // goes to header: __ATTR__FORMAT(3) 
    809     char    *buffer; 
    810     int      psize; 
    811     va_list  parg; 
    812  
     885    va_list parg; 
    813886    va_start(parg, templat); 
    814     gbs_strensure_mem(strstr, len+2); 
    815  
    816     buffer = strstr->GBS_strcat_data+strstr->GBS_strcat_pos; 
    817  
    818 #ifdef LINUX 
    819     psize = vsnprintf(buffer, len, templat, parg); 
    820 #else 
    821     psize = vsprintf(buffer, templat, parg); 
    822 #endif 
    823  
    824     assert_or_exit(psize >= 0 && psize <= len); 
    825     strstr->GBS_strcat_pos += psize; 
     887    strstr->vprintf(len+2, templat, parg); 
    826888} 
    827889 
    828890void GBS_chrcat(GBS_strstruct *strstr, char ch) { 
    829     gbs_strensure_mem(strstr, 1); 
    830     strstr->GBS_strcat_data[strstr->GBS_strcat_pos++] = ch; 
    831     strstr->GBS_strcat_data[strstr->GBS_strcat_pos] = 0; 
     891    strstr->put(ch); 
    832892} 
    833893 
    834894void GBS_chrncat(GBS_strstruct *strstr, char ch, size_t n) { 
    835     gbs_strensure_mem(strstr, n); 
    836     memset(strstr->GBS_strcat_data+strstr->GBS_strcat_pos, ch, n); 
    837  
    838     strstr->GBS_strcat_pos                          += n; 
    839     strstr->GBS_strcat_data[strstr->GBS_strcat_pos]  = 0; 
     895    strstr->nput(ch, n); 
    840896} 
    841897 
    842898void GBS_intcat(GBS_strstruct *strstr, long val) { 
    843     char buffer[200]; 
     899    char buffer[100]; 
    844900    long len = sprintf(buffer, "%li", val); 
    845901    GBS_strncat(strstr, buffer, len); 
     
    847903 
    848904void GBS_floatcat(GBS_strstruct *strstr, double val) { 
    849     char buffer[200]; 
     905    char buffer[100]; 
    850906    long len = sprintf(buffer, "%f", val); 
    851907    GBS_strncat(strstr, buffer, len); 
    852908} 
     909 
     910// -------------------------------------------------------------------------------- 
    853911 
    854912char *GBS_eval_env(GB_CSTR p) { 
     
    879937    if (error) { 
    880938        GB_export_error(error); 
    881         free(GBS_strclose(out)); 
     939        GBS_strforget(out); 
    882940        return 0; 
    883941    } 
     
    19632021} 
    19642022 
     2023// -------------------------------------------------------------------------------- 
     2024 
     2025#if (UNIT_TESTS == 1) 
     2026 
     2027#include <test_unit.h> 
     2028 
     2029#define EXPECT_CONTENT(content) TEST_ASSERT_EQUAL(GBS_mempntr(strstr), content) 
     2030 
     2031void TEST_GBS_strstruct() { 
     2032    { 
     2033        GBS_strstruct *strstr = GBS_stropen(1000); EXPECT_CONTENT(""); 
     2034 
     2035        GBS_chrncat(strstr, 'b', 3);        EXPECT_CONTENT("bbb"); 
     2036        GBS_intcat(strstr, 17);             EXPECT_CONTENT("bbb17"); 
     2037        GBS_chrcat(strstr, '_');            EXPECT_CONTENT("bbb17_"); 
     2038        GBS_floatcat(strstr, 3.5);          EXPECT_CONTENT("bbb17_3.500000"); 
     2039 
     2040        TEST_ASSERT_EQUAL(GBS_memoffset(strstr), 14); 
     2041        GBS_str_cut_tail(strstr, 13);       EXPECT_CONTENT("b"); 
     2042        GBS_strcat(strstr, "utter");        EXPECT_CONTENT("butter"); 
     2043        GBS_strncat(strstr, "flying", 3);   EXPECT_CONTENT("butterfly"); 
     2044 
     2045        GBS_strnprintf(strstr, 200, "%c%s", ' ', "flutters"); 
     2046        EXPECT_CONTENT("butterfly flutters"); 
     2047 
     2048        free(GBS_strclose(strstr)); 
     2049    } 
     2050    { 
     2051        // re-alloc smaller 
     2052        GBS_strstruct *strstr = GBS_stropen(500); EXPECT_CONTENT(""); 
     2053        GBS_strforget(strstr); 
     2054    } 
     2055 
     2056    // trigger downsize of oversized block 
     2057    for (int i = 0; i<12; ++i) { 
     2058        GBS_strstruct *strstr = GBS_stropen(10); 
     2059        GBS_strforget(strstr); 
     2060    } 
     2061 
     2062    { 
     2063        GBS_strstruct *strstr     = GBS_stropen(10); 
     2064        size_t         oldbufsize = strstr->get_buffer_size(); 
     2065        GBS_chrncat(strstr, 'x', 20);               // trigger reallocation of buffer 
     2066 
     2067        TEST_ASSERT(oldbufsize != strstr->get_buffer_size()); // did we reallocate? 
     2068        EXPECT_CONTENT("xxxxxxxxxxxxxxxxxxxx"); 
     2069        GBS_strforget(strstr); 
     2070    } 
     2071} 
     2072 
     2073#endif 
     2074