1
0
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:
Matthew Woehlke
2025-07-29 11:19:55 -04:00
parent a69131cd88
commit f2bdc2176f
10 changed files with 141 additions and 87 deletions

View File

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

View File

@@ -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))
{
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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
View 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))
{
}

View File

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