[String] Use leak-free local storage implementation of VA
This commit is contained in:
parent
a739e3bc8d
commit
49c0b7d3a1
@ -9,7 +9,7 @@ namespace Utils
|
|||||||
{
|
{
|
||||||
const char *VA(const char *fmt, ...)
|
const char *VA(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
static VAProvider<8, 256> provider;
|
static thread_local VAProvider<8, 256> provider;
|
||||||
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
|
@ -8,38 +8,29 @@ namespace Utils
|
|||||||
class VAProvider
|
class VAProvider
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
VAProvider() : currentBuffer(0) {}
|
||||||
|
|
||||||
typename std::enable_if<(Buffers != 0 && MinBufferSize != 0), char*>::type
|
typename std::enable_if<(Buffers != 0 && MinBufferSize != 0), char*>::type
|
||||||
get(const char* format, va_list ap)
|
get(const char* format, va_list ap)
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> _(this->accessMutex);
|
++this->currentBuffer %= ARRAYSIZE(this->stringPool);
|
||||||
|
auto entry = &this->stringPool[this->currentBuffer];
|
||||||
|
|
||||||
auto threadBuffers = this->stringBuffers.find(std::this_thread::get_id());
|
if (!entry->size || !entry->buffer)
|
||||||
if (threadBuffers == this->stringBuffers.end())
|
|
||||||
{
|
{
|
||||||
this->stringBuffers[std::this_thread::get_id()] = Pool();
|
*entry = Entry(MinBufferSize);
|
||||||
threadBuffers = this->stringBuffers.find(std::this_thread::get_id());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!threadBuffers->second.stringPool.size()) threadBuffers->second.stringPool.resize(Buffers);
|
|
||||||
|
|
||||||
++threadBuffers->second.currentBuffer %= threadBuffers->second.stringPool.size();
|
|
||||||
auto& entry = threadBuffers->second.stringPool[threadBuffers->second.currentBuffer];
|
|
||||||
|
|
||||||
if (!entry.size || !entry.buffer)
|
|
||||||
{
|
|
||||||
entry = Entry(MinBufferSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
int res = vsnprintf_s(entry.buffer, entry.size, _TRUNCATE, format, ap);
|
int res = vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap);
|
||||||
if (res > 0) break; // Success
|
if (res > 0) break; // Success
|
||||||
if (res == 0) return ""; // Error
|
if (res == 0) return ""; // Error
|
||||||
|
|
||||||
entry.doubleSize();
|
entry->doubleSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
return entry.buffer;
|
return entry->buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -73,20 +64,8 @@ namespace Utils
|
|||||||
char* buffer;
|
char* buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Pool
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Pool() : currentBuffer(0)
|
|
||||||
{
|
|
||||||
this->stringPool.resize(Buffers);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t currentBuffer;
|
size_t currentBuffer;
|
||||||
std::vector<Entry> stringPool;
|
Entry stringPool[Buffers];
|
||||||
};
|
|
||||||
|
|
||||||
std::mutex accessMutex;
|
|
||||||
std::unordered_map<std::thread::id, Pool> stringBuffers;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *VA(const char *fmt, ...);
|
const char *VA(const char *fmt, ...);
|
||||||
|
Loading…
Reference in New Issue
Block a user