mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-09 09:38:19 +00:00
Merge pull request #7712 from furo321/rework-cfilecollection
Rework `CFileCollection`.
This commit is contained in:
commit
a9c316055f
|
@ -1,8 +1,8 @@
|
|||
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
|
||||
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||
|
||||
#include <algorithm>
|
||||
#include <base/math.h>
|
||||
#include <base/system.h>
|
||||
|
||||
#include <engine/storage.h>
|
||||
|
||||
|
@ -10,6 +10,9 @@
|
|||
|
||||
bool CFileCollection::IsFilenameValid(const char *pFilename)
|
||||
{
|
||||
if(!str_endswith(pFilename, m_aFileExt))
|
||||
return false;
|
||||
|
||||
if(m_aFileDesc[0] == '\0')
|
||||
{
|
||||
int FilenameLength = str_length(pFilename);
|
||||
|
@ -23,8 +26,7 @@ bool CFileCollection::IsFilenameValid(const char *pFilename)
|
|||
else
|
||||
{
|
||||
if(str_length(pFilename) != m_FileDescLength + TIMESTAMP_LENGTH + m_FileExtLength ||
|
||||
str_comp_num(pFilename, m_aFileDesc, m_FileDescLength) ||
|
||||
str_comp(pFilename + m_FileDescLength + TIMESTAMP_LENGTH, m_aFileExt))
|
||||
!str_startswith(pFilename, m_aFileDesc))
|
||||
return false;
|
||||
|
||||
pFilename += m_FileDescLength;
|
||||
|
@ -85,51 +87,9 @@ int64_t CFileCollection::ExtractTimestamp(const char *pTimestring)
|
|||
return Timestamp;
|
||||
}
|
||||
|
||||
void CFileCollection::BuildTimestring(int64_t Timestamp, char *pTimestring)
|
||||
{
|
||||
pTimestring[19] = 0;
|
||||
pTimestring[18] = (Timestamp & 0xF) + '0';
|
||||
Timestamp >>= 4;
|
||||
pTimestring[17] = (Timestamp & 0xF) + '0';
|
||||
Timestamp >>= 4;
|
||||
pTimestring[16] = '-';
|
||||
pTimestring[15] = (Timestamp & 0xF) + '0';
|
||||
Timestamp >>= 4;
|
||||
pTimestring[14] = (Timestamp & 0xF) + '0';
|
||||
Timestamp >>= 4;
|
||||
pTimestring[13] = '-';
|
||||
pTimestring[12] = (Timestamp & 0xF) + '0';
|
||||
Timestamp >>= 4;
|
||||
pTimestring[11] = (Timestamp & 0xF) + '0';
|
||||
Timestamp >>= 4;
|
||||
pTimestring[10] = '_';
|
||||
pTimestring[9] = (Timestamp & 0xF) + '0';
|
||||
Timestamp >>= 4;
|
||||
pTimestring[8] = (Timestamp & 0xF) + '0';
|
||||
Timestamp >>= 4;
|
||||
pTimestring[7] = '-';
|
||||
pTimestring[6] = (Timestamp & 0xF) + '0';
|
||||
Timestamp >>= 4;
|
||||
pTimestring[5] = (Timestamp & 0xF) + '0';
|
||||
Timestamp >>= 4;
|
||||
pTimestring[4] = '-';
|
||||
pTimestring[3] = (Timestamp & 0xF) + '0';
|
||||
Timestamp >>= 4;
|
||||
pTimestring[2] = (Timestamp & 0xF) + '0';
|
||||
Timestamp >>= 4;
|
||||
pTimestring[1] = (Timestamp & 0xF) + '0';
|
||||
Timestamp >>= 4;
|
||||
pTimestring[0] = (Timestamp & 0xF) + '0';
|
||||
}
|
||||
|
||||
void CFileCollection::Init(IStorage *pStorage, const char *pPath, const char *pFileDesc, const char *pFileExt, int MaxEntries)
|
||||
{
|
||||
mem_zero(m_aTimestamps, sizeof(m_aTimestamps));
|
||||
m_NumTimestamps = 0;
|
||||
m_Remove = -1;
|
||||
// MAX_ENTRIES - 1 to make sure that we can insert one entry into the sorted
|
||||
// list and then remove the oldest one
|
||||
m_MaxEntries = clamp(MaxEntries, 1, static_cast<int>(MAX_ENTRIES) - 1);
|
||||
m_vTimestamps.clear();
|
||||
str_copy(m_aFileDesc, pFileDesc);
|
||||
m_FileDescLength = str_length(m_aFileDesc);
|
||||
str_copy(m_aFileExt, pFileExt);
|
||||
|
@ -138,84 +98,28 @@ void CFileCollection::Init(IStorage *pStorage, const char *pPath, const char *pF
|
|||
m_pStorage = pStorage;
|
||||
|
||||
m_pStorage->ListDirectory(IStorage::TYPE_SAVE, m_aPath, FilelistCallback, this);
|
||||
}
|
||||
std::sort(m_vTimestamps.begin(), m_vTimestamps.end(), [](const CFileEntry &lhs, const CFileEntry &rhs) { return lhs.m_Timestamp < rhs.m_Timestamp; });
|
||||
|
||||
void CFileCollection::AddEntry(int64_t Timestamp)
|
||||
{
|
||||
if(m_NumTimestamps == 0)
|
||||
int FilesDeleted = 0;
|
||||
for(auto FileEntry : m_vTimestamps)
|
||||
{
|
||||
// empty list
|
||||
m_aTimestamps[m_NumTimestamps++] = Timestamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
// add entry to the sorted list
|
||||
if(Timestamp < m_aTimestamps[0])
|
||||
if((int)m_vTimestamps.size() - FilesDeleted <= MaxEntries)
|
||||
break;
|
||||
|
||||
char aBuf[IO_MAX_PATH_LENGTH];
|
||||
if(m_aFileDesc[0] == '\0')
|
||||
{
|
||||
// first entry
|
||||
if(m_NumTimestamps <= m_MaxEntries)
|
||||
{
|
||||
mem_move(m_aTimestamps + 1, m_aTimestamps, m_NumTimestamps * sizeof(int64_t));
|
||||
m_aTimestamps[0] = Timestamp;
|
||||
++m_NumTimestamps;
|
||||
}
|
||||
}
|
||||
else if(Timestamp >= m_aTimestamps[m_NumTimestamps - 1])
|
||||
{
|
||||
// last entry
|
||||
if(m_NumTimestamps > m_MaxEntries)
|
||||
{
|
||||
mem_move(m_aTimestamps, m_aTimestamps + 1, (m_NumTimestamps - 1) * sizeof(int64_t));
|
||||
m_aTimestamps[m_NumTimestamps - 1] = Timestamp;
|
||||
}
|
||||
else
|
||||
m_aTimestamps[m_NumTimestamps++] = Timestamp;
|
||||
str_format(aBuf, sizeof(aBuf), "%s/%s", m_aPath, FileEntry.m_aFilename);
|
||||
}
|
||||
else
|
||||
{
|
||||
// middle entry
|
||||
int Left = 0, Right = m_NumTimestamps - 1;
|
||||
while(Right - Left > 1)
|
||||
{
|
||||
int Mid = (Left + Right) / 2;
|
||||
if(m_aTimestamps[Mid] > Timestamp)
|
||||
Right = Mid;
|
||||
else
|
||||
Left = Mid;
|
||||
}
|
||||
|
||||
if(m_NumTimestamps > m_MaxEntries)
|
||||
{
|
||||
mem_move(m_aTimestamps, m_aTimestamps + 1, (Right - 1) * sizeof(int64_t));
|
||||
m_aTimestamps[Right - 1] = Timestamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
mem_move(m_aTimestamps + Right + 1, m_aTimestamps + Right, (m_NumTimestamps - Right) * sizeof(int64_t));
|
||||
m_aTimestamps[Right] = Timestamp;
|
||||
++m_NumTimestamps;
|
||||
}
|
||||
char aTimestring[TIMESTAMP_LENGTH];
|
||||
str_timestamp_ex(FileEntry.m_Timestamp, aTimestring, sizeof(aBuf), FORMAT_NOSPACE);
|
||||
str_format(aBuf, sizeof(aBuf), "%s/%s_%s%s", m_aPath, m_aFileDesc, aTimestring, m_aFileExt);
|
||||
}
|
||||
|
||||
// remove old file only after we inserted the new entry, otherwise we can't
|
||||
// know which one is the oldest
|
||||
if(m_NumTimestamps > m_MaxEntries)
|
||||
{
|
||||
if(m_aFileDesc[0] == '\0') // consider an empty file desc as a wild card
|
||||
{
|
||||
m_Remove = m_aTimestamps[0];
|
||||
m_pStorage->ListDirectory(IStorage::TYPE_SAVE, m_aPath, RemoveCallback, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
char aBuf[IO_MAX_PATH_LENGTH];
|
||||
char aTimestring[TIMESTAMP_LENGTH];
|
||||
BuildTimestring(m_aTimestamps[0], aTimestring);
|
||||
|
||||
str_format(aBuf, sizeof(aBuf), "%s/%s_%s%s", m_aPath, m_aFileDesc, aTimestring, m_aFileExt);
|
||||
m_pStorage->RemoveFile(aBuf, IStorage::TYPE_SAVE);
|
||||
}
|
||||
}
|
||||
m_pStorage->RemoveFile(aBuf, IStorage::TYPE_SAVE);
|
||||
FilesDeleted++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -244,30 +148,7 @@ int CFileCollection::FilelistCallback(const char *pFilename, int IsDir, int Stor
|
|||
int64_t Timestamp = pThis->GetTimestamp(pFilename);
|
||||
|
||||
// add the entry
|
||||
pThis->AddEntry(Timestamp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CFileCollection::RemoveCallback(const char *pFilename, int IsDir, int StorageType, void *pUser)
|
||||
{
|
||||
CFileCollection *pThis = static_cast<CFileCollection *>(pUser);
|
||||
|
||||
// check for valid file name format
|
||||
if(IsDir || !pThis->IsFilenameValid(pFilename))
|
||||
return 0;
|
||||
|
||||
// extract the timestamp
|
||||
int64_t Timestamp = pThis->GetTimestamp(pFilename);
|
||||
|
||||
if(Timestamp == pThis->m_Remove)
|
||||
{
|
||||
char aBuf[IO_MAX_PATH_LENGTH];
|
||||
str_format(aBuf, sizeof(aBuf), "%s/%s", pThis->m_aPath, pFilename);
|
||||
pThis->m_pStorage->RemoveFile(aBuf, IStorage::TYPE_SAVE);
|
||||
pThis->m_Remove = -1;
|
||||
return 1;
|
||||
}
|
||||
pThis->m_vTimestamps.emplace_back(Timestamp, pFilename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
#ifndef ENGINE_SHARED_FILECOLLECTION_H
|
||||
#define ENGINE_SHARED_FILECOLLECTION_H
|
||||
|
||||
#include <base/system.h>
|
||||
#include <base/types.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
class IStorage;
|
||||
|
||||
|
@ -13,32 +15,36 @@ class CFileCollection
|
|||
{
|
||||
enum
|
||||
{
|
||||
MAX_ENTRIES = 1001,
|
||||
TIMESTAMP_LENGTH = 20, // _YYYY-MM-DD_HH-MM-SS
|
||||
};
|
||||
|
||||
int64_t m_aTimestamps[MAX_ENTRIES];
|
||||
int m_NumTimestamps;
|
||||
int m_MaxEntries;
|
||||
struct CFileEntry
|
||||
{
|
||||
int64_t m_Timestamp;
|
||||
char m_aFilename[IO_MAX_PATH_LENGTH];
|
||||
CFileEntry(int64_t Timestamp, const char *pFilename)
|
||||
{
|
||||
m_Timestamp = Timestamp;
|
||||
str_copy(m_aFilename, pFilename);
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<CFileEntry> m_vTimestamps;
|
||||
char m_aFileDesc[128];
|
||||
int m_FileDescLength;
|
||||
char m_aFileExt[32];
|
||||
int m_FileExtLength;
|
||||
char m_aPath[IO_MAX_PATH_LENGTH];
|
||||
IStorage *m_pStorage;
|
||||
int64_t m_Remove; // Timestamp we want to remove
|
||||
|
||||
bool IsFilenameValid(const char *pFilename);
|
||||
int64_t ExtractTimestamp(const char *pTimestring);
|
||||
void BuildTimestring(int64_t Timestamp, char *pTimestring);
|
||||
int64_t GetTimestamp(const char *pFilename);
|
||||
|
||||
public:
|
||||
void Init(IStorage *pStorage, const char *pPath, const char *pFileDesc, const char *pFileExt, int MaxEntries);
|
||||
void AddEntry(int64_t Timestamp);
|
||||
|
||||
static int FilelistCallback(const char *pFilename, int IsDir, int StorageType, void *pUser);
|
||||
static int RemoveCallback(const char *pFilename, int IsDir, int StorageType, void *pUser);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue