data: refreshing with DB
* database stores modification time of files. * FileManager updates internal state based on database info. * reimplemented FileManager's check if a file is in project. * implemented clearing data of updated or removed files before reparsing the updated and added files.
This commit is contained in:
@@ -69,17 +69,17 @@ void Application::loadProject(const FilePath& projectSettingsFilePath)
|
||||
{
|
||||
MessageStatus("Loading Project: " + projectSettingsFilePath.str()).dispatch();
|
||||
|
||||
updateRecentProjects(projectSettingsFilePath);
|
||||
|
||||
m_storageCache->clear();
|
||||
m_componentManager->refreshViews();
|
||||
|
||||
m_project = Project::create(m_storageCache.get());
|
||||
m_project->loadProjectSettings(projectSettingsFilePath);
|
||||
m_project->parseCode();
|
||||
|
||||
updateRecentProjects(projectSettingsFilePath);
|
||||
}
|
||||
|
||||
void Application::reloadProject()
|
||||
void Application::refreshProject()
|
||||
{
|
||||
MessageStatus("Refreshing Project").dispatch();
|
||||
|
||||
@@ -142,10 +142,11 @@ void Application::handleMessage(MessageRefresh* message)
|
||||
if (message->uiOnly)
|
||||
{
|
||||
m_componentManager->refreshViews();
|
||||
return;
|
||||
}
|
||||
|
||||
reloadProject();
|
||||
else
|
||||
{
|
||||
refreshProject();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::handleMessage(MessageSaveProject* message)
|
||||
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
~Application();
|
||||
|
||||
void loadProject(const FilePath& projectSettingsFilePath);
|
||||
void reloadProject();
|
||||
void refreshProject();
|
||||
void saveProject(const FilePath& projectSettingsFilePath);
|
||||
|
||||
private:
|
||||
|
||||
+9
-6
@@ -29,7 +29,7 @@ bool Project::loadProjectSettings(const FilePath& projectSettingsFile)
|
||||
{
|
||||
m_projectSettingsFilepath = projectSettingsFile;
|
||||
|
||||
m_fileManager.reset();
|
||||
//m_fileManager.reset();
|
||||
updateFileManager();
|
||||
}
|
||||
return success;
|
||||
@@ -59,7 +59,7 @@ void Project::clearProjectSettings()
|
||||
m_projectSettingsFilepath = FilePath();
|
||||
ProjectSettings::getInstance()->clear();
|
||||
|
||||
m_fileManager.reset();
|
||||
//m_fileManager.reset();
|
||||
}
|
||||
|
||||
void Project::reloadProjectSettings()
|
||||
@@ -91,11 +91,13 @@ void Project::parseCode()
|
||||
std::set<FilePath> updatedFilePaths = m_fileManager.getUpdatedFilePaths();
|
||||
std::set<FilePath> removedFilePaths = m_fileManager.getRemovedFilePaths();
|
||||
|
||||
utility::append(updatedFilePaths, m_storage->getDependingFilePathsAndRemoveFileNodes(updatedFilePaths));
|
||||
utility::append(updatedFilePaths, m_storage->getDependingFilePathsAndRemoveFileNodes(removedFilePaths));
|
||||
utility::append(updatedFilePaths, m_storage->getDependingFilePaths(updatedFilePaths));
|
||||
utility::append(removedFilePaths, m_storage->getDependingFilePaths(removedFilePaths));
|
||||
|
||||
m_storage->clearFileData(updatedFilePaths);
|
||||
m_storage->clearFileData(removedFilePaths);
|
||||
m_storage->clearFileElements(updatedFilePaths);
|
||||
m_storage->clearFileElements(removedFilePaths);
|
||||
|
||||
m_storage->removeUnusedNames();
|
||||
|
||||
std::vector<FilePath> filesToParse;
|
||||
filesToParse.insert(filesToParse.end(), addedFilePaths.begin(), addedFilePaths.end());
|
||||
@@ -167,5 +169,6 @@ Parser::Arguments Project::getParserArguments() const
|
||||
|
||||
Project::Project(StorageAccessProxy* storageAccessProxy)
|
||||
: m_storageAccessProxy(storageAccessProxy)
|
||||
, m_fileManager(storageAccessProxy)
|
||||
{
|
||||
}
|
||||
|
||||
+120
-11
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "data/graph/Node.h"
|
||||
#include "data/location/TokenLocation.h"
|
||||
#include "utility/logging/logging.h"
|
||||
|
||||
SqliteStorage::SqliteStorage(const std::string& dbFilePath)
|
||||
{
|
||||
@@ -68,13 +69,13 @@ Id SqliteStorage::addNode(int type, Id nameId)
|
||||
return id;
|
||||
}
|
||||
|
||||
Id SqliteStorage::addFile(Id nameId, const std::string& filePath)
|
||||
Id SqliteStorage::addFile(Id nameId, const std::string& filePath, const std::string& modificationTime)
|
||||
{
|
||||
Id id = addNode(Node::NODE_FILE, nameId);
|
||||
|
||||
m_database.execDML((
|
||||
"INSERT INTO file(id, path) VALUES("
|
||||
+ std::to_string(id) + ", '" + filePath + "');"
|
||||
"INSERT INTO file(id, path, modification_time) VALUES("
|
||||
+ std::to_string(id) + ", '" + filePath + "', '" + modificationTime + "');"
|
||||
).c_str());
|
||||
|
||||
return id;
|
||||
@@ -126,6 +127,59 @@ void SqliteStorage::removeNameHierarchyElement(Id id)
|
||||
).c_str());
|
||||
}
|
||||
|
||||
void SqliteStorage::removeElementsWithLocationInFile(Id fileId)
|
||||
{
|
||||
m_database.execDML((
|
||||
"DELETE FROM element WHERE id IN (SELECT element_id FROM source_location WHERE source_location.file_node_id == " + std::to_string(fileId) + ");"
|
||||
).c_str());
|
||||
}
|
||||
|
||||
void SqliteStorage::removeFile(Id id)
|
||||
{
|
||||
if (isFile(id))
|
||||
{
|
||||
m_database.execDML((
|
||||
"DELETE FROM element WHERE id == " + std::to_string(id) + ";"
|
||||
).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_WARNING("Removing file from DB failed since there is no file element with id " + std::to_string(id));
|
||||
}
|
||||
}
|
||||
|
||||
void SqliteStorage::removeUnusedNameHierarchyElements()
|
||||
{
|
||||
m_database.execDML(
|
||||
"DELETE FROM name_hierarchy_element WHERE NOT EXISTS (SELECT * FROM node where node.name_id == name_hierarchy_element.id);"
|
||||
);
|
||||
}
|
||||
|
||||
std::vector<StorageNode> SqliteStorage::getAllNodes() const
|
||||
{
|
||||
std::vector<StorageNode> nodes;
|
||||
|
||||
CppSQLite3Query q = m_database.execQuery(
|
||||
"SELECT id, type, name_id FROM node;"
|
||||
);
|
||||
|
||||
while (!q.eof())
|
||||
{
|
||||
const Id id = q.getIntField(0, 0);
|
||||
const int type = q.getIntField(1, -1);
|
||||
const Id nameId = q.getIntField(2, 0);
|
||||
|
||||
if (id != 0 && type != -1 && nameId != 0)
|
||||
{
|
||||
nodes.push_back(StorageNode(id, type, nameId));
|
||||
}
|
||||
|
||||
q.nextRow();
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
bool SqliteStorage::isEdge(Id elementId) const
|
||||
{
|
||||
int count = m_database.execScalar(("SELECT count(*) FROM edge WHERE id = " + std::to_string(elementId) + ";").c_str());
|
||||
@@ -340,7 +394,7 @@ StorageNode SqliteStorage::getNodeByName(const std::string& nodeName) const
|
||||
StorageFile SqliteStorage::getFileById(const Id id) const
|
||||
{
|
||||
return getFirstFile(
|
||||
"SELECT node.id, node.name_id, file.path FROM node INNER JOIN file ON node.id = file.id "
|
||||
"SELECT node.id, node.name_id, file.path, file.modification_time FROM node INNER JOIN file ON node.id = file.id "
|
||||
"WHERE node.id == " + std::to_string(id) + ";"
|
||||
);
|
||||
}
|
||||
@@ -349,12 +403,12 @@ StorageFile SqliteStorage::getFileByName(const std::string& fileName) const
|
||||
{
|
||||
Id nameId = getNameHierarchyElementIdByName(fileName);
|
||||
|
||||
StorageFile storageFile(0, 0, "");
|
||||
StorageFile storageFile(0, 0, "", "");
|
||||
|
||||
if (nameId != 0)
|
||||
{
|
||||
storageFile = getFirstFile(
|
||||
"SELECT node.id, node.name_id, file.path FROM node INNER JOIN file ON node.id = file.id "
|
||||
"SELECT node.id, node.name_id, file.path, file.modification_time FROM node INNER JOIN file ON node.id = file.id "
|
||||
"WHERE node.name_id == " + std::to_string(nameId) + ";"
|
||||
);
|
||||
}
|
||||
@@ -362,6 +416,11 @@ StorageFile SqliteStorage::getFileByName(const std::string& fileName) const
|
||||
return storageFile;
|
||||
}
|
||||
|
||||
std::vector<StorageFile> SqliteStorage::getAllFiles() const
|
||||
{
|
||||
return getAllFiles("SELECT file.id, node.name_id, file.path, file.modification_time FROM file INNER JOIN node ON file.id = node.id;");
|
||||
}
|
||||
|
||||
void SqliteStorage::setNodeType(int type, Id nodeId)
|
||||
{
|
||||
m_database.execDML((
|
||||
@@ -390,6 +449,31 @@ Id SqliteStorage::getNameHierarchyElementIdByNodeId(const Id nodeId) const
|
||||
);
|
||||
}
|
||||
|
||||
std::vector<StorageNameHierarchyElement> SqliteStorage::getAllNameHierarchyElements() const
|
||||
{
|
||||
std::vector<StorageNameHierarchyElement> ret;
|
||||
|
||||
CppSQLite3Query q = m_database.execQuery(
|
||||
"SELECT * FROM name_hierarchy_element;"
|
||||
);
|
||||
|
||||
while (!q.eof())
|
||||
{
|
||||
const Id id = q.getIntField(0, 0);
|
||||
const std::string name = q.getStringField(1, "");
|
||||
const Id parent_id = q.getIntField(2, 0);
|
||||
|
||||
|
||||
if (id != 0 && name != "" && parent_id != 0)
|
||||
{
|
||||
ret.push_back(StorageNameHierarchyElement(id, name, parent_id));
|
||||
}
|
||||
q.nextRow();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
NameHierarchy SqliteStorage::getNameHierarchyById(const Id id) const
|
||||
{
|
||||
CppSQLite3Query q = m_database.execQuery((
|
||||
@@ -554,6 +638,7 @@ void SqliteStorage::setupTables()
|
||||
"CREATE TABLE IF NOT EXISTS file("
|
||||
"id INTEGER NOT NULL, "
|
||||
"path TEXT, "
|
||||
"modification_time TEXT, "
|
||||
"PRIMARY KEY(id), "
|
||||
"FOREIGN KEY(id) REFERENCES node(id) ON DELETE CASCADE);"
|
||||
);
|
||||
@@ -589,16 +674,40 @@ StorageFile SqliteStorage::getFirstFile(const std::string& query) const
|
||||
|
||||
if (!q.eof())
|
||||
{
|
||||
const Id id = q.getIntField(0, 0);
|
||||
const Id nameId = q.getIntField(1, 0);
|
||||
const std::string filePath = q.getStringField(2, "");
|
||||
const Id id = q.getIntField(0, 0);
|
||||
const Id nameId = q.getIntField(1, 0);
|
||||
const std::string filePath = q.getStringField(2, "");
|
||||
const std::string modificationTime = q.getStringField(3, "");
|
||||
|
||||
if (id != 0 && nameId != 0)
|
||||
{
|
||||
return StorageFile(id, nameId, filePath);
|
||||
return StorageFile(id, nameId, filePath, modificationTime);
|
||||
}
|
||||
}
|
||||
return StorageFile(0, 0, "");
|
||||
return StorageFile(0, 0, "", "");
|
||||
}
|
||||
|
||||
std::vector<StorageFile> SqliteStorage::getAllFiles(const std::string& query) const
|
||||
{
|
||||
std::vector<StorageFile> files;
|
||||
|
||||
CppSQLite3Query q = m_database.execQuery(query.c_str());
|
||||
|
||||
while (!q.eof())
|
||||
{
|
||||
const Id id = q.getIntField(0, 0);
|
||||
const Id nameId = q.getIntField(1, 0);
|
||||
const std::string filePath = q.getStringField(2, "");
|
||||
const std::string modificationTime = q.getStringField(3, "");
|
||||
|
||||
if (id != 0 && nameId != 0)
|
||||
{
|
||||
files.push_back(StorageFile(id, nameId, filePath, modificationTime));
|
||||
}
|
||||
q.nextRow();
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
StorageSourceLocation SqliteStorage::getFirstSourceLocation(const std::string& query) const
|
||||
|
||||
@@ -28,13 +28,18 @@ public:
|
||||
|
||||
Id addEdge(int type, Id sourceNodeId, Id targetNodeId);
|
||||
Id addNode(int type, Id nameId);
|
||||
Id addFile(Id nameId, const std::string& filePath);
|
||||
Id addFile(Id nameId, const std::string& filePath, const std::string& modificationTime);
|
||||
int addSourceLocation(Id elementId, Id fileNodeId, uint startLine, uint startCol, uint endLine, uint endCol, bool isScope);
|
||||
Id addNameHierarchyElement(const std::string& name);
|
||||
Id addNameHierarchyElement(const std::string& name, Id parentId);
|
||||
|
||||
void removeElement(Id id);
|
||||
void removeNameHierarchyElement(Id id);
|
||||
void removeElementsWithLocationInFile(Id fileId);
|
||||
void removeFile(Id id);
|
||||
void removeUnusedNameHierarchyElements();
|
||||
|
||||
std::vector<StorageNode> getAllNodes() const;
|
||||
|
||||
bool isEdge(Id elementId) const;
|
||||
bool isNode(Id elementId) const;
|
||||
@@ -53,6 +58,7 @@ public:
|
||||
|
||||
StorageFile getFileById(const Id id) const;
|
||||
StorageFile getFileByName(const std::string& fileName) const;
|
||||
std::vector<StorageFile> getAllFiles() const;
|
||||
|
||||
void setNodeType(int type, Id nodeId);
|
||||
|
||||
@@ -61,6 +67,8 @@ public:
|
||||
|
||||
Id getNameHierarchyElementIdByNodeId(const Id nodeId) const;
|
||||
|
||||
std::vector<StorageNameHierarchyElement> getAllNameHierarchyElements() const;
|
||||
|
||||
NameHierarchy getNameHierarchyById(const Id id) const;
|
||||
|
||||
StorageSourceLocation getSourceLocationById(const Id id) const;
|
||||
@@ -79,6 +87,7 @@ private:
|
||||
void setupTables();
|
||||
|
||||
StorageFile getFirstFile(const std::string& query) const;
|
||||
std::vector<StorageFile> getAllFiles(const std::string& query) const;
|
||||
StorageSourceLocation getFirstSourceLocation(const std::string& query) const;
|
||||
std::vector<StorageSourceLocation> getAllSourceLocations(const std::string& query) const;
|
||||
|
||||
|
||||
+97
-20
@@ -3,9 +3,10 @@
|
||||
#include <sstream>
|
||||
#include <queue>
|
||||
|
||||
#include "utility/file/FileSystem.h"
|
||||
#include "utility/logging/logging.h"
|
||||
#include "utility/utilityString.h"
|
||||
#include "utility/utility.h"
|
||||
#include "utility/utilityString.h"
|
||||
|
||||
#include "data/graph/token_component/TokenComponentAggregation.h"
|
||||
#include "data/graph/token_component/TokenComponentName.h"
|
||||
@@ -38,15 +39,66 @@ void Storage::clear()
|
||||
m_errorLocationCollection.clear();
|
||||
}
|
||||
|
||||
void Storage::clearFileData(const std::set<FilePath>& filePaths)
|
||||
void Storage::clearFileElements(const std::set<FilePath>& filePaths)
|
||||
{
|
||||
// TODO: Implement this one
|
||||
for (const FilePath& filePath: filePaths)
|
||||
{
|
||||
clearFileElements(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
std::set<FilePath> Storage::getDependingFilePathsAndRemoveFileNodes(const std::set<FilePath>& filePaths)
|
||||
void Storage::clearFileElements(const FilePath& filePath)
|
||||
{
|
||||
// TODO: Implement this one
|
||||
return std::set<FilePath>();
|
||||
Id fileId = m_sqliteStorage.getFileByName(filePath.fileName()).id;
|
||||
if (fileId != 0)
|
||||
{
|
||||
m_sqliteStorage.removeElementsWithLocationInFile(fileId);
|
||||
m_sqliteStorage.removeFile(fileId);
|
||||
}
|
||||
}
|
||||
|
||||
std::set<FilePath> Storage::getDependingFilePaths(const std::set<FilePath>& filePaths)
|
||||
{
|
||||
std::set<FilePath> dependingFilePaths;
|
||||
for (const FilePath& filePath: filePaths)
|
||||
{
|
||||
std::set<FilePath> dependingFilePathsSubset = getDependingFilePaths(filePath);
|
||||
dependingFilePaths.insert(dependingFilePathsSubset.begin(), dependingFilePathsSubset.end());
|
||||
}
|
||||
return dependingFilePaths;
|
||||
}
|
||||
|
||||
std::set<FilePath> Storage::getDependingFilePaths(const FilePath& filePath)
|
||||
{
|
||||
std::set<FilePath> dependingFilePaths;
|
||||
|
||||
Id fileNodeId = m_sqliteStorage.getFileByName(filePath.fileName()).id;
|
||||
std::vector<StorageEdge> incomingEdges = m_sqliteStorage.getEdgesByTargetType(
|
||||
fileNodeId, Edge::typeToInt(Edge::EDGE_INCLUDE)
|
||||
);
|
||||
for (StorageEdge incomingEdge: incomingEdges)
|
||||
{
|
||||
Id dependingFileId = incomingEdge.sourceNodeId;
|
||||
FilePath dependingFilePath = FilePath(m_sqliteStorage.getFileById(dependingFileId).filePath);
|
||||
|
||||
dependingFilePaths.insert(dependingFilePath);
|
||||
|
||||
std::set<FilePath> dependingFilePathsSubset = getDependingFilePaths(dependingFilePath);
|
||||
dependingFilePaths.insert(dependingFilePathsSubset.begin(), dependingFilePathsSubset.end());
|
||||
}
|
||||
|
||||
return dependingFilePaths;
|
||||
}
|
||||
|
||||
void Storage::removeUnusedNames()
|
||||
{
|
||||
m_sqliteStorage.removeUnusedNameHierarchyElements();
|
||||
m_tokenIndex.clear();
|
||||
|
||||
for (StorageNode node: m_sqliteStorage.getAllNodes())
|
||||
{
|
||||
m_tokenIndex.addNode(m_sqliteStorage.getNameHierarchyById(node.nameId))->addTokenId(node.id);
|
||||
}
|
||||
}
|
||||
|
||||
void Storage::logGraph() const
|
||||
@@ -399,7 +451,7 @@ Id Storage::onTemplateArgumentTypeParsed(
|
||||
const NameHierarchy& templateNameHierarchy)
|
||||
{
|
||||
Id argumentNodeId = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, argumentNameHierarchy);
|
||||
// TODO add location for arg
|
||||
// does not need a source location because this type that is already defined (and therefore has a location).
|
||||
|
||||
Id templateNodeId = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, templateNameHierarchy);
|
||||
|
||||
@@ -413,7 +465,7 @@ Id Storage::onTemplateDefaultArgumentTypeParsed(
|
||||
const NameHierarchy& templateArgumentTypeNameHierarchy // actually this is the template parameter???
|
||||
){
|
||||
Id defaultArgumentNodeId = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, defaultArgumentTypeUsage.dataType->getTypeNameHierarchy());
|
||||
// TODO add location for defarg
|
||||
// does not need a source location because this type that is already defined (and therefore has a location).
|
||||
|
||||
Id argumentNodeId = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, templateArgumentTypeNameHierarchy);
|
||||
|
||||
@@ -427,7 +479,7 @@ Id Storage::onTemplateRecordParameterTypeParsed(
|
||||
const NameHierarchy& templateRecordNameHierarchy
|
||||
){
|
||||
Id parameterNodeId = addNodeHierarchy(Node::NODE_TEMPLATE_PARAMETER_TYPE, templateParameterTypeNameHierarchy);
|
||||
// TODO add location for param
|
||||
addSourceLocation(parameterNodeId, location, false);
|
||||
|
||||
Id recordNodeId = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, templateRecordNameHierarchy);
|
||||
|
||||
@@ -447,7 +499,7 @@ Id Storage::onTemplateRecordSpecializationParsed(
|
||||
}
|
||||
|
||||
Id specializedNodeId = addNodeHierarchy(specializedRecordNodeType, specializedRecordNameHierarchy);
|
||||
// TODO add location for specialized
|
||||
addSourceLocation(specializedNodeId, location, false);
|
||||
|
||||
Id recordNodeId = addNodeHierarchy(Node::NODE_UNDEFINED_TYPE, specializedFromNameHierarchy);
|
||||
|
||||
@@ -460,7 +512,7 @@ Id Storage::onTemplateFunctionParameterTypeParsed(
|
||||
const ParseLocation& location, const NameHierarchy& templateParameterTypeNameHierarchy, const ParseFunction function
|
||||
){
|
||||
Id parameterNodeId = addNodeHierarchy(Node::NODE_TEMPLATE_PARAMETER_TYPE, templateParameterTypeNameHierarchy);
|
||||
// TODO add location for parameter
|
||||
addSourceLocation(parameterNodeId, location, false);
|
||||
|
||||
Id functionNodeId = addNodeHierarchyWithDistinctSignature(Node::NODE_UNDEFINED_FUNCTION, function);
|
||||
|
||||
@@ -473,7 +525,7 @@ Id Storage::onTemplateFunctionSpecializationParsed(
|
||||
const ParseLocation& location, const ParseFunction specializedFunction, const ParseFunction templateFunction
|
||||
){
|
||||
Id specializedNodeId = addNodeHierarchyWithDistinctSignature(Node::NODE_FUNCTION, specializedFunction);
|
||||
// TODO add location for specialized
|
||||
addSourceLocation(specializedNodeId, location, false);
|
||||
|
||||
Id functionNodeId = addNodeHierarchyWithDistinctSignature(Node::NODE_UNDEFINED_FUNCTION, templateFunction);
|
||||
|
||||
@@ -482,9 +534,9 @@ Id Storage::onTemplateFunctionSpecializationParsed(
|
||||
return specializedNodeId;
|
||||
}
|
||||
|
||||
Id Storage::onFileParsed(const std::string& filePath)
|
||||
Id Storage::onFileParsed(const FileInfo& fileInfo)
|
||||
{
|
||||
const std::string fileName = FilePath(filePath).fileName();
|
||||
const std::string fileName = fileInfo.path.fileName();
|
||||
|
||||
Id nameHierarchyElementId = m_sqliteStorage.getNameHierarchyElementIdByName(fileName);
|
||||
if (nameHierarchyElementId == 0)
|
||||
@@ -495,7 +547,11 @@ Id Storage::onFileParsed(const std::string& filePath)
|
||||
Id fileNodeId = m_sqliteStorage.getFileByName(fileName).id;
|
||||
if (fileNodeId == 0)
|
||||
{
|
||||
fileNodeId = m_sqliteStorage.addFile(nameHierarchyElementId, filePath);
|
||||
fileNodeId = m_sqliteStorage.addFile(
|
||||
nameHierarchyElementId,
|
||||
fileInfo.path.str(),
|
||||
utility::timeToString(fileInfo.lastWriteTime)
|
||||
);
|
||||
}
|
||||
|
||||
NameHierarchy nameHierarchy;
|
||||
@@ -505,10 +561,10 @@ Id Storage::onFileParsed(const std::string& filePath)
|
||||
return fileNodeId;
|
||||
}
|
||||
|
||||
Id Storage::onFileIncludeParsed(const ParseLocation& location, const std::string& filePath, const std::string& includedPath)
|
||||
Id Storage::onFileIncludeParsed(const ParseLocation& location, const FileInfo& fileInfo, const FileInfo& includedFileInfo)
|
||||
{
|
||||
const Id fileNodeId = onFileParsed(filePath);
|
||||
const Id includedFileNodeId = onFileParsed(includedPath);
|
||||
const Id fileNodeId = onFileParsed(fileInfo);
|
||||
const Id includedFileNodeId = onFileParsed(includedFileInfo);
|
||||
|
||||
addEdge(fileNodeId, includedFileNodeId, Edge::EDGE_INCLUDE, location);
|
||||
|
||||
@@ -556,6 +612,27 @@ Id Storage::getIdForEdgeWithName(const std::string& name) const
|
||||
return m_sqliteStorage.getEdgeBySourceTargetType(sourceId, targetId, type).id;
|
||||
}
|
||||
|
||||
std::vector<FileInfo> Storage::getInfoOnAllFiles() const
|
||||
{
|
||||
std::vector<FileInfo> fileInfos;
|
||||
|
||||
std::vector<StorageFile> storageFiles = m_sqliteStorage.getAllFiles();
|
||||
for (size_t i = 0; i < storageFiles.size(); i++)
|
||||
{
|
||||
boost::posix_time::ptime modificationTime = boost::posix_time::not_a_date_time;
|
||||
if (storageFiles[i].modificationTime != "not-a-date-time")
|
||||
{
|
||||
modificationTime = boost::posix_time::time_from_string(storageFiles[i].modificationTime);
|
||||
}
|
||||
fileInfos.push_back(FileInfo(
|
||||
FilePath(storageFiles[i].filePath),
|
||||
modificationTime
|
||||
));
|
||||
}
|
||||
|
||||
return fileInfos;
|
||||
}
|
||||
|
||||
std::string Storage::getNameForNodeWithId(Id nodeId) const
|
||||
{
|
||||
Id nameHierarchyElementId = m_sqliteStorage.getNameHierarchyElementIdByNodeId(nodeId);
|
||||
@@ -1035,11 +1112,11 @@ int Storage::addSourceLocation(int elementNodeId, const ParseLocation& location,
|
||||
}
|
||||
else
|
||||
{
|
||||
Id fileNodeId = m_sqliteStorage.getFileByName(FilePath(location.filePath).fileName()).id;
|
||||
Id fileNodeId = m_sqliteStorage.getFileByName(location.filePath.fileName()).id;
|
||||
if (fileNodeId == 0)
|
||||
{
|
||||
LOG_ERROR("No filenode created for file: " + location.filePath.str());
|
||||
fileNodeId = onFileParsed(location.filePath.str()); // TODO: make onFileParsed accept filePath
|
||||
fileNodeId = onFileParsed(FileSystem::getFileInfoForPath(location.filePath));
|
||||
}
|
||||
int locationId = m_sqliteStorage.addSourceLocation(
|
||||
elementNodeId, fileNodeId, location.startLineNumber, location.startColumnNumber,
|
||||
|
||||
@@ -23,8 +23,11 @@ public:
|
||||
virtual ~Storage();
|
||||
|
||||
void clear();
|
||||
void clearFileData(const std::set<FilePath>& filePaths);
|
||||
std::set<FilePath> getDependingFilePathsAndRemoveFileNodes(const std::set<FilePath>& filePaths);
|
||||
void clearFileElements(const std::set<FilePath>& filePaths);
|
||||
void clearFileElements(const FilePath& filePath);
|
||||
std::set<FilePath> getDependingFilePaths(const std::set<FilePath>& filePaths);
|
||||
std::set<FilePath> getDependingFilePaths(const FilePath& filePath);
|
||||
void removeUnusedNames();
|
||||
|
||||
void logGraph() const;
|
||||
void logLocations() const;
|
||||
@@ -105,14 +108,16 @@ public:
|
||||
virtual Id onTemplateFunctionSpecializationParsed(
|
||||
const ParseLocation& location, const ParseFunction specializedFunction, const ParseFunction templateFunction);
|
||||
|
||||
virtual Id onFileParsed(const std::string& filePath);
|
||||
virtual Id onFileParsed(const FileInfo& fileInfo);
|
||||
virtual Id onFileIncludeParsed(
|
||||
const ParseLocation& location, const std::string& filePath, const std::string& includedPath);
|
||||
const ParseLocation& location, const FileInfo& fileInfo, const FileInfo& includedFileInfo);
|
||||
|
||||
// StorageAccess implementation
|
||||
virtual Id getIdForNodeWithName(const std::string& fullName) const;
|
||||
virtual Id getIdForEdgeWithName(const std::string& name) const;
|
||||
|
||||
virtual std::vector<FileInfo> getInfoOnAllFiles() const;
|
||||
|
||||
virtual std::string getNameForNodeWithId(Id nodeId) const;
|
||||
virtual Node::NodeType getNodeTypeForNodeWithId(Id nodeId) const;
|
||||
virtual std::vector<SearchMatch> getAutocompletionMatches(
|
||||
|
||||
@@ -30,13 +30,14 @@ struct StorageNode
|
||||
|
||||
struct StorageFile
|
||||
{
|
||||
StorageFile(Id id, Id nameId, const std::string& filePath)
|
||||
: id(id), nameId(nameId), filePath(filePath)
|
||||
StorageFile(Id id, Id nameId, const std::string& filePath, const std::string& modificationTime)
|
||||
: id(id), nameId(nameId), filePath(filePath), modificationTime(modificationTime)
|
||||
{}
|
||||
|
||||
Id id;
|
||||
Id nameId;
|
||||
std::string filePath;
|
||||
std::string modificationTime;
|
||||
};
|
||||
|
||||
struct StorageNameHierarchyElement
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "data/graph/Node.h"
|
||||
#include "data/search/SearchMatch.h"
|
||||
|
||||
struct FileInfo;
|
||||
class Graph;
|
||||
class TokenLocation;
|
||||
class TokenLocationCollection;
|
||||
@@ -24,6 +25,8 @@ public:
|
||||
virtual Id getIdForNodeWithName(const std::string& name) const = 0;
|
||||
virtual Id getIdForEdgeWithName(const std::string& name) const = 0;
|
||||
|
||||
virtual std::vector<FileInfo> getInfoOnAllFiles() const = 0;
|
||||
|
||||
virtual std::string getNameForNodeWithId(Id id) const = 0;
|
||||
virtual Node::NodeType getNodeTypeForNodeWithId(Id id) const = 0;
|
||||
virtual std::vector<SearchMatch> getAutocompletionMatches(
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
#include "data/access/StorageAccessProxy.h"
|
||||
|
||||
#include "utility/logging/logging.h"
|
||||
|
||||
#include "data/graph/Graph.h"
|
||||
#include "data/location/TokenLocationCollection.h"
|
||||
#include "data/location/TokenLocationFile.h"
|
||||
|
||||
#include "utility/logging/logging.h"
|
||||
#include "utility/file/FileInfo.h"
|
||||
|
||||
StorageAccessProxy::StorageAccessProxy()
|
||||
: m_subject(nullptr)
|
||||
{
|
||||
@@ -51,6 +52,16 @@ Id StorageAccessProxy::getIdForEdgeWithName(const std::string& name) const
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<FileInfo> StorageAccessProxy::getInfoOnAllFiles() const
|
||||
{
|
||||
std::vector<FileInfo> fileInfos;
|
||||
if (hasSubject())
|
||||
{
|
||||
fileInfos = m_subject->getInfoOnAllFiles();
|
||||
}
|
||||
return fileInfos;
|
||||
}
|
||||
|
||||
Node::NodeType StorageAccessProxy::getNodeTypeForNodeWithId(Id id) const
|
||||
{
|
||||
if(hasSubject())
|
||||
|
||||
@@ -16,6 +16,8 @@ public:
|
||||
virtual Id getIdForNodeWithName(const std::string& name) const;
|
||||
virtual Id getIdForEdgeWithName(const std::string& name) const;
|
||||
|
||||
virtual std::vector<FileInfo> getInfoOnAllFiles() const;
|
||||
|
||||
virtual std::string getNameForNodeWithId(Id id) const;
|
||||
virtual Node::NodeType getNodeTypeForNodeWithId(Id id) const;
|
||||
virtual std::vector<SearchMatch> getAutocompletionMatches(
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include "utility/types.h"
|
||||
#include "data/name/NameHierarchy.h"
|
||||
#include "utility/file/FileInfo.h"
|
||||
|
||||
struct ParseFunction;
|
||||
struct ParseLocation;
|
||||
@@ -125,9 +126,9 @@ public:
|
||||
virtual Id onTemplateFunctionSpecializationParsed(
|
||||
const ParseLocation& location, const ParseFunction specializedFunction, const ParseFunction templateFunction) = 0;
|
||||
|
||||
virtual Id onFileParsed(const std::string& filePath) = 0;
|
||||
virtual Id onFileParsed(const FileInfo& fileInfo) = 0;
|
||||
virtual Id onFileIncludeParsed(
|
||||
const ParseLocation& location, const std::string& filePath, const std::string& includedPath) = 0;
|
||||
const ParseLocation& location, const FileInfo& fileInfo, const FileInfo& includedFileInfo) = 0;
|
||||
};
|
||||
|
||||
#endif // PARSER_CLIENT_H
|
||||
|
||||
@@ -345,16 +345,27 @@ bool ASTVisitor::VisitClassTemplateDecl(clang::ClassTemplateDecl* declaration)
|
||||
{
|
||||
clang::ClassTemplateSpecializationDecl* specializationDecl = *it;
|
||||
|
||||
ParseLocation specializationLocation = getParseLocationForNamedDecl(*it);
|
||||
if (specializationDecl->getSpecializationKind() == clang::TSK_ImplicitInstantiation)
|
||||
{
|
||||
specializationLocation = getParseLocation(specializationDecl->getPointOfInstantiation());
|
||||
}
|
||||
|
||||
NameHierarchy specializedRecordNameHierarchy = utility::getDeclNameHierarchy(specializationDecl);
|
||||
|
||||
ParserClient::RecordType specializedRecordType = specializationDecl->isStruct() ? ParserClient::RECORD_STRUCT : ParserClient::RECORD_CLASS;
|
||||
|
||||
// The specializationParent can be an indirect specialization of the ClassTemplate (by specializing a partial specialization).
|
||||
NameHierarchy specializationParentNameHierarchy = utility::getTemplateSpecializationParentNameHierarchy(specializationDecl);
|
||||
|
||||
ParserClient::RecordType specializedRecordType = specializationDecl->isStruct() ? ParserClient::RECORD_STRUCT : ParserClient::RECORD_CLASS;
|
||||
NameHierarchy specializedRecordNameHierarchy = utility::getDeclNameHierarchy(specializationDecl);
|
||||
m_client->onTemplateRecordSpecializationParsed(
|
||||
getParseLocationForNamedDecl(*it), specializedRecordNameHierarchy, specializedRecordType, specializationParentNameHierarchy
|
||||
specializationLocation,
|
||||
specializedRecordNameHierarchy,
|
||||
specializedRecordType,
|
||||
specializationParentNameHierarchy
|
||||
);
|
||||
|
||||
std::string specializationFilePath = getParseLocationForNamedDecl(specializationDecl).filePath.str();
|
||||
std::string specializationFilePath = specializationLocation.filePath.str();
|
||||
|
||||
const clang::TemplateArgumentList &argList = specializationDecl->getTemplateArgs();
|
||||
for (size_t i = 0; i < argList.size(); i++)
|
||||
|
||||
@@ -26,7 +26,10 @@ void PreprocessorCallbacks::FileChanged(
|
||||
const clang::FileEntry *fileEntry = m_sourceManager.getFileEntryForID(m_sourceManager.getFileID(location));
|
||||
if (fileEntry && m_fileRegister->getFileManager()->hasFilePath(fileEntry->getName()))
|
||||
{
|
||||
m_client->onFileParsed(fileEntry->getName());
|
||||
m_client->onFileParsed(FileInfo(
|
||||
FilePath(fileEntry->getName()),
|
||||
boost::posix_time::from_time_t(fileEntry->getModificationTime())
|
||||
));
|
||||
m_fileRegister->markIncludeFileParsing(fileEntry->getName());
|
||||
}
|
||||
}
|
||||
@@ -40,12 +43,15 @@ void PreprocessorCallbacks::InclusionDirective(
|
||||
if (fileEntry && baseFileEntry)
|
||||
{
|
||||
std::string baseFilePath = baseFileEntry->getName();
|
||||
std::string filePath = fileEntry->getName();
|
||||
std::string includedFilePath = fileEntry->getName();
|
||||
|
||||
if (m_fileRegister->getFileManager()->hasFilePath(baseFilePath) &&
|
||||
m_fileRegister->getFileManager()->hasFilePath(filePath))
|
||||
if (m_fileRegister->getFileManager()->hasFilePath(baseFilePath) && // check if file is in project
|
||||
m_fileRegister->getFileManager()->hasFilePath(includedFilePath))
|
||||
{
|
||||
m_client->onFileIncludeParsed(getParseLocation(fileNameRange.getAsRange()), baseFilePath, filePath);
|
||||
FileInfo baseFileInfo(baseFilePath, boost::posix_time::from_time_t(baseFileEntry->getModificationTime()));
|
||||
FileInfo includedFileInfo(includedFilePath, boost::posix_time::from_time_t(fileEntry->getModificationTime()));
|
||||
|
||||
m_client->onFileIncludeParsed(getParseLocation(fileNameRange.getAsRange()), baseFileInfo, includedFileInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
#include "FileInfo.h"
|
||||
|
||||
FileInfo::FileInfo()
|
||||
: path(FilePath(""))
|
||||
, lastWriteTime(boost::posix_time::not_a_date_time)
|
||||
{
|
||||
}
|
||||
|
||||
FileInfo::FileInfo(const FilePath& path, boost::posix_time::ptime lastWriteTime)
|
||||
: path(path)
|
||||
, lastWriteTime(lastWriteTime)
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
struct FileInfo
|
||||
{
|
||||
FileInfo();
|
||||
FileInfo(const FilePath& path, boost::posix_time::ptime lastWriteTime);
|
||||
|
||||
FilePath path;
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
#include <set>
|
||||
|
||||
#include "utility/file/FileSystem.h"
|
||||
#include "utility/utility.h"
|
||||
|
||||
FileManager::FileManager()
|
||||
FileManager::FileManager(StorageAccessProxy* storageAccessProxy)
|
||||
: m_storageAccessProxy(storageAccessProxy)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -35,58 +37,42 @@ void FileManager::setPaths(
|
||||
m_includeExtensions = includeExtensions;
|
||||
}
|
||||
|
||||
void FileManager::reset()
|
||||
{
|
||||
m_files.clear();
|
||||
m_addedFiles.clear();
|
||||
m_updatedFiles.clear();
|
||||
m_removedFiles.clear();
|
||||
}
|
||||
|
||||
void FileManager::fetchFilePaths()
|
||||
{
|
||||
std::map<FilePath, FileInfo> files;
|
||||
for (FileInfo oldFileInfo: m_storageAccessProxy->getInfoOnAllFiles())
|
||||
{
|
||||
files[oldFileInfo.path] = oldFileInfo;
|
||||
}
|
||||
|
||||
m_addedFiles.clear();
|
||||
m_updatedFiles.clear();
|
||||
m_removedFiles.clear();
|
||||
|
||||
for (std::map<FilePath, FileInfo>::iterator it = m_files.begin(); it != m_files.end(); it++)
|
||||
for (std::map<FilePath, FileInfo>::iterator it = files.begin(); it != files.end(); it++)
|
||||
{
|
||||
m_removedFiles.insert(it->first);
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::vector<FilePath>, std::vector<std::string>>> pathsExtensionsPairs;
|
||||
pathsExtensionsPairs.push_back(std::make_pair(m_includePaths, m_includeExtensions));
|
||||
pathsExtensionsPairs.push_back(std::make_pair(m_sourcePaths, m_sourceExtensions));
|
||||
|
||||
for (size_t i = 0; i < pathsExtensionsPairs.size(); i++)
|
||||
std::vector<FileInfo> fileInfos = getFileInfosInProject();
|
||||
for (FileInfo fileInfo: fileInfos)
|
||||
{
|
||||
std::vector<FileInfo> fileInfos =
|
||||
FileSystem::getFileInfosFromPaths(pathsExtensionsPairs[i].first, pathsExtensionsPairs[i].second);
|
||||
|
||||
for (FileInfo fileInfo: fileInfos)
|
||||
const FilePath& filePath = fileInfo.path;
|
||||
std::map<FilePath, FileInfo>::iterator it = files.find(filePath);
|
||||
if (it != files.end())
|
||||
{
|
||||
const FilePath& filePath = fileInfo.path;
|
||||
std::map<FilePath, FileInfo>::iterator it = m_files.find(filePath);
|
||||
if (it != m_files.end())
|
||||
m_removedFiles.erase(filePath);
|
||||
if (fileInfo.lastWriteTime > it->second.lastWriteTime)
|
||||
{
|
||||
m_removedFiles.erase(filePath);
|
||||
if (fileInfo.lastWriteTime > it->second.lastWriteTime)
|
||||
{
|
||||
it->second.lastWriteTime = fileInfo.lastWriteTime;
|
||||
m_updatedFiles.insert(fileInfo.path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_files.insert(std::pair<FilePath, FileInfo>(filePath, fileInfo));
|
||||
m_addedFiles.insert(filePath);
|
||||
it->second.lastWriteTime = fileInfo.lastWriteTime;
|
||||
m_updatedFiles.insert(fileInfo.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const FilePath& filePath : m_removedFiles)
|
||||
{
|
||||
m_files.erase(filePath);
|
||||
else
|
||||
{
|
||||
files.insert(std::pair<FilePath, FileInfo>(filePath, fileInfo));
|
||||
m_addedFiles.insert(filePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,7 +93,16 @@ std::set<FilePath> FileManager::getRemovedFilePaths() const
|
||||
|
||||
bool FileManager::hasFilePath(const FilePath& filePath) const
|
||||
{
|
||||
return (m_files.find(filePath) != m_files.end());
|
||||
std::vector<FileInfo> fileInfos = getFileInfosInProject();
|
||||
for (size_t i = 0; i < fileInfos.size(); i++)
|
||||
{
|
||||
if (fileInfos[i].path == filePath)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FileManager::hasSourceExtension(const FilePath& filePath) const
|
||||
@@ -119,3 +114,22 @@ bool FileManager::hasIncludeExtension(const FilePath& filePath) const
|
||||
{
|
||||
return filePath.hasExtension(m_includeExtensions);
|
||||
}
|
||||
|
||||
std::vector<FileInfo> FileManager::getFileInfosInProject() const
|
||||
{
|
||||
std::vector<FileInfo> fileInfos;
|
||||
|
||||
std::vector<std::pair<std::vector<FilePath>, std::vector<std::string>>> pathsExtensionsPairs;
|
||||
pathsExtensionsPairs.push_back(std::make_pair(m_includePaths, m_includeExtensions));
|
||||
pathsExtensionsPairs.push_back(std::make_pair(m_sourcePaths, m_sourceExtensions));
|
||||
|
||||
for (size_t i = 0; i < pathsExtensionsPairs.size(); i++)
|
||||
{
|
||||
utility::append(
|
||||
fileInfos,
|
||||
FileSystem::getFileInfosFromPaths(pathsExtensionsPairs[i].first, pathsExtensionsPairs[i].second)
|
||||
);
|
||||
}
|
||||
|
||||
return fileInfos;
|
||||
}
|
||||
|
||||
@@ -5,12 +5,13 @@
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
#include "FileInfo.h"
|
||||
#include "data/access/StorageAccessProxy.h"
|
||||
#include "utility/file/FileInfo.h"
|
||||
|
||||
class FileManager
|
||||
{
|
||||
public:
|
||||
FileManager();
|
||||
FileManager(StorageAccessProxy* storageAccessProxy);
|
||||
virtual ~FileManager();
|
||||
|
||||
const std::vector<FilePath>& getSourcePaths() const;
|
||||
@@ -23,7 +24,6 @@ public:
|
||||
std::vector<std::string> includeExtensions
|
||||
);
|
||||
|
||||
void reset();
|
||||
void fetchFilePaths();
|
||||
|
||||
std::set<FilePath> getAddedFilePaths() const;
|
||||
@@ -35,15 +35,18 @@ public:
|
||||
virtual bool hasIncludeExtension(const FilePath& filePath) const;
|
||||
|
||||
private:
|
||||
std::vector<FileInfo> getFileInfosInProject() const;
|
||||
|
||||
std::vector<FilePath> m_sourcePaths;
|
||||
std::vector<FilePath> m_includePaths;
|
||||
std::vector<std::string> m_sourceExtensions;
|
||||
std::vector<std::string> m_includeExtensions;
|
||||
|
||||
std::map<FilePath, FileInfo> m_files;
|
||||
std::set<FilePath> m_addedFiles;
|
||||
std::set<FilePath> m_updatedFiles;
|
||||
std::set<FilePath> m_removedFiles;
|
||||
|
||||
StorageAccessProxy* m_storageAccessProxy;
|
||||
};
|
||||
|
||||
#endif // FILE_MANAGER_H
|
||||
|
||||
@@ -52,7 +52,16 @@ std::vector<std::string> FileSystem::getFileNamesFromDirectoryUpdatedAfter(
|
||||
return files;
|
||||
}
|
||||
|
||||
|
||||
FileInfo FileSystem::getFileInfoForPath(FilePath filePath)
|
||||
{
|
||||
if (filePath.exists())
|
||||
{
|
||||
std::time_t t = boost::filesystem::last_write_time(filePath.path());
|
||||
boost::posix_time::ptime lastWriteTime = boost::posix_time::from_time_t(t);
|
||||
return FileInfo(filePath, lastWriteTime);
|
||||
}
|
||||
return FileInfo();
|
||||
}
|
||||
|
||||
std::vector<FileInfo> FileSystem::getFileInfosFromPaths(
|
||||
const std::vector<FilePath>& paths, const std::vector<std::string>& fileExtensions
|
||||
@@ -85,7 +94,7 @@ std::vector<FileInfo> FileSystem::getFileInfosFromPaths(
|
||||
return files;
|
||||
}
|
||||
|
||||
std::string FileSystem::getTimeStringNow()
|
||||
std::string FileSystem::getTimeStringNow() // TODO: move to utility
|
||||
{
|
||||
return boost::posix_time::to_iso_string(boost::posix_time::second_clock::universal_time());
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ public:
|
||||
static std::vector<std::string> getFileNamesFromDirectoryUpdatedAfter(
|
||||
const std::string& path, const std::vector<std::string>& extensions, const std::string& timeString);
|
||||
|
||||
static FileInfo getFileInfoForPath(FilePath filePath);
|
||||
|
||||
static std::vector<FileInfo> getFileInfosFromPaths(
|
||||
const std::vector<FilePath>& paths, const std::vector<std::string>& fileExtensions);
|
||||
|
||||
|
||||
@@ -21,6 +21,23 @@ float utility::duration(std::function<void()> func)
|
||||
return duration(start);
|
||||
}
|
||||
|
||||
std::string utility::timeToString(const time_t time)
|
||||
{
|
||||
char buff[20];
|
||||
strftime(buff, 20, "%Y-%m-%d %H:%M:%S", localtime(&time));
|
||||
return std::string(buff);
|
||||
}
|
||||
|
||||
std::string utility::timeToString(const boost::posix_time::ptime time)
|
||||
{
|
||||
std::stringstream stream;
|
||||
boost::posix_time::time_facet* facet = new boost::posix_time::time_facet();
|
||||
facet->format("%Y-%m-%d %H:%M:%S");
|
||||
stream.imbue(std::locale(std::locale::classic(), facet));
|
||||
stream << time;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
bool utility::intersectionPoint(Vec2f a1, Vec2f b1, Vec2f a2, Vec2f b2, Vec2f* i)
|
||||
{
|
||||
Vec2f p = a1;
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
#include <deque>
|
||||
#include <chrono>
|
||||
#include <set>
|
||||
#include <time.h>
|
||||
|
||||
#include "boost/date_time/posix_time/posix_time.hpp"
|
||||
|
||||
#include "utility/math/Vector2.h"
|
||||
|
||||
@@ -15,6 +18,9 @@ namespace utility
|
||||
float duration(const TimePoint& start);
|
||||
float duration(std::function<void()> func);
|
||||
|
||||
std::string timeToString(const time_t time);
|
||||
std::string timeToString(const boost::posix_time::ptime time);
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> concat(const std::vector<T>& a, const std::vector<T>& b);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user