mirror of
https://github.com/nlohmann/json.git
synced 2026-09-30 11:40:30 +00:00
Compare commits
6
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb62a61c04 | ||
|
|
f9b9b303cb | ||
|
|
ed9510ed75 | ||
|
|
3acf3a1c3d | ||
|
|
3a64ae470b | ||
|
|
32912a5e80 |
@@ -7,6 +7,16 @@ on:
|
||||
- develop
|
||||
paths:
|
||||
- docs/mkdocs/**
|
||||
# the site also embeds these files via pymdownx.snippets
|
||||
# (mkdocs.yml sets restrict_base_path: false for this)
|
||||
- .clang-tidy
|
||||
- .github/CODE_OF_CONDUCT.md
|
||||
- .github/CONTRIBUTING.md
|
||||
- .github/SECURITY.md
|
||||
- cmake/clang_flags.cmake
|
||||
- cmake/gcc_flags.cmake
|
||||
- tests/fmt_formatter/project/main.cpp
|
||||
- tools/astyle/.astylerc
|
||||
workflow_dispatch:
|
||||
|
||||
# we don't want to have concurrent jobs, and we don't want to cancel running jobs to avoid broken publications
|
||||
@@ -23,7 +33,7 @@ jobs:
|
||||
contents: write
|
||||
|
||||
if: github.repository == 'nlohmann/json'
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Harden Runner
|
||||
uses: step-security/harden-runner@e14015d583714f6e62063499dc959a02595150a1 # v2.21.1
|
||||
|
||||
@@ -346,6 +346,8 @@ jobs:
|
||||
container: intel/oneapi-hpckit:latest
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
@@ -358,6 +360,8 @@ jobs:
|
||||
container: nvcr.io/nvidia/nvhpc:25.5-devel-cuda12.9-ubuntu22.04
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Run CMake
|
||||
|
||||
@@ -87,6 +87,8 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Get latest CMake and ninja
|
||||
uses: lukka/get-cmake@fffaaafeea488556c2c12dad60690008bc1caacb # v4.4.2
|
||||
- name: Set extra CXX_FLAGS for latest std_version
|
||||
@@ -123,6 +125,8 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Run CMake (Release)
|
||||
run: cmake -S . -B build -G "Visual Studio 18 2026" -A ARM64 -DJSON_BuildTests=On -DCMAKE_CXX_FLAGS="/W4 /WX"
|
||||
if: matrix.build_type == 'Release'
|
||||
|
||||
+16
-5
@@ -11,20 +11,31 @@ EXAMPLES = $(wildcard mkdocs/docs/examples/*.cpp)
|
||||
|
||||
cxx_standard = $(lastword c++11 $(filter c++%, $(subst ., ,$1)))
|
||||
|
||||
# common compile flags for the stand-alone example files
|
||||
EXAMPLE_CPPFLAGS = -I $(SRCDIR) -DJSON_USE_GLOBAL_UDLS=0
|
||||
EXAMPLE_WARNFLAGS = -Werror=deprecated-declarations
|
||||
|
||||
# examples that document deprecated API and are allowed to use it
|
||||
DEPRECATED_EXAMPLES = $(addprefix mkdocs/docs/examples/, \
|
||||
json_pointer__operator__equal_stringtype \
|
||||
json_pointer__operator__notequal_stringtype \
|
||||
json_pointer__operator_string_t)
|
||||
$(DEPRECATED_EXAMPLES:=.output) $(DEPRECATED_EXAMPLES:=.test): EXAMPLE_WARNFLAGS = -Wno-deprecated-declarations
|
||||
|
||||
# create output from a stand-alone example file
|
||||
%.output: %.cpp
|
||||
@echo "standard $(call cxx_standard $(<:.cpp=))"
|
||||
@echo "standard $(call cxx_standard,$(<:.cpp=))"
|
||||
$(MAKE) $(<:.cpp=) \
|
||||
CPPFLAGS="-I $(SRCDIR) -DJSON_USE_GLOBAL_UDLS=0" \
|
||||
CXXFLAGS="-std=$(call cxx_standard,$(<:.cpp=)) -Wno-deprecated-declarations"
|
||||
CPPFLAGS="$(EXAMPLE_CPPFLAGS)" \
|
||||
CXXFLAGS="-std=$(call cxx_standard,$(<:.cpp=)) $(EXAMPLE_WARNFLAGS)"
|
||||
./$(<:.cpp=) > $@
|
||||
rm $(<:.cpp=)
|
||||
|
||||
# compare created output with current output of the example files
|
||||
%.test: %.cpp
|
||||
$(MAKE) $(<:.cpp=) \
|
||||
CPPFLAGS="-I $(SRCDIR) -DJSON_USE_GLOBAL_UDLS=0" \
|
||||
CXXFLAGS="-std=$(call cxx_standard,$(<:.cpp=)) -Wno-deprecated-declarations"
|
||||
CPPFLAGS="$(EXAMPLE_CPPFLAGS)" \
|
||||
CXXFLAGS="-std=$(call cxx_standard,$(<:.cpp=)) $(EXAMPLE_WARNFLAGS)"
|
||||
./$(<:.cpp=) > $@
|
||||
diff $@ $(<:.cpp=.output)
|
||||
rm $(<:.cpp=) $@
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<key>dashIndexFilePath</key>
|
||||
<string>index.html</string>
|
||||
<key>DashDocSetFallbackURL</key>
|
||||
<string>https://nlohmann.github.io/json/</string>
|
||||
<string>https://json.nlohmann.me/</string>
|
||||
<key>isJavaScriptEnabled</key>
|
||||
<true/>
|
||||
</dict>
|
||||
|
||||
@@ -7,10 +7,11 @@ documentation browsers like [Dash](https://kapeli.com/dash), [Velocity](https://
|
||||
The docset can be created with
|
||||
|
||||
```sh
|
||||
make nlohmann_json.docset
|
||||
make JSON_for_Modern_C++.docset
|
||||
```
|
||||
|
||||
The generated folder `nlohmann_json.docset` can then be opened in the documentation browser.
|
||||
The generated folder `JSON_for_Modern_C++.docset` can then be opened in the documentation browser. `make all` builds a
|
||||
`JSON_for_Modern_C++.tgz` archive instead, and `make install_docset_zeal` installs the docset for Zeal directly.
|
||||
|
||||
A recent version is also part of the [Dash user contributions](https://github.com/Kapeli/Dash-User-Contributions/tree/master/docsets/JSON_for_Modern_C%2B%2B).
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ range will yield over/underflow when used in a constructor. During deserializati
|
||||
will automatically be stored as [`number_unsigned_t`](number_unsigned_t.md) or [`number_float_t`](number_float_t.md).
|
||||
|
||||
[RFC 8259](https://tools.ietf.org/html/rfc8259) further states:
|
||||
> Note that when such software is used, numbers that are integers and are in the range $[-2^{53}+1, 2^{53}-1]$ are
|
||||
> Note that when such software is used, numbers that are integers and are in the range [-2<sup>53</sup>+1, 2<sup>53</sup>-1] are
|
||||
> interoperable in the sense that implementations will agree exactly on their numeric values.
|
||||
|
||||
As this range is a subrange of the exactly supported range [INT64_MIN, INT64_MAX], this class's integer type is
|
||||
|
||||
@@ -52,7 +52,7 @@ when used in a constructor. During deserialization, too large or small integer n
|
||||
as [`number_integer_t`](number_integer_t.md) or [`number_float_t`](number_float_t.md).
|
||||
|
||||
[RFC 8259](https://tools.ietf.org/html/rfc8259) further states:
|
||||
> Note that when such software is used, numbers that are integers and are in the range $[-2^{53}+1, 2^{53}-1]$ are
|
||||
> Note that when such software is used, numbers that are integers and are in the range [-2<sup>53</sup>+1, 2<sup>53</sup>-1] are
|
||||
> interoperable in the sense that implementations will agree exactly on their numeric values.
|
||||
|
||||
As this range is a subrange (when considered in conjunction with the `number_integer_t` type) of the exactly supported
|
||||
|
||||
@@ -54,7 +54,7 @@ classDiagram
|
||||
|
||||
## Notes
|
||||
|
||||
For an input with $n$ bytes, 1 is the index of the first character and $n+1$ is the index of the terminating null byte
|
||||
For an input with <i>n</i> bytes, 1 is the index of the first character and <i>n</i>+1 is the index of the terminating null byte
|
||||
or the end of file. This also holds true when reading a byte vector for binary formats.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/hUJYo1HWmfTBLMGn"><b>online</b></a>
|
||||
@@ -1 +0,0 @@
|
||||
<a target="_blank" href="https://wandbox.org/permlink/AWbpa8e1xRV3y4MM"><b>online</b></a>
|
||||
@@ -61,7 +61,7 @@ The library uses the following mapping from JSON values types to BJData types ac
|
||||
|
||||
The following values can **not** be converted to a BJData value:
|
||||
|
||||
- strings with more than 18446744073709551615 bytes, i.e., $2^{64}-1$ bytes (theoretical)
|
||||
- strings with more than 18446744073709551615 bytes, i.e., 2<sup>64</sup>-1 bytes (theoretical)
|
||||
|
||||
!!! info "Unused BJData markers"
|
||||
|
||||
|
||||
@@ -273,7 +273,7 @@ When the default type is used, the maximal unsigned integer number that can be s
|
||||
|
||||
[RFC 8259](https://tools.ietf.org/html/rfc8259) further states:
|
||||
|
||||
> Note that when such software is used, numbers that are integers and are in the range $[-2^{53}+1, 2^{53}-1]$ are interoperable in the sense that implementations will agree exactly on their numeric values.
|
||||
> Note that when such software is used, numbers that are integers and are in the range [-2<sup>53</sup>+1, 2<sup>53</sup>-1] are interoperable in the sense that implementations will agree exactly on their numeric values.
|
||||
|
||||
As this range is a subrange of the exactly supported range [`INT64_MIN`, `INT64_MAX`], this class's integer type is interoperable.
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ On number interoperability, the following remarks are made:
|
||||
for numeric magnitude and precision than is widely available.
|
||||
|
||||
Note that when such software is used, numbers that are integers and
|
||||
are in the range $[-2^{53}+1, 2^{53}-1]$ are interoperable in the
|
||||
are in the range [-2<sup>53</sup>+1, 2<sup>53</sup>-1] are interoperable in the
|
||||
sense that implementations will agree exactly on their numeric
|
||||
values.
|
||||
|
||||
@@ -95,9 +95,9 @@ This is the same behavior as the code `#!c double x = 3.141592653589793238462643
|
||||
|
||||
!!! success "Interoperability"
|
||||
|
||||
- The library is interoperable with respect to the specification, because its supported range $[-2^{63}, 2^{64}-1]$ is
|
||||
larger than the described range $[-2^{53}+1, 2^{53}-1]$.
|
||||
- All integers outside the range $[-2^{63}, 2^{64}-1]$, as well as floating-point numbers are stored as `double`.
|
||||
- The library is interoperable with respect to the specification, because its supported range [-2<sup>63</sup>, 2<sup>64</sup>-1] is
|
||||
larger than the described range [-2<sup>53</sup>+1, 2<sup>53</sup>-1].
|
||||
- All integers outside the range [-2<sup>63</sup>, 2<sup>64</sup>-1], as well as floating-point numbers are stored as `double`.
|
||||
This also concurs with the specification above.
|
||||
|
||||
### Zeros
|
||||
|
||||
@@ -349,7 +349,6 @@ markdown_extensions:
|
||||
- toc:
|
||||
permalink: true
|
||||
- md_in_html
|
||||
- pymdownx.arithmatex
|
||||
- pymdownx.betterem:
|
||||
smart_enable: all
|
||||
- pymdownx.caret
|
||||
@@ -441,6 +440,3 @@ plugins:
|
||||
|
||||
extra_css:
|
||||
- css/custom.css
|
||||
|
||||
extra_javascript:
|
||||
- https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-MML-AM_CHTML
|
||||
|
||||
@@ -79,9 +79,9 @@ def check_structure() -> None:
|
||||
report("whitespace/line_length", f"{file}:{lineno+1} ({current_section})", f"line is too long ({len(line)} vs. 160 chars)")
|
||||
|
||||
# sections in `<!-- NOLINT -->` comments are treated as present
|
||||
if line.startswith("<!-- NOLINT"):
|
||||
current_section = line.strip("<!-- NOLINT")
|
||||
current_section = current_section.strip(" -->")
|
||||
nolint_match = re.match(r"<!--\s*NOLINT\s+(.*?)\s*-->", line)
|
||||
if nolint_match:
|
||||
current_section = nolint_match.group(1)
|
||||
existing_sections.append(current_section)
|
||||
|
||||
# check if sections are correct
|
||||
@@ -97,7 +97,7 @@ def check_structure() -> None:
|
||||
if len(unexpected):
|
||||
report("style/numbering", f"{file}:{lineno} ({current_section})", f'unexpected overloads: {", ".join([f"({x})" for x in unexpected])}')
|
||||
|
||||
current_section = line.strip("## ")
|
||||
current_section = line[3:]
|
||||
existing_sections.append(current_section)
|
||||
|
||||
if current_section in expected_sections:
|
||||
@@ -141,7 +141,7 @@ def check_structure() -> None:
|
||||
# check that non-example admonitions have titles
|
||||
untitled_admonition = re.match(r"^(\?\?\?|!!!) ([^ ]+)$", line)
|
||||
if untitled_admonition and untitled_admonition.group(2) != "example":
|
||||
report("style/admonition_title", f"{file}:{lineno} ({current_section})", f'"{untitled_admonition.group(2)}" admonitions should have a title')
|
||||
report("style/admonition_title", f"{file}:{lineno+1} ({current_section})", f'"{untitled_admonition.group(2)}" admonitions should have a title')
|
||||
|
||||
previous_line = line
|
||||
|
||||
|
||||
@@ -19,17 +19,11 @@ namespace detail
|
||||
/*!
|
||||
@brief the number of nesting levels an operation recurses into
|
||||
|
||||
Operations that walk a value (copying, comparing, serializing, hashing, merging,
|
||||
...) recurse once
|
||||
Operations that walk a value (serializing, hashing, merging, ...) recurse once
|
||||
per nesting level, which is fastest, but a value nested deeply enough would
|
||||
exhaust the call stack. So they recurse only this many levels deep and finish
|
||||
whatever lies below with an explicit stack. All of them share this limit.
|
||||
|
||||
Most of them pass the depth down as an argument. The copy constructor and the
|
||||
comparison operators cannot, as their signatures are fixed, so they count it
|
||||
in basic_json::nesting_depth() instead, a byte per thread; the limit must
|
||||
therefore stay below 255.
|
||||
|
||||
@sa https://github.com/nlohmann/json/issues/5387
|
||||
*/
|
||||
constexpr std::size_t recursion_depth_limit() noexcept
|
||||
|
||||
@@ -898,8 +898,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
#ifndef JSON_NO_THREAD_LOCAL
|
||||
// nesting_depth() is a byte and may exceed the limit by one level
|
||||
static_assert(detail::recursion_depth_limit() < 255, "the nesting depth count must fit in a byte");
|
||||
/// the number of levels an operation descends into before it finishes the
|
||||
/// value below it without the call stack
|
||||
static constexpr std::uint8_t nesting_depth_limit()
|
||||
{
|
||||
return 128;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief how many levels the operation going on in this thread has descended into
|
||||
@@ -941,7 +945,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
static_cast<void>(may_descend);
|
||||
return true;
|
||||
#else
|
||||
return !may_descend || nesting_depth() >= detail::recursion_depth_limit();
|
||||
return !may_descend || nesting_depth() >= nesting_depth_limit();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -965,7 +969,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
#ifdef JSON_NO_THREAD_LOCAL
|
||||
: m_okay(false)
|
||||
#else
|
||||
: m_okay(nesting_depth() < detail::recursion_depth_limit())
|
||||
: m_okay(nesting_depth() < nesting_depth_limit())
|
||||
#endif
|
||||
{
|
||||
#ifndef JSON_NO_THREAD_LOCAL
|
||||
@@ -1169,7 +1173,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
The values whose copy has not been created yet are kept on an explicit
|
||||
worklist rather than on the call stack. This is only reached for values
|
||||
nested deeper than @ref detail::recursion_depth_limit levels, which is why it copies
|
||||
nested deeper than @ref nesting_depth_limit levels, which is why it copies
|
||||
every container by hand instead of letting the container do it: the fast
|
||||
ways of doing so would descend into the elements and defeat the purpose.
|
||||
*/
|
||||
@@ -1235,7 +1239,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
Copying a container copies its elements, so a value nested deeply enough
|
||||
used to exhaust the call stack. The descent is bounded here: the first
|
||||
@ref detail::recursion_depth_limit levels are copied by the containers themselves, just
|
||||
@ref nesting_depth_limit levels are copied by the containers themselves, just
|
||||
as they always were, and anything below that is copied without the call
|
||||
stack by @ref copy_iteratively. Copying a value can therefore no longer
|
||||
exhaust the stack, however deeply it is nested, just like destroying one
|
||||
@@ -1373,7 +1377,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/*!
|
||||
@brief compare @a lhs and @a rhs without descending into them
|
||||
|
||||
Reached once a comparison has descended @ref detail::recursion_depth_limit levels, so
|
||||
Reached once a comparison has descended @ref nesting_depth_limit levels, so
|
||||
that comparing values cannot exhaust the call stack however deeply they are
|
||||
nested. The two values are walked in lockstep on an explicit stack and
|
||||
compared lexicographically, element by element in the order the containers
|
||||
|
||||
@@ -7281,17 +7281,11 @@ namespace detail
|
||||
/*!
|
||||
@brief the number of nesting levels an operation recurses into
|
||||
|
||||
Operations that walk a value (copying, comparing, serializing, hashing, merging,
|
||||
...) recurse once
|
||||
Operations that walk a value (serializing, hashing, merging, ...) recurse once
|
||||
per nesting level, which is fastest, but a value nested deeply enough would
|
||||
exhaust the call stack. So they recurse only this many levels deep and finish
|
||||
whatever lies below with an explicit stack. All of them share this limit.
|
||||
|
||||
Most of them pass the depth down as an argument. The copy constructor and the
|
||||
comparison operators cannot, as their signatures are fixed, so they count it
|
||||
in basic_json::nesting_depth() instead, a byte per thread; the limit must
|
||||
therefore stay below 255.
|
||||
|
||||
@sa https://github.com/nlohmann/json/issues/5387
|
||||
*/
|
||||
constexpr std::size_t recursion_depth_limit() noexcept
|
||||
@@ -26985,8 +26979,12 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
}
|
||||
|
||||
#ifndef JSON_NO_THREAD_LOCAL
|
||||
// nesting_depth() is a byte and may exceed the limit by one level
|
||||
static_assert(detail::recursion_depth_limit() < 255, "the nesting depth count must fit in a byte");
|
||||
/// the number of levels an operation descends into before it finishes the
|
||||
/// value below it without the call stack
|
||||
static constexpr std::uint8_t nesting_depth_limit()
|
||||
{
|
||||
return 128;
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief how many levels the operation going on in this thread has descended into
|
||||
@@ -27028,7 +27026,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
static_cast<void>(may_descend);
|
||||
return true;
|
||||
#else
|
||||
return !may_descend || nesting_depth() >= detail::recursion_depth_limit();
|
||||
return !may_descend || nesting_depth() >= nesting_depth_limit();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -27052,7 +27050,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
#ifdef JSON_NO_THREAD_LOCAL
|
||||
: m_okay(false)
|
||||
#else
|
||||
: m_okay(nesting_depth() < detail::recursion_depth_limit())
|
||||
: m_okay(nesting_depth() < nesting_depth_limit())
|
||||
#endif
|
||||
{
|
||||
#ifndef JSON_NO_THREAD_LOCAL
|
||||
@@ -27256,7 +27254,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
The values whose copy has not been created yet are kept on an explicit
|
||||
worklist rather than on the call stack. This is only reached for values
|
||||
nested deeper than @ref detail::recursion_depth_limit levels, which is why it copies
|
||||
nested deeper than @ref nesting_depth_limit levels, which is why it copies
|
||||
every container by hand instead of letting the container do it: the fast
|
||||
ways of doing so would descend into the elements and defeat the purpose.
|
||||
*/
|
||||
@@ -27322,7 +27320,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
|
||||
Copying a container copies its elements, so a value nested deeply enough
|
||||
used to exhaust the call stack. The descent is bounded here: the first
|
||||
@ref detail::recursion_depth_limit levels are copied by the containers themselves, just
|
||||
@ref nesting_depth_limit levels are copied by the containers themselves, just
|
||||
as they always were, and anything below that is copied without the call
|
||||
stack by @ref copy_iteratively. Copying a value can therefore no longer
|
||||
exhaust the stack, however deeply it is nested, just like destroying one
|
||||
@@ -27460,7 +27458,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec
|
||||
/*!
|
||||
@brief compare @a lhs and @a rhs without descending into them
|
||||
|
||||
Reached once a comparison has descended @ref detail::recursion_depth_limit levels, so
|
||||
Reached once a comparison has descended @ref nesting_depth_limit levels, so
|
||||
that comparing values cannot exhaust the call stack however deeply they are
|
||||
nested. The two values are walked in lockstep on an explicit stack and
|
||||
compared lexicographically, element by element in the order the containers
|
||||
|
||||
Reference in New Issue
Block a user