Merge topic 'refactor-cmDefinitions'

b48ea26a cmDefinitions: Invert conditional code.
5ccff640 cmDefinitions: Externalize looping for ClosureKeys.
f79cd99d cmDefinitions: Implement MakeClosure in terms of reverse iterators.
aa4d1ee8 cmDefinitions: Convert MakeClosure into a static method.
60becdc6 cmDefinitions: Implement MakeClosure in terms of a list of ancestors.
d858f363 cmDefinitions: Use list of cmDefinitions* to create closure.
aaaa65b6 cmMakefile: Remove stack adaptor for the VarStack.
f983d891 cmDefinitions: Replace recursion with loop.
24885d4e cmDefinitions: Replace private constructor with MakeClosure.
012a75a0 cmDefinitions: Make ClosureKeys API vector-based.
ca9fa77d cmDefinitions: Inline GetClosureKeys implementation.
78e1454e cmDefinitions: Replace ClosureKeys recursion with looping.
818bf727 cmDefinitions: Change LocalKeys to return a vector.
5067ae41 cmDefinitions: Externalize the Set logic.
60200ca5 cmDefinitions: Add an Erase method.
b43c162e cmMakefile: Use the Internal class to enclose the VarStack.
This commit is contained in:
Brad King 2015-04-30 11:19:20 -04:00 committed by CMake Topic Stage
commit 5e35d4a67f
3 changed files with 179 additions and 134 deletions

View File

@ -29,13 +29,14 @@ cmDefinitions::GetInternal(const std::string& key)
{
return i->second;
}
if(cmDefinitions* up = this->Up)
cmDefinitions* up = this->Up;
if(!up)
{
// Query the parent scope and store the result locally.
Def def = up->GetInternal(key);
return this->Map.insert(MapType::value_type(key, def)).first->second;
return this->NoDef;
}
return this->NoDef;
// Query the parent scope and store the result locally.
Def def = up->GetInternal(key);
return this->Map.insert(MapType::value_type(key, def)).first->second;
}
//----------------------------------------------------------------------------
@ -49,107 +50,86 @@ const char* cmDefinitions::Get(const std::string& key)
void cmDefinitions::Set(const std::string& key, const char* value)
{
Def def(value);
if(this->Up || def.Exists)
{
// In lower scopes we store keys, defined or not.
this->Map[key] = def;
}
else
{
// In the top-most scope we need not store undefined keys.
this->Map.erase(key);
}
this->Map[key] = def;
}
void cmDefinitions::Erase(const std::string& key)
{
this->Map.erase(key);
}
//----------------------------------------------------------------------------
std::set<std::string> cmDefinitions::LocalKeys() const
std::vector<std::string> cmDefinitions::LocalKeys() const
{
std::set<std::string> keys;
std::vector<std::string> keys;
keys.reserve(this->Map.size());
// Consider local definitions.
for(MapType::const_iterator mi = this->Map.begin();
mi != this->Map.end(); ++mi)
{
if (mi->second.Exists)
{
keys.insert(mi->first);
keys.push_back(mi->first);
}
}
return keys;
}
//----------------------------------------------------------------------------
cmDefinitions cmDefinitions::Closure() const
{
return cmDefinitions(ClosureTag(), this);
}
//----------------------------------------------------------------------------
cmDefinitions::cmDefinitions(ClosureTag const&, cmDefinitions const* root):
Up(0)
cmDefinitions cmDefinitions::MakeClosure(
std::list<cmDefinitions>::const_reverse_iterator rbegin,
std::list<cmDefinitions>::const_reverse_iterator rend)
{
std::set<std::string> undefined;
this->ClosureImpl(undefined, root);
cmDefinitions closure;
closure.MakeClosure(undefined, rbegin, rend);
return closure;
}
//----------------------------------------------------------------------------
void cmDefinitions::ClosureImpl(std::set<std::string>& undefined,
cmDefinitions const* defs)
void
cmDefinitions::MakeClosure(std::set<std::string>& undefined,
std::list<cmDefinitions>::const_reverse_iterator rbegin,
std::list<cmDefinitions>::const_reverse_iterator rend)
{
// Consider local definitions.
for(MapType::const_iterator mi = defs->Map.begin();
mi != defs->Map.end(); ++mi)
for (std::list<cmDefinitions>::const_reverse_iterator it = rbegin;
it != rend; ++it)
{
// Use this key if it is not already set or unset.
if(this->Map.find(mi->first) == this->Map.end() &&
undefined.find(mi->first) == undefined.end())
// Consider local definitions.
for(MapType::const_iterator mi = it->Map.begin();
mi != it->Map.end(); ++mi)
{
if(mi->second.Exists)
// Use this key if it is not already set or unset.
if(this->Map.find(mi->first) == this->Map.end() &&
undefined.find(mi->first) == undefined.end())
{
this->Map.insert(*mi);
}
else
{
undefined.insert(mi->first);
if(mi->second.Exists)
{
this->Map.insert(*mi);
}
else
{
undefined.insert(mi->first);
}
}
}
}
// Traverse parents.
if(cmDefinitions const* up = defs->Up)
{
this->ClosureImpl(undefined, up);
}
}
//----------------------------------------------------------------------------
std::set<std::string> cmDefinitions::ClosureKeys() const
std::vector<std::string>
cmDefinitions::ClosureKeys(std::set<std::string>& bound) const
{
std::set<std::string> defined;
std::set<std::string> undefined;
this->ClosureKeys(defined, undefined);
return defined;
}
//----------------------------------------------------------------------------
void cmDefinitions::ClosureKeys(std::set<std::string>& defined,
std::set<std::string>& undefined) const
{
// Consider local definitions.
std::vector<std::string> defined;
defined.reserve(this->Map.size());
for(MapType::const_iterator mi = this->Map.begin();
mi != this->Map.end(); ++mi)
{
// Use this key if it is not already set or unset.
if(defined.find(mi->first) == defined.end() &&
undefined.find(mi->first) == undefined.end())
if(bound.insert(mi->first).second && mi->second.Exists)
{
std::set<std::string>& m = mi->second.Exists? defined : undefined;
m.insert(mi->first);
defined.push_back(mi->first);
}
}
// Traverse parents.
if(cmDefinitions const* up = this->Up)
{
up->ClosureKeys(defined, undefined);
}
return defined;
}

