aboutsummaryrefslogtreecommitdiff
path: root/mesonbuild/compilers
diff options
context:
space:
mode:
Diffstat (limited to 'mesonbuild/compilers')
-rw-r--r--mesonbuild/compilers/compilers.py82
1 files changed, 64 insertions, 18 deletions
diff --git a/mesonbuild/compilers/compilers.py b/mesonbuild/compilers/compilers.py
index 07b07d9..6b6df94 100644
--- a/mesonbuild/compilers/compilers.py
+++ b/mesonbuild/compilers/compilers.py
@@ -14,8 +14,10 @@
import contextlib, os.path, re, tempfile
import collections.abc
+from collections import deque
import itertools
import typing as T
+from functools import lru_cache
from ..linkers import (
GnuLikeDynamicLinkerMixin, LinkerEnvVarsMixin, SolarisDynamicLinker,
@@ -465,6 +467,47 @@ class CompilerArgs(collections.abc.MutableSequence):
iterable: T.Optional[T.Iterable[str]] = None):
self.compiler = compiler
self.__container = list(iterable) if iterable is not None else [] # type: T.List[str]
+ self.pre = deque()
+ self.post = deque()
+
+ # Flush the saved pre and post list into the __container list
+ #
+ # This correctly deduplicates the entries after _can_dedup definition
+ # Note: This function is designed to work without delete operations, as deletions are worsening the performance a lot.
+ def flush_pre_post(self):
+ pre_flush = deque()
+ pre_flush_set = set()
+ post_flush = deque()
+ post_flush_set = set()
+
+ #The two lists are here walked from the front to the back, in order to not need removals for deduplication
+ for a in reversed(self.pre):
+ dedup = self._can_dedup(a)
+ if a not in pre_flush_set:
+ pre_flush.appendleft(a)
+ if dedup == 2:
+ pre_flush_set.add(a)
+ for a in reversed(self.post):
+ dedup = self._can_dedup(a)
+ if a not in post_flush_set:
+ post_flush.appendleft(a)
+ if dedup == 2:
+ post_flush_set.add(a)
+
+ #pre and post will overwrite every element that is in the container
+ #only copy over args that are in __container but not in the post flush or pre flush set
+
+ for a in self.__container:
+ if a not in post_flush_set and a not in pre_flush_set:
+ pre_flush.append(a)
+
+ self.__container = list(pre_flush) + list(post_flush)
+ self.pre.clear()
+ self.post.clear()
+
+ def __iter__(self):
+ self.flush_pre_post()
+ return iter(self.__container);
@T.overload # noqa: F811
def __getitem__(self, index: int) -> str: # noqa: F811
@@ -475,6 +518,7 @@ class CompilerArgs(collections.abc.MutableSequence):
pass
def __getitem__(self, index): # noqa: F811
+ self.flush_pre_post()
return self.__container[index]
@T.overload # noqa: F811
@@ -486,21 +530,26 @@ class CompilerArgs(collections.abc.MutableSequence):
pass
def __setitem__(self, index, value) -> None: # noqa: F811
+ self.flush_pre_post()
self.__container[index] = value
def __delitem__(self, index: T.Union[int, slice]) -> None:
+ self.flush_pre_post()
del self.__container[index]
def __len__(self) -> int:
- return len(self.__container)
+ return len(self.__container) + len(self.pre) + len(self.post)
def insert(self, index: int, value: str) -> None:
+ self.flush_pre_post()
self.__container.insert(index, value)
def copy(self) -> 'CompilerArgs':
+ self.flush_pre_post()
return CompilerArgs(self.compiler, self.__container.copy())
@classmethod
+ @lru_cache(maxsize=None)
def _can_dedup(cls, arg):
'''
Returns whether the argument can be safely de-duped. This is dependent
@@ -555,6 +604,7 @@ class CompilerArgs(collections.abc.MutableSequence):
return 0
@classmethod
+ @lru_cache(maxsize=None)
def _should_prepend(cls, arg):
if arg.startswith(cls.prepend_prefixes):
return True
@@ -568,6 +618,7 @@ class CompilerArgs(collections.abc.MutableSequence):
# between static libraries, and for recursively searching for symbols
# needed by static libraries that are provided by object files or
# shared libraries.
+ self.flush_pre_post()
if copy:
new = self.copy()
else:
@@ -627,6 +678,7 @@ class CompilerArgs(collections.abc.MutableSequence):
for absolute paths to libraries, etc, which can always be de-duped
safely.
'''
+ self.flush_pre_post()
if os.path.isabs(arg):
self.append(arg)
else:
@@ -638,6 +690,7 @@ class CompilerArgs(collections.abc.MutableSequence):
reordering or de-dup except for absolute paths where the order of
include search directories is not relevant
'''
+ self.flush_pre_post()
for elem in iterable:
self.append_direct(elem)
@@ -653,6 +706,7 @@ class CompilerArgs(collections.abc.MutableSequence):
self.extend_direct(lflags)
def __add__(self, args: T.Iterable[str]) -> 'CompilerArgs':
+ self.flush_pre_post()
new = self.copy()
new += args
return new
@@ -662,8 +716,7 @@ class CompilerArgs(collections.abc.MutableSequence):
Add two CompilerArgs while taking into account overriding of arguments
and while preserving the order of arguments as much as possible
'''
- pre = [] # type: T.List[str]
- post = [] # type: T.List[str]
+ tmp_pre = deque()
if not isinstance(args, collections.abc.Iterable):
raise TypeError('can only concatenate Iterable[str] (not "{}") to CompilerArgs'.format(args))
for arg in args:
@@ -673,32 +726,24 @@ class CompilerArgs(collections.abc.MutableSequence):
dedup = self._can_dedup(arg)
if dedup == 1:
# Argument already exists and adding a new instance is useless
- if arg in self or arg in pre or arg in post:
+ if arg in self.__container or arg in self.pre or arg in self.post:
continue
- if dedup == 2:
- # Remove all previous occurrences of the arg and add it anew
- if arg in self:
- self.remove(arg)
- if arg in pre:
- pre.remove(arg)
- if arg in post:
- post.remove(arg)
if self._should_prepend(arg):
- pre.append(arg)
+ tmp_pre.appendleft(arg)
else:
- post.append(arg)
- # Insert at the beginning
- self[:0] = pre
- # Append to the end
- self.__container += post
+ self.post.append(arg)
+ self.pre.extendleft(tmp_pre)
+ #pre and post is going to be merged later before a iter call
return self
def __radd__(self, args: T.Iterable[str]):
+ self.flush_pre_post()
new = CompilerArgs(self.compiler, args)
new += self
return new
def __eq__(self, other: T.Any) -> T.Union[bool, type(NotImplemented)]:
+ self.flush_pre_post()
# Only allow equality checks against other CompilerArgs and lists instances
if isinstance(other, CompilerArgs):
return self.compiler == other.compiler and self.__container == other.__container
@@ -713,6 +758,7 @@ class CompilerArgs(collections.abc.MutableSequence):
self.__iadd__(args)
def __repr__(self) -> str:
+ self.flush_pre_post()
return 'CompilerArgs({!r}, {!r})'.format(self.compiler, self.__container)
class Compiler: