From d19a2cba655b09a99f6447399de8174d995559aa Mon Sep 17 00:00:00 2001 From: janwas Date: Tue, 20 Nov 2007 18:44:36 +0000 Subject: [PATCH] include boost smart pointers from PCH factor out the "atom_fn" mechanism into lib/allocators/string_pool.cpp factor out FAT date/time handling into lib/fat_time.cpp path_util: replace strcpy with SAFE_STRCPY; add additional functions that avoid passing an output buffer via StringPool This was SVN commit r5474. --- source/lib/allocators/headerless.h | 2 - source/lib/allocators/string_pool.cpp | 94 +++++++++++++++++++++ source/lib/allocators/string_pool.h | 46 ++++++++++ source/lib/app_hooks.h | 2 +- source/lib/fat_time.cpp | 59 +++++++++++++ source/lib/fat_time.h | 2 + source/lib/lockfree.h | 8 -- source/lib/path_util.cpp | 43 ++++++++-- source/lib/path_util.h | 18 +++- source/lib/precompiled.h | 3 + source/lib/res/file/archive/zip.cpp | 51 +---------- source/lib/sysdep/win/wposix/wposix_types.h | 2 +- 12 files changed, 258 insertions(+), 72 deletions(-) create mode 100644 source/lib/allocators/string_pool.cpp create mode 100644 source/lib/allocators/string_pool.h create mode 100644 source/lib/fat_time.cpp create mode 100644 source/lib/fat_time.h diff --git a/source/lib/allocators/headerless.h b/source/lib/allocators/headerless.h index a720e6f709..a7c5d667b4 100644 --- a/source/lib/allocators/headerless.h +++ b/source/lib/allocators/headerless.h @@ -11,8 +11,6 @@ #ifndef INCLUDED_HEADERLESS #define INCLUDED_HEADERLESS -#include - /** * (header-less) pool-based heap allocator * provides Allocate and Deallocate without requiring in-band headers; diff --git a/source/lib/allocators/string_pool.cpp b/source/lib/allocators/string_pool.cpp new file mode 100644 index 0000000000..1c8cce035a --- /dev/null +++ b/source/lib/allocators/string_pool.cpp @@ -0,0 +1,94 @@ +/** + * ========================================================================= + * File : string_pool.cpp + * Project : 0 A.D. + * Description : shared storage for strings + * ========================================================================= + */ + +// license: GPL; see lib/license.txt + +#include "precompiled.h" +#include "string_pool.h" + +#include "lib/rand.h" +#include "lib/sysdep/cpu.h" // cpu_memcpy + + +StringPool::StringPool(size_t maxSize) +{ + pool_create(&m_pool, maxSize, POOL_VARIABLE_ALLOCS); +} + + +StringPool::~StringPool() +{ + m_map.clear(); + (void)pool_destroy(&m_pool); +} + + +const char* StringPool::UniqueCopy(const char* string) +{ + // early out: check if it already lies in the pool + if(Contains(string)) + return string; + + // check if equivalent to an existing string. + // + // rationale: the entire storage could be done via container, + // rather than simply using it as a lookup mapping. + // however, DynHashTbl together with Pool (see above) is more efficient. + const char* existingString = m_map.find(string); + if(existingString) + return existingString; + + const size_t length = strlen(string); + const char* uniqueCopy = (const char*)pool_alloc(&m_pool, length+1); + if(!uniqueCopy) + throw std::bad_alloc(); + cpu_memcpy((void*)uniqueCopy, string, length); + ((char*)uniqueCopy)[length] = '\0'; + + m_map.insert(uniqueCopy, uniqueCopy); + + return uniqueCopy; +} + + +bool StringPool::Contains(const char* string) const +{ + return pool_contains(&m_pool, (void*)string); +} + + +const char* StringPool::RandomString() const +{ + // there had better be names in m_pool, else this will fail. + debug_assert(m_pool.da.pos != 0); + +again: + const size_t start_ofs = (size_t)rand(0, (uint)m_pool.da.pos); + + // scan back to start of string (don't scan ahead; this must + // work even if m_pool only contains one entry). + const char* start = (const char*)m_pool.da.base + start_ofs; + for(size_t i = 0; i < start_ofs; i++) + { + if(*start == '\0') + break; + start--; + } + + // skip past the '\0' we found. loop is needed because there may be + // several if we land in padding (due to pool alignment). + size_t chars_left = m_pool.da.pos - start_ofs; + for(; *start == '\0'; start++) + { + // we had landed in padding at the end of the buffer. + if(chars_left-- == 0) + goto again; + } + + return start; +} diff --git a/source/lib/allocators/string_pool.h b/source/lib/allocators/string_pool.h new file mode 100644 index 0000000000..5d11593b20 --- /dev/null +++ b/source/lib/allocators/string_pool.h @@ -0,0 +1,46 @@ +/** + * ========================================================================= + * File : string_pool.h + * Project : 0 A.D. + * Description : shared storage for strings + * ========================================================================= + */ + +// license: GPL; see lib/license.txt + +#ifndef INCLUDED_STRING_POOL +#define INCLUDED_STRING_POOL + +#include "lib/adts.h" // DynHashTbl +#include "pool.h" + +class StringPool +{ +public: + StringPool(size_t maxSize); + ~StringPool(); + + /** + * allocate a copy of the string. + * + * @return a unique pointer for the string (addresses are equal iff + * the string contents match). can return 0, but would raise a + * warning first. + **/ + const char* UniqueCopy(const char* string); + + bool Contains(const char* string) const; + + const char* RandomString() const; + +private: + // rationale: we want an O(1) Contains() so that redundant UniqueCopy + // calls are cheap. that requires allocating from one contiguous arena, + // which is also more memory-efficient than the heap (no headers). + Pool m_pool; + + typedef DynHashTbl Map; + Map m_map; +}; + +#endif // #ifndef INCLUDED_STRING_POOL diff --git a/source/lib/app_hooks.h b/source/lib/app_hooks.h index 64681a18c8..44db5a6a7d 100644 --- a/source/lib/app_hooks.h +++ b/source/lib/app_hooks.h @@ -97,7 +97,7 @@ extern void ah_override_gl_upload_caps(void); * if implementing via static storage, be sure to guarantee reentrancy * (e.g. by only filling the string once). * must be callable at any time - in particular, before VFS init. - * this means file_make_full_native_path cannot be used; it is best + * this means path_MakeAbsolute cannot be used; it is best * to specify a path relative to sys_get_executable_name. * * @return full native path; must end with directory separator (e.g. '/'). diff --git a/source/lib/fat_time.cpp b/source/lib/fat_time.cpp new file mode 100644 index 0000000000..bbac911dcb --- /dev/null +++ b/source/lib/fat_time.cpp @@ -0,0 +1,59 @@ +/** + * ========================================================================= + * File : fat_time.cpp + * Project : 0 A.D. + * Description : timestamp conversion: DOS FAT <-> Unix time_t + * ========================================================================= + */ + +// license: GPL; see lib/license.txt + +#include "precompiled.h" +#include "fat_time.h" + +#include + +#include "lib/bits.h" + + +time_t time_t_from_FAT(u32 fat_timedate) +{ + const uint fat_time = bits(fat_timedate, 0, 15); + const uint fat_date = bits(fat_timedate, 16, 31); + + struct tm t; // struct tm format: + t.tm_sec = bits(fat_time, 0,4) * 2; // [0,59] + t.tm_min = bits(fat_time, 5,10); // [0,59] + t.tm_hour = bits(fat_time, 11,15); // [0,23] + t.tm_mday = bits(fat_date, 0,4); // [1,31] + t.tm_mon = bits(fat_date, 5,8) - 1; // [0,11] + t.tm_year = bits(fat_date, 9,15) + 80; // since 1900 + t.tm_isdst = -1; // unknown - let libc determine + + // otherwise: totally bogus, and at the limit of 32-bit time_t + debug_assert(t.tm_year < 138); + + time_t ret = mktime(&t); + debug_assert(ret != (time_t)-1); // mktime shouldn't fail + return ret; +} + + +u32 FAT_from_time_t(time_t time) +{ + // (values are adjusted for DST) + struct tm* t = localtime(&time); + + u16 fat_time = 0; + fat_time |= (t->tm_sec/2); // 5 + fat_time |= (t->tm_min) << 5; // 6 + fat_time |= (t->tm_hour) << 11; // 5 + + u16 fat_date = 0; + fat_date |= (t->tm_mday); // 5 + fat_date |= (t->tm_mon+1) << 5; // 4 + fat_date |= (t->tm_year-80) << 9; // 7 + + u32 fat_timedate = u32_from_u16(fat_date, fat_time); + return fat_timedate; +} diff --git a/source/lib/fat_time.h b/source/lib/fat_time.h new file mode 100644 index 0000000000..a5411c2947 --- /dev/null +++ b/source/lib/fat_time.h @@ -0,0 +1,2 @@ +extern time_t time_t_from_FAT(u32 fat_timedate); +extern u32 FAT_from_time_t(time_t time); diff --git a/source/lib/lockfree.h b/source/lib/lockfree.h index de356fcff0..b4b0fd29e7 100644 --- a/source/lib/lockfree.h +++ b/source/lib/lockfree.h @@ -223,12 +223,4 @@ private: volatile uintptr_t m_status; }; - -struct LF_RefCountedMemRange -{ - void* mem; - size_t size; - LF_ReferenceCounter refs; -}; - #endif // #ifndef INCLUDED_LOCKFREE diff --git a/source/lib/path_util.cpp b/source/lib/path_util.cpp index d43412b22c..02508eb0d1 100644 --- a/source/lib/path_util.cpp +++ b/source/lib/path_util.cpp @@ -11,8 +11,8 @@ #include "precompiled.h" #include "path_util.h" -#include -#include +#include +#include ERROR_ASSOCIATE(ERR::PATH_LENGTH, "Path exceeds PATH_MAX characters", ENAMETOOLONG); @@ -178,18 +178,27 @@ LibError path_append(char* dst, const char* path1, const char* path2, uint flags if(total_len > PATH_MAX) WARN_RETURN(ERR::PATH_LENGTH); - strcpy(dst, path1); // safe + SAFE_STRCPY(dst, path1); dst += len1; if(need_separator) *dst++ = '/'; - strcpy(dst, path2); // safe + SAFE_STRCPY(dst, path2); if(need_terminator) - strcpy(dst+len2, "/"); // safe + SAFE_STRCPY(dst+len2, "/"); return INFO::OK; } +const char* path_append2(const char* path1, const char* path2, uint flags) +{ + char dst[PATH_MAX]; + LibError ret = path_append(dst, path1, path2, flags); + debug_assert(ret == INFO::OK); + return path_Pool()->UniqueCopy(dst); +} + + // strip from the start of , prepend , // and write to . // returns ERR::FAIL (without warning!) if the beginning of doesn't @@ -274,10 +283,17 @@ void path_strip_fn(char* path) // fill with the directory path portion of // ("" if root dir, otherwise ending with '/'). // note: copies to and proceeds to path_strip_fn it. -void path_dir_only(const char* path, char* dir) +void path_dir_only(const char* pathname, char* path) { - path_copy(dir, path); - path_strip_fn(dir); + path_copy(path, pathname); + path_strip_fn(path); +} + +const char* path_dir_only2(const char* pathname) +{ + char path[PATH_MAX]; + path_dir_only(pathname, path); + return path_Pool()->UniqueCopy(path); } @@ -406,3 +422,14 @@ LibError path_package_append_file(PathPackage* pp, const char* path) CHECK_ERR(strcpy_s(pp->end, pp->chars_left, path)); return INFO::OK; } + + +//----------------------------------------------------------------------------- + +StringPool* path_Pool() +{ + static StringPool* instance; + if(!instance) + instance = new StringPool(8*MiB); + return instance; +} diff --git a/source/lib/path_util.h b/source/lib/path_util.h index 8328f1b3a8..4cbfd9c659 100644 --- a/source/lib/path_util.h +++ b/source/lib/path_util.h @@ -21,6 +21,8 @@ #ifndef INCLUDED_PATH_UTIL #define INCLUDED_PATH_UTIL +#include "lib/allocators/string_pool.h" + #include "posix/posix_types.h" // PATH_MAX @@ -102,8 +104,10 @@ enum PathAppendFlags * @param flags see PathAppendFlags. * @return LibError **/ -extern LibError path_append(char* dst, const char* path1, const char* path2, - uint flags = 0); +extern LibError path_append(char* dst, const char* path1, const char* path2, uint flags = 0); + +// same as path_append, but returns a unique pointer to the result +extern const char* path_append2(const char* path1, const char* path2, uint flags); /** * at the start of a path, replace the given substring with another. @@ -156,6 +160,8 @@ extern void path_strip_fn(char* path); **/ extern void path_dir_only(const char* path, char* dir); +extern const char* path_dir_only2(const char* path); + /** * get filename's extension. * @@ -229,4 +235,12 @@ extern void path_package_copy(PathPackage* pp_dst, const PathPackage* pp_src); **/ extern LibError path_package_append_file(PathPackage* pp, const char* path); + +//----------------------------------------------------------------------------- + +/** + * @return a shared instance of a StringPool (used to store pathnames). + **/ +extern StringPool* path_Pool(); + #endif // #ifndef INCLUDED_PATH_UTIL diff --git a/source/lib/precompiled.h b/source/lib/precompiled.h index 03d7b12421..103afe0357 100644 --- a/source/lib/precompiled.h +++ b/source/lib/precompiled.h @@ -180,3 +180,6 @@ // Boost #include // noncopyable +#include +#include +#include diff --git a/source/lib/res/file/archive/zip.cpp b/source/lib/res/file/archive/zip.cpp index 7d3641680f..0595ed95f1 100644 --- a/source/lib/res/file/archive/zip.cpp +++ b/source/lib/res/file/archive/zip.cpp @@ -20,56 +20,7 @@ #include "lib/timer.h" #include "lib/res/res.h" #include "../file_internal.h" - - -//----------------------------------------------------------------------------- -// timestamp conversion: DOS FAT <-> Unix time_t -//----------------------------------------------------------------------------- - -// must not be static because these are tested by unit test - -time_t time_t_from_FAT(u32 fat_timedate) -{ - const uint fat_time = bits(fat_timedate, 0, 15); - const uint fat_date = bits(fat_timedate, 16, 31); - - struct tm t; // struct tm format: - t.tm_sec = bits(fat_time, 0,4) * 2; // [0,59] - t.tm_min = bits(fat_time, 5,10); // [0,59] - t.tm_hour = bits(fat_time, 11,15); // [0,23] - t.tm_mday = bits(fat_date, 0,4); // [1,31] - t.tm_mon = bits(fat_date, 5,8) - 1; // [0,11] - t.tm_year = bits(fat_date, 9,15) + 80; // since 1900 - t.tm_isdst = -1; // unknown - let libc determine - - // otherwise: totally bogus, and at the limit of 32-bit time_t - debug_assert(t.tm_year < 138); - - time_t ret = mktime(&t); - if(ret == (time_t)-1) - debug_warn("mktime failed"); - return ret; -} - - -u32 FAT_from_time_t(time_t time) -{ - // (values are adjusted for DST) - struct tm* t = localtime(&time); - - u16 fat_time = 0; - fat_time |= (t->tm_sec/2); // 5 - fat_time |= (t->tm_min) << 5; // 6 - fat_time |= (t->tm_hour) << 11; // 5 - - u16 fat_date = 0; - fat_date |= (t->tm_mday); // 5 - fat_date |= (t->tm_mon+1) << 5; // 4 - fat_date |= (t->tm_year-80) << 9; // 7 - - u32 fat_timedate = u32_from_u16(fat_date, fat_time); - return fat_timedate; -} +#include "lib/fat_time.h" //----------------------------------------------------------------------------- diff --git a/source/lib/sysdep/win/wposix/wposix_types.h b/source/lib/sysdep/win/wposix/wposix_types.h index 4037407222..4bd2425882 100644 --- a/source/lib/sysdep/win/wposix/wposix_types.h +++ b/source/lib/sysdep/win/wposix/wposix_types.h @@ -62,7 +62,7 @@ typedef long ssize_t; // // Win32 MAX_PATH is 260; our number may be a bit more efficient. -#define PATH_MAX 256 +#define PATH_MAX 256u #if OS_WIN # ifndef SIZE_MAX // VC2005 already defines this in limits.h