Skip to content

Commit

Permalink
Merge pull request FreeCAD#10667 from chennes/toponamingHasherToDocument
Browse files Browse the repository at this point in the history
App/Toponaming: Add StringHasher to Document
  • Loading branch information
chennes authored Sep 20, 2023
2 parents 0b191c4 + 6704cc6 commit e36e16d
Show file tree
Hide file tree
Showing 8 changed files with 224 additions and 2 deletions.
59 changes: 58 additions & 1 deletion src/App/Document.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ recompute path. Also, it enables more complicated dependencies beyond trees.
#endif

#include <boost/algorithm/string.hpp>
#include <boost/bimap.hpp>
#include <boost/graph/strong_components.hpp>

#ifdef USE_OLD_DAG
Expand Down Expand Up @@ -102,6 +103,7 @@ recompute path. Also, it enables more complicated dependencies beyond trees.
#include "License.h"
#include "Link.h"
#include "MergeDocuments.h"
#include "StringHasher.h"
#include "Transactions.h"

#ifdef _MSC_VER
Expand Down Expand Up @@ -136,6 +138,7 @@ static bool globalIsRelabeling;

DocumentP::DocumentP()
{
Hasher = new StringHasher;
static std::random_device _RD;
static std::mt19937 _RGEN(_RD());
static std::uniform_int_distribution<> _RDIST(0, 5000);
Expand Down Expand Up @@ -921,11 +924,27 @@ std::string Document::getTransientDirectoryName(const std::string& uuid, const s

void Document::Save (Base::Writer &writer) const
{
d->hashers.clear();
addStringHasher(d->Hasher);

writer.Stream() << R"(<Document SchemaVersion="4" ProgramVersion=")"
<< App::Application::Config()["BuildVersionMajor"] << "."
<< App::Application::Config()["BuildVersionMinor"] << "R"
<< App::Application::Config()["BuildRevision"]
<< "\" FileVersion=\"" << writer.getFileVersion() << "\">" << endl;
<< "\" FileVersion=\"" << writer.getFileVersion()
<< "\" StringHasher=\"1\">\n";

writer.incInd();

d->Hasher->setPersistenceFileName("StringHasher.Table");
for (auto o : d->objectArray) {
o->beforeSave();
}
beforeSave();

d->Hasher->Save(writer);

writer.decInd();

PropertyContainer::Save(writer);

Expand All @@ -937,7 +956,9 @@ void Document::Save (Base::Writer &writer) const
void Document::Restore(Base::XMLReader &reader)
{
int i,Cnt;
d->hashers.clear();
d->touchedObjs.clear();
addStringHasher(d->Hasher);
setStatus(Document::PartialDoc,false);

reader.readElement("Document");
Expand All @@ -954,6 +975,12 @@ void Document::Restore(Base::XMLReader &reader)
reader.FileVersion = 0;
}

if (reader.hasAttribute("StringHasher")) {
d->Hasher->Restore(reader);
} else {
d->Hasher->clear();
}

// When this document was created the FileName and Label properties
// were set to the absolute path or file name, respectively. To save
// the document to the file it was loaded from or to show the file name
Expand Down Expand Up @@ -1018,6 +1045,30 @@ void Document::Restore(Base::XMLReader &reader)
reader.readEndElement("Document");
}

std::pair<bool,int> Document::addStringHasher(const StringHasherRef & hasher) const {
if (!hasher)
return std::make_pair(false, 0);
auto ret = d->hashers.left.insert(HasherMap::left_map::value_type(hasher,(int)d->hashers.size()));
if (ret.second)
hasher->clearMarks();
return std::make_pair(ret.second,ret.first->second);
}

StringHasherRef Document::getStringHasher(int idx) const {
if(idx<0) {
return d->Hasher;
return d->Hasher;
}
StringHasherRef hasher;
auto it = d->hashers.right.find(idx);
if(it == d->hashers.right.end()) {
hasher = new StringHasher;
d->hashers.right.insert(HasherMap::right_map::value_type(idx,hasher));
}else
hasher = it->second;
return hasher;
}

struct DocExportStatus {
Document::ExportStatus status;
std::set<const App::DocumentObject*> objs;
Expand Down Expand Up @@ -1054,6 +1105,7 @@ Document::ExportStatus Document::isExporting(const App::DocumentObject *obj) con
void Document::exportObjects(const std::vector<App::DocumentObject*>& obj, std::ostream& out) {

DocumentExporting exporting(obj);
d->hashers.clear();

if(FC_LOG_INSTANCE.isEnabled(FC_LOGLEVEL_LOG)) {
for(auto o : obj) {
Expand Down Expand Up @@ -1090,6 +1142,7 @@ void Document::exportObjects(const std::vector<App::DocumentObject*>& obj, std::

// write additional files
writer.writeFiles();
d->hashers.clear();
}

#define FC_ATTR_DEPENDENCIES "Dependencies"
Expand Down Expand Up @@ -1401,6 +1454,7 @@ void Document::addRecomputeObject(DocumentObject *obj) {
std::vector<App::DocumentObject*>
Document::importObjects(Base::XMLReader& reader)
{
d->hashers.clear();
Base::FlagToggler<> flag(globalIsRestoring, false);
Base::ObjectStatusLocker<Status, Document> restoreBit(Status::Restoring, this);
Base::ObjectStatusLocker<Status, Document> restoreBit2(Status::Importing, this);
Expand Down Expand Up @@ -1452,6 +1506,7 @@ Document::importObjects(Base::XMLReader& reader)
o->setStatus(App::ObjImporting,false);
}

d->hashers.clear();
return objs;
}

Expand All @@ -1464,6 +1519,8 @@ unsigned int Document::getMemSize () const
for (it = d->objectArray.begin(); it != d->objectArray.end(); ++it)
size += (*it)->getMemSize();

size += d->Hasher->getMemSize();

// size of the document properties...
size += PropertyContainer::getMemSize();

Expand Down
35 changes: 35 additions & 0 deletions src/App/Document.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
#ifndef APP_DOCUMENT_H
#define APP_DOCUMENT_H

#include <CXX/Objects.hxx>
#include <Base/Observer.h>
#include <Base/Persistence.h>
#include <Base/Type.h>
#include <Base/Handle.h>

#include "PropertyContainer.h"
#include "PropertyLinks.h"
#include "PropertyStandard.h"
Expand All @@ -44,6 +50,8 @@ namespace App
class DocumentPy; // the python document class
class Application;
class Transaction;
class StringHasher;
using StringHasherRef = Base::Reference<StringHasher>;
}

namespace App
Expand Down Expand Up @@ -465,6 +473,33 @@ class AppExport Document : public App::PropertyContainer
(const App::DocumentObject* from, const App::DocumentObject* to) const;
//@}

/** Called by a property during save to store its StringHasher
*
* @param hasher: the input hasher
* @return Returns a pair<bool,int>. The boolean indicates if the
* StringHasher has been added before. The integer is the hasher index.
*
* The StringHasher object is designed to be shared among multiple objects.
* We must not save duplicate copies of the same hasher, and must be
* able to restore with the same sharing relationship. This function returns
* whether the hasher has been added before by other objects, and the index
* of the hasher. If the hasher has not been added before, the object must
* save the hasher by calling StringHasher::Save
*/
std::pair<bool,int> addStringHasher(const StringHasherRef & hasher) const;

/** Called by property to restore its StringHasher
*
* @param index: the index previously returned by calling addStringHasher()
* during save. Or if is negative, then return document's own string hasher.
*
* @return Return the resulting string hasher.
*
* The caller is responsible for restoring the hasher if the caller is the first
* owner of the hasher, i.e. if addStringHasher() returns true during save.
*/
StringHasherRef getStringHasher(int index=-1) const;

/** Return the links to a given object
*
* @param links: holds the links found
Expand Down
2 changes: 2 additions & 0 deletions src/App/Property.h
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,8 @@ class AppExport Property : public Base::Persistence
*/
int64_t getID() const {return _id;}

virtual void beforeSave() const {}

friend class PropertyContainer;
friend struct PropertyData;
friend class DynamicProperty;
Expand Down
20 changes: 19 additions & 1 deletion src/App/PropertyContainer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,23 @@ void PropertyContainer::handleChangedPropertyType(XMLReader &reader, const char

PropertyData PropertyContainer::propertyData;

void PropertyContainer::beforeSave() const
{
std::map<std::string, Property*> Map;
getPropertyMap(Map);
for (auto& entry : Map) {
auto prop = entry.second;
if (!prop->testStatus(Property::PropDynamic)
&& (prop->testStatus(Property::Transient)
|| ((getPropertyType(prop) & Prop_Transient) != 0))) {
// Nothing
}
else {
prop->beforeSave();
}
}
}

void PropertyContainer::Save (Base::Writer &writer) const
{
std::map<std::string,Property*> Map;
Expand All @@ -237,8 +254,9 @@ void PropertyContainer::Save (Base::Writer &writer) const
{
transients.push_back(prop);
it = Map.erase(it);
}else
} else {
++it;
}
}

writer.incInd(); // indentation for 'Properties Count'
Expand Down
1 change: 1 addition & 0 deletions src/App/PropertyContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,7 @@ class AppExport PropertyContainer: public Base::Persistence

void Save (Base::Writer &writer) const override;
void Restore(Base::XMLReader &reader) override;
virtual void beforeSave() const;

virtual void editProperty(const char * /*propName*/) {}

Expand Down
7 changes: 7 additions & 0 deletions src/App/private/DocumentP.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,14 @@

#include <App/DocumentObject.h>
#include <App/DocumentObserver.h>
#include <App/StringHasher.h>
#include <CXX/Objects.hxx>
#include <boost/bimap.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <unordered_map>
#include <unordered_set>


// using VertexProperty = boost::property<boost::vertex_root_t, DocumentObject* >;
using DependencyList = boost::adjacency_list <
boost::vecS, // class OutEdgeListS : a Sequence or an AssociativeContainer
Expand All @@ -47,6 +50,7 @@ using Node = std::vector <size_t>;
using Path = std::vector <size_t>;

namespace App {
using HasherMap = boost::bimap<StringHasherRef, int>;
class Transaction;

// Pimpl class
Expand Down Expand Up @@ -74,6 +78,7 @@ struct DocumentP
unsigned int UndoMemSize;
unsigned int UndoMaxStackSize;
std::string programVersion;
mutable HasherMap hashers;
#ifdef USE_OLD_DAG
DependencyList DepList;
std::map<DocumentObject*, Vertex> VertexObjectList;
Expand All @@ -82,6 +87,8 @@ struct DocumentP
std::multimap<const App::DocumentObject*,
std::unique_ptr<App::DocumentObjectExecReturn> > _RecomputeLog;

StringHasherRef Hasher;

DocumentP();

void addRecomputeLog(const char *why, App::DocumentObject *obj) {
Expand Down
1 change: 1 addition & 0 deletions tests/src/App/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ target_sources(
${CMAKE_CURRENT_SOURCE_DIR}/Application.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Branding.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ComplexGeoData.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Document.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Expression.cpp
${CMAKE_CURRENT_SOURCE_DIR}/ElementMap.cpp
${CMAKE_CURRENT_SOURCE_DIR}/IndexedName.cpp
Expand Down
Loading

0 comments on commit e36e16d

Please sign in to comment.