mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-14 02:08:27 +08:00
cmStack: New, mutable stack class
We would like to record additional information in the find-package stack, but we don't have the information at the point a stack entry is created. The most sane way to handle this appears to be making the stack mutable, at least under specific circumstances. To facilitate this, we need a mutable stack type. Refactor cmConstStack into cmStack, with the ability to either allow or forbid mutation of its data. Re-add cmConstStack as a type alias. This doesn't yet allow mutating cmFindPackageStack, but it's a necessary step toward being able to do so.
This commit is contained in:
@@ -148,8 +148,6 @@ add_library(
|
||||
cmComputeTargetDepends.cxx
|
||||
cmConfigureLog.h
|
||||
cmConfigureLog.cxx
|
||||
cmConstStack.h
|
||||
cmConstStack.tcc
|
||||
cmCPackPropertiesGenerator.h
|
||||
cmCPackPropertiesGenerator.cxx
|
||||
cmCryptoHash.cxx
|
||||
@@ -458,6 +456,8 @@ add_library(
|
||||
cmSourceFileLocationKind.h
|
||||
cmSourceGroup.cxx
|
||||
cmSourceGroup.h
|
||||
cmStack.h
|
||||
cmStack.tcc
|
||||
cmStandardLevel.h
|
||||
cmStandardLevelResolver.cxx
|
||||
cmStandardLevelResolver.h
|
||||
|
@@ -1,62 +0,0 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
template <typename T, typename Stack>
|
||||
struct cmConstStack<T, Stack>::Entry
|
||||
{
|
||||
Entry(std::shared_ptr<Entry const> parent, T value)
|
||||
: Value(std::move(value))
|
||||
, Parent(std::move(parent))
|
||||
{
|
||||
}
|
||||
|
||||
T Value;
|
||||
std::shared_ptr<Entry const> Parent;
|
||||
};
|
||||
|
||||
template <typename T, typename Stack>
|
||||
cmConstStack<T, Stack>::cmConstStack() = default;
|
||||
|
||||
template <typename T, typename Stack>
|
||||
Stack cmConstStack<T, Stack>::Push(T value) const
|
||||
{
|
||||
return Stack(this->TopEntry, std::move(value));
|
||||
}
|
||||
|
||||
template <typename T, typename Stack>
|
||||
Stack cmConstStack<T, Stack>::Pop() const
|
||||
{
|
||||
assert(this->TopEntry);
|
||||
return Stack(this->TopEntry->Parent);
|
||||
}
|
||||
|
||||
template <typename T, typename Stack>
|
||||
T const& cmConstStack<T, Stack>::Top() const
|
||||
{
|
||||
assert(this->TopEntry);
|
||||
return this->TopEntry->Value;
|
||||
}
|
||||
|
||||
template <typename T, typename Stack>
|
||||
bool cmConstStack<T, Stack>::Empty() const
|
||||
{
|
||||
return !this->TopEntry;
|
||||
}
|
||||
|
||||
template <typename T, typename Stack>
|
||||
cmConstStack<T, Stack>::cmConstStack(std::shared_ptr<Entry const> parent,
|
||||
T value)
|
||||
: TopEntry(
|
||||
std::make_shared<Entry const>(std::move(parent), std::move(value)))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, typename Stack>
|
||||
cmConstStack<T, Stack>::cmConstStack(std::shared_ptr<Entry const> top)
|
||||
: TopEntry(std::move(top))
|
||||
{
|
||||
}
|
@@ -3,5 +3,6 @@
|
||||
#define cmFindPackageStack_cxx
|
||||
#include "cmFindPackageStack.h"
|
||||
|
||||
#include "cmConstStack.tcc" // IWYU pragma: keep
|
||||
template class cmConstStack<cmFindPackageCall, cmFindPackageStack>;
|
||||
#include "cmStack.tcc" // IWYU pragma: keep
|
||||
template class cmStack<cmFindPackageCall const, cmFindPackageStack,
|
||||
cmStackType::Const>;
|
||||
|
@@ -7,7 +7,7 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "cmConstStack.h"
|
||||
#include "cmStack.h"
|
||||
|
||||
/**
|
||||
* Represents one call to find_package.
|
||||
@@ -25,9 +25,10 @@ public:
|
||||
class cmFindPackageStack
|
||||
: public cmConstStack<cmFindPackageCall, cmFindPackageStack>
|
||||
{
|
||||
using cmConstStack::cmConstStack;
|
||||
friend class cmConstStack<cmFindPackageCall, cmFindPackageStack>;
|
||||
using cmStack::cmStack;
|
||||
friend cmFindPackageStack::Base;
|
||||
};
|
||||
#ifndef cmFindPackageStack_cxx
|
||||
extern template class cmConstStack<cmFindPackageCall, cmFindPackageStack>;
|
||||
extern template class cmStack<cmFindPackageCall const, cmFindPackageStack,
|
||||
cmStackType::Const>;
|
||||
#endif
|
||||
|
@@ -456,8 +456,9 @@ bool cmListFile::ParseString(char const* str, char const* virtual_filename,
|
||||
return !parseError;
|
||||
}
|
||||
|
||||
#include "cmConstStack.tcc"
|
||||
template class cmConstStack<cmListFileContext, cmListFileBacktrace>;
|
||||
#include "cmStack.tcc"
|
||||
template class cmStack<cmListFileContext const, cmListFileBacktrace,
|
||||
cmStackType::Const>;
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, cmListFileContext const& lfc)
|
||||
{
|
||||
|
@@ -12,8 +12,8 @@
|
||||
|
||||
#include <cm/optional>
|
||||
|
||||
#include "cmConstStack.h"
|
||||
#include "cmList.h"
|
||||
#include "cmStack.h"
|
||||
#include "cmSystemTools.h"
|
||||
|
||||
/** \class cmListFileCache
|
||||
@@ -169,11 +169,12 @@ bool operator!=(cmListFileContext const& lhs, cmListFileContext const& rhs);
|
||||
class cmListFileBacktrace
|
||||
: public cmConstStack<cmListFileContext, cmListFileBacktrace>
|
||||
{
|
||||
using cmConstStack::cmConstStack;
|
||||
friend class cmConstStack<cmListFileContext, cmListFileBacktrace>;
|
||||
using cmStack::cmStack;
|
||||
friend cmListFileBacktrace::Base;
|
||||
};
|
||||
#ifndef cmListFileCache_cxx
|
||||
extern template class cmConstStack<cmListFileContext, cmListFileBacktrace>;
|
||||
extern template class cmStack<cmListFileContext const, cmListFileBacktrace,
|
||||
cmStackType::Const>;
|
||||
#endif
|
||||
|
||||
// Wrap type T as a value with a backtrace. For purposes of
|
||||
|
@@ -50,6 +50,7 @@
|
||||
#include "cmRange.h"
|
||||
#include "cmSourceFile.h"
|
||||
#include "cmSourceFileLocation.h"
|
||||
#include "cmStack.h"
|
||||
#include "cmState.h"
|
||||
#include "cmStateDirectory.h"
|
||||
#include "cmStateTypes.h"
|
||||
|
@@ -5,19 +5,31 @@
|
||||
#include "cmConfigure.h" // IWYU pragma: keep
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
/** Base class template for CRTP to represent a stack of constant values.
|
||||
Provide value semantics, but use efficient reference-counting underneath
|
||||
to avoid copies. */
|
||||
template <typename T, typename Stack>
|
||||
class cmConstStack
|
||||
enum class cmStackType
|
||||
{
|
||||
struct Entry;
|
||||
Const,
|
||||
Mutable,
|
||||
};
|
||||
|
||||
template <typename T, cmStackType Mutable>
|
||||
struct cmStackEntry;
|
||||
|
||||
/** Base class template for CRTP to represent a stack of values.
|
||||
Copies of the stack <i>share data</i>; mutating data on one copy will
|
||||
change the data on <i>all</i> copies. */
|
||||
template <typename T, typename Stack,
|
||||
cmStackType Mutable = cmStackType::Mutable>
|
||||
class cmStack
|
||||
{
|
||||
using Entry = cmStackEntry<T, Mutable>;
|
||||
|
||||
std::shared_ptr<Entry const> TopEntry;
|
||||
|
||||
public:
|
||||
/** Default-construct an empty stack. */
|
||||
cmConstStack();
|
||||
cmStack();
|
||||
|
||||
/** Get a stack with the given call context added to the top. */
|
||||
Stack Push(T value) const;
|
||||
@@ -29,11 +41,21 @@ public:
|
||||
/** Get the value at the top of the stack.
|
||||
This may be called only if Empty() would return false. */
|
||||
T const& Top() const;
|
||||
template <bool E = (Mutable == cmStackType::Mutable)>
|
||||
typename std::enable_if<E, T>::type& Top();
|
||||
|
||||
/** Return true if this stack is empty. */
|
||||
bool Empty() const;
|
||||
|
||||
protected:
|
||||
cmConstStack(std::shared_ptr<Entry const> parent, T value);
|
||||
cmConstStack(std::shared_ptr<Entry const> top);
|
||||
using Base = cmStack<T, Stack, Mutable>;
|
||||
|
||||
cmStack(std::shared_ptr<Entry const> parent, T value);
|
||||
cmStack(std::shared_ptr<Entry const> top);
|
||||
};
|
||||
|
||||
/** Specialization of cmStack for CRTP to represent a stack of constant values.
|
||||
Provide value semantics, but use efficient reference-counting underneath
|
||||
to avoid copies. */
|
||||
template <typename T, typename Stack>
|
||||
using cmConstStack = cmStack<T const, Stack, cmStackType::Const>;
|
85
Source/cmStack.tcc
Normal file
85
Source/cmStack.tcc
Normal file
@@ -0,0 +1,85 @@
|
||||
/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
|
||||
file LICENSE.rst or https://cmake.org/licensing for details. */
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
template <typename T>
|
||||
struct cmStackEntry<T, cmStackType::Mutable>
|
||||
{
|
||||
cmStackEntry(std::shared_ptr<cmStackEntry const> parent, T value)
|
||||
: Value(std::move(value))
|
||||
, Parent(std::move(parent))
|
||||
{
|
||||
}
|
||||
|
||||
T mutable Value;
|
||||
std::shared_ptr<cmStackEntry const> Parent;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct cmStackEntry<T, cmStackType::Const>
|
||||
{
|
||||
cmStackEntry(std::shared_ptr<cmStackEntry const> parent, T value)
|
||||
: Value(std::move(value))
|
||||
, Parent(std::move(parent))
|
||||
{
|
||||
}
|
||||
|
||||
T Value;
|
||||
std::shared_ptr<cmStackEntry const> Parent;
|
||||
};
|
||||
|
||||
template <typename T, typename Stack, cmStackType Mutable>
|
||||
cmStack<T, Stack, Mutable>::cmStack() = default;
|
||||
|
||||
template <typename T, typename Stack, cmStackType Mutable>
|
||||
Stack cmStack<T, Stack, Mutable>::Push(T value) const
|
||||
{
|
||||
return Stack(this->TopEntry, std::move(value));
|
||||
}
|
||||
|
||||
template <typename T, typename Stack, cmStackType Mutable>
|
||||
Stack cmStack<T, Stack, Mutable>::Pop() const
|
||||
{
|
||||
assert(this->TopEntry);
|
||||
return Stack(this->TopEntry->Parent);
|
||||
}
|
||||
|
||||
template <typename T, typename Stack, cmStackType Mutable>
|
||||
T const& cmStack<T, Stack, Mutable>::Top() const
|
||||
{
|
||||
assert(this->TopEntry);
|
||||
return this->TopEntry->Value;
|
||||
}
|
||||
|
||||
template <typename T, typename Stack, cmStackType Mutable>
|
||||
template <bool E>
|
||||
typename std::enable_if<E, T>::type& cmStack<T, Stack, Mutable>::Top()
|
||||
{
|
||||
static_assert(Mutable == cmStackType::Mutable,
|
||||
"T& cmStack::Top should only exist for mutable cmStack");
|
||||
assert(this->TopEntry);
|
||||
return this->TopEntry->Value;
|
||||
}
|
||||
|
||||
template <typename T, typename Stack, cmStackType Mutable>
|
||||
bool cmStack<T, Stack, Mutable>::Empty() const
|
||||
{
|
||||
return !this->TopEntry;
|
||||
}
|
||||
|
||||
template <typename T, typename Stack, cmStackType Mutable>
|
||||
cmStack<T, Stack, Mutable>::cmStack(std::shared_ptr<Entry const> parent,
|
||||
T value)
|
||||
: TopEntry(
|
||||
std::make_shared<Entry const>(std::move(parent), std::move(value)))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename T, typename Stack, cmStackType Mutable>
|
||||
cmStack<T, Stack, Mutable>::cmStack(std::shared_ptr<Entry const> top)
|
||||
: TopEntry(std::move(top))
|
||||
{
|
||||
}
|
@@ -92,8 +92,12 @@
|
||||
{ include: [ "\"form.h\"", private, "\"cmCursesStandardIncludes.h\"", public ] },
|
||||
{ include: [ "<form.h>", private, "\"cmCursesStandardIncludes.h\"", public ] },
|
||||
|
||||
# Help IWYU understand our explicit instantiation for cmConstStack.
|
||||
{ symbol: [ "cmConstStack::cmConstStack<T, Stack>", private, "\"cmConstStack.h\"", public ] },
|
||||
# Help IWYU understand our explicit instantiation for cmStack.
|
||||
{ symbol: [ "cmStack::cmStack<T, Stack, Mutable>", private, "\"cmStack.h\"", public ] },
|
||||
{ symbol: [ "cmStack<cmFindPackageCall, cmFindPackageStack, cmStackType::Mutable>::Empty", private, "\"cmStack.h\"", public ] },
|
||||
{ symbol: [ "cmStack<cmFindPackageCall, cmFindPackageStack, cmStackType::Mutable>::Top", private, "\"cmStack.h\"", public ] },
|
||||
{ symbol: [ "cmStack<cmFindPackageCall, cmFindPackageStack, cmStackType::Mutable>::Pop", private, "\"cmStack.h\"", public ] },
|
||||
{ symbol: [ "cmStack<cmFindPackageCall, cmFindPackageStack, cmStackType::Mutable>::Push", private, "\"cmStack.h\"", public ] },
|
||||
]
|
||||
|
||||
# vim: set ft=toml:
|
||||
|
Reference in New Issue
Block a user