1
0
forked from 0ad/0ad

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:
janwas 2007-11-20 18:44:36 +00:00
parent 6e7cab5a64
commit d19a2cba65
12 changed files with 258 additions and 72 deletions

View File

@ -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;

View 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;
}

View 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

View File

@ -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
View 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
View File

@ -0,0 +1,2 @@
extern time_t time_t_from_FAT(u32 fat_timedate);
extern u32 FAT_from_time_t(time_t time);

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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>

View File

@ -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"
//-----------------------------------------------------------------------------

View File

@ -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