Merge pull request #7712 from furo321/rework-cfilecollection

Rework `CFileCollection`.
This commit is contained in:
Dennis Felsing 2023-12-26 08:02:40 +00:00 committed by GitHub
commit a9c316055f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 35 additions and 148 deletions

View file

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

View file

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