mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-13 19:48: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. */
|
/* (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. */
|
/* If you are missing that file, acquire a complete release at teeworlds.com. */
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <base/math.h>
|
#include <base/math.h>
|
||||||
#include <base/system.h>
|
|
||||||
|
|
||||||
#include <engine/storage.h>
|
#include <engine/storage.h>
|
||||||
|
|
||||||
|
@ -10,6 +10,9 @@
|
||||||
|
|
||||||
bool CFileCollection::IsFilenameValid(const char *pFilename)
|
bool CFileCollection::IsFilenameValid(const char *pFilename)
|
||||||
{
|
{
|
||||||
|
if(!str_endswith(pFilename, m_aFileExt))
|
||||||
|
return false;
|
||||||
|
|
||||||
if(m_aFileDesc[0] == '\0')
|
if(m_aFileDesc[0] == '\0')
|
||||||
{
|
{
|
||||||
int FilenameLength = str_length(pFilename);
|
int FilenameLength = str_length(pFilename);
|
||||||
|
@ -23,8 +26,7 @@ bool CFileCollection::IsFilenameValid(const char *pFilename)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(str_length(pFilename) != m_FileDescLength + TIMESTAMP_LENGTH + m_FileExtLength ||
|
if(str_length(pFilename) != m_FileDescLength + TIMESTAMP_LENGTH + m_FileExtLength ||
|
||||||
str_comp_num(pFilename, m_aFileDesc, m_FileDescLength) ||
|
!str_startswith(pFilename, m_aFileDesc))
|
||||||
str_comp(pFilename + m_FileDescLength + TIMESTAMP_LENGTH, m_aFileExt))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
pFilename += m_FileDescLength;
|
pFilename += m_FileDescLength;
|
||||||
|
@ -85,51 +87,9 @@ int64_t CFileCollection::ExtractTimestamp(const char *pTimestring)
|
||||||
return Timestamp;
|
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)
|
void CFileCollection::Init(IStorage *pStorage, const char *pPath, const char *pFileDesc, const char *pFileExt, int MaxEntries)
|
||||||
{
|
{
|
||||||
mem_zero(m_aTimestamps, sizeof(m_aTimestamps));
|
m_vTimestamps.clear();
|
||||||
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);
|
|
||||||
str_copy(m_aFileDesc, pFileDesc);
|
str_copy(m_aFileDesc, pFileDesc);
|
||||||
m_FileDescLength = str_length(m_aFileDesc);
|
m_FileDescLength = str_length(m_aFileDesc);
|
||||||
str_copy(m_aFileExt, pFileExt);
|
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 = pStorage;
|
||||||
|
|
||||||
m_pStorage->ListDirectory(IStorage::TYPE_SAVE, m_aPath, FilelistCallback, this);
|
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)
|
int FilesDeleted = 0;
|
||||||
{
|
for(auto FileEntry : m_vTimestamps)
|
||||||
if(m_NumTimestamps == 0)
|
|
||||||
{
|
{
|
||||||
// empty list
|
if((int)m_vTimestamps.size() - FilesDeleted <= MaxEntries)
|
||||||
m_aTimestamps[m_NumTimestamps++] = Timestamp;
|
break;
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// add entry to the sorted list
|
|
||||||
if(Timestamp < m_aTimestamps[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;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 aBuf[IO_MAX_PATH_LENGTH];
|
||||||
|
if(m_aFileDesc[0] == '\0')
|
||||||
|
{
|
||||||
|
str_format(aBuf, sizeof(aBuf), "%s/%s", m_aPath, FileEntry.m_aFilename);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
char aTimestring[TIMESTAMP_LENGTH];
|
char aTimestring[TIMESTAMP_LENGTH];
|
||||||
BuildTimestring(m_aTimestamps[0], aTimestring);
|
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);
|
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);
|
int64_t Timestamp = pThis->GetTimestamp(pFilename);
|
||||||
|
|
||||||
// add the entry
|
// add the entry
|
||||||
pThis->AddEntry(Timestamp);
|
pThis->m_vTimestamps.emplace_back(Timestamp, pFilename);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,11 @@
|
||||||
#ifndef ENGINE_SHARED_FILECOLLECTION_H
|
#ifndef ENGINE_SHARED_FILECOLLECTION_H
|
||||||
#define ENGINE_SHARED_FILECOLLECTION_H
|
#define ENGINE_SHARED_FILECOLLECTION_H
|
||||||
|
|
||||||
|
#include <base/system.h>
|
||||||
#include <base/types.h>
|
#include <base/types.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
class IStorage;
|
class IStorage;
|
||||||
|
|
||||||
|
@ -13,32 +15,36 @@ class CFileCollection
|
||||||
{
|
{
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
MAX_ENTRIES = 1001,
|
|
||||||
TIMESTAMP_LENGTH = 20, // _YYYY-MM-DD_HH-MM-SS
|
TIMESTAMP_LENGTH = 20, // _YYYY-MM-DD_HH-MM-SS
|
||||||
};
|
};
|
||||||
|
|
||||||
int64_t m_aTimestamps[MAX_ENTRIES];
|
struct CFileEntry
|
||||||
int m_NumTimestamps;
|
{
|
||||||
int m_MaxEntries;
|
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];
|
char m_aFileDesc[128];
|
||||||
int m_FileDescLength;
|
int m_FileDescLength;
|
||||||
char m_aFileExt[32];
|
char m_aFileExt[32];
|
||||||
int m_FileExtLength;
|
int m_FileExtLength;
|
||||||
char m_aPath[IO_MAX_PATH_LENGTH];
|
char m_aPath[IO_MAX_PATH_LENGTH];
|
||||||
IStorage *m_pStorage;
|
IStorage *m_pStorage;
|
||||||
int64_t m_Remove; // Timestamp we want to remove
|
|
||||||
|
|
||||||
bool IsFilenameValid(const char *pFilename);
|
bool IsFilenameValid(const char *pFilename);
|
||||||
int64_t ExtractTimestamp(const char *pTimestring);
|
int64_t ExtractTimestamp(const char *pTimestring);
|
||||||
void BuildTimestring(int64_t Timestamp, char *pTimestring);
|
|
||||||
int64_t GetTimestamp(const char *pFilename);
|
int64_t GetTimestamp(const char *pFilename);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void Init(IStorage *pStorage, const char *pPath, const char *pFileDesc, const char *pFileExt, int MaxEntries);
|
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 FilelistCallback(const char *pFilename, int IsDir, int StorageType, void *pUser);
|
||||||
static int RemoveCallback(const char *pFilename, int IsDir, int StorageType, void *pUser);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue