mirror of
https://github.com/aantron/better-enums.git
synced 2025-12-06 16:56:42 +08:00
Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
520d8ee390 | ||
|
|
d65550f378 | ||
|
|
1e8f499ddf | ||
|
|
f3ff0a6917 | ||
|
|
68ca02d1f5 | ||
|
|
517387fba0 | ||
|
|
fb8b398b02 | ||
|
|
c35576bed0 | ||
|
|
2422dd6f26 | ||
|
|
894eab5284 | ||
|
|
fd646ae537 | ||
|
|
abb693d4ef | ||
|
|
2f1fcaae7a | ||
|
|
3e115c0c17 | ||
|
|
c730fc8ae8 | ||
|
|
f480b7ef1c | ||
|
|
1a3c4f9e5a | ||
|
|
21c374914c | ||
|
|
dcbd3c0554 | ||
|
|
89bc057a63 | ||
|
|
5dcd59bd29 | ||
|
|
fa39f5c89e | ||
|
|
4b76e7783b | ||
|
|
1ea7f04bb9 | ||
|
|
e1756cdb07 | ||
|
|
5a677ac72b | ||
|
|
8a0d376b53 |
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
github: aantron
|
||||||
23
LICENSE.md
Normal file
23
LICENSE.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
Copyright (c) 2012-2024, Anton Bachin
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
25
README.md
25
README.md
@ -1,7 +1,5 @@
|
|||||||
# Better Enums [![version 0.11.2][version]][releases] [![Try online][wandbox-img]][wandbox] [![Travis status][travis-img]][travis] [![AppVeyor status][appveyor-img]][appveyor] [![BSD license][license-img]][license]
|
# Better Enums [![Try online][wandbox-img]][wandbox] [![Travis status][travis-img]][travis] [![AppVeyor status][appveyor-img]][appveyor]
|
||||||
|
|
||||||
[version]: https://img.shields.io/badge/version-0.11.2-blue.svg
|
|
||||||
[releases]: https://github.com/aantron/better-enums/releases
|
|
||||||
[wandbox]: http://melpon.org/wandbox/permlink/2QCi3cwQnplAToge
|
[wandbox]: http://melpon.org/wandbox/permlink/2QCi3cwQnplAToge
|
||||||
[wandbox-img]: https://img.shields.io/badge/try%20it-online-blue.svg
|
[wandbox-img]: https://img.shields.io/badge/try%20it-online-blue.svg
|
||||||
[appveyor]: https://ci.appveyor.com/project/aantron/better-enums/branch/master
|
[appveyor]: https://ci.appveyor.com/project/aantron/better-enums/branch/master
|
||||||
@ -98,27 +96,8 @@ a comparison:
|
|||||||
|
|
||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
## Contact and development
|
## History
|
||||||
|
|
||||||
Don't hesitate to contact me about features or bugs:
|
|
||||||
[antonbachin@yahoo.com][email], or open an issue on GitHub.
|
|
||||||
|
|
||||||
If you'd like to help develop Better Enums, see [`CONTRIBUTING`][contributing].
|
|
||||||
One area that could use fresh ideas is finding a compile-time data structure
|
|
||||||
that both compiles quickly and allows lookup in sub-linear time.
|
|
||||||
|
|
||||||
[email]: mailto:antonbachin@yahoo.com
|
|
||||||
[contributing]: https://github.com/aantron/better-enums/blob/master/doc/CONTRIBUTING.md
|
|
||||||
|
|
||||||
<br/>
|
|
||||||
|
|
||||||
## License and history
|
|
||||||
|
|
||||||
Better Enums is released under the BSD 2-clause license. See
|
|
||||||
[`LICENSE`][license].
|
|
||||||
|
|
||||||
The original version of the library was developed by the author in the winter of
|
The original version of the library was developed by the author in the winter of
|
||||||
2012-2013 at Hudson River Trading, as a replacement for an older generator
|
2012-2013 at Hudson River Trading, as a replacement for an older generator
|
||||||
called `BETTER_ENUM`.
|
called `BETTER_ENUM`.
|
||||||
|
|
||||||
[license]: https://github.com/aantron/better-enums/blob/master/doc/LICENSE
|
|
||||||
|
|||||||
@ -228,7 +228,7 @@ If the given string is the exact name of a declared constant, returns the
|
|||||||
constant. Otherwise, throws `std::runtime_error`. Running time is linear in the
|
constant. Otherwise, throws `std::runtime_error`. Running time is linear in the
|
||||||
number of declared constants multiplied by the length of the longest constant.
|
number of declared constants multiplied by the length of the longest constant.
|
||||||
|
|
||||||
#### static constexpr optional<Enum> <em>_from_string_nothrow</em>(const char*)
|
#### static constexpr optional<Enum> <em>_from_string_nothrow</em>(const char*)
|
||||||
|
|
||||||
Same as [`_from_string`](#_from_string), but does not throw an exception on
|
Same as [`_from_string`](#_from_string), but does not throw an exception on
|
||||||
failure. Returns an [optional value](#StructBetter_enumsoptional) instead.
|
failure. Returns an [optional value](#StructBetter_enumsoptional) instead.
|
||||||
@ -238,7 +238,7 @@ failure. Returns an [optional value](#StructBetter_enumsoptional) instead.
|
|||||||
Same as [`_from_string`](#_from_string), but comparison is up to case, in the
|
Same as [`_from_string`](#_from_string), but comparison is up to case, in the
|
||||||
usual sense in the Latin-1 encoding.
|
usual sense in the Latin-1 encoding.
|
||||||
|
|
||||||
#### static constexpr optional<Enum> <em>_from_string_nocase_nothrow</em>(const char*)
|
#### static constexpr optional<Enum> <em>_from_string_nocase_nothrow</em>(const char*)
|
||||||
|
|
||||||
Is to [`_from_string_nocase`](#_from_string_nocase) as
|
Is to [`_from_string_nocase`](#_from_string_nocase) as
|
||||||
[`_from_string_nothrow`](#_from_string_nothrow) is to
|
[`_from_string_nothrow`](#_from_string_nothrow) is to
|
||||||
@ -342,7 +342,7 @@ of one of the declared constants.
|
|||||||
<em>Enum::_from_integral</em>(<em>2</em>); // Enum::C
|
<em>Enum::_from_integral</em>(<em>2</em>); // Enum::C
|
||||||
<em>Enum::_from_integral</em>(<em>42</em>); // std::runtime_error
|
<em>Enum::_from_integral</em>(<em>42</em>); // std::runtime_error
|
||||||
|
|
||||||
#### static constexpr optional<Enum> <em>_from_integral_nothrow</em>(_integral)
|
#### static constexpr optional<Enum> <em>_from_integral_nothrow</em>(_integral)
|
||||||
|
|
||||||
Checked conversion as [`_from_integral`](#_from_integral), but does not throw an
|
Checked conversion as [`_from_integral`](#_from_integral), but does not throw an
|
||||||
exception on failure. Returns an [optional value](#StructBetter_enumsoptional)
|
exception on failure. Returns an [optional value](#StructBetter_enumsoptional)
|
||||||
@ -370,6 +370,34 @@ constants.
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Index lookup
|
||||||
|
|
||||||
|
#### member constexpr std::size_t <em>_to_index</em>() const
|
||||||
|
|
||||||
|
Returns the index of a Better Enum value within its enum declaration. The index
|
||||||
|
is determined from the value only; if two constants in the declaration have the
|
||||||
|
same value, this function may return the index of either constant.
|
||||||
|
|
||||||
|
If the value does not correspond to any constant in the declaration (for
|
||||||
|
example, if it was obtained using an unchecked conversion or a cast), then the
|
||||||
|
behavior of `value._to_index` is undefined.
|
||||||
|
|
||||||
|
#### static constexpr Enum <em>_from_index</em>(size_t)
|
||||||
|
|
||||||
|
Returns the value of the constant with the given index. Throws
|
||||||
|
`std::runtime_error` if not given the index of one of the constants.
|
||||||
|
|
||||||
|
#### static constexpr Enum <em>_from_index_unchecked</em>(size_t)
|
||||||
|
|
||||||
|
Returns the value of the constant with the given index. If not given one of the
|
||||||
|
constants in the declaration of the enum, the returned value is undefined.
|
||||||
|
|
||||||
|
#### static constexpr optional<Enum> <em>_from_index_nothrow</em>(size_t)
|
||||||
|
|
||||||
|
Returns the value of the constant with the given index.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Stream operators
|
### Stream operators
|
||||||
|
|
||||||
#### non-member std::ostream& <em>operator <<</em>(std::ostream&, const Enum&)
|
#### non-member std::ostream& <em>operator <<</em>(std::ostream&, const Enum&)
|
||||||
@ -385,6 +413,21 @@ as [`_from_string`](#_from_string). In case of failure, sets the stream's
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
### Hashing
|
||||||
|
|
||||||
|
#### macro <em>BETTER_ENUMS_DECLARE_STD_HASH</em>(Enum)
|
||||||
|
|
||||||
|
Use this outside namespace scope to declare a specialization of `std::hash` for
|
||||||
|
the type `Enum`. For example:
|
||||||
|
|
||||||
|
// This declaration might be inside a namespace.
|
||||||
|
<em>BETTER_ENUM</em>(<em>Channel</em>, int, Red, Green, Blue)
|
||||||
|
|
||||||
|
// Later, outside the namespace:
|
||||||
|
<em>BETTER_ENUMS_DECLARE_STD_HASH</em>(<em>Channel</em>)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%% class = api
|
%% class = api
|
||||||
|
|
||||||
%% description = Detailed description of the Better Enums API.
|
%% description = Detailed description of the Better Enums API.
|
||||||
|
|||||||
@ -1,15 +0,0 @@
|
|||||||
## Contact
|
|
||||||
|
|
||||||
- Send me an email: [antonbachin@yahoo.com](mailto:antonbachin@yahoo.com).
|
|
||||||
- Visit the [GitHub]($repo) project to open an issue or get a development
|
|
||||||
version.
|
|
||||||
|
|
||||||
I'm happy to hear any feedback. If you have any trouble using the library or
|
|
||||||
parsing the documentation, please don't hesitate to let me know. I'd also be
|
|
||||||
interested to hear about your use case, if you are willing to share :)
|
|
||||||
|
|
||||||
And, if you find this library helpful, give it a star on GitHub to let me know
|
|
||||||
you use it :)
|
|
||||||
|
|
||||||
%% description =
|
|
||||||
Contact information for Better Enums bugs, issues, support, and feedback.
|
|
||||||
68
doc/LICENSE
68
doc/LICENSE
@ -1,68 +0,0 @@
|
|||||||
Better Enums is distributed under the terms of the 2-clause BSD license. Its
|
|
||||||
text is given below.
|
|
||||||
|
|
||||||
|
|
||||||
Copyright (c) 2012-2019, Anton Bachin
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation and/or
|
|
||||||
other materials provided with the distribution.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Better Enums uses the mistune library as part of its documentation generator.
|
|
||||||
Its web address and license are given below.
|
|
||||||
|
|
||||||
|
|
||||||
http://mistune.readthedocs.org/en/latest/
|
|
||||||
|
|
||||||
|
|
||||||
Copyright (c) 2014 - 2015, Hsiaoming Yang
|
|
||||||
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without modification,
|
|
||||||
are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
* Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer in the documentation and/or
|
|
||||||
other materials provided with the distribution.
|
|
||||||
|
|
||||||
* Neither the name of the creator nor the names of its contributors may be used
|
|
||||||
to endorse or promote products derived from this software without specific prior
|
|
||||||
written permission.
|
|
||||||
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
||||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
||||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
||||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
||||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
||||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
||||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
@ -88,3 +88,15 @@ Here they are:
|
|||||||
|
|
||||||
%% description = Optional Better Enums features, disabled by default for
|
%% description = Optional Better Enums features, disabled by default for
|
||||||
performance or compatibility reasons.
|
performance or compatibility reasons.
|
||||||
|
|
||||||
|
### Injecting tokens
|
||||||
|
|
||||||
|
You can define `BETTER_ENUMS_CLASS_ATTRIBUTE` before declaring a Better Enum, to
|
||||||
|
inject tokens into the class declaration. For example, in
|
||||||
|
|
||||||
|
#define <em>BETTER_ENUMS_CLASS_ATTRIBUTE</em> <em>__attribute__(foo)</em>
|
||||||
|
<em>BETTER_ENUM</em>(<em>Channel</em>, int, Red, Green, Blue)
|
||||||
|
|
||||||
|
The resulting enum declaration will begin with
|
||||||
|
|
||||||
|
class <em>__attribute__(foo)</em> <em>Channel</em> {
|
||||||
|
|||||||
@ -19,7 +19,7 @@ pre {
|
|||||||
background-color: #477093;
|
background-color: #477093;
|
||||||
padding: 1.5em 20px;
|
padding: 1.5em 20px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
overflow: scroll;
|
overflow: auto;
|
||||||
color: rgba(255, 255, 255, 0.6);
|
color: rgba(255, 255, 255, 0.6);
|
||||||
font-size: 78%;
|
font-size: 78%;
|
||||||
max-width: 84ex;
|
max-width: 84ex;
|
||||||
|
|||||||
@ -69,10 +69,7 @@ It's what built-in enums ought to support. Better Enums simply adds the missing
|
|||||||
features. And, it is based on the best known techniques, thoroughly tested,
|
features. And, it is based on the best known techniques, thoroughly tested,
|
||||||
fast, portable, and documented exhaustively.
|
fast, portable, and documented exhaustively.
|
||||||
|
|
||||||
To use it, just include <code>enum.h</code>.
|
To use it, just include <code>enum.h</code> and begin the
|
||||||
|
|
||||||
Try it live online in
|
|
||||||
[Wandbox](http://melpon.org/wandbox/permlink/6kFervewqeDsNAGu), or begin the
|
|
||||||
[tutorial](${prefix}tutorial/HelloWorld.html)!
|
[tutorial](${prefix}tutorial/HelloWorld.html)!
|
||||||
|
|
||||||
<div class="hack"></div>
|
<div class="hack"></div>
|
||||||
|
|||||||
2
doc/template/footer.tmpl
vendored
2
doc/template/footer.tmpl
vendored
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
<footer>
|
<footer>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
Copyright © 2015-2019 Anton Bachin. Released under the BSD 2-clause
|
Copyright © 2015-2024 Anton Bachin. Released under the BSD 2-clause
|
||||||
license. See
|
license. See
|
||||||
<a href="https://github.com/aantron/better-enums/blob/$ref/doc/LICENSE">
|
<a href="https://github.com/aantron/better-enums/blob/$ref/doc/LICENSE">
|
||||||
LICENSE</a>.
|
LICENSE</a>.
|
||||||
|
|||||||
1
doc/template/header.tmpl
vendored
1
doc/template/header.tmpl
vendored
@ -25,7 +25,6 @@ $ga
|
|||||||
<a href="${prefix}index.html">Home</a>
|
<a href="${prefix}index.html">Home</a>
|
||||||
<a href="${prefix}tutorial/HelloWorld.html">Tutorial</a>
|
<a href="${prefix}tutorial/HelloWorld.html">Tutorial</a>
|
||||||
<a href="${prefix}ApiReference.html">Reference</a>
|
<a href="${prefix}ApiReference.html">Reference</a>
|
||||||
<a href="${prefix}Contact.html">Contact</a>
|
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
|||||||
2
doc/template/ref.tmpl
vendored
2
doc/template/ref.tmpl
vendored
@ -1 +1 @@
|
|||||||
0.11.2
|
0.11.3
|
||||||
2
doc/template/version.tmpl
vendored
2
doc/template/version.tmpl
vendored
@ -1 +1 @@
|
|||||||
0.11.2
|
0.11.3
|
||||||
80
enum.h
80
enum.h
@ -1,6 +1,7 @@
|
|||||||
// This file is part of Better Enums, released under the BSD 2-clause license.
|
// This file is part of Better Enums, released under the BSD 2-clause license.
|
||||||
// See doc/LICENSE for details, or visit http://github.com/aantron/better-enums.
|
// See LICENSE.md for details, or visit http://github.com/aantron/better-enums.
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifndef BETTER_ENUMS_ENUM_H
|
#ifndef BETTER_ENUMS_ENUM_H
|
||||||
@ -14,6 +15,48 @@
|
|||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
|
||||||
|
// in-line, non-#pragma warning handling
|
||||||
|
// not supported in very old compilers (namely gcc 4.4 or less)
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# ifdef __clang__
|
||||||
|
# define BETTER_ENUMS_IGNORE_OLD_CAST_HEADER _Pragma("clang diagnostic push")
|
||||||
|
# define BETTER_ENUMS_IGNORE_OLD_CAST_BEGIN _Pragma("clang diagnostic ignored \"-Wold-style-cast\"")
|
||||||
|
# define BETTER_ENUMS_IGNORE_OLD_CAST_END _Pragma("clang diagnostic pop")
|
||||||
|
# define BETTER_ENUMS_IGNORE_ATTRIBUTES_HEADER
|
||||||
|
# define BETTER_ENUMS_IGNORE_ATTRIBUTES_BEGIN
|
||||||
|
# define BETTER_ENUMS_IGNORE_ATTRIBUTES_END
|
||||||
|
# else
|
||||||
|
# define BETTER_ENUMS_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100)
|
||||||
|
# if BETTER_ENUMS_GCC_VERSION > 40400
|
||||||
|
# define BETTER_ENUMS_IGNORE_OLD_CAST_HEADER _Pragma("GCC diagnostic push")
|
||||||
|
# define BETTER_ENUMS_IGNORE_OLD_CAST_BEGIN _Pragma("GCC diagnostic ignored \"-Wold-style-cast\"")
|
||||||
|
# define BETTER_ENUMS_IGNORE_OLD_CAST_END _Pragma("GCC diagnostic pop")
|
||||||
|
# if (BETTER_ENUMS_GCC_VERSION >= 70300)
|
||||||
|
# define BETTER_ENUMS_IGNORE_ATTRIBUTES_HEADER _Pragma("GCC diagnostic push")
|
||||||
|
# define BETTER_ENUMS_IGNORE_ATTRIBUTES_BEGIN _Pragma("GCC diagnostic ignored \"-Wattributes\"")
|
||||||
|
# define BETTER_ENUMS_IGNORE_ATTRIBUTES_END _Pragma("GCC diagnostic pop")
|
||||||
|
# else
|
||||||
|
# define BETTER_ENUMS_IGNORE_ATTRIBUTES_HEADER
|
||||||
|
# define BETTER_ENUMS_IGNORE_ATTRIBUTES_BEGIN
|
||||||
|
# define BETTER_ENUMS_IGNORE_ATTRIBUTES_END
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# define BETTER_ENUMS_IGNORE_OLD_CAST_HEADER
|
||||||
|
# define BETTER_ENUMS_IGNORE_OLD_CAST_BEGIN
|
||||||
|
# define BETTER_ENUMS_IGNORE_OLD_CAST_END
|
||||||
|
# define BETTER_ENUMS_IGNORE_ATTRIBUTES_HEADER
|
||||||
|
# define BETTER_ENUMS_IGNORE_ATTRIBUTES_BEGIN
|
||||||
|
# define BETTER_ENUMS_IGNORE_ATTRIBUTES_END
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
#else // empty definitions for compilers that don't support _Pragma
|
||||||
|
# define BETTER_ENUMS_IGNORE_OLD_CAST_HEADER
|
||||||
|
# define BETTER_ENUMS_IGNORE_OLD_CAST_BEGIN
|
||||||
|
# define BETTER_ENUMS_IGNORE_OLD_CAST_END
|
||||||
|
# define BETTER_ENUMS_IGNORE_ATTRIBUTES_HEADER
|
||||||
|
# define BETTER_ENUMS_IGNORE_ATTRIBUTES_BEGIN
|
||||||
|
# define BETTER_ENUMS_IGNORE_ATTRIBUTES_END
|
||||||
|
#endif
|
||||||
|
|
||||||
// Feature detection.
|
// Feature detection.
|
||||||
|
|
||||||
@ -364,6 +407,8 @@ continue_with(T, U value) { return value; }
|
|||||||
|
|
||||||
// Values array declaration helper.
|
// Values array declaration helper.
|
||||||
|
|
||||||
|
//! Get intrinsic value of an (Enum::value) by taking advantage of
|
||||||
|
// C-conversion's parentheses priority
|
||||||
template <typename EnumType>
|
template <typename EnumType>
|
||||||
struct _eat_assign {
|
struct _eat_assign {
|
||||||
explicit BETTER_ENUMS_CONSTEXPR_ _eat_assign(EnumType value) : _value(value)
|
explicit BETTER_ENUMS_CONSTEXPR_ _eat_assign(EnumType value) : _value(value)
|
||||||
@ -583,6 +628,10 @@ constexpr const char *_final_ ## index = \
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef BETTER_ENUMS_CLASS_ATTRIBUTE
|
||||||
|
# define BETTER_ENUMS_CLASS_ATTRIBUTE
|
||||||
|
#endif
|
||||||
|
|
||||||
#define BETTER_ENUMS_TYPE(SetUnderlyingType, SwitchType, GenerateSwitchType, \
|
#define BETTER_ENUMS_TYPE(SetUnderlyingType, SwitchType, GenerateSwitchType, \
|
||||||
GenerateStrings, ToStringConstexpr, \
|
GenerateStrings, ToStringConstexpr, \
|
||||||
DeclareInitialize, DefineInitialize, CallInitialize, \
|
DeclareInitialize, DefineInitialize, CallInitialize, \
|
||||||
@ -594,7 +643,7 @@ BETTER_ENUMS_ID(GenerateSwitchType(Underlying, __VA_ARGS__)) \
|
|||||||
\
|
\
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
class Enum { \
|
class BETTER_ENUMS_CLASS_ATTRIBUTE Enum { \
|
||||||
private: \
|
private: \
|
||||||
typedef ::better_enums::optional<Enum> _optional; \
|
typedef ::better_enums::optional<Enum> _optional; \
|
||||||
typedef ::better_enums::optional<std::size_t> _optional_index; \
|
typedef ::better_enums::optional<std::size_t> _optional_index; \
|
||||||
@ -624,12 +673,12 @@ class Enum { \
|
|||||||
\
|
\
|
||||||
BETTER_ENUMS_CONSTEXPR_ std::size_t _to_index() const; \
|
BETTER_ENUMS_CONSTEXPR_ std::size_t _to_index() const; \
|
||||||
BETTER_ENUMS_IF_EXCEPTIONS( \
|
BETTER_ENUMS_IF_EXCEPTIONS( \
|
||||||
BETTER_ENUMS_CONSTEXPR_ static Enum _from_index(std::size_t value); \
|
BETTER_ENUMS_CONSTEXPR_ static Enum _from_index(std::size_t index); \
|
||||||
) \
|
) \
|
||||||
BETTER_ENUMS_CONSTEXPR_ static Enum \
|
BETTER_ENUMS_CONSTEXPR_ static Enum \
|
||||||
_from_index_unchecked(std::size_t value); \
|
_from_index_unchecked(std::size_t index); \
|
||||||
BETTER_ENUMS_CONSTEXPR_ static _optional \
|
BETTER_ENUMS_CONSTEXPR_ static _optional \
|
||||||
_from_index_nothrow(std::size_t value); \
|
_from_index_nothrow(std::size_t index); \
|
||||||
\
|
\
|
||||||
ToStringConstexpr const char* _to_string() const; \
|
ToStringConstexpr const char* _to_string() const; \
|
||||||
BETTER_ENUMS_IF_EXCEPTIONS( \
|
BETTER_ENUMS_IF_EXCEPTIONS( \
|
||||||
@ -690,19 +739,25 @@ static ::better_enums::_initialize_at_program_start<Enum> \
|
|||||||
\
|
\
|
||||||
enum _putNamesInThisScopeAlso { __VA_ARGS__ }; \
|
enum _putNamesInThisScopeAlso { __VA_ARGS__ }; \
|
||||||
\
|
\
|
||||||
|
BETTER_ENUMS_IGNORE_OLD_CAST_HEADER \
|
||||||
|
BETTER_ENUMS_IGNORE_OLD_CAST_BEGIN \
|
||||||
BETTER_ENUMS_CONSTEXPR_ const Enum _value_array[] = \
|
BETTER_ENUMS_CONSTEXPR_ const Enum _value_array[] = \
|
||||||
{ BETTER_ENUMS_ID(BETTER_ENUMS_EAT_ASSIGN(Enum, __VA_ARGS__)) }; \
|
{ BETTER_ENUMS_ID(BETTER_ENUMS_EAT_ASSIGN(Enum, __VA_ARGS__)) }; \
|
||||||
|
BETTER_ENUMS_IGNORE_OLD_CAST_END \
|
||||||
\
|
\
|
||||||
BETTER_ENUMS_ID(GenerateStrings(Enum, __VA_ARGS__)) \
|
BETTER_ENUMS_ID(GenerateStrings(Enum, __VA_ARGS__)) \
|
||||||
\
|
\
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
|
BETTER_ENUMS_IGNORE_ATTRIBUTES_HEADER \
|
||||||
|
BETTER_ENUMS_IGNORE_ATTRIBUTES_BEGIN \
|
||||||
BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
|
BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
|
||||||
inline const Enum \
|
inline const Enum \
|
||||||
operator +(Enum::_enumerated enumerated) \
|
operator +(Enum::_enumerated enumerated) \
|
||||||
{ \
|
{ \
|
||||||
return static_cast<Enum>(enumerated); \
|
return static_cast<Enum>(enumerated); \
|
||||||
} \
|
} \
|
||||||
|
BETTER_ENUMS_IGNORE_ATTRIBUTES_END \
|
||||||
\
|
\
|
||||||
BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional_index \
|
BETTER_ENUMS_CONSTEXPR_ inline Enum::_optional_index \
|
||||||
Enum::_from_value_loop(Enum::_integral value, std::size_t index) \
|
Enum::_from_value_loop(Enum::_integral value, std::size_t index) \
|
||||||
@ -873,6 +928,8 @@ ToStringConstexpr inline Enum::_name_iterable Enum::_names() \
|
|||||||
\
|
\
|
||||||
DefineInitialize(Enum) \
|
DefineInitialize(Enum) \
|
||||||
\
|
\
|
||||||
|
BETTER_ENUMS_IGNORE_ATTRIBUTES_HEADER \
|
||||||
|
BETTER_ENUMS_IGNORE_ATTRIBUTES_BEGIN \
|
||||||
BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
|
BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
|
||||||
inline bool operator ==(const Enum &a, const Enum &b) \
|
inline bool operator ==(const Enum &a, const Enum &b) \
|
||||||
{ return a._to_integral() == b._to_integral(); } \
|
{ return a._to_integral() == b._to_integral(); } \
|
||||||
@ -896,6 +953,7 @@ inline bool operator >(const Enum &a, const Enum &b) \
|
|||||||
BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
|
BETTER_ENUMS_UNUSED BETTER_ENUMS_CONSTEXPR_ \
|
||||||
inline bool operator >=(const Enum &a, const Enum &b) \
|
inline bool operator >=(const Enum &a, const Enum &b) \
|
||||||
{ return a._to_integral() >= b._to_integral(); } \
|
{ return a._to_integral() >= b._to_integral(); } \
|
||||||
|
BETTER_ENUMS_IGNORE_ATTRIBUTES_END \
|
||||||
\
|
\
|
||||||
\
|
\
|
||||||
template <typename Char, typename Traits> \
|
template <typename Char, typename Traits> \
|
||||||
@ -1255,4 +1313,16 @@ BETTER_ENUMS_CONSTEXPR_ map<Enum, T> make_map(T (*f)(Enum))
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define BETTER_ENUMS_DECLARE_STD_HASH(type) \
|
||||||
|
namespace std { \
|
||||||
|
template <> struct hash<type> \
|
||||||
|
{ \
|
||||||
|
size_t operator()(const type &x) const \
|
||||||
|
{ \
|
||||||
|
return std::hash<size_t>()(x._to_integral()); \
|
||||||
|
} \
|
||||||
|
}; \
|
||||||
|
}
|
||||||
|
|
||||||
#endif // #ifndef BETTER_ENUMS_ENUM_H
|
#endif // #ifndef BETTER_ENUMS_ENUM_H
|
||||||
|
// clang-format on
|
||||||
|
|||||||
@ -31,7 +31,10 @@ BETTER_ENUM(Namespaced, short, One, Two)
|
|||||||
// be changed to be more precise in the future.
|
// be changed to be more precise in the future.
|
||||||
#ifdef BETTER_ENUMS_HAVE_CONSTEXPR_
|
#ifdef BETTER_ENUMS_HAVE_CONSTEXPR_
|
||||||
|
|
||||||
|
BETTER_ENUMS_DECLARE_STD_HASH(Channel)
|
||||||
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
// Type properties.
|
// Type properties.
|
||||||
static_assert_1(std::is_class<Channel>());
|
static_assert_1(std::is_class<Channel>());
|
||||||
@ -161,6 +164,24 @@ static_assert_1(same_string(Depth::_names()[0], "HighColor"));
|
|||||||
|
|
||||||
|
|
||||||
// Run-time testing.
|
// Run-time testing.
|
||||||
|
class HashTests : public CxxTest::TestSuite {
|
||||||
|
public:
|
||||||
|
void test_same_values()
|
||||||
|
{
|
||||||
|
#ifdef _ENUM_HAVE_CONSTEXPR
|
||||||
|
TS_ASSERT_EQUALS(
|
||||||
|
std::hash<Channel>().operator()(Channel::Red),
|
||||||
|
std::hash<int>().operator()(0));
|
||||||
|
TS_ASSERT_EQUALS(
|
||||||
|
std::hash<Channel>().operator()(Channel::Green),
|
||||||
|
std::hash<int>().operator()(1));
|
||||||
|
TS_ASSERT_EQUALS(
|
||||||
|
std::hash<Channel>().operator()(Channel::Blue),
|
||||||
|
std::hash<int>().operator()(2));
|
||||||
|
#endif // #ifdef _ENUM_HAVE_CONSTEXPR
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
class EnumTests : public CxxTest::TestSuite {
|
class EnumTests : public CxxTest::TestSuite {
|
||||||
public:
|
public:
|
||||||
void test_constant_values()
|
void test_constant_values()
|
||||||
@ -313,59 +334,59 @@ class EnumTests : public CxxTest::TestSuite {
|
|||||||
+test::Namespaced::One);
|
+test::Namespaced::One);
|
||||||
TS_ASSERT_EQUALS(strcmp(*test::Namespaced::_names().begin(), "One"), 0);
|
TS_ASSERT_EQUALS(strcmp(*test::Namespaced::_names().begin(), "One"), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_to_index()
|
void test_to_index()
|
||||||
{
|
{
|
||||||
TS_ASSERT_EQUALS((+Channel::Red)._to_index(), 0);
|
TS_ASSERT_EQUALS((+Channel::Red)._to_index(), 0);
|
||||||
TS_ASSERT_EQUALS((+Channel::Green)._to_index(), 1);
|
TS_ASSERT_EQUALS((+Channel::Green)._to_index(), 1);
|
||||||
TS_ASSERT_EQUALS((+Channel::Blue)._to_index(), 2);
|
TS_ASSERT_EQUALS((+Channel::Blue)._to_index(), 2);
|
||||||
|
|
||||||
TS_ASSERT_EQUALS((+Depth::HighColor)._to_index(), 0);
|
TS_ASSERT_EQUALS((+Depth::HighColor)._to_index(), 0);
|
||||||
TS_ASSERT_EQUALS((+Depth::TrueColor)._to_index(), 1);
|
TS_ASSERT_EQUALS((+Depth::TrueColor)._to_index(), 1);
|
||||||
|
|
||||||
TS_ASSERT_EQUALS((+Compression::None)._to_index(), 0);
|
TS_ASSERT_EQUALS((+Compression::None)._to_index(), 0);
|
||||||
TS_ASSERT_EQUALS((+Compression::Huffman)._to_index(), 1);
|
TS_ASSERT_EQUALS((+Compression::Huffman)._to_index(), 1);
|
||||||
// TS_ASSERT_EQUALS((+Compression::Default)._to_index(), 2); // This won't pass as Compression::Huffman == Compression::Default
|
// TS_ASSERT_EQUALS((+Compression::Default)._to_index(), 2); // This won't pass as Compression::Huffman == Compression::Default
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_from_index()
|
void test_from_index()
|
||||||
{
|
{
|
||||||
TS_ASSERT_EQUALS((+Channel::Red), Channel::_from_index(0));
|
TS_ASSERT_EQUALS((+Channel::Red), Channel::_from_index(0));
|
||||||
TS_ASSERT_EQUALS((+Channel::Green), Channel::_from_index(1));
|
TS_ASSERT_EQUALS((+Channel::Green), Channel::_from_index(1));
|
||||||
TS_ASSERT_EQUALS((+Channel::Blue), Channel::_from_index(2));
|
TS_ASSERT_EQUALS((+Channel::Blue), Channel::_from_index(2));
|
||||||
TS_ASSERT_THROWS(Channel::_from_index(42), std::runtime_error);
|
TS_ASSERT_THROWS(Channel::_from_index(42), std::runtime_error);
|
||||||
|
|
||||||
TS_ASSERT_EQUALS((+Depth::HighColor), Depth::_from_index(0));
|
TS_ASSERT_EQUALS((+Depth::HighColor), Depth::_from_index(0));
|
||||||
TS_ASSERT_EQUALS((+Depth::TrueColor), Depth::_from_index(1));
|
TS_ASSERT_EQUALS((+Depth::TrueColor), Depth::_from_index(1));
|
||||||
TS_ASSERT_THROWS(Depth::_from_index(42), std::runtime_error);
|
TS_ASSERT_THROWS(Depth::_from_index(42), std::runtime_error);
|
||||||
|
|
||||||
TS_ASSERT_EQUALS((+Compression::None), Compression::_from_index(0));
|
TS_ASSERT_EQUALS((+Compression::None), Compression::_from_index(0));
|
||||||
TS_ASSERT_EQUALS((+Compression::Huffman), Compression::_from_index(1));
|
TS_ASSERT_EQUALS((+Compression::Huffman), Compression::_from_index(1));
|
||||||
TS_ASSERT_EQUALS((+Compression::Default), Compression::_from_index(2));
|
TS_ASSERT_EQUALS((+Compression::Default), Compression::_from_index(2));
|
||||||
TS_ASSERT_THROWS(Compression::_from_index(42), std::runtime_error);
|
TS_ASSERT_THROWS(Compression::_from_index(42), std::runtime_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_from_index_nothrow()
|
void test_from_index_nothrow()
|
||||||
{
|
{
|
||||||
better_enums::optional<Channel> maybe_channel = Channel::_from_index_nothrow(0);
|
better_enums::optional<Channel> maybe_channel = Channel::_from_index_nothrow(0);
|
||||||
TS_ASSERT(maybe_channel);
|
TS_ASSERT(maybe_channel);
|
||||||
TS_ASSERT_EQUALS(*maybe_channel, +Channel::Red);
|
TS_ASSERT_EQUALS(*maybe_channel, +Channel::Red);
|
||||||
|
|
||||||
maybe_channel = Channel::_from_index_nothrow(1);
|
maybe_channel = Channel::_from_index_nothrow(1);
|
||||||
TS_ASSERT(maybe_channel);
|
TS_ASSERT(maybe_channel);
|
||||||
TS_ASSERT_EQUALS(*maybe_channel, +Channel::Green);
|
TS_ASSERT_EQUALS(*maybe_channel, +Channel::Green);
|
||||||
|
|
||||||
maybe_channel = Channel::_from_index_nothrow(2);
|
maybe_channel = Channel::_from_index_nothrow(2);
|
||||||
TS_ASSERT(maybe_channel);
|
TS_ASSERT(maybe_channel);
|
||||||
TS_ASSERT_EQUALS(*maybe_channel, +Channel::Blue);
|
TS_ASSERT_EQUALS(*maybe_channel, +Channel::Blue);
|
||||||
|
|
||||||
maybe_channel = Channel::_from_index_nothrow(45);
|
maybe_channel = Channel::_from_index_nothrow(45);
|
||||||
TS_ASSERT(!maybe_channel);
|
TS_ASSERT(!maybe_channel);
|
||||||
|
|
||||||
better_enums::optional<Depth> maybe_depth = Depth::_from_index_nothrow(0);
|
better_enums::optional<Depth> maybe_depth = Depth::_from_index_nothrow(0);
|
||||||
TS_ASSERT(maybe_depth);
|
TS_ASSERT(maybe_depth);
|
||||||
TS_ASSERT_EQUALS(*maybe_depth, +Depth::HighColor);
|
TS_ASSERT_EQUALS(*maybe_depth, +Depth::HighColor);
|
||||||
|
|
||||||
maybe_depth = Depth::_from_index_nothrow(1);
|
maybe_depth = Depth::_from_index_nothrow(1);
|
||||||
TS_ASSERT(maybe_depth);
|
TS_ASSERT(maybe_depth);
|
||||||
TS_ASSERT_EQUALS(*maybe_depth, +Depth::TrueColor);
|
TS_ASSERT_EQUALS(*maybe_depth, +Depth::TrueColor);
|
||||||
@ -376,11 +397,11 @@ class EnumTests : public CxxTest::TestSuite {
|
|||||||
better_enums::optional<Compression> maybe_compression = Compression::_from_index_nothrow(0);
|
better_enums::optional<Compression> maybe_compression = Compression::_from_index_nothrow(0);
|
||||||
TS_ASSERT(maybe_compression);
|
TS_ASSERT(maybe_compression);
|
||||||
TS_ASSERT_EQUALS(*maybe_compression, +Compression::None);
|
TS_ASSERT_EQUALS(*maybe_compression, +Compression::None);
|
||||||
|
|
||||||
maybe_compression = Compression::_from_index_nothrow(1);
|
maybe_compression = Compression::_from_index_nothrow(1);
|
||||||
TS_ASSERT(maybe_compression);
|
TS_ASSERT(maybe_compression);
|
||||||
TS_ASSERT_EQUALS(*maybe_compression, +Compression::Huffman);
|
TS_ASSERT_EQUALS(*maybe_compression, +Compression::Huffman);
|
||||||
|
|
||||||
maybe_compression = Compression::_from_index_nothrow(2);
|
maybe_compression = Compression::_from_index_nothrow(2);
|
||||||
TS_ASSERT(maybe_compression);
|
TS_ASSERT(maybe_compression);
|
||||||
TS_ASSERT_EQUALS(*maybe_compression, +Compression::Default);
|
TS_ASSERT_EQUALS(*maybe_compression, +Compression::Default);
|
||||||
@ -388,17 +409,17 @@ class EnumTests : public CxxTest::TestSuite {
|
|||||||
maybe_compression = Compression::_from_index_nothrow(45);
|
maybe_compression = Compression::_from_index_nothrow(45);
|
||||||
TS_ASSERT(!maybe_compression);
|
TS_ASSERT(!maybe_compression);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_from_index_unchecked()
|
void test_from_index_unchecked()
|
||||||
{
|
{
|
||||||
|
|
||||||
TS_ASSERT_EQUALS((+Channel::Red), Channel::_from_index_unchecked(0));
|
TS_ASSERT_EQUALS((+Channel::Red), Channel::_from_index_unchecked(0));
|
||||||
TS_ASSERT_EQUALS((+Channel::Green), Channel::_from_index_unchecked(1));
|
TS_ASSERT_EQUALS((+Channel::Green), Channel::_from_index_unchecked(1));
|
||||||
TS_ASSERT_EQUALS((+Channel::Blue), Channel::_from_index_unchecked(2));
|
TS_ASSERT_EQUALS((+Channel::Blue), Channel::_from_index_unchecked(2));
|
||||||
|
|
||||||
TS_ASSERT_EQUALS((+Depth::HighColor), Depth::_from_index_unchecked(0));
|
TS_ASSERT_EQUALS((+Depth::HighColor), Depth::_from_index_unchecked(0));
|
||||||
TS_ASSERT_EQUALS((+Depth::TrueColor), Depth::_from_index_unchecked(1));
|
TS_ASSERT_EQUALS((+Depth::TrueColor), Depth::_from_index_unchecked(1));
|
||||||
|
|
||||||
TS_ASSERT_EQUALS((+Compression::None), Compression::_from_index_unchecked(0));
|
TS_ASSERT_EQUALS((+Compression::None), Compression::_from_index_unchecked(0));
|
||||||
TS_ASSERT_EQUALS((+Compression::Huffman), Compression::_from_index_unchecked(1));
|
TS_ASSERT_EQUALS((+Compression::Huffman), Compression::_from_index_unchecked(1));
|
||||||
TS_ASSERT_EQUALS((+Compression::Default), Compression::_from_index_unchecked(2));
|
TS_ASSERT_EQUALS((+Compression::Default), Compression::_from_index_unchecked(2));
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user