View File

@ -17,6 +17,8 @@
#include "cmsys/hash_map.hxx"
#endif
#include <list>
/** \class cmDefinitions
* \brief Store a scope of variable definitions for CMake language.
*
@ -40,15 +42,17 @@ public:
/** Set (or unset if null) a value associated with a key. */
void Set(const std::string& key, const char* value);
void Erase(const std::string& key);
/** Get the set of all local keys. */
std::set<std::string> LocalKeys() const;
std::vector<std::string> LocalKeys() const;
/** Compute the closure of all defined keys with values.
This flattens the scope. The result has no parent. */
cmDefinitions Closure() const;
std::vector<std::string>
ClosureKeys(std::set<std::string>& bound) const;
/** Compute the set of all defined keys. */
std::set<std::string> ClosureKeys() const;
static cmDefinitions MakeClosure(
std::list<cmDefinitions>::const_reverse_iterator rbegin,
std::list<cmDefinitions>::const_reverse_iterator rend);
private:
// String with existence boolean.
@ -79,15 +83,9 @@ private:
// Internal query and update methods.
Def const& GetInternal(const std::string& key);
// Implementation of Closure() method.
struct ClosureTag {};
cmDefinitions(ClosureTag const&, cmDefinitions const* root);
void ClosureImpl(std::set<std::string>& undefined,
cmDefinitions const* defs);
// Implementation of ClosureKeys() method.
void ClosureKeys(std::set<std::string>& defined,
std::set<std::string>& undefined) const;
void MakeClosure(std::set<std::string>& undefined,
std::list<cmDefinitions>::const_reverse_iterator rbegin,
std::list<cmDefinitions>::const_reverse_iterator rend);
};
#endif

View File

