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.
This commit is contained in:
parent
6e7cab5a64
commit
d19a2cba65
@ -11,8 +11,6 @@
|
||||
#ifndef INCLUDED_HEADERLESS
|
||||
#define INCLUDED_HEADERLESS
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
/**
|
||||
* (header-less) pool-based heap allocator
|
||||
* provides Allocate and Deallocate without requiring in-band headers;
|
||||
|
94
source/lib/allocators/string_pool.cpp
Normal file
94
source/lib/allocators/string_pool.cpp
Normal file
@ -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;
|
||||
}
|
46
source/lib/allocators/string_pool.h
Normal file
46
source/lib/allocators/string_pool.h
Normal file
@ -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<const char*, const char*> Map;
|
||||
Map m_map;
|
||||
};
|
||||
|
||||
#endif // #ifndef INCLUDED_STRING_POOL
|
@ -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. '/').
|
||||
|
59
source/lib/fat_time.cpp
Normal file
59
source/lib/fat_time.cpp
Normal file
@ -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 <ctime>
|
||||
|
||||
#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;
|
||||
}
|
2
source/lib/fat_time.h
Normal file
2
source/lib/fat_time.h
Normal file
@ -0,0 +1,2 @@
|
||||
extern time_t time_t_from_FAT(u32 fat_timedate);
|
||||
extern u32 FAT_from_time_t(time_t time);
|
@ -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
|
||||
|
@ -11,8 +11,8 @@
|
||||
#include "precompiled.h"
|
||||
#include "path_util.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <cstring>
|
||||
#include <cerrno>
|
||||
|
||||
|
||||
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 <remove> from the start of <src>, prepend <replace>,
|
||||
// and write to <dst>.
|
||||
// returns ERR::FAIL (without warning!) if the beginning of <src> doesn't
|
||||
@ -274,10 +283,17 @@ void path_strip_fn(char* path)
|
||||
// fill <dir> with the directory path portion of <path>
|
||||
// ("" if root dir, otherwise ending with '/').
|
||||
// note: copies to <dir> 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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -180,3 +180,6 @@
|
||||
|
||||
// Boost
|
||||
#include <boost/utility.hpp> // noncopyable
|
||||
#include <boost/shared_array.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/scoped_ptr.hpp>
|
||||
|
@ -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"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user