mirror of
https://github.com/boostorg/container.git
synced 2025-07-31 04:57:16 +02:00
Sync from upstream.
This commit is contained in:
106
.github/workflows/ci.yml
vendored
106
.github/workflows/ci.yml
vendored
@ -128,9 +128,16 @@ jobs:
|
||||
- toolset: gcc-13
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
os: ubuntu-latest
|
||||
container: ubuntu:23.04
|
||||
container: ubuntu:24.04
|
||||
install: g++-13-multilib
|
||||
address-model: 32,64
|
||||
# Linux, gcc-14
|
||||
- toolset: gcc-14
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
os: ubuntu-latest
|
||||
container: ubuntu:24.04
|
||||
install: g++-14-multilib
|
||||
address-model: 32,64
|
||||
# Linux, gcc-12 UBSAN
|
||||
- name: UBSAN
|
||||
toolset: gcc-12
|
||||
@ -285,16 +292,23 @@ jobs:
|
||||
- toolset: clang
|
||||
compiler: clang++-16
|
||||
cxxstd: "03,11,14,17,20,2b"
|
||||
container: ubuntu:23.04
|
||||
container: ubuntu:24.04
|
||||
os: ubuntu-latest
|
||||
install: clang-16
|
||||
# Linux, clang-17
|
||||
- toolset: clang
|
||||
compiler: clang++-17
|
||||
cxxstd: "03,11,14,17,20,2b"
|
||||
container: ubuntu:23.10
|
||||
container: ubuntu:24.04
|
||||
os: ubuntu-latest
|
||||
install: clang-17
|
||||
# Linux, clang-18
|
||||
- toolset: clang
|
||||
compiler: clang++-18
|
||||
cxxstd: "03,11,14,17,20,2b"
|
||||
container: ubuntu:24.04
|
||||
os: ubuntu-latest
|
||||
install: clang-18
|
||||
# Linux, clang-15 libc++
|
||||
- toolset: clang
|
||||
compiler: clang++-15
|
||||
@ -304,10 +318,17 @@ jobs:
|
||||
- clang-15
|
||||
- libc++-15-dev
|
||||
- libc++abi-15-dev
|
||||
sources:
|
||||
- "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main"
|
||||
source_keys:
|
||||
- "https://apt.llvm.org/llvm-snapshot.gpg.key"
|
||||
cxxflags: -stdlib=libc++
|
||||
linkflags: -stdlib=libc++
|
||||
# Linux, clang-18 libc++
|
||||
- toolset: clang
|
||||
compiler: clang++-18
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
os: ubuntu-24.04
|
||||
install:
|
||||
- clang-18
|
||||
- libc++-18-dev
|
||||
- libc++abi-18-dev
|
||||
cxxflags: -stdlib=libc++
|
||||
linkflags: -stdlib=libc++
|
||||
# Linux, clang-14 libc++, ubsan
|
||||
@ -323,13 +344,22 @@ jobs:
|
||||
- clang-14
|
||||
- libc++-14-dev
|
||||
- libc++abi-14-dev
|
||||
# Linux, clang-18 libc++, ubsan
|
||||
- name: UBSAN
|
||||
toolset: clang
|
||||
compiler: clang++-18
|
||||
cxxstd: "11,14,17,20"
|
||||
cxxflags: -stdlib=libc++
|
||||
linkflags: -stdlib=libc++
|
||||
ubsan: 1
|
||||
os: ubuntu-24.04
|
||||
install:
|
||||
- clang-18
|
||||
- libc++-18-dev
|
||||
- libc++abi-18-dev
|
||||
#------------------
|
||||
# MacOS, clang
|
||||
#------------------
|
||||
# Macos 11, clang
|
||||
- toolset: clang
|
||||
cxxstd: "11,14,17,2a"
|
||||
os: macos-11
|
||||
# Macos 12, clang
|
||||
- toolset: clang
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
@ -338,6 +368,10 @@ jobs:
|
||||
- toolset: clang
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
os: macos-13
|
||||
# Macos 17, clang
|
||||
- toolset: clang
|
||||
cxxstd: "11,14,17,20,2b"
|
||||
os: macos-14
|
||||
|
||||
timeout-minutes: 180
|
||||
runs-on: ${{matrix.os}}
|
||||
@ -357,7 +391,6 @@ jobs:
|
||||
if [ -f "/etc/debian_version" ]
|
||||
then
|
||||
apt-get -o Acquire::Retries=$NET_RETRY_COUNT update
|
||||
apt-get -o Acquire::Retries=$NET_RETRY_COUNT dist-upgrade -y
|
||||
if [ "$(apt-cache search "^python-is-python3$" | wc -l)" -ne 0 ]
|
||||
then
|
||||
PYTHON_PACKAGE="python-is-python3"
|
||||
@ -368,7 +401,6 @@ jobs:
|
||||
fi
|
||||
fi
|
||||
git config --global pack.threads 0
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Install packages
|
||||
if: matrix.install
|
||||
@ -425,8 +457,8 @@ jobs:
|
||||
done
|
||||
fi
|
||||
sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT update
|
||||
sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT dist-upgrade -y
|
||||
sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y ${{join(matrix.install, ' ')}}
|
||||
|
||||
- name: Setup GCC Toolchain
|
||||
if: matrix.gcc_toolchain
|
||||
run: |
|
||||
@ -438,6 +470,7 @@ jobs:
|
||||
ln -s /usr/bin "$GCC_TOOLCHAIN_ROOT/bin"
|
||||
mkdir -p "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET"
|
||||
ln -s "/usr/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}"
|
||||
|
||||
- name: Setup Boost
|
||||
run: |
|
||||
echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY
|
||||
@ -483,11 +516,25 @@ jobs:
|
||||
then
|
||||
DEPINST_ARGS+=("--git_args" "--jobs $GIT_FETCH_JOBS")
|
||||
fi
|
||||
mkdir -p snapshot
|
||||
cd snapshot
|
||||
echo "Downloading library snapshot: https://github.com/${GITHUB_REPOSITORY}/archive/${GITHUB_SHA}.tar.gz"
|
||||
curl -L --retry "$NET_RETRY_COUNT" -o "${LIBRARY}-${GITHUB_SHA}.tar.gz" "https://github.com/${GITHUB_REPOSITORY}/archive/${GITHUB_SHA}.tar.gz"
|
||||
tar -xf "${LIBRARY}-${GITHUB_SHA}.tar.gz"
|
||||
if [ ! -d "${LIBRARY}-${GITHUB_SHA}" ]
|
||||
then
|
||||
echo "Library snapshot does not contain the library directory ${LIBRARY}-${GITHUB_SHA}:"
|
||||
ls -la
|
||||
exit 1
|
||||
fi
|
||||
rm -f "${LIBRARY}-${GITHUB_SHA}.tar.gz"
|
||||
cd ..
|
||||
git clone -b "$BOOST_BRANCH" --depth 1 "https://github.com/boostorg/boost.git" "boost-root"
|
||||
cd boost-root
|
||||
mkdir -p libs/$LIBRARY
|
||||
cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY
|
||||
mkdir -p libs
|
||||
rm -rf "libs/$LIBRARY"
|
||||
mv -f "../snapshot/${LIBRARY}-${GITHUB_SHA}" "libs/$LIBRARY"
|
||||
rm -rf "../snapshot"
|
||||
git submodule update --init tools/boostdep
|
||||
DEPINST_ARGS+=("$LIBRARY")
|
||||
python tools/boostdep/depinst/depinst.py "${DEPINST_ARGS[@]}"
|
||||
@ -502,10 +549,11 @@ jobs:
|
||||
fi
|
||||
echo " ;" >> ~/user-config.jam
|
||||
fi
|
||||
|
||||
- name: Run tests
|
||||
if: matrix.cmake_tests == ''
|
||||
run: |
|
||||
cd ../boost-root
|
||||
cd boost-root
|
||||
B2_ARGS=("-j" "$BUILD_JOBS" "toolset=${{matrix.toolset}}" "cxxstd=${{matrix.cxxstd}}")
|
||||
if [ -n "${{matrix.build_variant}}" ]
|
||||
then
|
||||
@ -536,6 +584,7 @@ jobs:
|
||||
fi
|
||||
B2_ARGS+=("libs/$LIBRARY/test")
|
||||
./b2 "${B2_ARGS[@]}"
|
||||
|
||||
windows:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@ -562,11 +611,10 @@ jobs:
|
||||
addrmd: 64
|
||||
os: windows-2019
|
||||
|
||||
timeout-minutes: 180
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Setup Boost
|
||||
shell: cmd
|
||||
run: |
|
||||
@ -580,16 +628,32 @@ jobs:
|
||||
set BOOST_BRANCH=develop
|
||||
for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master
|
||||
echo BOOST_BRANCH: %BOOST_BRANCH%
|
||||
mkdir snapshot
|
||||
cd snapshot
|
||||
echo Downloading library snapshot: https://github.com/%GITHUB_REPOSITORY%/archive/%GITHUB_SHA%.zip
|
||||
curl -L --retry %NET_RETRY_COUNT% -o "%LIBRARY%-%GITHUB_SHA%.zip" "https://github.com/%GITHUB_REPOSITORY%/archive/%GITHUB_SHA%.zip"
|
||||
tar -xf "%LIBRARY%-%GITHUB_SHA%.zip"
|
||||
if not exist "%LIBRARY%-%GITHUB_SHA%\" (
|
||||
echo Library snapshot does not contain the library directory %LIBRARY%-%GITHUB_SHA%:
|
||||
dir
|
||||
exit /b 1
|
||||
)
|
||||
del /f "%LIBRARY%-%GITHUB_SHA%.zip"
|
||||
cd ..
|
||||
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\
|
||||
if not exist "libs\" mkdir libs
|
||||
if exist "libs\%LIBRARY%\" rmdir /s /q "libs\%LIBRARY%"
|
||||
move /Y "..\snapshot\%LIBRARY%-%GITHUB_SHA%" "libs\%LIBRARY%"
|
||||
rmdir /s /q "..\snapshot"
|
||||
git submodule update --init tools/boostdep
|
||||
python tools/boostdep/depinst/depinst.py --git_args "--jobs %GIT_FETCH_JOBS%" %LIBRARY%
|
||||
cmd /c bootstrap
|
||||
b2 -d0 headers
|
||||
|
||||
- name: Run tests
|
||||
shell: cmd
|
||||
run: |
|
||||
cd ../boost-root
|
||||
cd boost-root
|
||||
b2 -j %NUMBER_OF_PROCESSORS% libs/%LIBRARY%/test toolset=${{matrix.toolset}} cxxstd=${{matrix.cxxstd}} address-model=${{matrix.addrmd}} variant=debug,release embed-manifest-via=linker
|
||||
|
||||
|
@ -1421,6 +1421,7 @@ use [*Boost.Container]? There are several reasons for that:
|
||||
* [@https://github.com/boostorg/container/issues/266 GitHub #266: ['"small_vector<T> is misaligned on the stack in 32 bits"]].
|
||||
* [@https://github.com/boostorg/container/issues/259 GitHub #259: ['"Global variables"]].
|
||||
* [@https://github.com/boostorg/container/issues/245 GitHub #245: ['"flat_tree::insert ordered range doesn't assert sorting"]].
|
||||
* [@https://github.com/boostorg/container/issues/241 GitHub #241: ['"flat_map should support same interface as std::map"]].
|
||||
|
||||
[endsect]
|
||||
|
||||
|
@ -49,9 +49,10 @@
|
||||
|
||||
#ifndef BOOST_CONTAINER_DOXYGEN_INVOKED
|
||||
|
||||
#if defined(BOOST_GCC) && (BOOST_GCC >= 40600)
|
||||
#if defined(BOOST_CONTAINER_GCC_COMPATIBLE_HAS_DIAGNOSTIC_IGNORED)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-result"
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#endif
|
||||
|
||||
#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_FUNCNAME allocate
|
||||
@ -75,7 +76,7 @@
|
||||
#define BOOST_INTRUSIVE_HAS_MEMBER_FUNCTION_CALLABLE_WITH_MAX 9
|
||||
#include <boost/intrusive/detail/has_member_function_callable_with.hpp>
|
||||
|
||||
#if defined(BOOST_GCC) && (BOOST_GCC >= 40600)
|
||||
#if defined(BOOST_CONTAINER_GCC_COMPATIBLE_HAS_DIAGNOSTIC_IGNORED)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
|
@ -1127,9 +1127,6 @@ class flat_tree
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline iterator erase(const_iterator position)
|
||||
{ return this->m_data.m_seq.erase(position); }
|
||||
|
||||
size_type erase(const key_type& k)
|
||||
{
|
||||
std::pair<iterator,iterator > itp = this->equal_range(k);
|
||||
@ -1149,6 +1146,40 @@ class flat_tree
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class K>
|
||||
inline typename dtl::enable_if_c<
|
||||
dtl::is_transparent<key_compare>::value && //transparent
|
||||
!dtl::is_convertible<K, iterator>::value && //not convertible to iterator
|
||||
!dtl::is_convertible<K, const_iterator>::value //not convertible to const_iterator
|
||||
, size_type>::type
|
||||
erase(const K& k)
|
||||
{
|
||||
std::pair<iterator, iterator > itp = this->equal_range(k);
|
||||
size_type ret = static_cast<size_type>(itp.second - itp.first);
|
||||
if (ret) {
|
||||
this->m_data.m_seq.erase(itp.first, itp.second);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class K>
|
||||
inline typename dtl::enable_if_c<
|
||||
dtl::is_transparent<key_compare>::value && //transparent
|
||||
!dtl::is_convertible<K, iterator>::value && //not convertible to iterator
|
||||
!dtl::is_convertible<K, const_iterator>::value //not convertible to const_iterator
|
||||
, size_type>::type
|
||||
erase_unique(const K& k)
|
||||
{
|
||||
const_iterator i = static_cast<const flat_tree&>(*this).find(k);
|
||||
size_type ret = static_cast<size_type>(i != this->cend());
|
||||
if (ret)
|
||||
this->erase(i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline iterator erase(const_iterator position)
|
||||
{ return this->m_data.m_seq.erase(position); }
|
||||
|
||||
inline iterator erase(const_iterator first, const_iterator last)
|
||||
{ return this->m_data.m_seq.erase(first, last); }
|
||||
|
||||
|
@ -536,6 +536,19 @@ struct node_alloc_holder
|
||||
return this->icont().erase_and_dispose(k, chain_holder.get_chain_builder());
|
||||
}
|
||||
|
||||
template<class Key, class KeyCompare>
|
||||
inline size_type erase_key(const Key& k, KeyCompare cmp, version_1)
|
||||
{
|
||||
return this->icont().erase_and_dispose(k, cmp, Destroyer(this->node_alloc()));
|
||||
}
|
||||
|
||||
template<class Key, class KeyCompare>
|
||||
inline size_type erase_key(const Key& k, KeyCompare cmp, version_2)
|
||||
{
|
||||
allocator_multialloc_chain_node_deallocator<NodeAlloc> chain_holder(this->node_alloc());
|
||||
return this->icont().erase_and_dispose(k, cmp, chain_holder.get_chain_builder());
|
||||
}
|
||||
|
||||
protected:
|
||||
struct cloner
|
||||
{
|
||||
|
@ -1142,6 +1142,31 @@ class tree
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <class K>
|
||||
inline typename dtl::enable_if_c<
|
||||
dtl::is_transparent<key_compare>::value && //transparent
|
||||
!dtl::is_convertible<K, iterator>::value && //not convertible to iterator
|
||||
!dtl::is_convertible<K, const_iterator>::value //not convertible to const_iterator
|
||||
, size_type>::type
|
||||
erase(const K& k)
|
||||
{ return AllocHolder::erase_key(k, KeyNodeCompare(key_comp()), alloc_version()); }
|
||||
|
||||
template <class K>
|
||||
inline typename dtl::enable_if_c<
|
||||
dtl::is_transparent<key_compare>::value && //transparent
|
||||
!dtl::is_convertible<K, iterator>::value && //not convertible to iterator
|
||||
!dtl::is_convertible<K, const_iterator>::value //not convertible to const_iterator
|
||||
, size_type>::type
|
||||
erase_unique(const K& k)
|
||||
{
|
||||
iterator i = this->find(k);
|
||||
size_type ret = static_cast<size_type>(i != this->end());
|
||||
|
||||
if (ret)
|
||||
this->erase(i);
|
||||
return ret;
|
||||
}
|
||||
|
||||
iterator erase(const_iterator first, const_iterator last)
|
||||
{
|
||||
BOOST_ASSERT(first == last || (first != this->cend() && (priv_is_linked)(first)));
|
||||
|
@ -236,4 +236,10 @@ namespace boost {
|
||||
# define BOOST_CONTAINER_CONSTANT_VAR static BOOST_CONSTEXPR_OR_CONST
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && ((__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 40600)
|
||||
#define BOOST_CONTAINER_GCC_COMPATIBLE_HAS_DIAGNOSTIC_IGNORED
|
||||
#elif defined(__clang__)
|
||||
#define BOOST_CONTAINER_GCC_COMPATIBLE_HAS_DIAGNOSTIC_IGNORED
|
||||
#endif
|
||||
|
||||
#endif //#ifndef BOOST_CONTAINER_DETAIL_WORKAROUND_HPP
|
||||
|
@ -1315,6 +1315,23 @@ class flat_map
|
||||
inline size_type erase(const key_type& x)
|
||||
{ return m_flat_tree.erase_unique(x); }
|
||||
|
||||
//! <b>Requires</b>: This overload is available only if
|
||||
//! key_compare::is_transparent exists.
|
||||
//!
|
||||
//! <b>Effects</b>: If present, erases the element in the container with key equivalent to x.
|
||||
//!
|
||||
//! <b>Returns</b>: Returns the number of erased elements (0/1).
|
||||
template <class K>
|
||||
inline BOOST_CONTAINER_DOC1ST
|
||||
(size_type
|
||||
, typename dtl::enable_if_c<
|
||||
dtl::is_transparent<key_compare>::value && //transparent
|
||||
!dtl::is_convertible<K BOOST_MOVE_I iterator>::value && //not convertible to iterator
|
||||
!dtl::is_convertible<K BOOST_MOVE_I const_iterator>::value //not convertible to const_iterator
|
||||
BOOST_MOVE_I size_type>::type)
|
||||
erase(const K& x)
|
||||
{ return m_flat_tree.erase_unique(x); }
|
||||
|
||||
//! <b>Effects</b>: Erases all the elements in the range [first, last).
|
||||
//!
|
||||
//! <b>Returns</b>: Returns last.
|
||||
@ -2678,6 +2695,23 @@ class flat_multimap
|
||||
inline size_type erase(const key_type& x)
|
||||
{ return m_flat_tree.erase(x); }
|
||||
|
||||
//! <b>Requires</b>: This overload is available only if
|
||||
//! key_compare::is_transparent exists.
|
||||
//!
|
||||
//! <b>Effects</b>: Erases all elements in the container with key equivalent to x.
|
||||
//!
|
||||
//! <b>Returns</b>: Returns the number of erased elements.
|
||||
template <class K>
|
||||
inline BOOST_CONTAINER_DOC1ST
|
||||
(size_type
|
||||
, typename dtl::enable_if_c<
|
||||
dtl::is_transparent<key_compare>::value && //transparent
|
||||
!dtl::is_convertible<K BOOST_MOVE_I iterator>::value && //not convertible to iterator
|
||||
!dtl::is_convertible<K BOOST_MOVE_I const_iterator>::value //not convertible to const_iterator
|
||||
BOOST_MOVE_I size_type>::type)
|
||||
erase(const K& x)
|
||||
{ return m_flat_tree.erase(x); }
|
||||
|
||||
//! <b>Effects</b>: Erases all the elements in the range [first, last).
|
||||
//!
|
||||
//! <b>Returns</b>: Returns last.
|
||||
|
@ -969,6 +969,23 @@ class map
|
||||
inline size_type erase(const key_type& x)
|
||||
{ return this->base_t::erase_unique(x); }
|
||||
|
||||
//! <b>Requires</b>: This overload is available only if
|
||||
//! key_compare::is_transparent exists.
|
||||
//!
|
||||
//! <b>Effects</b>: If present, erases the element in the container with key equivalent to x.
|
||||
//!
|
||||
//! <b>Returns</b>: Returns the number of erased elements (0/1).
|
||||
template <class K>
|
||||
inline BOOST_CONTAINER_DOC1ST
|
||||
(size_type
|
||||
, typename dtl::enable_if_c<
|
||||
dtl::is_transparent<key_compare>::value && //transparent
|
||||
!dtl::is_convertible<K BOOST_MOVE_I iterator>::value && //not convertible to iterator
|
||||
!dtl::is_convertible<K BOOST_MOVE_I const_iterator>::value //not convertible to const_iterator
|
||||
BOOST_MOVE_I size_type>::type)
|
||||
erase(const K& x)
|
||||
{ return this->base_t::erase_unique(x); }
|
||||
|
||||
#if defined(BOOST_CONTAINER_DOXYGEN_INVOKED)
|
||||
|
||||
//! <b>Effects</b>: Erases the element pointed to by p.
|
||||
|
@ -560,6 +560,15 @@ bool test_heterogeneous_lookups()
|
||||
if(cmmap1.equal_range(find_me).second->second != 'e')
|
||||
return false;
|
||||
|
||||
//erase
|
||||
if (map1.erase(find_me) != 1)
|
||||
return false;
|
||||
if (map1.erase(find_me) != 0)
|
||||
return false;
|
||||
if (mmap1.erase(find_me) != 2)
|
||||
return false;
|
||||
if (mmap1.erase(find_me) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -361,6 +361,15 @@ bool test_heterogeneous_lookups()
|
||||
if(cmmap1.equal_range(find_me).second->second != 'e')
|
||||
return false;
|
||||
|
||||
//erase
|
||||
if (map1.erase(find_me) != 1)
|
||||
return false;
|
||||
if (map1.erase(find_me) != 0)
|
||||
return false;
|
||||
if (mmap1.erase(find_me) != 2)
|
||||
return false;
|
||||
if (mmap1.erase(find_me) != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user