@ -46,10 +46,107 @@
class cmMakefile::Internals
{
public:
std::stack<cmDefinitions, std::list<cmDefinitions> > VarStack;
std::list<cmDefinitions> VarStack;
std::stack<std::set<std::string> > VarInitStack;
std::stack<std::set<std::string> > VarUsageStack;
bool IsSourceFileTryCompile;
void PushDefinitions()
{
cmDefinitions* parent = 0;
if (!this->VarStack.empty())
{
parent = &this->VarStack.back();
}
this->VarStack.push_back(cmDefinitions(parent));
}
void InitializeDefinitions(cmMakefile* parent)
{
this->VarStack.back() =
cmDefinitions::MakeClosure(parent->Internal->VarStack.rbegin(),
parent->Internal->VarStack.rend());
}
const char* GetDefinition(std::string const& name)
{
return this->VarStack.back().Get(name);
}
void SetDefinition(std::string const& name, std::string const& value)
{
this->VarStack.back().Set(name, value.c_str());
}
void RemoveDefinition(std::string const& name)
{
if (this->VarStack.size() > 1)
{
// In lower scopes we store keys, defined or not.
this->VarStack.back().Set(name, 0);
}
else
{
this->VarStack.back().Erase(name);
}
}
std::vector<std::string> LocalKeys() const
{
return this->VarStack.back().LocalKeys();
}
std::vector<std::string> ClosureKeys() const
{
std::vector<std::string> closureKeys;
std::set<std::string> bound;
for (std::list<cmDefinitions>::const_reverse_iterator it =
this->VarStack.rbegin(); it != this->VarStack.rend(); ++it)
{
std::vector<std::string> const& localKeys = it->ClosureKeys(bound);
closureKeys.insert(closureKeys.end(),
localKeys.begin(), localKeys.end());
}
return closureKeys;
}
void PopDefinitions()
{
this->VarStack.pop_back();
}
bool RaiseScope(std::string const& var, const char* varDef, cmMakefile* mf)
{
cmDefinitions& cur = this->VarStack.back();
if(cmDefinitions* up = cur.GetParent())
{
// First localize the definition in the current scope.
cur.Get(var);
// Now update the definition in the parent scope.
up->Set(var, varDef);
}
else if(cmLocalGenerator* plg = mf->GetLocalGenerator()->GetParent())
{
// Update the definition in the parent directory top scope. This
// directory's scope was initialized by the closure of the parent
// scope, so we do not need to localize the definition first.
cmMakefile* parent = plg->GetMakefile();
if (varDef)
{
parent->AddDefinition(var, varDef);
}
else
{
parent->RemoveDefinition(var);
}
}
else
{
return false;
}
return true;
}
};
// default is not to be building executables
@ -59,11 +156,9 @@ cmMakefile::cmMakefile(cmLocalGenerator* localGenerator)
StateSnapshot(localGenerator->GetGlobalGenerator()
->GetCMakeInstance()->GetState())
{
const cmDefinitions& defs = cmDefinitions();
const std::set<std::string> globalKeys = defs.LocalKeys();
this->Internal->VarStack.push(defs);
this->Internal->VarInitStack.push(globalKeys);
this->Internal->VarUsageStack.push(globalKeys);
this->Internal->PushDefinitions();
this->Internal->VarInitStack.push(std::set<std::string>());
this->Internal->VarUsageStack.push(std::set<std::string>());
this->Internal->IsSourceFileTryCompile = false;
if (this->LocalGenerator->GetParent())
@ -1496,7 +1591,7 @@ void cmMakefile::InitializeFromParent()
cmMakefile *parent = this->LocalGenerator->GetParent()->GetMakefile();
// Initialize definitions with the closure of the parent scope.
this->Internal->VarStack.top() = parent->Internal->VarStack.top().Closure();
this->Internal->InitializeDefinitions(parent);
this->AddDefinition("CMAKE_CURRENT_SOURCE_DIR",
this->GetCurrentSourceDirectory());
@ -1690,7 +1785,7 @@ void cmMakefile::AddDefinition(const std::string& name, const char* value)
return;
}
this->Internal->VarStack.top().Set(name, value);
this->Internal->SetDefinition(name, value);
if (!this->Internal->VarUsageStack.empty() &&
this->VariableInitialized(name))
{
@ -1760,13 +1855,13 @@ void cmMakefile::AddCacheDefinition(const std::string& name, const char* value,
this->GetState()->AddCacheEntry(name, haveVal ? val.c_str() : 0,
doc, type);
// if there was a definition then remove it
this->Internal->VarStack.top().Set(name, 0);
this->Internal->RemoveDefinition(name);
}
void cmMakefile::AddDefinition(const std::string& name, bool value)
{
this->Internal->VarStack.top().Set(name, value? "ON" : "OFF");
this->Internal->SetDefinition(name, value ? "ON" : "OFF");
if (!this->Internal->VarUsageStack.empty() &&
this->VariableInitialized(name))
{
@ -1790,9 +1885,8 @@ void cmMakefile::CheckForUnusedVariables() const
{
return;
}
const cmDefinitions& defs = this->Internal->VarStack.top();
const std::set<std::string>& locals = defs.LocalKeys();
std::set<std::string>::const_iterator it = locals.begin();
const std::vector<std::string>& locals = this->Internal->LocalKeys();
std::vector<std::string>::const_iterator it = locals.begin();
for (; it != locals.end(); ++it)
{
this->CheckForUnused("out of scope", *it);
@ -1865,7 +1959,7 @@ void cmMakefile::CheckForUnused(const char* reason,
void cmMakefile::RemoveDefinition(const std::string& name)
{
this->Internal->VarStack.top().Set(name, 0);
this->Internal->RemoveDefinition(name);
if (!this->Internal->VarUsageStack.empty() &&
this->VariableInitialized(name))
{
@ -2338,7 +2432,7 @@ const char* cmMakefile::GetRequiredDefinition(const std::string& name) const
bool cmMakefile::IsDefinitionSet(const std::string& name) const
{
const char* def = this->Internal->VarStack.top().Get(name);
const char* def = this->Internal->GetDefinition(name);
this->Internal->VarUsageStack.top().insert(name);
if(!def)
{
@ -2364,7 +2458,7 @@ const char* cmMakefile::GetDefinition(const std::string& name) const
{
this->Internal->VarUsageStack.top().insert(name);
}
const char* def = this->Internal->VarStack.top().Get(name);
const char* def = this->Internal->GetDefinition(name);
if(!def)
{
def = this->GetState()->GetInitializedCacheValue(name);
@ -2404,9 +2498,7 @@ std::vector<std::string> cmMakefile
std::vector<std::string> res;
if ( !cacheonly )
{
std::set<std::string> definitions =
this->Internal->VarStack.top().ClosureKeys();
res.insert(res.end(), definitions.begin(), definitions.end());
res = this->Internal->ClosureKeys();
}
std::vector<std::string> cacheKeys =
this->GetState()->GetCacheEntryKeys();
@ -4297,10 +4389,9 @@ std::string cmMakefile::GetListFileStack() const
void cmMakefile::PushScope()
{
cmDefinitions* parent = &this->Internal->VarStack.top();
this->Internal->PushDefinitions();
const std::set<std::string>& init = this->Internal->VarInitStack.top();
const std::set<std::string>& usage = this->Internal->VarUsageStack.top();
this->Internal->VarStack.push(cmDefinitions(parent));
this->Internal->VarInitStack.push(init);
this->Internal->VarUsageStack.push(usage);
@ -4321,13 +4412,12 @@ void cmMakefile::PopScope()
this->PopLoopBlockBarrier();
cmDefinitions* current = &this->Internal->VarStack.top();
std::set<std::string> init = this->Internal->VarInitStack.top();
std::set<std::string> usage = this->Internal->VarUsageStack.top();
const std::set<std::string>& locals = current->LocalKeys();
const std::vector<std::string>& locals = this->Internal->LocalKeys();
// Remove initialization and usage information for variables in the local
// scope.
std::set<std::string>::const_iterator it = locals.begin();
std::vector<std::string>::const_iterator it = locals.begin();
for (; it != locals.end(); ++it)
{
init.erase(*it);
@ -4340,7 +4430,8 @@ void cmMakefile::PopScope()
usage.erase(*it);
}
}
this->Internal->VarStack.pop();
this->Internal->PopDefinitions();
this->Internal->VarInitStack.pop();
this->Internal->VarUsageStack.pop();
// Push initialization and usage up to the parent scope.
@ -4355,31 +4446,7 @@ void cmMakefile::RaiseScope(const std::string& var, const char *varDef)
return;
}
cmDefinitions& cur = this->Internal->VarStack.top();
if(cmDefinitions* up = cur.GetParent())
{
// First localize the definition in the current scope.
cur.Get(var);
// Now update the definition in the parent scope.
up->Set(var, varDef);
}
else if(cmLocalGenerator* plg = this->LocalGenerator->GetParent())
{
// Update the definition in the parent directory top scope. This
// directory's scope was initialized by the closure of the parent
// scope, so we do not need to localize the definition first.
cmMakefile* parent = plg->GetMakefile();
if (varDef)
{
parent->AddDefinition(var, varDef);
}
else
{
parent->RemoveDefinition(var);
}
}
else
if (!this->Internal->RaiseScope(var, varDef, this))
{
std::ostringstream m;
m << "Cannot set \"" << var << "\": current scope has no parent.";