First!
This commit is contained in:
commit
f5b60562e8
|
@ -0,0 +1,5 @@
|
||||||
|
bin/
|
||||||
|
obj/
|
||||||
|
xmr-stak-amd.layout
|
||||||
|
xmr-stak-amd.depend
|
||||||
|
config-debug.txt
|
|
@ -0,0 +1,35 @@
|
||||||
|
project(xmr-stak-amd)
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 2.8.10)
|
||||||
|
|
||||||
|
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
|
||||||
|
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1)
|
||||||
|
message(FATAL_ERROR "GCC version must be at least 5.1!")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_library(MHTD NAMES microhttpd)
|
||||||
|
if("${MHTD}" STREQUAL "MHTD-NOTFOUND")
|
||||||
|
message(FATAL_ERROR "libmicrohttpd is required")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#set(CMAKE_VERBOSE_MAKEFILE ON)
|
||||||
|
set(CMAKE_CONFIGURATION_TYPES "RELEASE;STATIC")
|
||||||
|
if("${CMAKE_BUILD_TYPE}" STREQUAL "")
|
||||||
|
set(CMAKE_BUILD_TYPE RELEASE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_C_FLAGS "-DNDEBUG -march=westmere -O3 -m64 -s")
|
||||||
|
set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} -std=c++11")
|
||||||
|
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS_RELSEASE "")
|
||||||
|
set(CMAKE_EXE_LINKER_FLAGS_STATIC "-static-libgcc -static-libstdc++")
|
||||||
|
|
||||||
|
set(EXECUTABLE_OUTPUT_PATH "bin")
|
||||||
|
|
||||||
|
file(GLOB SOURCES "crypto/*.c" "crypto/*.cpp" "amd_gpu/*.c" "*.cpp")
|
||||||
|
|
||||||
|
add_executable(xmr-stak-amd ${SOURCES})
|
||||||
|
target_link_libraries(xmr-stak-amd pthread microhttpd OpenCL)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,620 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The GNU General Public License is a free, copyleft license for
|
||||||
|
software and other kinds of works.
|
||||||
|
|
||||||
|
The licenses for most software and other practical works are designed
|
||||||
|
to take away your freedom to share and change the works. By contrast,
|
||||||
|
the GNU General Public License is intended to guarantee your freedom to
|
||||||
|
share and change all versions of a program--to make sure it remains free
|
||||||
|
software for all its users. We, the Free Software Foundation, use the
|
||||||
|
GNU General Public License for most of our software; it applies also to
|
||||||
|
any other work released this way by its authors. You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
them if you wish), that you receive source code or can get it if you
|
||||||
|
want it, that you can change the software or use pieces of it in new
|
||||||
|
free programs, and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to prevent others from denying you
|
||||||
|
these rights or asking you to surrender the rights. Therefore, you have
|
||||||
|
certain responsibilities if you distribute copies of the software, or if
|
||||||
|
you modify it: responsibilities to respect the freedom of others.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must pass on to the recipients the same
|
||||||
|
freedoms that you received. You must make sure that they, too, receive
|
||||||
|
or can get the source code. And you must show them these terms so they
|
||||||
|
know their rights.
|
||||||
|
|
||||||
|
Developers that use the GNU GPL protect your rights with two steps:
|
||||||
|
(1) assert copyright on the software, and (2) offer you this License
|
||||||
|
giving you legal permission to copy, distribute and/or modify it.
|
||||||
|
|
||||||
|
For the developers' and authors' protection, the GPL clearly explains
|
||||||
|
that there is no warranty for this free software. For both users' and
|
||||||
|
authors' sake, the GPL requires that modified versions be marked as
|
||||||
|
changed, so that their problems will not be attributed erroneously to
|
||||||
|
authors of previous versions.
|
||||||
|
|
||||||
|
Some devices are designed to deny users access to install or run
|
||||||
|
modified versions of the software inside them, although the manufacturer
|
||||||
|
can do so. This is fundamentally incompatible with the aim of
|
||||||
|
protecting users' freedom to change the software. The systematic
|
||||||
|
pattern of such abuse occurs in the area of products for individuals to
|
||||||
|
use, which is precisely where it is most unacceptable. Therefore, we
|
||||||
|
have designed this version of the GPL to prohibit the practice for those
|
||||||
|
products. If such problems arise substantially in other domains, we
|
||||||
|
stand ready to extend this provision to those domains in future versions
|
||||||
|
of the GPL, as needed to protect the freedom of users.
|
||||||
|
|
||||||
|
Finally, every program is threatened constantly by software patents.
|
||||||
|
States should not allow patents to restrict development and use of
|
||||||
|
software on general-purpose computers, but in those that do, we wish to
|
||||||
|
avoid the special danger that patents applied to a free program could
|
||||||
|
make it effectively proprietary. To prevent this, the GPL assures that
|
||||||
|
patents cannot be used to render the program non-free.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
0. Definitions.
|
||||||
|
|
||||||
|
"This License" refers to version 3 of the GNU General Public License.
|
||||||
|
|
||||||
|
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||||
|
works, such as semiconductor masks.
|
||||||
|
|
||||||
|
"The Program" refers to any copyrightable work licensed under this
|
||||||
|
License. Each licensee is addressed as "you". "Licensees" and
|
||||||
|
"recipients" may be individuals or organizations.
|
||||||
|
|
||||||
|
To "modify" a work means to copy from or adapt all or part of the work
|
||||||
|
in a fashion requiring copyright permission, other than the making of an
|
||||||
|
exact copy. The resulting work is called a "modified version" of the
|
||||||
|
earlier work or a work "based on" the earlier work.
|
||||||
|
|
||||||
|
A "covered work" means either the unmodified Program or a work based
|
||||||
|
on the Program.
|
||||||
|
|
||||||
|
To "propagate" a work means to do anything with it that, without
|
||||||
|
permission, would make you directly or secondarily liable for
|
||||||
|
infringement under applicable copyright law, except executing it on a
|
||||||
|
computer or modifying a private copy. Propagation includes copying,
|
||||||
|
distribution (with or without modification), making available to the
|
||||||
|
public, and in some countries other activities as well.
|
||||||
|
|
||||||
|
To "convey" a work means any kind of propagation that enables other
|
||||||
|
parties to make or receive copies. Mere interaction with a user through
|
||||||
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
|
to the extent that it includes a convenient and prominently visible
|
||||||
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
|
tells the user that there is no warranty for the work (except to the
|
||||||
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
work under this License, and how to view a copy of this License. If
|
||||||
|
the interface presents a list of user commands or options, such as a
|
||||||
|
menu, a prominent item in the list meets this criterion.
|
||||||
|
|
||||||
|
1. Source Code.
|
||||||
|
|
||||||
|
The "source code" for a work means the preferred form of the work
|
||||||
|
for making modifications to it. "Object code" means any non-source
|
||||||
|
form of a work.
|
||||||
|
|
||||||
|
A "Standard Interface" means an interface that either is an official
|
||||||
|
standard defined by a recognized standards body, or, in the case of
|
||||||
|
interfaces specified for a particular programming language, one that
|
||||||
|
is widely used among developers working in that language.
|
||||||
|
|
||||||
|
The "System Libraries" of an executable work include anything, other
|
||||||
|
than the work as a whole, that (a) is included in the normal form of
|
||||||
|
packaging a Major Component, but which is not part of that Major
|
||||||
|
Component, and (b) serves only to enable use of the work with that
|
||||||
|
Major Component, or to implement a Standard Interface for which an
|
||||||
|
implementation is available to the public in source code form. A
|
||||||
|
"Major Component", in this context, means a major essential component
|
||||||
|
(kernel, window system, and so on) of the specific operating system
|
||||||
|
(if any) on which the executable work runs, or a compiler used to
|
||||||
|
produce the work, or an object code interpreter used to run it.
|
||||||
|
|
||||||
|
The "Corresponding Source" for a work in object code form means all
|
||||||
|
the source code needed to generate, install, and (for an executable
|
||||||
|
work) run the object code and to modify the work, including scripts to
|
||||||
|
control those activities. However, it does not include the work's
|
||||||
|
System Libraries, or general-purpose tools or generally available free
|
||||||
|
programs which are used unmodified in performing those activities but
|
||||||
|
which are not part of the work. For example, Corresponding Source
|
||||||
|
includes interface definition files associated with source files for
|
||||||
|
the work, and the source code for shared libraries and dynamically
|
||||||
|
linked subprograms that the work is specifically designed to require,
|
||||||
|
such as by intimate data communication or control flow between those
|
||||||
|
subprograms and other parts of the work.
|
||||||
|
|
||||||
|
The Corresponding Source need not include anything that users
|
||||||
|
can regenerate automatically from other parts of the Corresponding
|
||||||
|
Source.
|
||||||
|
|
||||||
|
The Corresponding Source for a work in source code form is that
|
||||||
|
same work.
|
||||||
|
|
||||||
|
2. Basic Permissions.
|
||||||
|
|
||||||
|
All rights granted under this License are granted for the term of
|
||||||
|
copyright on the Program, and are irrevocable provided the stated
|
||||||
|
conditions are met. This License explicitly affirms your unlimited
|
||||||
|
permission to run the unmodified Program. The output from running a
|
||||||
|
covered work is covered by this License only if the output, given its
|
||||||
|
content, constitutes a covered work. This License acknowledges your
|
||||||
|
rights of fair use or other equivalent, as provided by copyright law.
|
||||||
|
|
||||||
|
You may make, run and propagate covered works that you do not
|
||||||
|
convey, without conditions so long as your license otherwise remains
|
||||||
|
in force. You may convey covered works to others for the sole purpose
|
||||||
|
of having them make modifications exclusively for you, or provide you
|
||||||
|
with facilities for running those works, provided that you comply with
|
||||||
|
the terms of this License in conveying all material for which you do
|
||||||
|
not control copyright. Those thus making or running the covered works
|
||||||
|
for you must do so exclusively on your behalf, under your direction
|
||||||
|
and control, on terms that prohibit them from making any copies of
|
||||||
|
your copyrighted material outside their relationship with you.
|
||||||
|
|
||||||
|
Conveying under any other circumstances is permitted solely under
|
||||||
|
the conditions stated below. Sublicensing is not allowed; section 10
|
||||||
|
makes it unnecessary.
|
||||||
|
|
||||||
|
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||||
|
|
||||||
|
No covered work shall be deemed part of an effective technological
|
||||||
|
measure under any applicable law fulfilling obligations under article
|
||||||
|
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||||
|
similar laws prohibiting or restricting circumvention of such
|
||||||
|
measures.
|
||||||
|
|
||||||
|
When you convey a covered work, you waive any legal power to forbid
|
||||||
|
circumvention of technological measures to the extent such circumvention
|
||||||
|
is effected by exercising rights under this License with respect to
|
||||||
|
the covered work, and you disclaim any intention to limit operation or
|
||||||
|
modification of the work as a means of enforcing, against the work's
|
||||||
|
users, your or third parties' legal rights to forbid circumvention of
|
||||||
|
technological measures.
|
||||||
|
|
||||||
|
4. Conveying Verbatim Copies.
|
||||||
|
|
||||||
|
You may convey verbatim copies of the Program's source code as you
|
||||||
|
receive it, in any medium, provided that you conspicuously and
|
||||||
|
appropriately publish on each copy an appropriate copyright notice;
|
||||||
|
keep intact all notices stating that this License and any
|
||||||
|
non-permissive terms added in accord with section 7 apply to the code;
|
||||||
|
keep intact all notices of the absence of any warranty; and give all
|
||||||
|
recipients a copy of this License along with the Program.
|
||||||
|
|
||||||
|
You may charge any price or no price for each copy that you convey,
|
||||||
|
and you may offer support or warranty protection for a fee.
|
||||||
|
|
||||||
|
5. Conveying Modified Source Versions.
|
||||||
|
|
||||||
|
You may convey a work based on the Program, or the modifications to
|
||||||
|
produce it from the Program, in the form of source code under the
|
||||||
|
terms of section 4, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) The work must carry prominent notices stating that you modified
|
||||||
|
it, and giving a relevant date.
|
||||||
|
|
||||||
|
b) The work must carry prominent notices stating that it is
|
||||||
|
released under this License and any conditions added under section
|
||||||
|
7. This requirement modifies the requirement in section 4 to
|
||||||
|
"keep intact all notices".
|
||||||
|
|
||||||
|
c) You must license the entire work, as a whole, under this
|
||||||
|
License to anyone who comes into possession of a copy. This
|
||||||
|
License will therefore apply, along with any applicable section 7
|
||||||
|
additional terms, to the whole of the work, and all its parts,
|
||||||
|
regardless of how they are packaged. This License gives no
|
||||||
|
permission to license the work in any other way, but it does not
|
||||||
|
invalidate such permission if you have separately received it.
|
||||||
|
|
||||||
|
d) If the work has interactive user interfaces, each must display
|
||||||
|
Appropriate Legal Notices; however, if the Program has interactive
|
||||||
|
interfaces that do not display Appropriate Legal Notices, your
|
||||||
|
work need not make them do so.
|
||||||
|
|
||||||
|
A compilation of a covered work with other separate and independent
|
||||||
|
works, which are not by their nature extensions of the covered work,
|
||||||
|
and which are not combined with it such as to form a larger program,
|
||||||
|
in or on a volume of a storage or distribution medium, is called an
|
||||||
|
"aggregate" if the compilation and its resulting copyright are not
|
||||||
|
used to limit the access or legal rights of the compilation's users
|
||||||
|
beyond what the individual works permit. Inclusion of a covered work
|
||||||
|
in an aggregate does not cause this License to apply to the other
|
||||||
|
parts of the aggregate.
|
||||||
|
|
||||||
|
6. Conveying Non-Source Forms.
|
||||||
|
|
||||||
|
You may convey a covered work in object code form under the terms
|
||||||
|
of sections 4 and 5, provided that you also convey the
|
||||||
|
machine-readable Corresponding Source under the terms of this License,
|
||||||
|
in one of these ways:
|
||||||
|
|
||||||
|
a) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by the
|
||||||
|
Corresponding Source fixed on a durable physical medium
|
||||||
|
customarily used for software interchange.
|
||||||
|
|
||||||
|
b) Convey the object code in, or embodied in, a physical product
|
||||||
|
(including a physical distribution medium), accompanied by a
|
||||||
|
written offer, valid for at least three years and valid for as
|
||||||
|
long as you offer spare parts or customer support for that product
|
||||||
|
model, to give anyone who possesses the object code either (1) a
|
||||||
|
copy of the Corresponding Source for all the software in the
|
||||||
|
product that is covered by this License, on a durable physical
|
||||||
|
medium customarily used for software interchange, for a price no
|
||||||
|
more than your reasonable cost of physically performing this
|
||||||
|
conveying of source, or (2) access to copy the
|
||||||
|
Corresponding Source from a network server at no charge.
|
||||||
|
|
||||||
|
c) Convey individual copies of the object code with a copy of the
|
||||||
|
written offer to provide the Corresponding Source. This
|
||||||
|
alternative is allowed only occasionally and noncommercially, and
|
||||||
|
only if you received the object code with such an offer, in accord
|
||||||
|
with subsection 6b.
|
||||||
|
|
||||||
|
d) Convey the object code by offering access from a designated
|
||||||
|
place (gratis or for a charge), and offer equivalent access to the
|
||||||
|
Corresponding Source in the same way through the same place at no
|
||||||
|
further charge. You need not require recipients to copy the
|
||||||
|
Corresponding Source along with the object code. If the place to
|
||||||
|
copy the object code is a network server, the Corresponding Source
|
||||||
|
may be on a different server (operated by you or a third party)
|
||||||
|
that supports equivalent copying facilities, provided you maintain
|
||||||
|
clear directions next to the object code saying where to find the
|
||||||
|
Corresponding Source. Regardless of what server hosts the
|
||||||
|
Corresponding Source, you remain obligated to ensure that it is
|
||||||
|
available for as long as needed to satisfy these requirements.
|
||||||
|
|
||||||
|
e) Convey the object code using peer-to-peer transmission, provided
|
||||||
|
you inform other peers where the object code and Corresponding
|
||||||
|
Source of the work are being offered to the general public at no
|
||||||
|
charge under subsection 6d.
|
||||||
|
|
||||||
|
A separable portion of the object code, whose source code is excluded
|
||||||
|
from the Corresponding Source as a System Library, need not be
|
||||||
|
included in conveying the object code work.
|
||||||
|
|
||||||
|
A "User Product" is either (1) a "consumer product", which means any
|
||||||
|
tangible personal property which is normally used for personal, family,
|
||||||
|
or household purposes, or (2) anything designed or sold for incorporation
|
||||||
|
into a dwelling. In determining whether a product is a consumer product,
|
||||||
|
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||||
|
product received by a particular user, "normally used" refers to a
|
||||||
|
typical or common use of that class of product, regardless of the status
|
||||||
|
of the particular user or of the way in which the particular user
|
||||||
|
actually uses, or expects or is expected to use, the product. A product
|
||||||
|
is a consumer product regardless of whether the product has substantial
|
||||||
|
commercial, industrial or non-consumer uses, unless such uses represent
|
||||||
|
the only significant mode of use of the product.
|
||||||
|
|
||||||
|
"Installation Information" for a User Product means any methods,
|
||||||
|
procedures, authorization keys, or other information required to install
|
||||||
|
and execute modified versions of a covered work in that User Product from
|
||||||
|
a modified version of its Corresponding Source. The information must
|
||||||
|
suffice to ensure that the continued functioning of the modified object
|
||||||
|
code is in no case prevented or interfered with solely because
|
||||||
|
modification has been made.
|
||||||
|
|
||||||
|
If you convey an object code work under this section in, or with, or
|
||||||
|
specifically for use in, a User Product, and the conveying occurs as
|
||||||
|
part of a transaction in which the right of possession and use of the
|
||||||
|
User Product is transferred to the recipient in perpetuity or for a
|
||||||
|
fixed term (regardless of how the transaction is characterized), the
|
||||||
|
Corresponding Source conveyed under this section must be accompanied
|
||||||
|
by the Installation Information. But this requirement does not apply
|
||||||
|
if neither you nor any third party retains the ability to install
|
||||||
|
modified object code on the User Product (for example, the work has
|
||||||
|
been installed in ROM).
|
||||||
|
|
||||||
|
The requirement to provide Installation Information does not include a
|
||||||
|
requirement to continue to provide support service, warranty, or updates
|
||||||
|
for a work that has been modified or installed by the recipient, or for
|
||||||
|
the User Product in which it has been modified or installed. Access to a
|
||||||
|
network may be denied when the modification itself materially and
|
||||||
|
adversely affects the operation of the network or violates the rules and
|
||||||
|
protocols for communication across the network.
|
||||||
|
|
||||||
|
Corresponding Source conveyed, and Installation Information provided,
|
||||||
|
in accord with this section must be in a format that is publicly
|
||||||
|
documented (and with an implementation available to the public in
|
||||||
|
source code form), and must require no special password or key for
|
||||||
|
unpacking, reading or copying.
|
||||||
|
|
||||||
|
7. Additional Terms.
|
||||||
|
|
||||||
|
"Additional permissions" are terms that supplement the terms of this
|
||||||
|
License by making exceptions from one or more of its conditions.
|
||||||
|
Additional permissions that are applicable to the entire Program shall
|
||||||
|
be treated as though they were included in this License, to the extent
|
||||||
|
that they are valid under applicable law. If additional permissions
|
||||||
|
apply only to part of the Program, that part may be used separately
|
||||||
|
under those permissions, but the entire Program remains governed by
|
||||||
|
this License without regard to the additional permissions.
|
||||||
|
|
||||||
|
When you convey a copy of a covered work, you may at your option
|
||||||
|
remove any additional permissions from that copy, or from any part of
|
||||||
|
it. (Additional permissions may be written to require their own
|
||||||
|
removal in certain cases when you modify the work.) You may place
|
||||||
|
additional permissions on material, added by you to a covered work,
|
||||||
|
for which you have or can give appropriate copyright permission.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, for material you
|
||||||
|
add to a covered work, you may (if authorized by the copyright holders of
|
||||||
|
that material) supplement the terms of this License with terms:
|
||||||
|
|
||||||
|
a) Disclaiming warranty or limiting liability differently from the
|
||||||
|
terms of sections 15 and 16 of this License; or
|
||||||
|
|
||||||
|
b) Requiring preservation of specified reasonable legal notices or
|
||||||
|
author attributions in that material or in the Appropriate Legal
|
||||||
|
Notices displayed by works containing it; or
|
||||||
|
|
||||||
|
c) Prohibiting misrepresentation of the origin of that material, or
|
||||||
|
requiring that modified versions of such material be marked in
|
||||||
|
reasonable ways as different from the original version; or
|
||||||
|
|
||||||
|
d) Limiting the use for publicity purposes of names of licensors or
|
||||||
|
authors of the material; or
|
||||||
|
|
||||||
|
e) Declining to grant rights under trademark law for use of some
|
||||||
|
trade names, trademarks, or service marks; or
|
||||||
|
|
||||||
|
f) Requiring indemnification of licensors and authors of that
|
||||||
|
material by anyone who conveys the material (or modified versions of
|
||||||
|
it) with contractual assumptions of liability to the recipient, for
|
||||||
|
any liability that these contractual assumptions directly impose on
|
||||||
|
those licensors and authors.
|
||||||
|
|
||||||
|
All other non-permissive additional terms are considered "further
|
||||||
|
restrictions" within the meaning of section 10. If the Program as you
|
||||||
|
received it, or any part of it, contains a notice stating that it is
|
||||||
|
governed by this License along with a term that is a further
|
||||||
|
restriction, you may remove that term. If a license document contains
|
||||||
|
a further restriction but permits relicensing or conveying under this
|
||||||
|
License, you may add to a covered work material governed by the terms
|
||||||
|
of that license document, provided that the further restriction does
|
||||||
|
not survive such relicensing or conveying.
|
||||||
|
|
||||||
|
If you add terms to a covered work in accord with this section, you
|
||||||
|
must place, in the relevant source files, a statement of the
|
||||||
|
additional terms that apply to those files, or a notice indicating
|
||||||
|
where to find the applicable terms.
|
||||||
|
|
||||||
|
Additional terms, permissive or non-permissive, may be stated in the
|
||||||
|
form of a separately written license, or stated as exceptions;
|
||||||
|
the above requirements apply either way.
|
||||||
|
|
||||||
|
8. Termination.
|
||||||
|
|
||||||
|
You may not propagate or modify a covered work except as expressly
|
||||||
|
provided under this License. Any attempt otherwise to propagate or
|
||||||
|
modify it is void, and will automatically terminate your rights under
|
||||||
|
this License (including any patent licenses granted under the third
|
||||||
|
paragraph of section 11).
|
||||||
|
|
||||||
|
However, if you cease all violation of this License, then your
|
||||||
|
license from a particular copyright holder is reinstated (a)
|
||||||
|
provisionally, unless and until the copyright holder explicitly and
|
||||||
|
finally terminates your license, and (b) permanently, if the copyright
|
||||||
|
holder fails to notify you of the violation by some reasonable means
|
||||||
|
prior to 60 days after the cessation.
|
||||||
|
|
||||||
|
Moreover, your license from a particular copyright holder is
|
||||||
|
reinstated permanently if the copyright holder notifies you of the
|
||||||
|
violation by some reasonable means, this is the first time you have
|
||||||
|
received notice of violation of this License (for any work) from that
|
||||||
|
copyright holder, and you cure the violation prior to 30 days after
|
||||||
|
your receipt of the notice.
|
||||||
|
|
||||||
|
Termination of your rights under this section does not terminate the
|
||||||
|
licenses of parties who have received copies or rights from you under
|
||||||
|
this License. If your rights have been terminated and not permanently
|
||||||
|
reinstated, you do not qualify to receive new licenses for the same
|
||||||
|
material under section 10.
|
||||||
|
|
||||||
|
9. Acceptance Not Required for Having Copies.
|
||||||
|
|
||||||
|
You are not required to accept this License in order to receive or
|
||||||
|
run a copy of the Program. Ancillary propagation of a covered work
|
||||||
|
occurring solely as a consequence of using peer-to-peer transmission
|
||||||
|
to receive a copy likewise does not require acceptance. However,
|
||||||
|
nothing other than this License grants you permission to propagate or
|
||||||
|
modify any covered work. These actions infringe copyright if you do
|
||||||
|
not accept this License. Therefore, by modifying or propagating a
|
||||||
|
covered work, you indicate your acceptance of this License to do so.
|
||||||
|
|
||||||
|
10. Automatic Licensing of Downstream Recipients.
|
||||||
|
|
||||||
|
Each time you convey a covered work, the recipient automatically
|
||||||
|
receives a license from the original licensors, to run, modify and
|
||||||
|
propagate that work, subject to this License. You are not responsible
|
||||||
|
for enforcing compliance by third parties with this License.
|
||||||
|
|
||||||
|
An "entity transaction" is a transaction transferring control of an
|
||||||
|
organization, or substantially all assets of one, or subdividing an
|
||||||
|
organization, or merging organizations. If propagation of a covered
|
||||||
|
work results from an entity transaction, each party to that
|
||||||
|
transaction who receives a copy of the work also receives whatever
|
||||||
|
licenses to the work the party's predecessor in interest had or could
|
||||||
|
give under the previous paragraph, plus a right to possession of the
|
||||||
|
Corresponding Source of the work from the predecessor in interest, if
|
||||||
|
the predecessor has it or can get it with reasonable efforts.
|
||||||
|
|
||||||
|
You may not impose any further restrictions on the exercise of the
|
||||||
|
rights granted or affirmed under this License. For example, you may
|
||||||
|
not impose a license fee, royalty, or other charge for exercise of
|
||||||
|
rights granted under this License, and you may not initiate litigation
|
||||||
|
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||||
|
any patent claim is infringed by making, using, selling, offering for
|
||||||
|
sale, or importing the Program or any portion of it.
|
||||||
|
|
||||||
|
11. Patents.
|
||||||
|
|
||||||
|
A "contributor" is a copyright holder who authorizes use under this
|
||||||
|
License of the Program or a work on which the Program is based. The
|
||||||
|
work thus licensed is called the contributor's "contributor version".
|
||||||
|
|
||||||
|
A contributor's "essential patent claims" are all patent claims
|
||||||
|
owned or controlled by the contributor, whether already acquired or
|
||||||
|
hereafter acquired, that would be infringed by some manner, permitted
|
||||||
|
by this License, of making, using, or selling its contributor version,
|
||||||
|
but do not include claims that would be infringed only as a
|
||||||
|
consequence of further modification of the contributor version. For
|
||||||
|
purposes of this definition, "control" includes the right to grant
|
||||||
|
patent sublicenses in a manner consistent with the requirements of
|
||||||
|
this License.
|
||||||
|
|
||||||
|
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||||
|
patent license under the contributor's essential patent claims, to
|
||||||
|
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||||
|
propagate the contents of its contributor version.
|
||||||
|
|
||||||
|
In the following three paragraphs, a "patent license" is any express
|
||||||
|
agreement or commitment, however denominated, not to enforce a patent
|
||||||
|
(such as an express permission to practice a patent or covenant not to
|
||||||
|
sue for patent infringement). To "grant" such a patent license to a
|
||||||
|
party means to make such an agreement or commitment not to enforce a
|
||||||
|
patent against the party.
|
||||||
|
|
||||||
|
If you convey a covered work, knowingly relying on a patent license,
|
||||||
|
and the Corresponding Source of the work is not available for anyone
|
||||||
|
to copy, free of charge and under the terms of this License, through a
|
||||||
|
publicly available network server or other readily accessible means,
|
||||||
|
then you must either (1) cause the Corresponding Source to be so
|
||||||
|
available, or (2) arrange to deprive yourself of the benefit of the
|
||||||
|
patent license for this particular work, or (3) arrange, in a manner
|
||||||
|
consistent with the requirements of this License, to extend the patent
|
||||||
|
license to downstream recipients. "Knowingly relying" means you have
|
||||||
|
actual knowledge that, but for the patent license, your conveying the
|
||||||
|
covered work in a country, or your recipient's use of the covered work
|
||||||
|
in a country, would infringe one or more identifiable patents in that
|
||||||
|
country that you have reason to believe are valid.
|
||||||
|
|
||||||
|
If, pursuant to or in connection with a single transaction or
|
||||||
|
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||||
|
covered work, and grant a patent license to some of the parties
|
||||||
|
receiving the covered work authorizing them to use, propagate, modify
|
||||||
|
or convey a specific copy of the covered work, then the patent license
|
||||||
|
you grant is automatically extended to all recipients of the covered
|
||||||
|
work and works based on it.
|
||||||
|
|
||||||
|
A patent license is "discriminatory" if it does not include within
|
||||||
|
the scope of its coverage, prohibits the exercise of, or is
|
||||||
|
conditioned on the non-exercise of one or more of the rights that are
|
||||||
|
specifically granted under this License. You may not convey a covered
|
||||||
|
work if you are a party to an arrangement with a third party that is
|
||||||
|
in the business of distributing software, under which you make payment
|
||||||
|
to the third party based on the extent of your activity of conveying
|
||||||
|
the work, and under which the third party grants, to any of the
|
||||||
|
parties who would receive the covered work from you, a discriminatory
|
||||||
|
patent license (a) in connection with copies of the covered work
|
||||||
|
conveyed by you (or copies made from those copies), or (b) primarily
|
||||||
|
for and in connection with specific products or compilations that
|
||||||
|
contain the covered work, unless you entered into that arrangement,
|
||||||
|
or that patent license was granted, prior to 28 March 2007.
|
||||||
|
|
||||||
|
Nothing in this License shall be construed as excluding or limiting
|
||||||
|
any implied license or other defenses to infringement that may
|
||||||
|
otherwise be available to you under applicable patent law.
|
||||||
|
|
||||||
|
12. No Surrender of Others' Freedom.
|
||||||
|
|
||||||
|
If conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot convey a
|
||||||
|
covered work so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you may
|
||||||
|
not convey it at all. For example, if you agree to terms that obligate you
|
||||||
|
to collect a royalty for further conveying from those to whom you convey
|
||||||
|
the Program, the only way you could satisfy both those terms and this
|
||||||
|
License would be to refrain entirely from conveying the Program.
|
||||||
|
|
||||||
|
13. Use with the GNU Affero General Public License.
|
||||||
|
|
||||||
|
Notwithstanding any other provision of this License, you have
|
||||||
|
permission to link or combine any covered work with a work licensed
|
||||||
|
under version 3 of the GNU Affero General Public License into a single
|
||||||
|
combined work, and to convey the resulting work. The terms of this
|
||||||
|
License will continue to apply to the part which is the covered work,
|
||||||
|
but the special requirements of the GNU Affero General Public License,
|
||||||
|
section 13, concerning interaction through a network will apply to the
|
||||||
|
combination as such.
|
||||||
|
|
||||||
|
14. Revised Versions of this License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions of
|
||||||
|
the GNU General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Program specifies that a certain numbered version of the GNU General
|
||||||
|
Public License "or any later version" applies to it, you have the
|
||||||
|
option of following the terms and conditions either of that numbered
|
||||||
|
version or of any later version published by the Free Software
|
||||||
|
Foundation. If the Program does not specify a version number of the
|
||||||
|
GNU General Public License, you may choose any version ever published
|
||||||
|
by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Program specifies that a proxy can decide which future
|
||||||
|
versions of the GNU General Public License can be used, that proxy's
|
||||||
|
public statement of acceptance of a version permanently authorizes you
|
||||||
|
to choose that version for the Program.
|
||||||
|
|
||||||
|
Later license versions may give you additional or different
|
||||||
|
permissions. However, no additional obligations are imposed on any
|
||||||
|
author or copyright holder as a result of your choosing to follow a
|
||||||
|
later version.
|
||||||
|
|
||||||
|
15. Disclaimer of Warranty.
|
||||||
|
|
||||||
|
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||||
|
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||||
|
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||||
|
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||||
|
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||||
|
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
16. Limitation of Liability.
|
||||||
|
|
||||||
|
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||||
|
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||||
|
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||||
|
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||||
|
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||||
|
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||||
|
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES.
|
||||||
|
|
||||||
|
17. Interpretation of Sections 15 and 16.
|
||||||
|
|
||||||
|
If the disclaimer of warranty and limitation of liability provided
|
||||||
|
above cannot be given local legal effect according to their terms,
|
||||||
|
reviewing courts shall apply local law that most closely approximates
|
||||||
|
an absolute waiver of all civil liability in connection with the
|
||||||
|
Program, unless a warranty or assumption of liability accompanies a
|
||||||
|
copy of the Program in return for a fee.
|
||||||
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
### XMR-Stak-AMD - Monero mining software
|
||||||
|
|
||||||
|
XMR-Stak is a universal Stratum pool miner. This is the AMD version.
|
||||||
|
|
||||||
|
#### Usage on Windows
|
||||||
|
1) Edit the config.txt file to enter your pool login and password.
|
||||||
|
2) Double click the exe file.
|
||||||
|
|
||||||
|
XMR-Stak should compile on any C++11 compliant compiler. Windows compiler is assumed to be MSVC 2015 CE. MSVC build environment is not vendored.
|
||||||
|
```
|
||||||
|
-----BEGIN PGP SIGNED MESSAGE-----
|
||||||
|
Hash: SHA256
|
||||||
|
|
||||||
|
Windows binary release checksums
|
||||||
|
|
||||||
|
sha1sum xmr-stak-cpu.exe
|
||||||
|
32f551c891040eda2c25e18e6287665471a5a653 xmr-stak-cpu.exe
|
||||||
|
|
||||||
|
sha3sum xmr-stak-cpu.exe
|
||||||
|
ed12841738c899a3eb61f51787aa670c25b64ce3c5a626717e6a8f6b xmr-stak-cpu.exe
|
||||||
|
|
||||||
|
date
|
||||||
|
Mon 16 Jan 15:13:25 GMT 2017
|
||||||
|
-----BEGIN PGP SIGNATURE-----
|
||||||
|
Version: GnuPG v2
|
||||||
|
|
||||||
|
iQEcBAEBCAAGBQJYfONvAAoJEPsk95p+1Bw02coH/0by+VMK76gnmpNjIxDcphkV
|
||||||
|
S1GG+f0sIAYUrGpoMCJTXbr7hU3Na+grTbt6xLM2Tb0xJjX4Mc47Cixajzy7+TTx
|
||||||
|
R2+CvBRl8LG9zob6JNiohvxD1+SK7RWDKWenFyDlr9BewgE/ArqZM+16BQBrLP9H
|
||||||
|
XIWy1wh/lcSYuS548tnUYdNOmEnR9TqA454M4r8PED85HSpNmvI+eG8fZ8OK471C
|
||||||
|
3yMupjYlAbiEBT+gE6bZwLeeCH9NO2gGeBAb31w8RBsMRjy+VvhFhTOoJwZbXj9e
|
||||||
|
sMUwNBu+fLVoilMVvp8SDpQ7Uw/WFT085N2eJiCCuEbHgFAwM3uwD6VHz3eXd0s=
|
||||||
|
=QJQj
|
||||||
|
-----END PGP SIGNATURE-----
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Usage on Linux
|
||||||
|
```
|
||||||
|
sudo apt-get install ocl-icd-opencl-dev
|
||||||
|
sudo apt-get install libmicrohttpd-dev
|
||||||
|
cmake .
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
GCC version 5.1 or higher is required for full C++11 support. CMake release compile scripts, as well as CodeBlocks build environment for debug builds is included.
|
||||||
|
|
||||||
|
To do a static build for a system without gcc 5.1+
|
||||||
|
```
|
||||||
|
cmake -DCMAKE_BUILD_TYPE=STATIC
|
||||||
|
make
|
||||||
|
```
|
||||||
|
Note - cmake caches variables, so if you want to do a dynamic build later you need to specify '-DCMAKE_BUILD_TYPE=RELEASE'
|
||||||
|
|
||||||
|
#### CPU mining performance
|
||||||
|
|
||||||
|
Performance is nearly identical to the closed source paid miners. Here are some numbers:
|
||||||
|
|
||||||
|
* **I7-2600K** - 266 H/s
|
||||||
|
* **I7-6700** - 276 H/s (with a separate GPU miner)
|
||||||
|
* **Dual X5650** - 466 H/s (depends on NUMA)
|
||||||
|
* **Dual E5640** - 365 H/s (same as above)
|
||||||
|
|
||||||
|
#### Example reports
|
||||||
|
```
|
||||||
|
HASHRATE REPORT
|
||||||
|
| ID | 2.5s | 60s | 15m | ID | 2.5s | 60s | 15m |
|
||||||
|
| 0 | 31.7 | 30.7 | 30.5 | 1 | 30.6 | 30.6 | 30.6 |
|
||||||
|
| 2 | 30.3 | 30.6 | 30.6 | 3 | 30.6 | 30.6 | 30.6 |
|
||||||
|
| 4 | 35.3 | 35.5 | 35.6 | 5 | 35.7 | 35.7 | 35.7 |
|
||||||
|
| 6 | 35.4 | 35.6 | 35.6 | 7 | 35.7 | 35.7 | 35.7 |
|
||||||
|
| 8 | 31.7 | 30.7 | 30.5 | 9 | 30.6 | 30.6 | 30.6 |
|
||||||
|
| 10 | 30.4 | 30.6 | 30.6 | 11 | 30.6 | 30.6 | 30.6 |
|
||||||
|
-----------------------------------------------------
|
||||||
|
Totals: 388.7 388.7 388.7 H/s
|
||||||
|
Highest: 388.7 H/s
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
RESULT REPORT
|
||||||
|
Difficulty : 8192
|
||||||
|
Good results : 5825 / 5826 (100.0 %)
|
||||||
|
Avg result time : 10.3 sec
|
||||||
|
Pool-side hashes : 22683648
|
||||||
|
|
||||||
|
Top 10 best results found:
|
||||||
|
| 0 | 15407238 | 1 | 12699745 |
|
||||||
|
| 2 | 12194202 | 3 | 6999845 |
|
||||||
|
| 4 | 5533935 | 5 | 5315338 |
|
||||||
|
| 6 | 4700351 | 7 | 4500227 |
|
||||||
|
| 8 | 4023567 | 9 | 4021473 |
|
||||||
|
|
||||||
|
Error details:
|
||||||
|
| Count | Error text | Last seen |
|
||||||
|
| 1 | [NETWORK ERROR] | 2017-01-02 21:29:15 |
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
CONNECTION REPORT
|
||||||
|
Connected since : 2017-01-02 21:29:40
|
||||||
|
Pool ping time : 288 ms
|
||||||
|
|
||||||
|
Network error log:
|
||||||
|
| Date | Error text |
|
||||||
|
| 2017-01-02 21:29:15 | CALL error: Timeout while waiting for a reply |
|
||||||
|
| 2017-01-02 21:29:30 | CONNECT error: GetAddrInfo: Name or service not known |
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Default dev donation
|
||||||
|
By default the miner will donate 1% of the hashpower (1 minute in 100 minutes) to my pool. If you want to change that, edit **donate-level.h** before you build the binaries.
|
||||||
|
|
||||||
|
If you want to donate directly to support further development, here is my wallet
|
||||||
|
* 4581HhZkQHgZrZjKeCfCJxZff9E3xCgHGF25zABZz7oR71TnbbgiS7sK9jveE6Dx6uMs2LwszDuvQJgRZQotdpHt1fTdDhk
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#### PGP Key
|
||||||
|
```
|
||||||
|
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
Version: GnuPG v2
|
||||||
|
|
||||||
|
mQENBFhYUmUBCAC6493W5y1MMs38ApRbI11jWUqNdFm686XLkZWGDfYImzL6pEYk
|
||||||
|
RdWkyt9ziCyA6NUeWFQYniv/z10RxYKq8ulVVJaKb9qPGMU0ESfdxlFNJkU/pf28
|
||||||
|
sEVBagGvGw8uFxjQONnBJ7y7iNRWMN7qSRS636wN5ryTHNsmqI4ClXPHkXkDCDUX
|
||||||
|
QvhXZpG9RRM6jsE3jBGz/LJi3FyZLo/vB60OZBODJ2IA0wSR41RRiOq01OqDueva
|
||||||
|
9jPoAokNglJfn/CniQ+lqUEXj1vjAZ1D5Mn9fISzA/UPen5Z7Sipaa9aAtsDBOfP
|
||||||
|
K9iPKOsWa2uTafoyXgiwEVXCCeMMUjCGaoFBABEBAAG0ImZpcmVpY2VfdWsgPGZp
|
||||||
|
cmVpY2UueG1yQGdtYWlsLmNvbT6JATcEEwEIACEFAlhYUmUCGwMFCwkIBwIGFQgJ
|
||||||
|
CgsCBBYCAwECHgECF4AACgkQ+yT3mn7UHDTEcQf8CMhqaZ0IOBxeBnsq5HZr2X6z
|
||||||
|
E5bODp5cPs6ha1tjH3CWpk1AFeykNtXH7kPW9hcDt/e4UQtcHs+lu6YU59X7xLJQ
|
||||||
|
udOkpWdmooJMXRWS/zeeon4ivT9d69jNnwubh8EJOyw8xm/se6n48BcewfHekW/6
|
||||||
|
mVrbhLbF1dnuUGXzRN1WxsUZx3uJd2UvrkJhAtHtX92/qIVhT0+3PXV0bmpHURlK
|
||||||
|
YKhhm8dPLV9jPX8QVRHQXCOHSMqy/KoWEe6CnT0Isbkq3JtS3K4VBVeTX9gkySRc
|
||||||
|
IFxrNJdXsI9BxKv4O8yajP8DohpoGLMDKZKSO0yq0BRMgMh0cw6Lk22uyulGALkB
|
||||||
|
DQRYWFJlAQgAqikfViOmIccCZKVMZfNHjnigKtQqNrbJpYZCOImql4FqbZu9F7TD
|
||||||
|
9HIXA43SPcwziWlyazSy8Pa9nCpc6PuPPO1wxAaNIc5nt+w/x2EGGTIFGjRoubmP
|
||||||
|
3i5jZzOFYsvR2W3PgVa3/ujeYYJYo1oeVeuGmmJRejs0rp1mbvBSKw1Cq6C4cI0x
|
||||||
|
GTY1yXFGLIgdfYNMmiLsTy1Qwq8YStbFKeUYAMMG3128SAIaT3Eet911f5Jx4tC8
|
||||||
|
6kWUr6PX1rQ0LQJqyIsLq9U53XybUksRfJC9IEfgvgBxRBHSD8WfqEhHjhW1VsZG
|
||||||
|
dcYgr7A1PIneWsCEY+5VUnqTlt2HPaKweQARAQABiQEfBBgBCAAJBQJYWFJlAhsM
|
||||||
|
AAoJEPsk95p+1Bw0Pr8H/0vZ6U2zaih03jOHOvsrYxRfDXSmgudOp1VS45aHIREd
|
||||||
|
2nrJ+drleeFVyb14UQqO/6iX9GuDX2yBEHdCg2aljeP98AaMU//RiEtebE6CUWsL
|
||||||
|
HPVXHIkxwBCBe0YkJINHUQqLz/5f6qLsNUp1uTH2++zhdBWvg+gErTYbx8aFMFYH
|
||||||
|
0GoOtqE5rtlAh5MTvDZm+UcDwKJCxhrLaN3R3dDoyrDNRTgHQQuX5/opJBiUnVNK
|
||||||
|
d+vugnxzpMIJQP11yCZkz/KxV8zQ2QPMuZdAoh3znd/vGCJcp0rWphn4pqxA4vDp
|
||||||
|
c4hC0Yg9Dha1OoE5CJCqVL+ic4vAyB1urAwBlsd/wH8=
|
||||||
|
=B5I+
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
**msvcp140.dll and vcruntime140.dll not available errors**
|
||||||
|
|
||||||
|
Download and install this [runtime package](https://www.microsoft.com/en-us/download/details.aspx?id=48145) from Microsoft. *Warning: Do NOT use "missing dll" sites - dll's are exe files with another name, and it is a fairly safe bet that any dll on a shady site like that will be trojaned. Please download offical runtimes from Microsoft above.*
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,668 @@
|
||||||
|
/*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
const char* sSourcePath = "opencl\\cryptonight.cl";
|
||||||
|
|
||||||
|
static inline void port_sleep(size_t sec)
|
||||||
|
{
|
||||||
|
Sleep(sec * 1000);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
const char* sSourcePath = "opencl/cryptonight.cl";
|
||||||
|
|
||||||
|
static inline void port_sleep(size_t sec)
|
||||||
|
{
|
||||||
|
sleep(sec);
|
||||||
|
}
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
#include "gpu.h"
|
||||||
|
|
||||||
|
const char* err_to_str(cl_int ret)
|
||||||
|
{
|
||||||
|
switch(ret)
|
||||||
|
{
|
||||||
|
case CL_SUCCESS:
|
||||||
|
return "CL_SUCCESS";
|
||||||
|
case CL_DEVICE_NOT_FOUND:
|
||||||
|
return "CL_DEVICE_NOT_FOUND";
|
||||||
|
case CL_DEVICE_NOT_AVAILABLE:
|
||||||
|
return "CL_DEVICE_NOT_AVAILABLE";
|
||||||
|
case CL_COMPILER_NOT_AVAILABLE:
|
||||||
|
return "CL_COMPILER_NOT_AVAILABLE";
|
||||||
|
case CL_MEM_OBJECT_ALLOCATION_FAILURE:
|
||||||
|
return "CL_MEM_OBJECT_ALLOCATION_FAILURE";
|
||||||
|
case CL_OUT_OF_RESOURCES:
|
||||||
|
return "CL_OUT_OF_RESOURCES";
|
||||||
|
case CL_OUT_OF_HOST_MEMORY:
|
||||||
|
return "CL_OUT_OF_HOST_MEMORY";
|
||||||
|
case CL_PROFILING_INFO_NOT_AVAILABLE:
|
||||||
|
return "CL_PROFILING_INFO_NOT_AVAILABLE";
|
||||||
|
case CL_MEM_COPY_OVERLAP:
|
||||||
|
return "CL_MEM_COPY_OVERLAP";
|
||||||
|
case CL_IMAGE_FORMAT_MISMATCH:
|
||||||
|
return "CL_IMAGE_FORMAT_MISMATCH";
|
||||||
|
case CL_IMAGE_FORMAT_NOT_SUPPORTED:
|
||||||
|
return "CL_IMAGE_FORMAT_NOT_SUPPORTED";
|
||||||
|
case CL_BUILD_PROGRAM_FAILURE:
|
||||||
|
return "CL_BUILD_PROGRAM_FAILURE";
|
||||||
|
case CL_MAP_FAILURE:
|
||||||
|
return "CL_MAP_FAILURE";
|
||||||
|
case CL_MISALIGNED_SUB_BUFFER_OFFSET:
|
||||||
|
return "CL_MISALIGNED_SUB_BUFFER_OFFSET";
|
||||||
|
case CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST:
|
||||||
|
return "CL_EXEC_STATUS_ERROR_FOR_EVENTS_IN_WAIT_LIST";
|
||||||
|
case CL_COMPILE_PROGRAM_FAILURE:
|
||||||
|
return "CL_COMPILE_PROGRAM_FAILURE";
|
||||||
|
case CL_LINKER_NOT_AVAILABLE:
|
||||||
|
return "CL_LINKER_NOT_AVAILABLE";
|
||||||
|
case CL_LINK_PROGRAM_FAILURE:
|
||||||
|
return "CL_LINK_PROGRAM_FAILURE";
|
||||||
|
case CL_DEVICE_PARTITION_FAILED:
|
||||||
|
return "CL_DEVICE_PARTITION_FAILED";
|
||||||
|
case CL_KERNEL_ARG_INFO_NOT_AVAILABLE:
|
||||||
|
return "CL_KERNEL_ARG_INFO_NOT_AVAILABLE";
|
||||||
|
case CL_INVALID_VALUE:
|
||||||
|
return "CL_INVALID_VALUE";
|
||||||
|
case CL_INVALID_DEVICE_TYPE:
|
||||||
|
return "CL_INVALID_DEVICE_TYPE";
|
||||||
|
case CL_INVALID_PLATFORM:
|
||||||
|
return "CL_INVALID_PLATFORM";
|
||||||
|
case CL_INVALID_DEVICE:
|
||||||
|
return "CL_INVALID_DEVICE";
|
||||||
|
case CL_INVALID_CONTEXT:
|
||||||
|
return "CL_INVALID_CONTEXT";
|
||||||
|
case CL_INVALID_QUEUE_PROPERTIES:
|
||||||
|
return "CL_INVALID_QUEUE_PROPERTIES";
|
||||||
|
case CL_INVALID_COMMAND_QUEUE:
|
||||||
|
return "CL_INVALID_COMMAND_QUEUE";
|
||||||
|
case CL_INVALID_HOST_PTR:
|
||||||
|
return "CL_INVALID_HOST_PTR";
|
||||||
|
case CL_INVALID_MEM_OBJECT:
|
||||||
|
return "CL_INVALID_MEM_OBJECT";
|
||||||
|
case CL_INVALID_IMAGE_FORMAT_DESCRIPTOR:
|
||||||
|
return "CL_INVALID_IMAGE_FORMAT_DESCRIPTOR";
|
||||||
|
case CL_INVALID_IMAGE_SIZE:
|
||||||
|
return "CL_INVALID_IMAGE_SIZE";
|
||||||
|
case CL_INVALID_SAMPLER:
|
||||||
|
return "CL_INVALID_SAMPLER";
|
||||||
|
case CL_INVALID_BINARY:
|
||||||
|
return "CL_INVALID_BINARY";
|
||||||
|
case CL_INVALID_BUILD_OPTIONS:
|
||||||
|
return "CL_INVALID_BUILD_OPTIONS";
|
||||||
|
case CL_INVALID_PROGRAM:
|
||||||
|
return "CL_INVALID_PROGRAM";
|
||||||
|
case CL_INVALID_PROGRAM_EXECUTABLE:
|
||||||
|
return "CL_INVALID_PROGRAM_EXECUTABLE";
|
||||||
|
case CL_INVALID_KERNEL_NAME:
|
||||||
|
return "CL_INVALID_KERNEL_NAME";
|
||||||
|
case CL_INVALID_KERNEL_DEFINITION:
|
||||||
|
return "CL_INVALID_KERNEL_DEFINITION";
|
||||||
|
case CL_INVALID_KERNEL:
|
||||||
|
return "CL_INVALID_KERNEL";
|
||||||
|
case CL_INVALID_ARG_INDEX:
|
||||||
|
return "CL_INVALID_ARG_INDEX";
|
||||||
|
case CL_INVALID_ARG_VALUE:
|
||||||
|
return "CL_INVALID_ARG_VALUE";
|
||||||
|
case CL_INVALID_ARG_SIZE:
|
||||||
|
return "CL_INVALID_ARG_SIZE";
|
||||||
|
case CL_INVALID_KERNEL_ARGS:
|
||||||
|
return "CL_INVALID_KERNEL_ARGS";
|
||||||
|
case CL_INVALID_WORK_DIMENSION:
|
||||||
|
return "CL_INVALID_WORK_DIMENSION";
|
||||||
|
case CL_INVALID_WORK_GROUP_SIZE:
|
||||||
|
return "CL_INVALID_WORK_GROUP_SIZE";
|
||||||
|
case CL_INVALID_WORK_ITEM_SIZE:
|
||||||
|
return "CL_INVALID_WORK_ITEM_SIZE";
|
||||||
|
case CL_INVALID_GLOBAL_OFFSET:
|
||||||
|
return "CL_INVALID_GLOBAL_OFFSET";
|
||||||
|
case CL_INVALID_EVENT_WAIT_LIST:
|
||||||
|
return "CL_INVALID_EVENT_WAIT_LIST";
|
||||||
|
case CL_INVALID_EVENT:
|
||||||
|
return "CL_INVALID_EVENT";
|
||||||
|
case CL_INVALID_OPERATION:
|
||||||
|
return "CL_INVALID_OPERATION";
|
||||||
|
case CL_INVALID_GL_OBJECT:
|
||||||
|
return "CL_INVALID_GL_OBJECT";
|
||||||
|
case CL_INVALID_BUFFER_SIZE:
|
||||||
|
return "CL_INVALID_BUFFER_SIZE";
|
||||||
|
case CL_INVALID_MIP_LEVEL:
|
||||||
|
return "CL_INVALID_MIP_LEVEL";
|
||||||
|
case CL_INVALID_GLOBAL_WORK_SIZE:
|
||||||
|
return "CL_INVALID_GLOBAL_WORK_SIZE";
|
||||||
|
case CL_INVALID_PROPERTY:
|
||||||
|
return "CL_INVALID_PROPERTY";
|
||||||
|
case CL_INVALID_IMAGE_DESCRIPTOR:
|
||||||
|
return "CL_INVALID_IMAGE_DESCRIPTOR";
|
||||||
|
case CL_INVALID_COMPILER_OPTIONS:
|
||||||
|
return "CL_INVALID_COMPILER_OPTIONS";
|
||||||
|
case CL_INVALID_LINKER_OPTIONS:
|
||||||
|
return "CL_INVALID_LINKER_OPTIONS";
|
||||||
|
case CL_INVALID_DEVICE_PARTITION_COUNT:
|
||||||
|
return "CL_INVALID_DEVICE_PARTITION_COUNT";
|
||||||
|
case CL_INVALID_PIPE_SIZE:
|
||||||
|
return "CL_INVALID_PIPE_SIZE";
|
||||||
|
case CL_INVALID_DEVICE_QUEUE:
|
||||||
|
return "CL_INVALID_DEVICE_QUEUE";
|
||||||
|
default:
|
||||||
|
return "UNKNOWN_ERROR";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void printer_print_msg(const char* fmt, ...);
|
||||||
|
|
||||||
|
char* LoadTextFile(const char* filename)
|
||||||
|
{
|
||||||
|
size_t flen;
|
||||||
|
char* out;
|
||||||
|
FILE* kernel = fopen(filename, "rb");
|
||||||
|
|
||||||
|
if(kernel == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
fseek(kernel, 0, SEEK_END);
|
||||||
|
flen = ftell(kernel);
|
||||||
|
fseek(kernel, 0, SEEK_SET);
|
||||||
|
|
||||||
|
out = (char*)malloc(flen+1);
|
||||||
|
size_t r = fread(out, flen, 1, kernel);
|
||||||
|
fclose(kernel);
|
||||||
|
|
||||||
|
if(r != 1)
|
||||||
|
{
|
||||||
|
free(out);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
out[flen] = '\0';
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t InitOpenCLGpu(cl_context opencl_ctx, GpuContext* ctx, char* source_code)
|
||||||
|
{
|
||||||
|
size_t MaximumWorkSize;
|
||||||
|
cl_int ret;
|
||||||
|
|
||||||
|
if((clGetDeviceInfo(ctx->DeviceID, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(size_t), &MaximumWorkSize, NULL)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when querying a device's max worksize using clGetDeviceInfo.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
printer_print_msg("Device %lu work size %lu / %lu.", ctx->deviceIdx, ctx->workSize, MaximumWorkSize);
|
||||||
|
#ifdef CL_VERSION_2_0
|
||||||
|
const cl_queue_properties CommandQueueProperties[] = { 0, 0, 0 };
|
||||||
|
ctx->CommandQueues = clCreateCommandQueueWithProperties(opencl_ctx, ctx->DeviceID, CommandQueueProperties, &ret);
|
||||||
|
#else
|
||||||
|
const cl_command_queue_properties CommandQueueProperties = { 0 };
|
||||||
|
ctx->CommandQueues = clCreateCommandQueue(opencl_ctx, ctx->DeviceID, CommandQueueProperties, &ret);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if(ret != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clCreateCommandQueueWithProperties.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->InputBuffer = clCreateBuffer(opencl_ctx, CL_MEM_READ_ONLY, 88, NULL, &ret);
|
||||||
|
if(ret != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clCreateBuffer to create input buffer.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t g_thd = ctx->rawIntensity;
|
||||||
|
ctx->ExtraBuffers[0] = clCreateBuffer(opencl_ctx, CL_MEM_READ_WRITE, (1 << 21) * g_thd, NULL, &ret);
|
||||||
|
if(ret != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clCreateBuffer to create hash scratchpads buffer.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->ExtraBuffers[1] = clCreateBuffer(opencl_ctx, CL_MEM_READ_WRITE, 200 * g_thd, NULL, &ret);
|
||||||
|
if(ret != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clCreateBuffer to create hash states buffer.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blake-256 branches
|
||||||
|
ctx->ExtraBuffers[2] = clCreateBuffer(opencl_ctx, CL_MEM_READ_WRITE, sizeof(cl_uint) * (g_thd + 2), NULL, &ret);
|
||||||
|
if(ret != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clCreateBuffer to create Branch 0 buffer.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Groestl-256 branches
|
||||||
|
ctx->ExtraBuffers[3] = clCreateBuffer(opencl_ctx, CL_MEM_READ_WRITE, sizeof(cl_uint) * (g_thd + 2), NULL, &ret);
|
||||||
|
if(ret != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clCreateBuffer to create Branch 1 buffer.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// JH-256 branches
|
||||||
|
ctx->ExtraBuffers[4] = clCreateBuffer(opencl_ctx, CL_MEM_READ_WRITE, sizeof(cl_uint) * (g_thd + 2), NULL, &ret);
|
||||||
|
if(ret != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clCreateBuffer to create Branch 2 buffer.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skein-512 branches
|
||||||
|
ctx->ExtraBuffers[5] = clCreateBuffer(opencl_ctx, CL_MEM_READ_WRITE, sizeof(cl_uint) * (g_thd + 2), NULL, &ret);
|
||||||
|
if(ret != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clCreateBuffer to create Branch 3 buffer.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume we may find up to 0xFF nonces in one run - it's reasonable
|
||||||
|
ctx->OutputBuffer = clCreateBuffer(opencl_ctx, CL_MEM_READ_WRITE, sizeof(cl_uint) * 0x100, NULL, &ret);
|
||||||
|
if(ret != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clCreateBuffer to create output buffer.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->Program = clCreateProgramWithSource(opencl_ctx, 1, (const char**)&source_code, NULL, &ret);
|
||||||
|
if(ret != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clCreateProgramWithSource on the contents of cryptonight.cl", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
char options[32];
|
||||||
|
snprintf(options, sizeof(options), "-I. -DWORKSIZE=%lu", ctx->workSize);
|
||||||
|
ret = clBuildProgram(ctx->Program, 1, &ctx->DeviceID, options, NULL, NULL);
|
||||||
|
if(ret != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
printer_print_msg("Error %s when calling clBuildProgram.", err_to_str(ret));
|
||||||
|
|
||||||
|
if((ret = clGetProgramBuildInfo(ctx->Program, ctx->DeviceID, CL_PROGRAM_BUILD_LOG, 0, NULL, &len)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clGetProgramBuildInfo for length of build log output.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* BuildLog = (char*)malloc(len + 1);
|
||||||
|
if((ret = clGetProgramBuildInfo(ctx->Program, ctx->DeviceID, CL_PROGRAM_BUILD_LOG, len, BuildLog, NULL)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
free(BuildLog);
|
||||||
|
printer_print_msg("Error %s when calling clGetProgramBuildInfo for build log.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
printer_print_msg("Build Log:\n%s", BuildLog);
|
||||||
|
free(BuildLog);
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
cl_build_status status;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if((ret = clGetProgramBuildInfo(ctx->Program, ctx->DeviceID, CL_PROGRAM_BUILD_STATUS, sizeof(cl_build_status), &status, NULL)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clGetProgramBuildInfo for status of build.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
port_sleep(1);
|
||||||
|
}
|
||||||
|
while(status == CL_BUILD_IN_PROGRESS);
|
||||||
|
|
||||||
|
const char *KernelNames[] = { "cn0", "cn1", "cn2", "Blake", "Groestl", "JH", "Skein" };
|
||||||
|
for(int i = 0; i < 7; ++i)
|
||||||
|
{
|
||||||
|
ctx->Kernels[i] = clCreateKernel(ctx->Program, KernelNames[i], &ret);
|
||||||
|
if(ret != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clCreateKernel for kernel %s.", err_to_str(ret), KernelNames[i]);
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx->Nonce = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// RequestedDeviceIdxs is a list of OpenCL device indexes
|
||||||
|
// NumDevicesRequested is number of devices in RequestedDeviceIdxs list
|
||||||
|
// Returns 0 on success, -1 on stupid params, -2 on OpenCL API error
|
||||||
|
size_t InitOpenCL(GpuContext* ctx, size_t num_gpus, size_t platform_idx)
|
||||||
|
{
|
||||||
|
cl_context opencl_ctx;
|
||||||
|
cl_int ret;
|
||||||
|
cl_uint entries;
|
||||||
|
|
||||||
|
if((ret = clGetPlatformIDs(0, NULL, &entries)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clGetPlatformIDs for number of platforms.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The number of platforms naturally is the index of the last platform plus one.
|
||||||
|
if(entries <= platform_idx)
|
||||||
|
{
|
||||||
|
printer_print_msg("Selected OpenCL platform index %d doesn't exist.", platform_idx);
|
||||||
|
return ERR_STUPID_PARAMS;
|
||||||
|
}
|
||||||
|
|
||||||
|
cl_platform_id PlatformIDList[entries];
|
||||||
|
if((ret = clGetPlatformIDs(entries, PlatformIDList, NULL)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clGetPlatformIDs for platform ID information.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = clGetDeviceIDs(PlatformIDList[platform_idx], CL_DEVICE_TYPE_GPU, 0, NULL, &entries)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clGetDeviceIDs for number of devices.", ret);
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same as the platform index sanity check, except we must check all requested device indexes
|
||||||
|
for(int i = 0; i < num_gpus; ++i)
|
||||||
|
{
|
||||||
|
if(entries <= ctx[i].deviceIdx)
|
||||||
|
{
|
||||||
|
printer_print_msg("Selected OpenCL device index %lu doesn't exist.\n", ctx[i].deviceIdx);
|
||||||
|
return ERR_STUPID_PARAMS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cl_device_id DeviceIDList[entries];
|
||||||
|
if((ret = clGetDeviceIDs(PlatformIDList[platform_idx], CL_DEVICE_TYPE_GPU, entries, DeviceIDList, NULL)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clGetDeviceIDs for device ID information.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indexes sanity checked above
|
||||||
|
cl_device_id TempDeviceList[num_gpus];
|
||||||
|
for(int i = 0; i < num_gpus; ++i)
|
||||||
|
{
|
||||||
|
ctx[i].DeviceID = DeviceIDList[ctx[i].deviceIdx];
|
||||||
|
TempDeviceList[i] = DeviceIDList[ctx[i].deviceIdx];
|
||||||
|
}
|
||||||
|
|
||||||
|
opencl_ctx = clCreateContext(NULL, num_gpus, TempDeviceList, NULL, NULL, &ret);
|
||||||
|
if(ret != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clCreateContext.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* source_code = LoadTextFile(sSourcePath);
|
||||||
|
for(int i = 0; i < num_gpus; ++i)
|
||||||
|
{
|
||||||
|
if((ret = InitOpenCLGpu(opencl_ctx, &ctx[i], source_code)) != ERR_SUCCESS)
|
||||||
|
{
|
||||||
|
free(source_code);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(source_code);
|
||||||
|
|
||||||
|
return ERR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t XMRSetJob(GpuContext* ctx, uint8_t* input, size_t input_len, uint32_t target)
|
||||||
|
{
|
||||||
|
cl_int ret;
|
||||||
|
|
||||||
|
if(input_len > 84)
|
||||||
|
return ERR_STUPID_PARAMS;
|
||||||
|
|
||||||
|
input[input_len] = 0x01;
|
||||||
|
memset(input + input_len + 1, 0, 88 - input_len - 1);
|
||||||
|
|
||||||
|
if((ret = clEnqueueWriteBuffer(ctx->CommandQueues, ctx->InputBuffer, CL_TRUE, 0, 88, input, 0, NULL, NULL)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clEnqueueWriteBuffer to fill input buffer.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = clSetKernelArg(ctx->Kernels[0], 0, sizeof(cl_mem), &ctx->InputBuffer)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clSetKernelArg for kernel 0, argument 0.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scratchpads
|
||||||
|
if((ret = clSetKernelArg(ctx->Kernels[0], 1, sizeof(cl_mem), ctx->ExtraBuffers + 0)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clSetKernelArg for kernel 0, argument 1.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// States
|
||||||
|
if((ret = clSetKernelArg(ctx->Kernels[0], 2, sizeof(cl_mem), ctx->ExtraBuffers + 1)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clSetKernelArg for kernel 0, argument 2.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CN2 Kernel
|
||||||
|
|
||||||
|
// Scratchpads
|
||||||
|
if((ret = clSetKernelArg(ctx->Kernels[1], 0, sizeof(cl_mem), ctx->ExtraBuffers + 0)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clSetKernelArg for kernel 1, argument 0.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// States
|
||||||
|
if((ret = clSetKernelArg(ctx->Kernels[1], 1, sizeof(cl_mem), ctx->ExtraBuffers + 1)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clSetKernelArg for kernel 1, argument 1.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// CN3 Kernel
|
||||||
|
// Scratchpads
|
||||||
|
if((ret = clSetKernelArg(ctx->Kernels[2], 0, sizeof(cl_mem), ctx->ExtraBuffers + 0)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clSetKernelArg for kernel 2, argument 0.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// States
|
||||||
|
if((ret = clSetKernelArg(ctx->Kernels[2], 1, sizeof(cl_mem), ctx->ExtraBuffers + 1)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clSetKernelArg for kernel 2, argument 1.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Branch 0
|
||||||
|
if((ret = clSetKernelArg(ctx->Kernels[2], 2, sizeof(cl_mem), ctx->ExtraBuffers + 2)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clSetKernelArg for kernel 2, argument 2.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Branch 1
|
||||||
|
if((ret = clSetKernelArg(ctx->Kernels[2], 3, sizeof(cl_mem), ctx->ExtraBuffers + 3)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clSetKernelArg for kernel 2, argument 3.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Branch 2
|
||||||
|
if((ret = clSetKernelArg(ctx->Kernels[2], 4, sizeof(cl_mem), ctx->ExtraBuffers + 4)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clSetKernelArg for kernel 2, argument 4.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Branch 3
|
||||||
|
if((ret = clSetKernelArg(ctx->Kernels[2], 5, sizeof(cl_mem), ctx->ExtraBuffers + 5)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clSetKernelArg for kernel 2, argument 5.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
// States
|
||||||
|
if((ret = clSetKernelArg(ctx->Kernels[i + 3], 0, sizeof(cl_mem), ctx->ExtraBuffers + 1)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clSetKernelArg for kernel %d, argument %d.", err_to_str(ret), i + 3, 0);
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nonce buffer
|
||||||
|
if((ret = clSetKernelArg(ctx->Kernels[i + 3], 1, sizeof(cl_mem), ctx->ExtraBuffers + (i + 2))) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clSetKernelArg for kernel %d, argument %d.", err_to_str(ret), i + 3, 1);
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output
|
||||||
|
if((ret = clSetKernelArg(ctx->Kernels[i + 3], 2, sizeof(cl_mem), &ctx->OutputBuffer)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clSetKernelArg for kernel %d, argument %d.", err_to_str(ret), i + 3, 2);
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Target
|
||||||
|
if((ret = clSetKernelArg(ctx->Kernels[i + 3], 3, sizeof(cl_uint), &target)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clSetKernelArg for kernel %d, argument %d.", err_to_str(ret), i + 3, 3);
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t XMRRunJob(GpuContext* ctx, cl_uint* HashOutput)
|
||||||
|
{
|
||||||
|
cl_int ret;
|
||||||
|
cl_uint zero = 0;
|
||||||
|
size_t BranchNonces[4] = {0};
|
||||||
|
|
||||||
|
size_t g_thd = ctx->rawIntensity;
|
||||||
|
size_t w_size = ctx->workSize;
|
||||||
|
|
||||||
|
for(int i = 2; i < 6; ++i)
|
||||||
|
{
|
||||||
|
if((ret = clEnqueueWriteBuffer(ctx->CommandQueues, ctx->ExtraBuffers[i], CL_FALSE, sizeof(cl_uint) * g_thd, sizeof(cl_uint), &zero, 0, NULL, NULL)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clEnqueueWriteBuffer to zero branch buffer counter %d.", err_to_str(ret), i - 2);
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = clEnqueueWriteBuffer(ctx->CommandQueues, ctx->OutputBuffer, CL_FALSE, sizeof(cl_uint) * 0xFF, sizeof(cl_uint), &zero, 0, NULL, NULL)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clEnqueueReadBuffer to fetch results.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
clFinish(ctx->CommandQueues);
|
||||||
|
|
||||||
|
size_t Nonce[2] = {ctx->Nonce, 1}, gthreads[2] = { g_thd, 8 }, lthreads[2] = { w_size, 8 };
|
||||||
|
if((ret = clEnqueueNDRangeKernel(ctx->CommandQueues, ctx->Kernels[0], 2, Nonce, gthreads, lthreads, 0, NULL, NULL)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clEnqueueNDRangeKernel for kernel %d.", err_to_str(ret), 0);
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*for(int i = 1; i < 3; ++i)
|
||||||
|
{
|
||||||
|
if((ret = clEnqueueNDRangeKernel(*ctx->CommandQueues, ctx->Kernels[i], 1, &ctx->Nonce, &g_thd, &w_size, 0, NULL, NULL)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
Log(LOG_CRITICAL, "Error %s when calling clEnqueueNDRangeKernel for kernel %d.", err_to_str(ret), i);
|
||||||
|
return(ERR_OCL_API);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
if((ret = clEnqueueNDRangeKernel(ctx->CommandQueues, ctx->Kernels[1], 1, &ctx->Nonce, &g_thd, &w_size, 0, NULL, NULL)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clEnqueueNDRangeKernel for kernel %d.", err_to_str(ret), 1);
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = clEnqueueNDRangeKernel(ctx->CommandQueues, ctx->Kernels[2], 2, Nonce, gthreads, lthreads, 0, NULL, NULL)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clEnqueueNDRangeKernel for kernel %d.", err_to_str(ret), 2);
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = clEnqueueReadBuffer(ctx->CommandQueues, ctx->ExtraBuffers[2], CL_FALSE, sizeof(cl_uint) * g_thd, sizeof(cl_uint), BranchNonces, 0, NULL, NULL)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clEnqueueReadBuffer to fetch results.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = clEnqueueReadBuffer(ctx->CommandQueues, ctx->ExtraBuffers[3], CL_FALSE, sizeof(cl_uint) * g_thd, sizeof(cl_uint), BranchNonces + 1, 0, NULL, NULL)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clEnqueueReadBuffer to fetch results.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = clEnqueueReadBuffer(ctx->CommandQueues, ctx->ExtraBuffers[4], CL_FALSE, sizeof(cl_uint) * g_thd, sizeof(cl_uint), BranchNonces + 2, 0, NULL, NULL)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clEnqueueReadBuffer to fetch results.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = clEnqueueReadBuffer(ctx->CommandQueues, ctx->ExtraBuffers[5], CL_FALSE, sizeof(cl_uint) * g_thd, sizeof(cl_uint), BranchNonces + 3, 0, NULL, NULL)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clEnqueueReadBuffer to fetch results.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
clFinish(ctx->CommandQueues);
|
||||||
|
|
||||||
|
for(int i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
if(BranchNonces[i])
|
||||||
|
{
|
||||||
|
// Threads
|
||||||
|
if((clSetKernelArg(ctx->Kernels[i + 3], 4, sizeof(cl_ulong), BranchNonces + i)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clSetKernelArg for kernel %d, argument %d.", err_to_str(ret), i + 3, 4);
|
||||||
|
return(ERR_OCL_API);
|
||||||
|
}
|
||||||
|
|
||||||
|
BranchNonces[i] += BranchNonces[i] + (w_size - (BranchNonces[i] & (w_size - 1)));
|
||||||
|
if((ret = clEnqueueNDRangeKernel(ctx->CommandQueues, ctx->Kernels[i + 3], 1, &ctx->Nonce, BranchNonces + i, &w_size, 0, NULL, NULL)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clEnqueueNDRangeKernel for kernel %d.", err_to_str(ret), i + 3);
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ret = clEnqueueReadBuffer(ctx->CommandQueues, ctx->OutputBuffer, CL_TRUE, 0, sizeof(cl_uint) * 0x100, HashOutput, 0, NULL, NULL)) != CL_SUCCESS)
|
||||||
|
{
|
||||||
|
printer_print_msg("Error %s when calling clEnqueueReadBuffer to fetch results.", err_to_str(ret));
|
||||||
|
return ERR_OCL_API;
|
||||||
|
}
|
||||||
|
|
||||||
|
clFinish(ctx->CommandQueues);
|
||||||
|
ctx->Nonce += g_thd;
|
||||||
|
|
||||||
|
return ERR_SUCCESS;
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <CL/cl.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define ERR_SUCCESS (0)
|
||||||
|
#define ERR_OCL_API (2)
|
||||||
|
#define ERR_STUPID_PARAMS (1)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
typedef struct _GpuContext
|
||||||
|
{
|
||||||
|
/*Input vars*/
|
||||||
|
size_t deviceIdx;
|
||||||
|
size_t rawIntensity;
|
||||||
|
size_t workSize;
|
||||||
|
|
||||||
|
/*Output vars*/
|
||||||
|
cl_device_id DeviceID;
|
||||||
|
cl_command_queue CommandQueues;
|
||||||
|
cl_mem InputBuffer;
|
||||||
|
cl_mem OutputBuffer;
|
||||||
|
cl_mem ExtraBuffers[6];
|
||||||
|
cl_program Program;
|
||||||
|
cl_kernel Kernels[7];
|
||||||
|
|
||||||
|
size_t Nonce;
|
||||||
|
} GpuContext;
|
||||||
|
|
||||||
|
size_t InitOpenCL(GpuContext* ctx, size_t num_gpus, size_t platform_idx);
|
||||||
|
size_t XMRSetJob(GpuContext* ctx, uint8_t* input, size_t input_len, uint32_t target);
|
||||||
|
size_t XMRRunJob(GpuContext* ctx, cl_uint* HashOutput);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif // __cplusplus
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "executor.h"
|
||||||
|
#include "minethd.h"
|
||||||
|
#include "jconf.h"
|
||||||
|
#include "console.h"
|
||||||
|
#include "donate-level.h"
|
||||||
|
#include "httpd.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
//Do a press any key for the windows folk. *insert any key joke here*
|
||||||
|
#ifdef _WIN32
|
||||||
|
void win_exit()
|
||||||
|
{
|
||||||
|
printer::inst()->print_str("Press any key to exit.");
|
||||||
|
get_key();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define strcasecmp _stricmp
|
||||||
|
|
||||||
|
#else
|
||||||
|
void win_exit() { return; }
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
const char* sFilename = "config.txt";
|
||||||
|
|
||||||
|
if(argc >= 2)
|
||||||
|
{
|
||||||
|
if(strcmp(argv[1], "-h") == 0)
|
||||||
|
{
|
||||||
|
printer::inst()->print_msg(L0, "Usage %s [CONFIG FILE]", argv[0]);
|
||||||
|
win_exit();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(argc >= 3 && strcasecmp(argv[1], "-c") == 0)
|
||||||
|
sFilename = argv[2];
|
||||||
|
else
|
||||||
|
sFilename = argv[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!jconf::inst()->parse_config(sFilename))
|
||||||
|
{
|
||||||
|
win_exit();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!minethd::init_gpus())
|
||||||
|
{
|
||||||
|
win_exit();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(jconf::inst()->GetHttpdPort() != 0)
|
||||||
|
{
|
||||||
|
if (!httpd::inst()->start_daemon())
|
||||||
|
{
|
||||||
|
win_exit();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printer::inst()->print_str("-------------------------------------------------------------------\n");
|
||||||
|
printer::inst()->print_str("XMR-Stak-CPU mining software, CPU Version.\n");
|
||||||
|
printer::inst()->print_str("Based on CPU mining code by wolf9466 (heavily optimized by myself).\n");
|
||||||
|
printer::inst()->print_str("Brought to you by fireice_uk under GPLv3.\n\n");
|
||||||
|
char buffer[64];
|
||||||
|
snprintf(buffer, sizeof(buffer), "Configurable dev donation level is set to %.1f %%\n\n", fDevDonationLevel * 100.0);
|
||||||
|
printer::inst()->print_str(buffer);
|
||||||
|
printer::inst()->print_str("You can use following keys to display reports:\n");
|
||||||
|
printer::inst()->print_str("'h' - hashrate\n");
|
||||||
|
printer::inst()->print_str("'r' - results\n");
|
||||||
|
printer::inst()->print_str("'c' - connection\n");
|
||||||
|
printer::inst()->print_str("-------------------------------------------------------------------\n");
|
||||||
|
|
||||||
|
executor::inst()->ex_start();
|
||||||
|
|
||||||
|
int key;
|
||||||
|
while(true)
|
||||||
|
{
|
||||||
|
key = get_key();
|
||||||
|
|
||||||
|
switch(key)
|
||||||
|
{
|
||||||
|
case 'h':
|
||||||
|
executor::inst()->push_event(ex_event(EV_USR_HASHRATE));
|
||||||
|
break;
|
||||||
|
case 'r':
|
||||||
|
executor::inst()->push_event(ex_event(EV_USR_RESULTS));
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
executor::inst()->push_event(ex_event(EV_USR_CONNSTAT));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* Number of GPUs that you have in your system. Each GPU will get its own CPU thread.
|
||||||
|
*/
|
||||||
|
"gpu_thread_num" : 6,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GPU configuration. You should play around with intensity and worksize as the fastest settings will vary.
|
||||||
|
* index - GPU index number usually starts from 0
|
||||||
|
* intensity - Number of parallel GPU threads (nothing to do with CPU threads)
|
||||||
|
* worksize - Number of local GPU threads (nothing to do with CPU threads)
|
||||||
|
* affine_to_cpu - This will affine the thread to a CPU. This can make a GPU miner play along nicer with a CPU miner.
|
||||||
|
*/
|
||||||
|
"gpu_threads_conf" : [
|
||||||
|
{ "index" : 0, "intensity" : 1000, "worksize" : 8, "affine_to_cpu" : false },
|
||||||
|
{ "index" : 1, "intensity" : 1000, "worksize" : 8, "affine_to_cpu" : false },
|
||||||
|
{ "index" : 2, "intensity" : 1000, "worksize" : 8, "affine_to_cpu" : false },
|
||||||
|
{ "index" : 3, "intensity" : 1000, "worksize" : 8, "affine_to_cpu" : false },
|
||||||
|
{ "index" : 4, "intensity" : 1000, "worksize" : 8, "affine_to_cpu" : false },
|
||||||
|
{ "index" : 5, "intensity" : 1000, "worksize" : 8, "affine_to_cpu" : false },
|
||||||
|
],
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Platform index. This will be 0 unless you have different OpenCL platform - eg. AMD and Intel.
|
||||||
|
*/
|
||||||
|
"platform_index" : 0,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pool_address - Pool address should be in the form "pool.supportxmr.com:3333". Only stratum pools are supported.
|
||||||
|
* wallet_address - Your wallet, or pool login.
|
||||||
|
* pool_password - Can be empty in most cases or "x".
|
||||||
|
*/
|
||||||
|
"pool_address" : "pool.supportxmr.com:3333",
|
||||||
|
"wallet_address" : "",
|
||||||
|
"pool_password" : "",
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Network timeouts.
|
||||||
|
* Because of the way this client is written it doesn't need to constantly talk (keep-alive) to the server to make
|
||||||
|
* sure it is there. We detect a buggy / overloaded server by the call timeout. The default values will be ok for
|
||||||
|
* nearly all cases. If they aren't the pool has most likely overload issues. Low call timeout values are preferable -
|
||||||
|
* long timeouts mean that we waste hashes on potentially stale jobs. Connection report will tell you how long the
|
||||||
|
* server usually takes to process our calls.
|
||||||
|
*
|
||||||
|
* call_timeout - How long should we wait for a response from the server before we assume it is dead and drop the connection.
|
||||||
|
* retry_time - How long should we wait before another connection attempt.
|
||||||
|
* Both values are in seconds.
|
||||||
|
*/
|
||||||
|
"call_timeout" : 10,
|
||||||
|
"retry_time" : 10,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Output control.
|
||||||
|
* Since most people are used to miners printing all the time, that's what we do by default too. This is suboptimal
|
||||||
|
* really, since you cannot see errors under pages and pages of text and performance stats. Given that we have internal
|
||||||
|
* performance monitors, there is very little reason to spew out pages of text instead of concise reports.
|
||||||
|
* Press 'h' (hashrate), 'r' (results) or 'c' (connection) to print reports.
|
||||||
|
*
|
||||||
|
* verbose_level - 0 - Don't print anything.
|
||||||
|
* 1 - Print intro, connection event, disconnect event
|
||||||
|
* 2 - All of level 1, and new job (block) event if the difficulty is different from the last job
|
||||||
|
* 3 - All of level 1, and new job (block) event in all cases, result submission event.
|
||||||
|
* 4 - All of level 3, and automatic hashrate report printing
|
||||||
|
*/
|
||||||
|
"verbose_level" : 3,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Automatic hashrate report
|
||||||
|
*
|
||||||
|
* h_print_time - How often, in seconds, should we print a hashrate report if verbose_level is set to 4.
|
||||||
|
* This option has no effect if verbose_level is not 4.
|
||||||
|
*/
|
||||||
|
"h_print_time" : 60,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Built-in web server
|
||||||
|
* I like checking my hashrate on my phone. Don't you?
|
||||||
|
* Keep in mind that you will need to set up port forwarding on your router if you want to access it from
|
||||||
|
* outside of your home network. Ports lower than 1024 on Linux systems will require root.
|
||||||
|
*
|
||||||
|
* httpd_port - Port we should listen on. Default, 0, will switch off the server.
|
||||||
|
*/
|
||||||
|
"httpd_port" : 0,
|
||||||
|
|
||||||
|
/*
|
||||||
|
* prefer_ipv4 - IPv6 preference. If the host is available on both IPv4 and IPv6 net, which one should be choose?
|
||||||
|
* This setting will only be needed in 2020's. No need to worry about it now.
|
||||||
|
*/
|
||||||
|
"prefer_ipv4" : true,
|
|
@ -0,0 +1,212 @@
|
||||||
|
/*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "console.h"
|
||||||
|
#include <time.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
int get_key()
|
||||||
|
{
|
||||||
|
DWORD mode, rd;
|
||||||
|
HANDLE h;
|
||||||
|
|
||||||
|
if ((h = GetStdHandle(STD_INPUT_HANDLE)) == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
GetConsoleMode( h, &mode );
|
||||||
|
SetConsoleMode( h, mode & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT) );
|
||||||
|
|
||||||
|
int c = 0;
|
||||||
|
ReadConsole( h, &c, 1, &rd, NULL );
|
||||||
|
SetConsoleMode( h, mode );
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_colour(out_colours cl)
|
||||||
|
{
|
||||||
|
WORD attr = 0;
|
||||||
|
|
||||||
|
switch(cl)
|
||||||
|
{
|
||||||
|
case K_RED:
|
||||||
|
attr = FOREGROUND_RED | FOREGROUND_INTENSITY;
|
||||||
|
break;
|
||||||
|
case K_GREEN:
|
||||||
|
attr = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
|
||||||
|
break;
|
||||||
|
case K_BLUE:
|
||||||
|
attr = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
|
||||||
|
break;
|
||||||
|
case K_YELLOW:
|
||||||
|
attr = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
|
||||||
|
break;
|
||||||
|
case K_CYAN:
|
||||||
|
attr = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
|
||||||
|
break;
|
||||||
|
case K_MAGENTA:
|
||||||
|
attr = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
|
||||||
|
break;
|
||||||
|
case K_WHITE:
|
||||||
|
attr = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_colour()
|
||||||
|
{
|
||||||
|
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#include <termios.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int get_key()
|
||||||
|
{
|
||||||
|
struct termios oldattr, newattr;
|
||||||
|
int ch;
|
||||||
|
tcgetattr( STDIN_FILENO, &oldattr );
|
||||||
|
newattr = oldattr;
|
||||||
|
newattr.c_lflag &= ~( ICANON | ECHO );
|
||||||
|
tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
|
||||||
|
ch = getchar();
|
||||||
|
tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_colour(out_colours cl)
|
||||||
|
{
|
||||||
|
switch(cl)
|
||||||
|
{
|
||||||
|
case K_RED:
|
||||||
|
fputs("\x1B[1;31m", stdout);
|
||||||
|
break;
|
||||||
|
case K_GREEN:
|
||||||
|
fputs("\x1B[1;32m", stdout);
|
||||||
|
break;
|
||||||
|
case K_BLUE:
|
||||||
|
fputs("\x1B[1;34m", stdout);
|
||||||
|
break;
|
||||||
|
case K_YELLOW:
|
||||||
|
fputs("\x1B[1;33m", stdout);
|
||||||
|
break;
|
||||||
|
case K_CYAN:
|
||||||
|
fputs("\x1B[1;36m", stdout);
|
||||||
|
break;
|
||||||
|
case K_MAGENTA:
|
||||||
|
fputs("\x1B[1;35m", stdout);
|
||||||
|
break;
|
||||||
|
case K_WHITE:
|
||||||
|
fputs("\x1B[1;37m", stdout);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_colour()
|
||||||
|
{
|
||||||
|
fputs("\x1B[0m", stdout);
|
||||||
|
}
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
inline void comp_localtime(const time_t* ctime, tm* stime)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
localtime_s(stime, ctime);
|
||||||
|
#else
|
||||||
|
localtime_r(ctime, stime);
|
||||||
|
#endif // __WIN32
|
||||||
|
}
|
||||||
|
|
||||||
|
printer* printer::oInst = nullptr;
|
||||||
|
|
||||||
|
printer::printer()
|
||||||
|
{
|
||||||
|
verbose_level = LINF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printer::print_msg(verbosity verbose, const char* fmt, ...)
|
||||||
|
{
|
||||||
|
if(verbose > verbose_level)
|
||||||
|
return;
|
||||||
|
|
||||||
|
char buf[1024];
|
||||||
|
size_t bpos;
|
||||||
|
tm stime;
|
||||||
|
|
||||||
|
time_t now = time(nullptr);
|
||||||
|
comp_localtime(&now, &stime);
|
||||||
|
strftime(buf, sizeof(buf), "[%F %T] : ", &stime);
|
||||||
|
bpos = strlen(buf);
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
vsnprintf(buf+bpos, sizeof(buf)-bpos, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
bpos = strlen(buf);
|
||||||
|
|
||||||
|
if(bpos+2 >= sizeof(buf))
|
||||||
|
return;
|
||||||
|
|
||||||
|
buf[bpos] = '\n';
|
||||||
|
buf[bpos+1] = '\0';
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lck(print_mutex);
|
||||||
|
fputs(buf, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printer::print_str(const char* str)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lck(print_mutex);
|
||||||
|
fputs(str, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void printer_print_msg(const char* fmt, ...)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
size_t bpos;
|
||||||
|
tm stime;
|
||||||
|
|
||||||
|
time_t now = time(nullptr);
|
||||||
|
comp_localtime(&now, &stime);
|
||||||
|
strftime(buf, sizeof(buf), "[%F %T] : ", &stime);
|
||||||
|
bpos = strlen(buf);
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
vsnprintf(buf+bpos, sizeof(buf)-bpos, fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
bpos = strlen(buf);
|
||||||
|
|
||||||
|
if(bpos+2 >= sizeof(buf))
|
||||||
|
return;
|
||||||
|
|
||||||
|
buf[bpos] = '\n';
|
||||||
|
buf[bpos+1] = '\0';
|
||||||
|
|
||||||
|
printer::inst()->print_str(buf);
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
#pragma once
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
enum out_colours { K_RED, K_GREEN, K_BLUE, K_YELLOW, K_CYAN, K_MAGENTA, K_WHITE, K_NONE };
|
||||||
|
|
||||||
|
// Warning - on Linux get_key will detect control keys, but not on Windows.
|
||||||
|
// We will only use it for alphanum keys anyway.
|
||||||
|
int get_key();
|
||||||
|
|
||||||
|
void set_colour(out_colours cl);
|
||||||
|
void reset_colour();
|
||||||
|
|
||||||
|
// on MSVC sizeof(long int) = 4, gcc sizeof(long int) = 8, this is the workaround
|
||||||
|
// now we can use %llu on both compilers
|
||||||
|
inline long long unsigned int int_port(size_t i)
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum verbosity : size_t { L0 = 0, L1 = 1, L2 = 2, L3 = 3, L4 = 4, LINF = 100};
|
||||||
|
|
||||||
|
class printer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static inline printer* inst()
|
||||||
|
{
|
||||||
|
if (oInst == nullptr) oInst = new printer;
|
||||||
|
return oInst;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline void set_verbose_level(size_t level) { verbose_level = (verbosity)level; }
|
||||||
|
void print_msg(verbosity verbose, const char* fmt, ...);
|
||||||
|
void print_str(const char* str);
|
||||||
|
|
||||||
|
private:
|
||||||
|
printer();
|
||||||
|
static printer* oInst;
|
||||||
|
|
||||||
|
std::mutex print_mutex;
|
||||||
|
verbosity verbose_level;
|
||||||
|
};
|
|
@ -0,0 +1,326 @@
|
||||||
|
/*
|
||||||
|
* The blake256_* and blake224_* functions are largely copied from
|
||||||
|
* blake256_light.c and blake224_light.c from the BLAKE website:
|
||||||
|
*
|
||||||
|
* http://131002.net/blake/
|
||||||
|
*
|
||||||
|
* The hmac_* functions implement HMAC-BLAKE-256 and HMAC-BLAKE-224.
|
||||||
|
* HMAC is specified by RFC 2104.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "c_blake256.h"
|
||||||
|
|
||||||
|
#define U8TO32(p) \
|
||||||
|
(((uint32_t)((p)[0]) << 24) | ((uint32_t)((p)[1]) << 16) | \
|
||||||
|
((uint32_t)((p)[2]) << 8) | ((uint32_t)((p)[3]) ))
|
||||||
|
#define U32TO8(p, v) \
|
||||||
|
(p)[0] = (uint8_t)((v) >> 24); (p)[1] = (uint8_t)((v) >> 16); \
|
||||||
|
(p)[2] = (uint8_t)((v) >> 8); (p)[3] = (uint8_t)((v) );
|
||||||
|
|
||||||
|
const uint8_t sigma[][16] = {
|
||||||
|
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15},
|
||||||
|
{14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3},
|
||||||
|
{11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4},
|
||||||
|
{ 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8},
|
||||||
|
{ 9, 0, 5, 7, 2, 4,10,15,14, 1,11,12, 6, 8, 3,13},
|
||||||
|
{ 2,12, 6,10, 0,11, 8, 3, 4,13, 7, 5,15,14, 1, 9},
|
||||||
|
{12, 5, 1,15,14,13, 4,10, 0, 7, 6, 3, 9, 2, 8,11},
|
||||||
|
{13,11, 7,14,12, 1, 3, 9, 5, 0,15, 4, 8, 6, 2,10},
|
||||||
|
{ 6,15,14, 9,11, 3, 0, 8,12, 2,13, 7, 1, 4,10, 5},
|
||||||
|
{10, 2, 8, 4, 7, 6, 1, 5,15,11, 9,14, 3,12,13, 0},
|
||||||
|
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15},
|
||||||
|
{14,10, 4, 8, 9,15,13, 6, 1,12, 0, 2,11, 7, 5, 3},
|
||||||
|
{11, 8,12, 0, 5, 2,15,13,10,14, 3, 6, 7, 1, 9, 4},
|
||||||
|
{ 7, 9, 3, 1,13,12,11,14, 2, 6, 5,10, 4, 0,15, 8}
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint32_t cst[16] = {
|
||||||
|
0x243F6A88, 0x85A308D3, 0x13198A2E, 0x03707344,
|
||||||
|
0xA4093822, 0x299F31D0, 0x082EFA98, 0xEC4E6C89,
|
||||||
|
0x452821E6, 0x38D01377, 0xBE5466CF, 0x34E90C6C,
|
||||||
|
0xC0AC29B7, 0xC97C50DD, 0x3F84D5B5, 0xB5470917
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t padding[] = {
|
||||||
|
0x80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void blake256_compress(state *S, const uint8_t *block) {
|
||||||
|
uint32_t v[16], m[16], i;
|
||||||
|
|
||||||
|
#define ROT(x,n) (((x)<<(32-n))|((x)>>(n)))
|
||||||
|
#define G(a,b,c,d,e) \
|
||||||
|
v[a] += (m[sigma[i][e]] ^ cst[sigma[i][e+1]]) + v[b]; \
|
||||||
|
v[d] = ROT(v[d] ^ v[a],16); \
|
||||||
|
v[c] += v[d]; \
|
||||||
|
v[b] = ROT(v[b] ^ v[c],12); \
|
||||||
|
v[a] += (m[sigma[i][e+1]] ^ cst[sigma[i][e]])+v[b]; \
|
||||||
|
v[d] = ROT(v[d] ^ v[a], 8); \
|
||||||
|
v[c] += v[d]; \
|
||||||
|
v[b] = ROT(v[b] ^ v[c], 7);
|
||||||
|
|
||||||
|
for (i = 0; i < 16; ++i) m[i] = U8TO32(block + i * 4);
|
||||||
|
for (i = 0; i < 8; ++i) v[i] = S->h[i];
|
||||||
|
v[ 8] = S->s[0] ^ 0x243F6A88;
|
||||||
|
v[ 9] = S->s[1] ^ 0x85A308D3;
|
||||||
|
v[10] = S->s[2] ^ 0x13198A2E;
|
||||||
|
v[11] = S->s[3] ^ 0x03707344;
|
||||||
|
v[12] = 0xA4093822;
|
||||||
|
v[13] = 0x299F31D0;
|
||||||
|
v[14] = 0x082EFA98;
|
||||||
|
v[15] = 0xEC4E6C89;
|
||||||
|
|
||||||
|
if (S->nullt == 0) {
|
||||||
|
v[12] ^= S->t[0];
|
||||||
|
v[13] ^= S->t[0];
|
||||||
|
v[14] ^= S->t[1];
|
||||||
|
v[15] ^= S->t[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 14; ++i) {
|
||||||
|
G(0, 4, 8, 12, 0);
|
||||||
|
G(1, 5, 9, 13, 2);
|
||||||
|
G(2, 6, 10, 14, 4);
|
||||||
|
G(3, 7, 11, 15, 6);
|
||||||
|
G(3, 4, 9, 14, 14);
|
||||||
|
G(2, 7, 8, 13, 12);
|
||||||
|
G(0, 5, 10, 15, 8);
|
||||||
|
G(1, 6, 11, 12, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < 16; ++i) S->h[i % 8] ^= v[i];
|
||||||
|
for (i = 0; i < 8; ++i) S->h[i] ^= S->s[i % 4];
|
||||||
|
}
|
||||||
|
|
||||||
|
void blake256_init(state *S) {
|
||||||
|
S->h[0] = 0x6A09E667;
|
||||||
|
S->h[1] = 0xBB67AE85;
|
||||||
|
S->h[2] = 0x3C6EF372;
|
||||||
|
S->h[3] = 0xA54FF53A;
|
||||||
|
S->h[4] = 0x510E527F;
|
||||||
|
S->h[5] = 0x9B05688C;
|
||||||
|
S->h[6] = 0x1F83D9AB;
|
||||||
|
S->h[7] = 0x5BE0CD19;
|
||||||
|
S->t[0] = S->t[1] = S->buflen = S->nullt = 0;
|
||||||
|
S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void blake224_init(state *S) {
|
||||||
|
S->h[0] = 0xC1059ED8;
|
||||||
|
S->h[1] = 0x367CD507;
|
||||||
|
S->h[2] = 0x3070DD17;
|
||||||
|
S->h[3] = 0xF70E5939;
|
||||||
|
S->h[4] = 0xFFC00B31;
|
||||||
|
S->h[5] = 0x68581511;
|
||||||
|
S->h[6] = 0x64F98FA7;
|
||||||
|
S->h[7] = 0xBEFA4FA4;
|
||||||
|
S->t[0] = S->t[1] = S->buflen = S->nullt = 0;
|
||||||
|
S->s[0] = S->s[1] = S->s[2] = S->s[3] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// datalen = number of bits
|
||||||
|
void blake256_update(state *S, const uint8_t *data, uint64_t datalen) {
|
||||||
|
int left = S->buflen >> 3;
|
||||||
|
int fill = 64 - left;
|
||||||
|
|
||||||
|
if (left && (((datalen >> 3) & 0x3F) >= (unsigned) fill)) {
|
||||||
|
memcpy((void *) (S->buf + left), (void *) data, fill);
|
||||||
|
S->t[0] += 512;
|
||||||
|
if (S->t[0] == 0) S->t[1]++;
|
||||||
|
blake256_compress(S, S->buf);
|
||||||
|
data += fill;
|
||||||
|
datalen -= (fill << 3);
|
||||||
|
left = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (datalen >= 512) {
|
||||||
|
S->t[0] += 512;
|
||||||
|
if (S->t[0] == 0) S->t[1]++;
|
||||||
|
blake256_compress(S, data);
|
||||||
|
data += 64;
|
||||||
|
datalen -= 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (datalen > 0) {
|
||||||
|
memcpy((void *) (S->buf + left), (void *) data, datalen >> 3);
|
||||||
|
S->buflen = (left << 3) + datalen;
|
||||||
|
} else {
|
||||||
|
S->buflen = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// datalen = number of bits
|
||||||
|
void blake224_update(state *S, const uint8_t *data, uint64_t datalen) {
|
||||||
|
blake256_update(S, data, datalen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void blake256_final_h(state *S, uint8_t *digest, uint8_t pa, uint8_t pb) {
|
||||||
|
uint8_t msglen[8];
|
||||||
|
uint32_t lo = S->t[0] + S->buflen, hi = S->t[1];
|
||||||
|
if (lo < (unsigned) S->buflen) hi++;
|
||||||
|
U32TO8(msglen + 0, hi);
|
||||||
|
U32TO8(msglen + 4, lo);
|
||||||
|
|
||||||
|
if (S->buflen == 440) { /* one padding byte */
|
||||||
|
S->t[0] -= 8;
|
||||||
|
blake256_update(S, &pa, 8);
|
||||||
|
} else {
|
||||||
|
if (S->buflen < 440) { /* enough space to fill the block */
|
||||||
|
if (S->buflen == 0) S->nullt = 1;
|
||||||
|
S->t[0] -= 440 - S->buflen;
|
||||||
|
blake256_update(S, padding, 440 - S->buflen);
|
||||||
|
} else { /* need 2 compressions */
|
||||||
|
S->t[0] -= 512 - S->buflen;
|
||||||
|
blake256_update(S, padding, 512 - S->buflen);
|
||||||
|
S->t[0] -= 440;
|
||||||
|
blake256_update(S, padding + 1, 440);
|
||||||
|
S->nullt = 1;
|
||||||
|
}
|
||||||
|
blake256_update(S, &pb, 8);
|
||||||
|
S->t[0] -= 8;
|
||||||
|
}
|
||||||
|
S->t[0] -= 64;
|
||||||
|
blake256_update(S, msglen, 64);
|
||||||
|
|
||||||
|
U32TO8(digest + 0, S->h[0]);
|
||||||
|
U32TO8(digest + 4, S->h[1]);
|
||||||
|
U32TO8(digest + 8, S->h[2]);
|
||||||
|
U32TO8(digest + 12, S->h[3]);
|
||||||
|
U32TO8(digest + 16, S->h[4]);
|
||||||
|
U32TO8(digest + 20, S->h[5]);
|
||||||
|
U32TO8(digest + 24, S->h[6]);
|
||||||
|
U32TO8(digest + 28, S->h[7]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void blake256_final(state *S, uint8_t *digest) {
|
||||||
|
blake256_final_h(S, digest, 0x81, 0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
void blake224_final(state *S, uint8_t *digest) {
|
||||||
|
blake256_final_h(S, digest, 0x80, 0x00);
|
||||||
|
}
|
||||||
|
|
||||||
|
// inlen = number of bytes
|
||||||
|
void blake256_hash(uint8_t *out, const uint8_t *in, uint64_t inlen) {
|
||||||
|
state S;
|
||||||
|
blake256_init(&S);
|
||||||
|
blake256_update(&S, in, inlen * 8);
|
||||||
|
blake256_final(&S, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// inlen = number of bytes
|
||||||
|
void blake224_hash(uint8_t *out, const uint8_t *in, uint64_t inlen) {
|
||||||
|
state S;
|
||||||
|
blake224_init(&S);
|
||||||
|
blake224_update(&S, in, inlen * 8);
|
||||||
|
blake224_final(&S, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// keylen = number of bytes
|
||||||
|
void hmac_blake256_init(hmac_state *S, const uint8_t *_key, uint64_t keylen) {
|
||||||
|
const uint8_t *key = _key;
|
||||||
|
uint8_t keyhash[32];
|
||||||
|
uint8_t pad[64];
|
||||||
|
uint64_t i;
|
||||||
|
|
||||||
|
if (keylen > 64) {
|
||||||
|
blake256_hash(keyhash, key, keylen);
|
||||||
|
key = keyhash;
|
||||||
|
keylen = 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
blake256_init(&S->inner);
|
||||||
|
memset(pad, 0x36, 64);
|
||||||
|
for (i = 0; i < keylen; ++i) {
|
||||||
|
pad[i] ^= key[i];
|
||||||
|
}
|
||||||
|
blake256_update(&S->inner, pad, 512);
|
||||||
|
|
||||||
|
blake256_init(&S->outer);
|
||||||
|
memset(pad, 0x5c, 64);
|
||||||
|
for (i = 0; i < keylen; ++i) {
|
||||||
|
pad[i] ^= key[i];
|
||||||
|
}
|
||||||
|
blake256_update(&S->outer, pad, 512);
|
||||||
|
|
||||||
|
memset(keyhash, 0, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// keylen = number of bytes
|
||||||
|
void hmac_blake224_init(hmac_state *S, const uint8_t *_key, uint64_t keylen) {
|
||||||
|
const uint8_t *key = _key;
|
||||||
|
uint8_t keyhash[32];
|
||||||
|
uint8_t pad[64];
|
||||||
|
uint64_t i;
|
||||||
|
|
||||||
|
if (keylen > 64) {
|
||||||
|
blake256_hash(keyhash, key, keylen);
|
||||||
|
key = keyhash;
|
||||||
|
keylen = 28;
|
||||||
|
}
|
||||||
|
|
||||||
|
blake224_init(&S->inner);
|
||||||
|
memset(pad, 0x36, 64);
|
||||||
|
for (i = 0; i < keylen; ++i) {
|
||||||
|
pad[i] ^= key[i];
|
||||||
|
}
|
||||||
|
blake224_update(&S->inner, pad, 512);
|
||||||
|
|
||||||
|
blake224_init(&S->outer);
|
||||||
|
memset(pad, 0x5c, 64);
|
||||||
|
for (i = 0; i < keylen; ++i) {
|
||||||
|
pad[i] ^= key[i];
|
||||||
|
}
|
||||||
|
blake224_update(&S->outer, pad, 512);
|
||||||
|
|
||||||
|
memset(keyhash, 0, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// datalen = number of bits
|
||||||
|
void hmac_blake256_update(hmac_state *S, const uint8_t *data, uint64_t datalen) {
|
||||||
|
// update the inner state
|
||||||
|
blake256_update(&S->inner, data, datalen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// datalen = number of bits
|
||||||
|
void hmac_blake224_update(hmac_state *S, const uint8_t *data, uint64_t datalen) {
|
||||||
|
// update the inner state
|
||||||
|
blake224_update(&S->inner, data, datalen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hmac_blake256_final(hmac_state *S, uint8_t *digest) {
|
||||||
|
uint8_t ihash[32];
|
||||||
|
blake256_final(&S->inner, ihash);
|
||||||
|
blake256_update(&S->outer, ihash, 256);
|
||||||
|
blake256_final(&S->outer, digest);
|
||||||
|
memset(ihash, 0, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hmac_blake224_final(hmac_state *S, uint8_t *digest) {
|
||||||
|
uint8_t ihash[32];
|
||||||
|
blake224_final(&S->inner, ihash);
|
||||||
|
blake224_update(&S->outer, ihash, 224);
|
||||||
|
blake224_final(&S->outer, digest);
|
||||||
|
memset(ihash, 0, 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// keylen = number of bytes; inlen = number of bytes
|
||||||
|
void hmac_blake256_hash(uint8_t *out, const uint8_t *key, uint64_t keylen, const uint8_t *in, uint64_t inlen) {
|
||||||
|
hmac_state S;
|
||||||
|
hmac_blake256_init(&S, key, keylen);
|
||||||
|
hmac_blake256_update(&S, in, inlen * 8);
|
||||||
|
hmac_blake256_final(&S, out);
|
||||||
|
}
|
||||||
|
|
||||||
|
// keylen = number of bytes; inlen = number of bytes
|
||||||
|
void hmac_blake224_hash(uint8_t *out, const uint8_t *key, uint64_t keylen, const uint8_t *in, uint64_t inlen) {
|
||||||
|
hmac_state S;
|
||||||
|
hmac_blake224_init(&S, key, keylen);
|
||||||
|
hmac_blake224_update(&S, in, inlen * 8);
|
||||||
|
hmac_blake224_final(&S, out);
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
#ifndef _BLAKE256_H_
|
||||||
|
#define _BLAKE256_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t h[8], s[4], t[2];
|
||||||
|
int buflen, nullt;
|
||||||
|
uint8_t buf[64];
|
||||||
|
} state;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
state inner;
|
||||||
|
state outer;
|
||||||
|
} hmac_state;
|
||||||
|
|
||||||
|
void blake256_init(state *);
|
||||||
|
void blake224_init(state *);
|
||||||
|
|
||||||
|
void blake256_update(state *, const uint8_t *, uint64_t);
|
||||||
|
void blake224_update(state *, const uint8_t *, uint64_t);
|
||||||
|
|
||||||
|
void blake256_final(state *, uint8_t *);
|
||||||
|
void blake224_final(state *, uint8_t *);
|
||||||
|
|
||||||
|
void blake256_hash(uint8_t *, const uint8_t *, uint64_t);
|
||||||
|
void blake224_hash(uint8_t *, const uint8_t *, uint64_t);
|
||||||
|
|
||||||
|
/* HMAC functions: */
|
||||||
|
|
||||||
|
void hmac_blake256_init(hmac_state *, const uint8_t *, uint64_t);
|
||||||
|
void hmac_blake224_init(hmac_state *, const uint8_t *, uint64_t);
|
||||||
|
|
||||||
|
void hmac_blake256_update(hmac_state *, const uint8_t *, uint64_t);
|
||||||
|
void hmac_blake224_update(hmac_state *, const uint8_t *, uint64_t);
|
||||||
|
|
||||||
|
void hmac_blake256_final(hmac_state *, uint8_t *);
|
||||||
|
void hmac_blake224_final(hmac_state *, uint8_t *);
|
||||||
|
|
||||||
|
void hmac_blake256_hash(uint8_t *, const uint8_t *, uint64_t, const uint8_t *, uint64_t);
|
||||||
|
void hmac_blake224_hash(uint8_t *, const uint8_t *, uint64_t, const uint8_t *, uint64_t);
|
||||||
|
|
||||||
|
#endif /* _BLAKE256_H_ */
|
|
@ -0,0 +1,360 @@
|
||||||
|
/* hash.c April 2012
|
||||||
|
* Groestl ANSI C code optimised for 32-bit machines
|
||||||
|
* Author: Thomas Krinninger
|
||||||
|
*
|
||||||
|
* This work is based on the implementation of
|
||||||
|
* Soeren S. Thomsen and Krystian Matusiewicz
|
||||||
|
*
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "c_groestl.h"
|
||||||
|
#include "groestl_tables.h"
|
||||||
|
|
||||||
|
#define P_TYPE 0
|
||||||
|
#define Q_TYPE 1
|
||||||
|
|
||||||
|
const uint8_t shift_Values[2][8] = {{0,1,2,3,4,5,6,7},{1,3,5,7,0,2,4,6}};
|
||||||
|
|
||||||
|
const uint8_t indices_cyclic[15] = {0,1,2,3,4,5,6,7,0,1,2,3,4,5,6};
|
||||||
|
|
||||||
|
|
||||||
|
#define ROTATE_COLUMN_DOWN(v1, v2, amount_bytes, temp_var) {temp_var = (v1<<(8*amount_bytes))|(v2>>(8*(4-amount_bytes))); \
|
||||||
|
v2 = (v2<<(8*amount_bytes))|(v1>>(8*(4-amount_bytes))); \
|
||||||
|
v1 = temp_var;}
|
||||||
|
|
||||||
|
|
||||||
|
#define COLUMN(x,y,i,c0,c1,c2,c3,c4,c5,c6,c7,tv1,tv2,tu,tl,t) \
|
||||||
|
tu = T[2*(uint32_t)x[4*c0+0]]; \
|
||||||
|
tl = T[2*(uint32_t)x[4*c0+0]+1]; \
|
||||||
|
tv1 = T[2*(uint32_t)x[4*c1+1]]; \
|
||||||
|
tv2 = T[2*(uint32_t)x[4*c1+1]+1]; \
|
||||||
|
ROTATE_COLUMN_DOWN(tv1,tv2,1,t) \
|
||||||
|
tu ^= tv1; \
|
||||||
|
tl ^= tv2; \
|
||||||
|
tv1 = T[2*(uint32_t)x[4*c2+2]]; \
|
||||||
|
tv2 = T[2*(uint32_t)x[4*c2+2]+1]; \
|
||||||
|
ROTATE_COLUMN_DOWN(tv1,tv2,2,t) \
|
||||||
|
tu ^= tv1; \
|
||||||
|
tl ^= tv2; \
|
||||||
|
tv1 = T[2*(uint32_t)x[4*c3+3]]; \
|
||||||
|
tv2 = T[2*(uint32_t)x[4*c3+3]+1]; \
|
||||||
|
ROTATE_COLUMN_DOWN(tv1,tv2,3,t) \
|
||||||
|
tu ^= tv1; \
|
||||||
|
tl ^= tv2; \
|
||||||
|
tl ^= T[2*(uint32_t)x[4*c4+0]]; \
|
||||||
|
tu ^= T[2*(uint32_t)x[4*c4+0]+1]; \
|
||||||
|
tv1 = T[2*(uint32_t)x[4*c5+1]]; \
|
||||||
|
tv2 = T[2*(uint32_t)x[4*c5+1]+1]; \
|
||||||
|
ROTATE_COLUMN_DOWN(tv1,tv2,1,t) \
|
||||||
|
tl ^= tv1; \
|
||||||
|
tu ^= tv2; \
|
||||||
|
tv1 = T[2*(uint32_t)x[4*c6+2]]; \
|
||||||
|
tv2 = T[2*(uint32_t)x[4*c6+2]+1]; \
|
||||||
|
ROTATE_COLUMN_DOWN(tv1,tv2,2,t) \
|
||||||
|
tl ^= tv1; \
|
||||||
|
tu ^= tv2; \
|
||||||
|
tv1 = T[2*(uint32_t)x[4*c7+3]]; \
|
||||||
|
tv2 = T[2*(uint32_t)x[4*c7+3]+1]; \
|
||||||
|
ROTATE_COLUMN_DOWN(tv1,tv2,3,t) \
|
||||||
|
tl ^= tv1; \
|
||||||
|
tu ^= tv2; \
|
||||||
|
y[i] = tu; \
|
||||||
|
y[i+1] = tl;
|
||||||
|
|
||||||
|
|
||||||
|
/* compute one round of P (short variants) */
|
||||||
|
static void RND512P(uint8_t *x, uint32_t *y, uint32_t r) {
|
||||||
|
uint32_t temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp;
|
||||||
|
uint32_t* x32 = (uint32_t*)x;
|
||||||
|
x32[ 0] ^= 0x00000000^r;
|
||||||
|
x32[ 2] ^= 0x00000010^r;
|
||||||
|
x32[ 4] ^= 0x00000020^r;
|
||||||
|
x32[ 6] ^= 0x00000030^r;
|
||||||
|
x32[ 8] ^= 0x00000040^r;
|
||||||
|
x32[10] ^= 0x00000050^r;
|
||||||
|
x32[12] ^= 0x00000060^r;
|
||||||
|
x32[14] ^= 0x00000070^r;
|
||||||
|
COLUMN(x,y, 0, 0, 2, 4, 6, 9, 11, 13, 15, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
|
||||||
|
COLUMN(x,y, 2, 2, 4, 6, 8, 11, 13, 15, 1, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
|
||||||
|
COLUMN(x,y, 4, 4, 6, 8, 10, 13, 15, 1, 3, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
|
||||||
|
COLUMN(x,y, 6, 6, 8, 10, 12, 15, 1, 3, 5, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
|
||||||
|
COLUMN(x,y, 8, 8, 10, 12, 14, 1, 3, 5, 7, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
|
||||||
|
COLUMN(x,y,10, 10, 12, 14, 0, 3, 5, 7, 9, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
|
||||||
|
COLUMN(x,y,12, 12, 14, 0, 2, 5, 7, 9, 11, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
|
||||||
|
COLUMN(x,y,14, 14, 0, 2, 4, 7, 9, 11, 13, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compute one round of Q (short variants) */
|
||||||
|
static void RND512Q(uint8_t *x, uint32_t *y, uint32_t r) {
|
||||||
|
uint32_t temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp;
|
||||||
|
uint32_t* x32 = (uint32_t*)x;
|
||||||
|
x32[ 0] = ~x32[ 0];
|
||||||
|
x32[ 1] ^= 0xffffffff^r;
|
||||||
|
x32[ 2] = ~x32[ 2];
|
||||||
|
x32[ 3] ^= 0xefffffff^r;
|
||||||
|
x32[ 4] = ~x32[ 4];
|
||||||
|
x32[ 5] ^= 0xdfffffff^r;
|
||||||
|
x32[ 6] = ~x32[ 6];
|
||||||
|
x32[ 7] ^= 0xcfffffff^r;
|
||||||
|
x32[ 8] = ~x32[ 8];
|
||||||
|
x32[ 9] ^= 0xbfffffff^r;
|
||||||
|
x32[10] = ~x32[10];
|
||||||
|
x32[11] ^= 0xafffffff^r;
|
||||||
|
x32[12] = ~x32[12];
|
||||||
|
x32[13] ^= 0x9fffffff^r;
|
||||||
|
x32[14] = ~x32[14];
|
||||||
|
x32[15] ^= 0x8fffffff^r;
|
||||||
|
COLUMN(x,y, 0, 2, 6, 10, 14, 1, 5, 9, 13, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
|
||||||
|
COLUMN(x,y, 2, 4, 8, 12, 0, 3, 7, 11, 15, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
|
||||||
|
COLUMN(x,y, 4, 6, 10, 14, 2, 5, 9, 13, 1, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
|
||||||
|
COLUMN(x,y, 6, 8, 12, 0, 4, 7, 11, 15, 3, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
|
||||||
|
COLUMN(x,y, 8, 10, 14, 2, 6, 9, 13, 1, 5, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
|
||||||
|
COLUMN(x,y,10, 12, 0, 4, 8, 11, 15, 3, 7, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
|
||||||
|
COLUMN(x,y,12, 14, 2, 6, 10, 13, 1, 5, 9, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
|
||||||
|
COLUMN(x,y,14, 0, 4, 8, 12, 15, 3, 7, 11, temp_v1, temp_v2, temp_upper_value, temp_lower_value, temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compute compression function (short variants) */
|
||||||
|
static void F512(uint32_t *h, const uint32_t *m) {
|
||||||
|
int i;
|
||||||
|
uint32_t Ptmp[2*COLS512];
|
||||||
|
uint32_t Qtmp[2*COLS512];
|
||||||
|
uint32_t y[2*COLS512];
|
||||||
|
uint32_t z[2*COLS512];
|
||||||
|
|
||||||
|
for (i = 0; i < 2*COLS512; i++) {
|
||||||
|
z[i] = m[i];
|
||||||
|
Ptmp[i] = h[i]^m[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* compute Q(m) */
|
||||||
|
RND512Q((uint8_t*)z, y, 0x00000000);
|
||||||
|
RND512Q((uint8_t*)y, z, 0x01000000);
|
||||||
|
RND512Q((uint8_t*)z, y, 0x02000000);
|
||||||
|
RND512Q((uint8_t*)y, z, 0x03000000);
|
||||||
|
RND512Q((uint8_t*)z, y, 0x04000000);
|
||||||
|
RND512Q((uint8_t*)y, z, 0x05000000);
|
||||||
|
RND512Q((uint8_t*)z, y, 0x06000000);
|
||||||
|
RND512Q((uint8_t*)y, z, 0x07000000);
|
||||||
|
RND512Q((uint8_t*)z, y, 0x08000000);
|
||||||
|
RND512Q((uint8_t*)y, Qtmp, 0x09000000);
|
||||||
|
|
||||||
|
/* compute P(h+m) */
|
||||||
|
RND512P((uint8_t*)Ptmp, y, 0x00000000);
|
||||||
|
RND512P((uint8_t*)y, z, 0x00000001);
|
||||||
|
RND512P((uint8_t*)z, y, 0x00000002);
|
||||||
|
RND512P((uint8_t*)y, z, 0x00000003);
|
||||||
|
RND512P((uint8_t*)z, y, 0x00000004);
|
||||||
|
RND512P((uint8_t*)y, z, 0x00000005);
|
||||||
|
RND512P((uint8_t*)z, y, 0x00000006);
|
||||||
|
RND512P((uint8_t*)y, z, 0x00000007);
|
||||||
|
RND512P((uint8_t*)z, y, 0x00000008);
|
||||||
|
RND512P((uint8_t*)y, Ptmp, 0x00000009);
|
||||||
|
|
||||||
|
/* compute P(h+m) + Q(m) + h */
|
||||||
|
for (i = 0; i < 2*COLS512; i++) {
|
||||||
|
h[i] ^= Ptmp[i]^Qtmp[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* digest up to msglen bytes of input (full blocks only) */
|
||||||
|
static void Transform(groestlHashState *ctx,
|
||||||
|
const uint8_t *input,
|
||||||
|
int msglen) {
|
||||||
|
|
||||||
|
/* digest message, one block at a time */
|
||||||
|
for (; msglen >= SIZE512;
|
||||||
|
msglen -= SIZE512, input += SIZE512) {
|
||||||
|
F512(ctx->chaining,(uint32_t*)input);
|
||||||
|
|
||||||
|
/* increment block counter */
|
||||||
|
ctx->block_counter1++;
|
||||||
|
if (ctx->block_counter1 == 0) ctx->block_counter2++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* given state h, do h <- P(h)+h */
|
||||||
|
static void OutputTransformation(groestlHashState *ctx) {
|
||||||
|
int j;
|
||||||
|
uint32_t temp[2*COLS512];
|
||||||
|
uint32_t y[2*COLS512];
|
||||||
|
uint32_t z[2*COLS512];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (j = 0; j < 2*COLS512; j++) {
|
||||||
|
temp[j] = ctx->chaining[j];
|
||||||
|
}
|
||||||
|
RND512P((uint8_t*)temp, y, 0x00000000);
|
||||||
|
RND512P((uint8_t*)y, z, 0x00000001);
|
||||||
|
RND512P((uint8_t*)z, y, 0x00000002);
|
||||||
|
RND512P((uint8_t*)y, z, 0x00000003);
|
||||||
|
RND512P((uint8_t*)z, y, 0x00000004);
|
||||||
|
RND512P((uint8_t*)y, z, 0x00000005);
|
||||||
|
RND512P((uint8_t*)z, y, 0x00000006);
|
||||||
|
RND512P((uint8_t*)y, z, 0x00000007);
|
||||||
|
RND512P((uint8_t*)z, y, 0x00000008);
|
||||||
|
RND512P((uint8_t*)y, temp, 0x00000009);
|
||||||
|
for (j = 0; j < 2*COLS512; j++) {
|
||||||
|
ctx->chaining[j] ^= temp[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialise context */
|
||||||
|
static void Init(groestlHashState* ctx) {
|
||||||
|
int i = 0;
|
||||||
|
/* allocate memory for state and data buffer */
|
||||||
|
|
||||||
|
for(;i<(SIZE512/sizeof(uint32_t));i++)
|
||||||
|
{
|
||||||
|
ctx->chaining[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set initial value */
|
||||||
|
ctx->chaining[2*COLS512-1] = u32BIG((uint32_t)HASH_BIT_LEN);
|
||||||
|
|
||||||
|
/* set other variables */
|
||||||
|
ctx->buf_ptr = 0;
|
||||||
|
ctx->block_counter1 = 0;
|
||||||
|
ctx->block_counter2 = 0;
|
||||||
|
ctx->bits_in_last_byte = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* update state with databitlen bits of input */
|
||||||
|
static void Update(groestlHashState* ctx,
|
||||||
|
const BitSequence* input,
|
||||||
|
DataLength databitlen) {
|
||||||
|
int index = 0;
|
||||||
|
int msglen = (int)(databitlen/8);
|
||||||
|
int rem = (int)(databitlen%8);
|
||||||
|
|
||||||
|
/* if the buffer contains data that has not yet been digested, first
|
||||||
|
add data to buffer until full */
|
||||||
|
if (ctx->buf_ptr) {
|
||||||
|
while (ctx->buf_ptr < SIZE512 && index < msglen) {
|
||||||
|
ctx->buffer[(int)ctx->buf_ptr++] = input[index++];
|
||||||
|
}
|
||||||
|
if (ctx->buf_ptr < SIZE512) {
|
||||||
|
/* buffer still not full, return */
|
||||||
|
if (rem) {
|
||||||
|
ctx->bits_in_last_byte = rem;
|
||||||
|
ctx->buffer[(int)ctx->buf_ptr++] = input[index];
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* digest buffer */
|
||||||
|
ctx->buf_ptr = 0;
|
||||||
|
Transform(ctx, ctx->buffer, SIZE512);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* digest bulk of message */
|
||||||
|
Transform(ctx, input+index, msglen-index);
|
||||||
|
index += ((msglen-index)/SIZE512)*SIZE512;
|
||||||
|
|
||||||
|
/* store remaining data in buffer */
|
||||||
|
while (index < msglen) {
|
||||||
|
ctx->buffer[(int)ctx->buf_ptr++] = input[index++];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if non-integral number of bytes have been supplied, store
|
||||||
|
remaining bits in last byte, together with information about
|
||||||
|
number of bits */
|
||||||
|
if (rem) {
|
||||||
|
ctx->bits_in_last_byte = rem;
|
||||||
|
ctx->buffer[(int)ctx->buf_ptr++] = input[index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BILB ctx->bits_in_last_byte
|
||||||
|
|
||||||
|
/* finalise: process remaining data (including padding), perform
|
||||||
|
output transformation, and write hash result to 'output' */
|
||||||
|
static void Final(groestlHashState* ctx,
|
||||||
|
BitSequence* output) {
|
||||||
|
int i, j = 0, hashbytelen = HASH_BIT_LEN/8;
|
||||||
|
uint8_t *s = (BitSequence*)ctx->chaining;
|
||||||
|
|
||||||
|
/* pad with '1'-bit and first few '0'-bits */
|
||||||
|
if (BILB) {
|
||||||
|
ctx->buffer[(int)ctx->buf_ptr-1] &= ((1<<BILB)-1)<<(8-BILB);
|
||||||
|
ctx->buffer[(int)ctx->buf_ptr-1] ^= 0x1<<(7-BILB);
|
||||||
|
BILB = 0;
|
||||||
|
}
|
||||||
|
else ctx->buffer[(int)ctx->buf_ptr++] = 0x80;
|
||||||
|
|
||||||
|
/* pad with '0'-bits */
|
||||||
|
if (ctx->buf_ptr > SIZE512-LENGTHFIELDLEN) {
|
||||||
|
/* padding requires two blocks */
|
||||||
|
while (ctx->buf_ptr < SIZE512) {
|
||||||
|
ctx->buffer[(int)ctx->buf_ptr++] = 0;
|
||||||
|
}
|
||||||
|
/* digest first padding block */
|
||||||
|
Transform(ctx, ctx->buffer, SIZE512);
|
||||||
|
ctx->buf_ptr = 0;
|
||||||
|
}
|
||||||
|
while (ctx->buf_ptr < SIZE512-LENGTHFIELDLEN) {
|
||||||
|
ctx->buffer[(int)ctx->buf_ptr++] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* length padding */
|
||||||
|
ctx->block_counter1++;
|
||||||
|
if (ctx->block_counter1 == 0) ctx->block_counter2++;
|
||||||
|
ctx->buf_ptr = SIZE512;
|
||||||
|
|
||||||
|
while (ctx->buf_ptr > SIZE512-(int)sizeof(uint32_t)) {
|
||||||
|
ctx->buffer[(int)--ctx->buf_ptr] = (uint8_t)ctx->block_counter1;
|
||||||
|
ctx->block_counter1 >>= 8;
|
||||||
|
}
|
||||||
|
while (ctx->buf_ptr > SIZE512-LENGTHFIELDLEN) {
|
||||||
|
ctx->buffer[(int)--ctx->buf_ptr] = (uint8_t)ctx->block_counter2;
|
||||||
|
ctx->block_counter2 >>= 8;
|
||||||
|
}
|
||||||
|
/* digest final padding block */
|
||||||
|
Transform(ctx, ctx->buffer, SIZE512);
|
||||||
|
/* perform output transformation */
|
||||||
|
OutputTransformation(ctx);
|
||||||
|
|
||||||
|
/* store hash result in output */
|
||||||
|
for (i = SIZE512-hashbytelen; i < SIZE512; i++,j++) {
|
||||||
|
output[j] = s[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* zeroise relevant variables and deallocate memory */
|
||||||
|
for (i = 0; i < COLS512; i++) {
|
||||||
|
ctx->chaining[i] = 0;
|
||||||
|
}
|
||||||
|
for (i = 0; i < SIZE512; i++) {
|
||||||
|
ctx->buffer[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hash bit sequence */
|
||||||
|
void groestl(const BitSequence* data,
|
||||||
|
DataLength databitlen,
|
||||||
|
BitSequence* hashval) {
|
||||||
|
|
||||||
|
groestlHashState context;
|
||||||
|
|
||||||
|
/* initialise */
|
||||||
|
Init(&context);
|
||||||
|
|
||||||
|
|
||||||
|
/* process message */
|
||||||
|
Update(&context, data, databitlen);
|
||||||
|
|
||||||
|
/* finalise */
|
||||||
|
Final(&context, hashval);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
static int crypto_hash(unsigned char *out,
|
||||||
|
const unsigned char *in,
|
||||||
|
unsigned long long len)
|
||||||
|
{
|
||||||
|
groestl(in, 8*len, out);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
|
@ -0,0 +1,60 @@
|
||||||
|
#ifndef __hash_h
|
||||||
|
#define __hash_h
|
||||||
|
/*
|
||||||
|
#include "crypto_uint8.h"
|
||||||
|
#include "crypto_uint32.h"
|
||||||
|
#include "crypto_uint64.h"
|
||||||
|
#include "crypto_hash.h"
|
||||||
|
|
||||||
|
typedef crypto_uint8 uint8_t;
|
||||||
|
typedef crypto_uint32 uint32_t;
|
||||||
|
typedef crypto_uint64 uint64_t;
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "hash.h"
|
||||||
|
|
||||||
|
/* some sizes (number of bytes) */
|
||||||
|
#define ROWS 8
|
||||||
|
#define LENGTHFIELDLEN ROWS
|
||||||
|
#define COLS512 8
|
||||||
|
|
||||||
|
#define SIZE512 (ROWS*COLS512)
|
||||||
|
|
||||||
|
#define ROUNDS512 10
|
||||||
|
#define HASH_BIT_LEN 256
|
||||||
|
|
||||||
|
#define ROTL32(v, n) ((((v)<<(n))|((v)>>(32-(n))))&li_32(ffffffff))
|
||||||
|
|
||||||
|
|
||||||
|
#define li_32(h) 0x##h##u
|
||||||
|
#define EXT_BYTE(var,n) ((uint8_t)((uint32_t)(var) >> (8*n)))
|
||||||
|
#define u32BIG(a) \
|
||||||
|
((ROTL32(a,8) & li_32(00FF00FF)) | \
|
||||||
|
(ROTL32(a,24) & li_32(FF00FF00)))
|
||||||
|
|
||||||
|
|
||||||
|
/* NIST API begin */
|
||||||
|
typedef struct {
|
||||||
|
uint32_t chaining[SIZE512/sizeof(uint32_t)]; /* actual state */
|
||||||
|
uint32_t block_counter1,
|
||||||
|
block_counter2; /* message block counter(s) */
|
||||||
|
BitSequence buffer[SIZE512]; /* data buffer */
|
||||||
|
int buf_ptr; /* data buffer pointer */
|
||||||
|
int bits_in_last_byte; /* no. of message bits in last byte of
|
||||||
|
data buffer */
|
||||||
|
} groestlHashState;
|
||||||
|
|
||||||
|
/*void Init(hashState*);
|
||||||
|
void Update(hashState*, const BitSequence*, DataLength);
|
||||||
|
void Final(hashState*, BitSequence*); */
|
||||||
|
void groestl(const BitSequence*, DataLength, BitSequence*);
|
||||||
|
/* NIST API end */
|
||||||
|
|
||||||
|
/*
|
||||||
|
int crypto_hash(unsigned char *out,
|
||||||
|
const unsigned char *in,
|
||||||
|
unsigned long long len);
|
||||||
|
*/
|
||||||
|
|
||||||
|
#endif /* __hash_h */
|
|
@ -0,0 +1,367 @@
|
||||||
|
/*This program gives the 64-bit optimized bitslice implementation of JH using ANSI C
|
||||||
|
|
||||||
|
--------------------------------
|
||||||
|
Performance
|
||||||
|
|
||||||
|
Microprocessor: Intel CORE 2 processor (Core 2 Duo Mobile T6600 2.2GHz)
|
||||||
|
Operating System: 64-bit Ubuntu 10.04 (Linux kernel 2.6.32-22-generic)
|
||||||
|
Speed for long message:
|
||||||
|
1) 45.8 cycles/byte compiler: Intel C++ Compiler 11.1 compilation option: icc -O2
|
||||||
|
2) 56.8 cycles/byte compiler: gcc 4.4.3 compilation option: gcc -O3
|
||||||
|
|
||||||
|
--------------------------------
|
||||||
|
Last Modified: January 16, 2011
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "c_jh.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*typedef unsigned long long uint64;*/
|
||||||
|
typedef uint64_t uint64;
|
||||||
|
|
||||||
|
/*define data alignment for different C compilers*/
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define DATA_ALIGN16(x) x __attribute__ ((aligned(16)))
|
||||||
|
#else
|
||||||
|
#define DATA_ALIGN16(x) __declspec(align(16)) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int hashbitlen; /*the message digest size*/
|
||||||
|
unsigned long long databitlen; /*the message size in bits*/
|
||||||
|
unsigned long long datasize_in_buffer; /*the size of the message remained in buffer; assumed to be multiple of 8bits except for the last partial block at the end of the message*/
|
||||||
|
DATA_ALIGN16(uint64 x[8][2]); /*the 1024-bit state, ( x[i][0] || x[i][1] ) is the ith row of the state in the pseudocode*/
|
||||||
|
unsigned char buffer[64]; /*the 512-bit message block to be hashed;*/
|
||||||
|
} hashState;
|
||||||
|
|
||||||
|
|
||||||
|
/*The initial hash value H(0)*/
|
||||||
|
const unsigned char JH224_H0[128]={0x2d,0xfe,0xdd,0x62,0xf9,0x9a,0x98,0xac,0xae,0x7c,0xac,0xd6,0x19,0xd6,0x34,0xe7,0xa4,0x83,0x10,0x5,0xbc,0x30,0x12,0x16,0xb8,0x60,0x38,0xc6,0xc9,0x66,0x14,0x94,0x66,0xd9,0x89,0x9f,0x25,0x80,0x70,0x6f,0xce,0x9e,0xa3,0x1b,0x1d,0x9b,0x1a,0xdc,0x11,0xe8,0x32,0x5f,0x7b,0x36,0x6e,0x10,0xf9,0x94,0x85,0x7f,0x2,0xfa,0x6,0xc1,0x1b,0x4f,0x1b,0x5c,0xd8,0xc8,0x40,0xb3,0x97,0xf6,0xa1,0x7f,0x6e,0x73,0x80,0x99,0xdc,0xdf,0x93,0xa5,0xad,0xea,0xa3,0xd3,0xa4,0x31,0xe8,0xde,0xc9,0x53,0x9a,0x68,0x22,0xb4,0xa9,0x8a,0xec,0x86,0xa1,0xe4,0xd5,0x74,0xac,0x95,0x9c,0xe5,0x6c,0xf0,0x15,0x96,0xd,0xea,0xb5,0xab,0x2b,0xbf,0x96,0x11,0xdc,0xf0,0xdd,0x64,0xea,0x6e};
|
||||||
|
const unsigned char JH256_H0[128]={0xeb,0x98,0xa3,0x41,0x2c,0x20,0xd3,0xeb,0x92,0xcd,0xbe,0x7b,0x9c,0xb2,0x45,0xc1,0x1c,0x93,0x51,0x91,0x60,0xd4,0xc7,0xfa,0x26,0x0,0x82,0xd6,0x7e,0x50,0x8a,0x3,0xa4,0x23,0x9e,0x26,0x77,0x26,0xb9,0x45,0xe0,0xfb,0x1a,0x48,0xd4,0x1a,0x94,0x77,0xcd,0xb5,0xab,0x26,0x2,0x6b,0x17,0x7a,0x56,0xf0,0x24,0x42,0xf,0xff,0x2f,0xa8,0x71,0xa3,0x96,0x89,0x7f,0x2e,0x4d,0x75,0x1d,0x14,0x49,0x8,0xf7,0x7d,0xe2,0x62,0x27,0x76,0x95,0xf7,0x76,0x24,0x8f,0x94,0x87,0xd5,0xb6,0x57,0x47,0x80,0x29,0x6c,0x5c,0x5e,0x27,0x2d,0xac,0x8e,0xd,0x6c,0x51,0x84,0x50,0xc6,0x57,0x5,0x7a,0xf,0x7b,0xe4,0xd3,0x67,0x70,0x24,0x12,0xea,0x89,0xe3,0xab,0x13,0xd3,0x1c,0xd7,0x69};
|
||||||
|
const unsigned char JH384_H0[128]={0x48,0x1e,0x3b,0xc6,0xd8,0x13,0x39,0x8a,0x6d,0x3b,0x5e,0x89,0x4a,0xde,0x87,0x9b,0x63,0xfa,0xea,0x68,0xd4,0x80,0xad,0x2e,0x33,0x2c,0xcb,0x21,0x48,0xf,0x82,0x67,0x98,0xae,0xc8,0x4d,0x90,0x82,0xb9,0x28,0xd4,0x55,0xea,0x30,0x41,0x11,0x42,0x49,0x36,0xf5,0x55,0xb2,0x92,0x48,0x47,0xec,0xc7,0x25,0xa,0x93,0xba,0xf4,0x3c,0xe1,0x56,0x9b,0x7f,0x8a,0x27,0xdb,0x45,0x4c,0x9e,0xfc,0xbd,0x49,0x63,0x97,0xaf,0xe,0x58,0x9f,0xc2,0x7d,0x26,0xaa,0x80,0xcd,0x80,0xc0,0x8b,0x8c,0x9d,0xeb,0x2e,0xda,0x8a,0x79,0x81,0xe8,0xf8,0xd5,0x37,0x3a,0xf4,0x39,0x67,0xad,0xdd,0xd1,0x7a,0x71,0xa9,0xb4,0xd3,0xbd,0xa4,0x75,0xd3,0x94,0x97,0x6c,0x3f,0xba,0x98,0x42,0x73,0x7f};
|
||||||
|
const unsigned char JH512_H0[128]={0x6f,0xd1,0x4b,0x96,0x3e,0x0,0xaa,0x17,0x63,0x6a,0x2e,0x5,0x7a,0x15,0xd5,0x43,0x8a,0x22,0x5e,0x8d,0xc,0x97,0xef,0xb,0xe9,0x34,0x12,0x59,0xf2,0xb3,0xc3,0x61,0x89,0x1d,0xa0,0xc1,0x53,0x6f,0x80,0x1e,0x2a,0xa9,0x5,0x6b,0xea,0x2b,0x6d,0x80,0x58,0x8e,0xcc,0xdb,0x20,0x75,0xba,0xa6,0xa9,0xf,0x3a,0x76,0xba,0xf8,0x3b,0xf7,0x1,0x69,0xe6,0x5,0x41,0xe3,0x4a,0x69,0x46,0xb5,0x8a,0x8e,0x2e,0x6f,0xe6,0x5a,0x10,0x47,0xa7,0xd0,0xc1,0x84,0x3c,0x24,0x3b,0x6e,0x71,0xb1,0x2d,0x5a,0xc1,0x99,0xcf,0x57,0xf6,0xec,0x9d,0xb1,0xf8,0x56,0xa7,0x6,0x88,0x7c,0x57,0x16,0xb1,0x56,0xe3,0xc2,0xfc,0xdf,0xe6,0x85,0x17,0xfb,0x54,0x5a,0x46,0x78,0xcc,0x8c,0xdd,0x4b};
|
||||||
|
|
||||||
|
/*42 round constants, each round constant is 32-byte (256-bit)*/
|
||||||
|
const unsigned char E8_bitslice_roundconstant[42][32]={
|
||||||
|
{0x72,0xd5,0xde,0xa2,0xdf,0x15,0xf8,0x67,0x7b,0x84,0x15,0xa,0xb7,0x23,0x15,0x57,0x81,0xab,0xd6,0x90,0x4d,0x5a,0x87,0xf6,0x4e,0x9f,0x4f,0xc5,0xc3,0xd1,0x2b,0x40},
|
||||||
|
{0xea,0x98,0x3a,0xe0,0x5c,0x45,0xfa,0x9c,0x3,0xc5,0xd2,0x99,0x66,0xb2,0x99,0x9a,0x66,0x2,0x96,0xb4,0xf2,0xbb,0x53,0x8a,0xb5,0x56,0x14,0x1a,0x88,0xdb,0xa2,0x31},
|
||||||
|
{0x3,0xa3,0x5a,0x5c,0x9a,0x19,0xe,0xdb,0x40,0x3f,0xb2,0xa,0x87,0xc1,0x44,0x10,0x1c,0x5,0x19,0x80,0x84,0x9e,0x95,0x1d,0x6f,0x33,0xeb,0xad,0x5e,0xe7,0xcd,0xdc},
|
||||||
|
{0x10,0xba,0x13,0x92,0x2,0xbf,0x6b,0x41,0xdc,0x78,0x65,0x15,0xf7,0xbb,0x27,0xd0,0xa,0x2c,0x81,0x39,0x37,0xaa,0x78,0x50,0x3f,0x1a,0xbf,0xd2,0x41,0x0,0x91,0xd3},
|
||||||
|
{0x42,0x2d,0x5a,0xd,0xf6,0xcc,0x7e,0x90,0xdd,0x62,0x9f,0x9c,0x92,0xc0,0x97,0xce,0x18,0x5c,0xa7,0xb,0xc7,0x2b,0x44,0xac,0xd1,0xdf,0x65,0xd6,0x63,0xc6,0xfc,0x23},
|
||||||
|
{0x97,0x6e,0x6c,0x3,0x9e,0xe0,0xb8,0x1a,0x21,0x5,0x45,0x7e,0x44,0x6c,0xec,0xa8,0xee,0xf1,0x3,0xbb,0x5d,0x8e,0x61,0xfa,0xfd,0x96,0x97,0xb2,0x94,0x83,0x81,0x97},
|
||||||
|
{0x4a,0x8e,0x85,0x37,0xdb,0x3,0x30,0x2f,0x2a,0x67,0x8d,0x2d,0xfb,0x9f,0x6a,0x95,0x8a,0xfe,0x73,0x81,0xf8,0xb8,0x69,0x6c,0x8a,0xc7,0x72,0x46,0xc0,0x7f,0x42,0x14},
|
||||||
|
{0xc5,0xf4,0x15,0x8f,0xbd,0xc7,0x5e,0xc4,0x75,0x44,0x6f,0xa7,0x8f,0x11,0xbb,0x80,0x52,0xde,0x75,0xb7,0xae,0xe4,0x88,0xbc,0x82,0xb8,0x0,0x1e,0x98,0xa6,0xa3,0xf4},
|
||||||
|
{0x8e,0xf4,0x8f,0x33,0xa9,0xa3,0x63,0x15,0xaa,0x5f,0x56,0x24,0xd5,0xb7,0xf9,0x89,0xb6,0xf1,0xed,0x20,0x7c,0x5a,0xe0,0xfd,0x36,0xca,0xe9,0x5a,0x6,0x42,0x2c,0x36},
|
||||||
|
{0xce,0x29,0x35,0x43,0x4e,0xfe,0x98,0x3d,0x53,0x3a,0xf9,0x74,0x73,0x9a,0x4b,0xa7,0xd0,0xf5,0x1f,0x59,0x6f,0x4e,0x81,0x86,0xe,0x9d,0xad,0x81,0xaf,0xd8,0x5a,0x9f},
|
||||||
|
{0xa7,0x5,0x6,0x67,0xee,0x34,0x62,0x6a,0x8b,0xb,0x28,0xbe,0x6e,0xb9,0x17,0x27,0x47,0x74,0x7,0x26,0xc6,0x80,0x10,0x3f,0xe0,0xa0,0x7e,0x6f,0xc6,0x7e,0x48,0x7b},
|
||||||
|
{0xd,0x55,0xa,0xa5,0x4a,0xf8,0xa4,0xc0,0x91,0xe3,0xe7,0x9f,0x97,0x8e,0xf1,0x9e,0x86,0x76,0x72,0x81,0x50,0x60,0x8d,0xd4,0x7e,0x9e,0x5a,0x41,0xf3,0xe5,0xb0,0x62},
|
||||||
|
{0xfc,0x9f,0x1f,0xec,0x40,0x54,0x20,0x7a,0xe3,0xe4,0x1a,0x0,0xce,0xf4,0xc9,0x84,0x4f,0xd7,0x94,0xf5,0x9d,0xfa,0x95,0xd8,0x55,0x2e,0x7e,0x11,0x24,0xc3,0x54,0xa5},
|
||||||
|
{0x5b,0xdf,0x72,0x28,0xbd,0xfe,0x6e,0x28,0x78,0xf5,0x7f,0xe2,0xf,0xa5,0xc4,0xb2,0x5,0x89,0x7c,0xef,0xee,0x49,0xd3,0x2e,0x44,0x7e,0x93,0x85,0xeb,0x28,0x59,0x7f},
|
||||||
|
{0x70,0x5f,0x69,0x37,0xb3,0x24,0x31,0x4a,0x5e,0x86,0x28,0xf1,0x1d,0xd6,0xe4,0x65,0xc7,0x1b,0x77,0x4,0x51,0xb9,0x20,0xe7,0x74,0xfe,0x43,0xe8,0x23,0xd4,0x87,0x8a},
|
||||||
|
{0x7d,0x29,0xe8,0xa3,0x92,0x76,0x94,0xf2,0xdd,0xcb,0x7a,0x9,0x9b,0x30,0xd9,0xc1,0x1d,0x1b,0x30,0xfb,0x5b,0xdc,0x1b,0xe0,0xda,0x24,0x49,0x4f,0xf2,0x9c,0x82,0xbf},
|
||||||
|
{0xa4,0xe7,0xba,0x31,0xb4,0x70,0xbf,0xff,0xd,0x32,0x44,0x5,0xde,0xf8,0xbc,0x48,0x3b,0xae,0xfc,0x32,0x53,0xbb,0xd3,0x39,0x45,0x9f,0xc3,0xc1,0xe0,0x29,0x8b,0xa0},
|
||||||
|
{0xe5,0xc9,0x5,0xfd,0xf7,0xae,0x9,0xf,0x94,0x70,0x34,0x12,0x42,0x90,0xf1,0x34,0xa2,0x71,0xb7,0x1,0xe3,0x44,0xed,0x95,0xe9,0x3b,0x8e,0x36,0x4f,0x2f,0x98,0x4a},
|
||||||
|
{0x88,0x40,0x1d,0x63,0xa0,0x6c,0xf6,0x15,0x47,0xc1,0x44,0x4b,0x87,0x52,0xaf,0xff,0x7e,0xbb,0x4a,0xf1,0xe2,0xa,0xc6,0x30,0x46,0x70,0xb6,0xc5,0xcc,0x6e,0x8c,0xe6},
|
||||||
|
{0xa4,0xd5,0xa4,0x56,0xbd,0x4f,0xca,0x0,0xda,0x9d,0x84,0x4b,0xc8,0x3e,0x18,0xae,0x73,0x57,0xce,0x45,0x30,0x64,0xd1,0xad,0xe8,0xa6,0xce,0x68,0x14,0x5c,0x25,0x67},
|
||||||
|
{0xa3,0xda,0x8c,0xf2,0xcb,0xe,0xe1,0x16,0x33,0xe9,0x6,0x58,0x9a,0x94,0x99,0x9a,0x1f,0x60,0xb2,0x20,0xc2,0x6f,0x84,0x7b,0xd1,0xce,0xac,0x7f,0xa0,0xd1,0x85,0x18},
|
||||||
|
{0x32,0x59,0x5b,0xa1,0x8d,0xdd,0x19,0xd3,0x50,0x9a,0x1c,0xc0,0xaa,0xa5,0xb4,0x46,0x9f,0x3d,0x63,0x67,0xe4,0x4,0x6b,0xba,0xf6,0xca,0x19,0xab,0xb,0x56,0xee,0x7e},
|
||||||
|
{0x1f,0xb1,0x79,0xea,0xa9,0x28,0x21,0x74,0xe9,0xbd,0xf7,0x35,0x3b,0x36,0x51,0xee,0x1d,0x57,0xac,0x5a,0x75,0x50,0xd3,0x76,0x3a,0x46,0xc2,0xfe,0xa3,0x7d,0x70,0x1},
|
||||||
|
{0xf7,0x35,0xc1,0xaf,0x98,0xa4,0xd8,0x42,0x78,0xed,0xec,0x20,0x9e,0x6b,0x67,0x79,0x41,0x83,0x63,0x15,0xea,0x3a,0xdb,0xa8,0xfa,0xc3,0x3b,0x4d,0x32,0x83,0x2c,0x83},
|
||||||
|
{0xa7,0x40,0x3b,0x1f,0x1c,0x27,0x47,0xf3,0x59,0x40,0xf0,0x34,0xb7,0x2d,0x76,0x9a,0xe7,0x3e,0x4e,0x6c,0xd2,0x21,0x4f,0xfd,0xb8,0xfd,0x8d,0x39,0xdc,0x57,0x59,0xef},
|
||||||
|
{0x8d,0x9b,0xc,0x49,0x2b,0x49,0xeb,0xda,0x5b,0xa2,0xd7,0x49,0x68,0xf3,0x70,0xd,0x7d,0x3b,0xae,0xd0,0x7a,0x8d,0x55,0x84,0xf5,0xa5,0xe9,0xf0,0xe4,0xf8,0x8e,0x65},
|
||||||
|
{0xa0,0xb8,0xa2,0xf4,0x36,0x10,0x3b,0x53,0xc,0xa8,0x7,0x9e,0x75,0x3e,0xec,0x5a,0x91,0x68,0x94,0x92,0x56,0xe8,0x88,0x4f,0x5b,0xb0,0x5c,0x55,0xf8,0xba,0xbc,0x4c},
|
||||||
|
{0xe3,0xbb,0x3b,0x99,0xf3,0x87,0x94,0x7b,0x75,0xda,0xf4,0xd6,0x72,0x6b,0x1c,0x5d,0x64,0xae,0xac,0x28,0xdc,0x34,0xb3,0x6d,0x6c,0x34,0xa5,0x50,0xb8,0x28,0xdb,0x71},
|
||||||
|
{0xf8,0x61,0xe2,0xf2,0x10,0x8d,0x51,0x2a,0xe3,0xdb,0x64,0x33,0x59,0xdd,0x75,0xfc,0x1c,0xac,0xbc,0xf1,0x43,0xce,0x3f,0xa2,0x67,0xbb,0xd1,0x3c,0x2,0xe8,0x43,0xb0},
|
||||||
|
{0x33,0xa,0x5b,0xca,0x88,0x29,0xa1,0x75,0x7f,0x34,0x19,0x4d,0xb4,0x16,0x53,0x5c,0x92,0x3b,0x94,0xc3,0xe,0x79,0x4d,0x1e,0x79,0x74,0x75,0xd7,0xb6,0xee,0xaf,0x3f},
|
||||||
|
{0xea,0xa8,0xd4,0xf7,0xbe,0x1a,0x39,0x21,0x5c,0xf4,0x7e,0x9,0x4c,0x23,0x27,0x51,0x26,0xa3,0x24,0x53,0xba,0x32,0x3c,0xd2,0x44,0xa3,0x17,0x4a,0x6d,0xa6,0xd5,0xad},
|
||||||
|
{0xb5,0x1d,0x3e,0xa6,0xaf,0xf2,0xc9,0x8,0x83,0x59,0x3d,0x98,0x91,0x6b,0x3c,0x56,0x4c,0xf8,0x7c,0xa1,0x72,0x86,0x60,0x4d,0x46,0xe2,0x3e,0xcc,0x8,0x6e,0xc7,0xf6},
|
||||||
|
{0x2f,0x98,0x33,0xb3,0xb1,0xbc,0x76,0x5e,0x2b,0xd6,0x66,0xa5,0xef,0xc4,0xe6,0x2a,0x6,0xf4,0xb6,0xe8,0xbe,0xc1,0xd4,0x36,0x74,0xee,0x82,0x15,0xbc,0xef,0x21,0x63},
|
||||||
|
{0xfd,0xc1,0x4e,0xd,0xf4,0x53,0xc9,0x69,0xa7,0x7d,0x5a,0xc4,0x6,0x58,0x58,0x26,0x7e,0xc1,0x14,0x16,0x6,0xe0,0xfa,0x16,0x7e,0x90,0xaf,0x3d,0x28,0x63,0x9d,0x3f},
|
||||||
|
{0xd2,0xc9,0xf2,0xe3,0x0,0x9b,0xd2,0xc,0x5f,0xaa,0xce,0x30,0xb7,0xd4,0xc,0x30,0x74,0x2a,0x51,0x16,0xf2,0xe0,0x32,0x98,0xd,0xeb,0x30,0xd8,0xe3,0xce,0xf8,0x9a},
|
||||||
|
{0x4b,0xc5,0x9e,0x7b,0xb5,0xf1,0x79,0x92,0xff,0x51,0xe6,0x6e,0x4,0x86,0x68,0xd3,0x9b,0x23,0x4d,0x57,0xe6,0x96,0x67,0x31,0xcc,0xe6,0xa6,0xf3,0x17,0xa,0x75,0x5},
|
||||||
|
{0xb1,0x76,0x81,0xd9,0x13,0x32,0x6c,0xce,0x3c,0x17,0x52,0x84,0xf8,0x5,0xa2,0x62,0xf4,0x2b,0xcb,0xb3,0x78,0x47,0x15,0x47,0xff,0x46,0x54,0x82,0x23,0x93,0x6a,0x48},
|
||||||
|
{0x38,0xdf,0x58,0x7,0x4e,0x5e,0x65,0x65,0xf2,0xfc,0x7c,0x89,0xfc,0x86,0x50,0x8e,0x31,0x70,0x2e,0x44,0xd0,0xb,0xca,0x86,0xf0,0x40,0x9,0xa2,0x30,0x78,0x47,0x4e},
|
||||||
|
{0x65,0xa0,0xee,0x39,0xd1,0xf7,0x38,0x83,0xf7,0x5e,0xe9,0x37,0xe4,0x2c,0x3a,0xbd,0x21,0x97,0xb2,0x26,0x1,0x13,0xf8,0x6f,0xa3,0x44,0xed,0xd1,0xef,0x9f,0xde,0xe7},
|
||||||
|
{0x8b,0xa0,0xdf,0x15,0x76,0x25,0x92,0xd9,0x3c,0x85,0xf7,0xf6,0x12,0xdc,0x42,0xbe,0xd8,0xa7,0xec,0x7c,0xab,0x27,0xb0,0x7e,0x53,0x8d,0x7d,0xda,0xaa,0x3e,0xa8,0xde},
|
||||||
|
{0xaa,0x25,0xce,0x93,0xbd,0x2,0x69,0xd8,0x5a,0xf6,0x43,0xfd,0x1a,0x73,0x8,0xf9,0xc0,0x5f,0xef,0xda,0x17,0x4a,0x19,0xa5,0x97,0x4d,0x66,0x33,0x4c,0xfd,0x21,0x6a},
|
||||||
|
{0x35,0xb4,0x98,0x31,0xdb,0x41,0x15,0x70,0xea,0x1e,0xf,0xbb,0xed,0xcd,0x54,0x9b,0x9a,0xd0,0x63,0xa1,0x51,0x97,0x40,0x72,0xf6,0x75,0x9d,0xbf,0x91,0x47,0x6f,0xe2}};
|
||||||
|
|
||||||
|
|
||||||
|
static void E8(hashState *state); /*The bijective function E8, in bitslice form*/
|
||||||
|
static void F8(hashState *state); /*The compression function F8 */
|
||||||
|
|
||||||
|
/*The API functions*/
|
||||||
|
static HashReturn Init(hashState *state, int hashbitlen);
|
||||||
|
static HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen);
|
||||||
|
static HashReturn Final(hashState *state, BitSequence *hashval);
|
||||||
|
HashReturn jh_hash(int hashbitlen, const BitSequence *data,DataLength databitlen, BitSequence *hashval);
|
||||||
|
|
||||||
|
/*swapping bit 2i with bit 2i+1 of 64-bit x*/
|
||||||
|
#define SWAP1(x) (x) = ((((x) & 0x5555555555555555ULL) << 1) | (((x) & 0xaaaaaaaaaaaaaaaaULL) >> 1));
|
||||||
|
/*swapping bits 4i||4i+1 with bits 4i+2||4i+3 of 64-bit x*/
|
||||||
|
#define SWAP2(x) (x) = ((((x) & 0x3333333333333333ULL) << 2) | (((x) & 0xccccccccccccccccULL) >> 2));
|
||||||
|
/*swapping bits 8i||8i+1||8i+2||8i+3 with bits 8i+4||8i+5||8i+6||8i+7 of 64-bit x*/
|
||||||
|
#define SWAP4(x) (x) = ((((x) & 0x0f0f0f0f0f0f0f0fULL) << 4) | (((x) & 0xf0f0f0f0f0f0f0f0ULL) >> 4));
|
||||||
|
/*swapping bits 16i||16i+1||......||16i+7 with bits 16i+8||16i+9||......||16i+15 of 64-bit x*/
|
||||||
|
#define SWAP8(x) (x) = ((((x) & 0x00ff00ff00ff00ffULL) << 8) | (((x) & 0xff00ff00ff00ff00ULL) >> 8));
|
||||||
|
/*swapping bits 32i||32i+1||......||32i+15 with bits 32i+16||32i+17||......||32i+31 of 64-bit x*/
|
||||||
|
#define SWAP16(x) (x) = ((((x) & 0x0000ffff0000ffffULL) << 16) | (((x) & 0xffff0000ffff0000ULL) >> 16));
|
||||||
|
/*swapping bits 64i||64i+1||......||64i+31 with bits 64i+32||64i+33||......||64i+63 of 64-bit x*/
|
||||||
|
#define SWAP32(x) (x) = (((x) << 32) | ((x) >> 32));
|
||||||
|
|
||||||
|
/*The MDS transform*/
|
||||||
|
#define L(m0,m1,m2,m3,m4,m5,m6,m7) \
|
||||||
|
(m4) ^= (m1); \
|
||||||
|
(m5) ^= (m2); \
|
||||||
|
(m6) ^= (m0) ^ (m3); \
|
||||||
|
(m7) ^= (m0); \
|
||||||
|
(m0) ^= (m5); \
|
||||||
|
(m1) ^= (m6); \
|
||||||
|
(m2) ^= (m4) ^ (m7); \
|
||||||
|
(m3) ^= (m4);
|
||||||
|
|
||||||
|
/*Two Sboxes are computed in parallel, each Sbox implements S0 and S1, selected by a constant bit*/
|
||||||
|
/*The reason to compute two Sboxes in parallel is to try to fully utilize the parallel processing power*/
|
||||||
|
#define SS(m0,m1,m2,m3,m4,m5,m6,m7,cc0,cc1) \
|
||||||
|
m3 = ~(m3); \
|
||||||
|
m7 = ~(m7); \
|
||||||
|
m0 ^= ((~(m2)) & (cc0)); \
|
||||||
|
m4 ^= ((~(m6)) & (cc1)); \
|
||||||
|
temp0 = (cc0) ^ ((m0) & (m1));\
|
||||||
|
temp1 = (cc1) ^ ((m4) & (m5));\
|
||||||
|
m0 ^= ((m2) & (m3)); \
|
||||||
|
m4 ^= ((m6) & (m7)); \
|
||||||
|
m3 ^= ((~(m1)) & (m2)); \
|
||||||
|
m7 ^= ((~(m5)) & (m6)); \
|
||||||
|
m1 ^= ((m0) & (m2)); \
|
||||||
|
m5 ^= ((m4) & (m6)); \
|
||||||
|
m2 ^= ((m0) & (~(m3))); \
|
||||||
|
m6 ^= ((m4) & (~(m7))); \
|
||||||
|
m0 ^= ((m1) | (m3)); \
|
||||||
|
m4 ^= ((m5) | (m7)); \
|
||||||
|
m3 ^= ((m1) & (m2)); \
|
||||||
|
m7 ^= ((m5) & (m6)); \
|
||||||
|
m1 ^= (temp0 & (m0)); \
|
||||||
|
m5 ^= (temp1 & (m4)); \
|
||||||
|
m2 ^= temp0; \
|
||||||
|
m6 ^= temp1;
|
||||||
|
|
||||||
|
/*The bijective function E8, in bitslice form*/
|
||||||
|
static void E8(hashState *state)
|
||||||
|
{
|
||||||
|
uint64 i,roundnumber,temp0,temp1;
|
||||||
|
|
||||||
|
for (roundnumber = 0; roundnumber < 42; roundnumber = roundnumber+7) {
|
||||||
|
/*round 7*roundnumber+0: Sbox, MDS and Swapping layers*/
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+0])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+0])[i+2] );
|
||||||
|
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
|
||||||
|
SWAP1(state->x[1][i]); SWAP1(state->x[3][i]); SWAP1(state->x[5][i]); SWAP1(state->x[7][i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*round 7*roundnumber+1: Sbox, MDS and Swapping layers*/
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+1])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+1])[i+2] );
|
||||||
|
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
|
||||||
|
SWAP2(state->x[1][i]); SWAP2(state->x[3][i]); SWAP2(state->x[5][i]); SWAP2(state->x[7][i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*round 7*roundnumber+2: Sbox, MDS and Swapping layers*/
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+2])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+2])[i+2] );
|
||||||
|
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
|
||||||
|
SWAP4(state->x[1][i]); SWAP4(state->x[3][i]); SWAP4(state->x[5][i]); SWAP4(state->x[7][i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*round 7*roundnumber+3: Sbox, MDS and Swapping layers*/
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+3])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+3])[i+2] );
|
||||||
|
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
|
||||||
|
SWAP8(state->x[1][i]); SWAP8(state->x[3][i]); SWAP8(state->x[5][i]); SWAP8(state->x[7][i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*round 7*roundnumber+4: Sbox, MDS and Swapping layers*/
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+4])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+4])[i+2] );
|
||||||
|
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
|
||||||
|
SWAP16(state->x[1][i]); SWAP16(state->x[3][i]); SWAP16(state->x[5][i]); SWAP16(state->x[7][i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*round 7*roundnumber+5: Sbox, MDS and Swapping layers*/
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+5])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+5])[i+2] );
|
||||||
|
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
|
||||||
|
SWAP32(state->x[1][i]); SWAP32(state->x[3][i]); SWAP32(state->x[5][i]); SWAP32(state->x[7][i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*round 7*roundnumber+6: Sbox and MDS layers*/
|
||||||
|
for (i = 0; i < 2; i++) {
|
||||||
|
SS(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i],((uint64*)E8_bitslice_roundconstant[roundnumber+6])[i],((uint64*)E8_bitslice_roundconstant[roundnumber+6])[i+2] );
|
||||||
|
L(state->x[0][i],state->x[2][i],state->x[4][i],state->x[6][i],state->x[1][i],state->x[3][i],state->x[5][i],state->x[7][i]);
|
||||||
|
}
|
||||||
|
/*round 7*roundnumber+6: swapping layer*/
|
||||||
|
for (i = 1; i < 8; i = i+2) {
|
||||||
|
temp0 = state->x[i][0]; state->x[i][0] = state->x[i][1]; state->x[i][1] = temp0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*The compression function F8 */
|
||||||
|
static void F8(hashState *state)
|
||||||
|
{
|
||||||
|
uint64 i;
|
||||||
|
|
||||||
|
/*xor the 512-bit message with the fist half of the 1024-bit hash state*/
|
||||||
|
for (i = 0; i < 8; i++) state->x[i >> 1][i & 1] ^= ((uint64*)state->buffer)[i];
|
||||||
|
|
||||||
|
/*the bijective function E8 */
|
||||||
|
E8(state);
|
||||||
|
|
||||||
|
/*xor the 512-bit message with the second half of the 1024-bit hash state*/
|
||||||
|
for (i = 0; i < 8; i++) state->x[(8+i) >> 1][(8+i) & 1] ^= ((uint64*)state->buffer)[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*before hashing a message, initialize the hash state as H0 */
|
||||||
|
static HashReturn Init(hashState *state, int hashbitlen)
|
||||||
|
{
|
||||||
|
state->databitlen = 0;
|
||||||
|
state->datasize_in_buffer = 0;
|
||||||
|
|
||||||
|
/*initialize the initial hash value of JH*/
|
||||||
|
state->hashbitlen = hashbitlen;
|
||||||
|
|
||||||
|
/*load the intital hash value into state*/
|
||||||
|
switch (hashbitlen)
|
||||||
|
{
|
||||||
|
case 224: memcpy(state->x,JH224_H0,128); break;
|
||||||
|
case 256: memcpy(state->x,JH256_H0,128); break;
|
||||||
|
case 384: memcpy(state->x,JH384_H0,128); break;
|
||||||
|
case 512: memcpy(state->x,JH512_H0,128); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*hash each 512-bit message block, except the last partial block*/
|
||||||
|
static HashReturn Update(hashState *state, const BitSequence *data, DataLength databitlen)
|
||||||
|
{
|
||||||
|
DataLength index; /*the starting address of the data to be compressed*/
|
||||||
|
|
||||||
|
state->databitlen += databitlen;
|
||||||
|
index = 0;
|
||||||
|
|
||||||
|
/*if there is remaining data in the buffer, fill it to a full message block first*/
|
||||||
|
/*we assume that the size of the data in the buffer is the multiple of 8 bits if it is not at the end of a message*/
|
||||||
|
|
||||||
|
/*There is data in the buffer, but the incoming data is insufficient for a full block*/
|
||||||
|
if ( (state->datasize_in_buffer > 0 ) && (( state->datasize_in_buffer + databitlen) < 512) ) {
|
||||||
|
if ( (databitlen & 7) == 0 ) {
|
||||||
|
memcpy(state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3)) ;
|
||||||
|
}
|
||||||
|
else memcpy(state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3)+1) ;
|
||||||
|
state->datasize_in_buffer += databitlen;
|
||||||
|
databitlen = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*There is data in the buffer, and the incoming data is sufficient for a full block*/
|
||||||
|
if ( (state->datasize_in_buffer > 0 ) && (( state->datasize_in_buffer + databitlen) >= 512) ) {
|
||||||
|
memcpy( state->buffer + (state->datasize_in_buffer >> 3), data, 64-(state->datasize_in_buffer >> 3) ) ;
|
||||||
|
index = 64-(state->datasize_in_buffer >> 3);
|
||||||
|
databitlen = databitlen - (512 - state->datasize_in_buffer);
|
||||||
|
F8(state);
|
||||||
|
state->datasize_in_buffer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*hash the remaining full message blocks*/
|
||||||
|
for ( ; databitlen >= 512; index = index+64, databitlen = databitlen - 512) {
|
||||||
|
memcpy(state->buffer, data+index, 64);
|
||||||
|
F8(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*store the partial block into buffer, assume that -- if part of the last byte is not part of the message, then that part consists of 0 bits*/
|
||||||
|
if ( databitlen > 0) {
|
||||||
|
if ((databitlen & 7) == 0)
|
||||||
|
memcpy(state->buffer, data+index, (databitlen & 0x1ff) >> 3);
|
||||||
|
else
|
||||||
|
memcpy(state->buffer, data+index, ((databitlen & 0x1ff) >> 3)+1);
|
||||||
|
state->datasize_in_buffer = databitlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*pad the message, process the padded block(s), truncate the hash value H to obtain the message digest*/
|
||||||
|
static HashReturn Final(hashState *state, BitSequence *hashval)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
if ( (state->databitlen & 0x1ff) == 0 ) {
|
||||||
|
/*pad the message when databitlen is multiple of 512 bits, then process the padded block*/
|
||||||
|
memset(state->buffer, 0, 64);
|
||||||
|
state->buffer[0] = 0x80;
|
||||||
|
state->buffer[63] = state->databitlen & 0xff;
|
||||||
|
state->buffer[62] = (state->databitlen >> 8) & 0xff;
|
||||||
|
state->buffer[61] = (state->databitlen >> 16) & 0xff;
|
||||||
|
state->buffer[60] = (state->databitlen >> 24) & 0xff;
|
||||||
|
state->buffer[59] = (state->databitlen >> 32) & 0xff;
|
||||||
|
state->buffer[58] = (state->databitlen >> 40) & 0xff;
|
||||||
|
state->buffer[57] = (state->databitlen >> 48) & 0xff;
|
||||||
|
state->buffer[56] = (state->databitlen >> 56) & 0xff;
|
||||||
|
F8(state);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/*set the rest of the bytes in the buffer to 0*/
|
||||||
|
if ( (state->datasize_in_buffer & 7) == 0)
|
||||||
|
for (i = (state->databitlen & 0x1ff) >> 3; i < 64; i++) state->buffer[i] = 0;
|
||||||
|
else
|
||||||
|
for (i = ((state->databitlen & 0x1ff) >> 3)+1; i < 64; i++) state->buffer[i] = 0;
|
||||||
|
|
||||||
|
/*pad and process the partial block when databitlen is not multiple of 512 bits, then hash the padded blocks*/
|
||||||
|
state->buffer[((state->databitlen & 0x1ff) >> 3)] |= 1 << (7- (state->databitlen & 7));
|
||||||
|
|
||||||
|
F8(state);
|
||||||
|
memset(state->buffer, 0, 64);
|
||||||
|
state->buffer[63] = state->databitlen & 0xff;
|
||||||
|
state->buffer[62] = (state->databitlen >> 8) & 0xff;
|
||||||
|
state->buffer[61] = (state->databitlen >> 16) & 0xff;
|
||||||
|
state->buffer[60] = (state->databitlen >> 24) & 0xff;
|
||||||
|
state->buffer[59] = (state->databitlen >> 32) & 0xff;
|
||||||
|
state->buffer[58] = (state->databitlen >> 40) & 0xff;
|
||||||
|
state->buffer[57] = (state->databitlen >> 48) & 0xff;
|
||||||
|
state->buffer[56] = (state->databitlen >> 56) & 0xff;
|
||||||
|
F8(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*truncating the final hash value to generate the message digest*/
|
||||||
|
switch(state->hashbitlen) {
|
||||||
|
case 224: memcpy(hashval,(unsigned char*)state->x+64+36,28); break;
|
||||||
|
case 256: memcpy(hashval,(unsigned char*)state->x+64+32,32); break;
|
||||||
|
case 384: memcpy(hashval,(unsigned char*)state->x+64+16,48); break;
|
||||||
|
case 512: memcpy(hashval,(unsigned char*)state->x+64,64); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* hash a message,
|
||||||
|
three inputs: message digest size in bits (hashbitlen); message (data); message length in bits (databitlen)
|
||||||
|
one output: message digest (hashval)
|
||||||
|
*/
|
||||||
|
HashReturn jh_hash(int hashbitlen, const BitSequence *data,DataLength databitlen, BitSequence *hashval)
|
||||||
|
{
|
||||||
|
hashState state;
|
||||||
|
|
||||||
|
if ( hashbitlen == 224 || hashbitlen == 256 || hashbitlen == 384 || hashbitlen == 512 ) {
|
||||||
|
Init(&state, hashbitlen);
|
||||||
|
Update(&state, data, databitlen);
|
||||||
|
Final(&state, hashval);
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return(BAD_HASHLEN);
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*This program gives the 64-bit optimized bitslice implementation of JH using ANSI C
|
||||||
|
|
||||||
|
--------------------------------
|
||||||
|
Performance
|
||||||
|
|
||||||
|
Microprocessor: Intel CORE 2 processor (Core 2 Duo Mobile T6600 2.2GHz)
|
||||||
|
Operating System: 64-bit Ubuntu 10.04 (Linux kernel 2.6.32-22-generic)
|
||||||
|
Speed for long message:
|
||||||
|
1) 45.8 cycles/byte compiler: Intel C++ Compiler 11.1 compilation option: icc -O2
|
||||||
|
2) 56.8 cycles/byte compiler: gcc 4.4.3 compilation option: gcc -O3
|
||||||
|
|
||||||
|
--------------------------------
|
||||||
|
Last Modified: January 16, 2011
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "hash.h"
|
||||||
|
|
||||||
|
HashReturn jh_hash(int hashbitlen, const BitSequence *data, DataLength databitlen, BitSequence *hashval);
|
|
@ -0,0 +1,128 @@
|
||||||
|
// keccak.c
|
||||||
|
// 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi>
|
||||||
|
// A baseline Keccak (3rd round) implementation.
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <memory.h>
|
||||||
|
|
||||||
|
#define HASH_DATA_AREA 136
|
||||||
|
#define KECCAK_ROUNDS 24
|
||||||
|
|
||||||
|
#ifndef ROTL64
|
||||||
|
#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const uint64_t keccakf_rndc[24] =
|
||||||
|
{
|
||||||
|
0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
|
||||||
|
0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
|
||||||
|
0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
|
||||||
|
0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
|
||||||
|
0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
|
||||||
|
0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
|
||||||
|
0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
|
||||||
|
0x8000000000008080, 0x0000000080000001, 0x8000000080008008
|
||||||
|
};
|
||||||
|
|
||||||
|
const int keccakf_rotc[24] =
|
||||||
|
{
|
||||||
|
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
|
||||||
|
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44
|
||||||
|
};
|
||||||
|
|
||||||
|
const int keccakf_piln[24] =
|
||||||
|
{
|
||||||
|
10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
|
||||||
|
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1
|
||||||
|
};
|
||||||
|
|
||||||
|
// update the state with given number of rounds
|
||||||
|
|
||||||
|
void keccakf(uint64_t st[25], int rounds)
|
||||||
|
{
|
||||||
|
int i, j, round;
|
||||||
|
uint64_t t, bc[5];
|
||||||
|
|
||||||
|
for (round = 0; round < rounds; ++round) {
|
||||||
|
|
||||||
|
// Theta
|
||||||
|
bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20];
|
||||||
|
bc[1] = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21];
|
||||||
|
bc[2] = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22];
|
||||||
|
bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23];
|
||||||
|
bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24];
|
||||||
|
|
||||||
|
for (i = 0; i < 5; ++i) {
|
||||||
|
t = bc[(i + 4) % 5] ^ ROTL64(bc[(i + 1) % 5], 1);
|
||||||
|
st[i ] ^= t;
|
||||||
|
st[i + 5] ^= t;
|
||||||
|
st[i + 10] ^= t;
|
||||||
|
st[i + 15] ^= t;
|
||||||
|
st[i + 20] ^= t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rho Pi
|
||||||
|
t = st[1];
|
||||||
|
for (i = 0; i < 24; ++i) {
|
||||||
|
bc[0] = st[keccakf_piln[i]];
|
||||||
|
st[keccakf_piln[i]] = ROTL64(t, keccakf_rotc[i]);
|
||||||
|
t = bc[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chi
|
||||||
|
for (j = 0; j < 25; j += 5) {
|
||||||
|
bc[0] = st[j ];
|
||||||
|
bc[1] = st[j + 1];
|
||||||
|
bc[2] = st[j + 2];
|
||||||
|
bc[3] = st[j + 3];
|
||||||
|
bc[4] = st[j + 4];
|
||||||
|
st[j ] ^= (~bc[1]) & bc[2];
|
||||||
|
st[j + 1] ^= (~bc[2]) & bc[3];
|
||||||
|
st[j + 2] ^= (~bc[3]) & bc[4];
|
||||||
|
st[j + 3] ^= (~bc[4]) & bc[0];
|
||||||
|
st[j + 4] ^= (~bc[0]) & bc[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iota
|
||||||
|
st[0] ^= keccakf_rndc[round];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute a keccak hash (md) of given byte length from "in"
|
||||||
|
typedef uint64_t state_t[25];
|
||||||
|
|
||||||
|
void keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen)
|
||||||
|
{
|
||||||
|
state_t st;
|
||||||
|
uint8_t temp[144];
|
||||||
|
int i, rsiz, rsizw;
|
||||||
|
|
||||||
|
rsiz = sizeof(state_t) == mdlen ? HASH_DATA_AREA : 200 - 2 * mdlen;
|
||||||
|
rsizw = rsiz / 8;
|
||||||
|
|
||||||
|
memset(st, 0, sizeof(st));
|
||||||
|
|
||||||
|
for ( ; inlen >= rsiz; inlen -= rsiz, in += rsiz) {
|
||||||
|
for (i = 0; i < rsizw; i++)
|
||||||
|
st[i] ^= ((uint64_t *) in)[i];
|
||||||
|
keccakf(st, KECCAK_ROUNDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// last block and padding
|
||||||
|
memcpy(temp, in, inlen);
|
||||||
|
temp[inlen++] = 1;
|
||||||
|
memset(temp + inlen, 0, rsiz - inlen);
|
||||||
|
temp[rsiz - 1] |= 0x80;
|
||||||
|
|
||||||
|
for (i = 0; i < rsizw; i++)
|
||||||
|
st[i] ^= ((uint64_t *) temp)[i];
|
||||||
|
|
||||||
|
keccakf(st, KECCAK_ROUNDS);
|
||||||
|
|
||||||
|
memcpy(md, st, mdlen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void keccak1600(const uint8_t *in, int inlen, uint8_t *md)
|
||||||
|
{
|
||||||
|
keccak(in, inlen, md, sizeof(state_t));
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
// keccak.h
|
||||||
|
// 19-Nov-11 Markku-Juhani O. Saarinen <mjos@iki.fi>
|
||||||
|
|
||||||
|
#ifndef KECCAK_H
|
||||||
|
#define KECCAK_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifndef KECCAK_ROUNDS
|
||||||
|
#define KECCAK_ROUNDS 24
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ROTL64
|
||||||
|
#define ROTL64(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// compute a keccak hash (md) of given byte length from "in"
|
||||||
|
int keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen);
|
||||||
|
|
||||||
|
// update the state
|
||||||
|
void keccakf(uint64_t st[25], int norounds);
|
||||||
|
|
||||||
|
void keccak1600(const uint8_t *in, int inlen, uint8_t *md);
|
||||||
|
|
||||||
|
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef _SKEIN_H_
|
||||||
|
#define _SKEIN_H_ 1
|
||||||
|
/**************************************************************************
|
||||||
|
**
|
||||||
|
** Interface declarations and internal definitions for Skein hashing.
|
||||||
|
**
|
||||||
|
** Source code author: Doug Whiting, 2008.
|
||||||
|
**
|
||||||
|
** This algorithm and source code is released to the public domain.
|
||||||
|
**
|
||||||
|
***************************************************************************
|
||||||
|
**
|
||||||
|
** The following compile-time switches may be defined to control some
|
||||||
|
** tradeoffs between speed, code size, error checking, and security.
|
||||||
|
**
|
||||||
|
** The "default" note explains what happens when the switch is not defined.
|
||||||
|
**
|
||||||
|
** SKEIN_DEBUG -- make callouts from inside Skein code
|
||||||
|
** to examine/display intermediate values.
|
||||||
|
** [default: no callouts (no overhead)]
|
||||||
|
**
|
||||||
|
** SKEIN_ERR_CHECK -- how error checking is handled inside Skein
|
||||||
|
** code. If not defined, most error checking
|
||||||
|
** is disabled (for performance). Otherwise,
|
||||||
|
** the switch value is interpreted as:
|
||||||
|
** 0: use assert() to flag errors
|
||||||
|
** 1: return SKEIN_FAIL to flag errors
|
||||||
|
**
|
||||||
|
***************************************************************************/
|
||||||
|
#include "skein_port.h" /* get platform-specific definitions */
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
SKEIN_SUCCESS = 0, /* return codes from Skein calls */
|
||||||
|
SKEIN_FAIL = 1,
|
||||||
|
SKEIN_BAD_HASHLEN = 2
|
||||||
|
}
|
||||||
|
SkeinHashReturn;
|
||||||
|
|
||||||
|
typedef size_t SkeinDataLength; /* bit count type */
|
||||||
|
typedef u08b_t SkeinBitSequence; /* bit stream type */
|
||||||
|
|
||||||
|
/* "all-in-one" call */
|
||||||
|
SkeinHashReturn skein_hash(int hashbitlen, const SkeinBitSequence *data,
|
||||||
|
SkeinDataLength databitlen, SkeinBitSequence *hashval);
|
||||||
|
|
||||||
|
#endif /* ifndef _SKEIN_H_ */
|
|
@ -0,0 +1,25 @@
|
||||||
|
#ifndef __CRYPTONIGHT_H_INCLUDED
|
||||||
|
#define __CRYPTONIGHT_H_INCLUDED
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#define MEMORY 2097152
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint8_t hash_state[224]; // Need only 200, explicit align
|
||||||
|
uint8_t long_state[MEMORY];
|
||||||
|
} cryptonight_ctx;
|
||||||
|
|
||||||
|
void cryptonight_hash_ctx(const void* input, size_t len, void* output, cryptonight_ctx* ctx);
|
||||||
|
void cryptonight_hash_ctx_soft(const void* input, size_t len, void* output, cryptonight_ctx* ctx);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,420 @@
|
||||||
|
/*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "cryptonight.h"
|
||||||
|
#include <memory.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#include <x86intrin.h>
|
||||||
|
static inline uint64_t _umul128(uint64_t a, uint64_t b, uint64_t* hi)
|
||||||
|
{
|
||||||
|
unsigned __int128 r = (unsigned __int128)a * (unsigned __int128)b;
|
||||||
|
*hi = r >> 64;
|
||||||
|
return (uint64_t)r;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define _mm256_set_m128i(v0, v1) _mm256_insertf128_si256(_mm256_castsi128_si256(v1), (v0), 1)
|
||||||
|
#else
|
||||||
|
#include <intrin.h>
|
||||||
|
#endif // __GNUC__
|
||||||
|
|
||||||
|
#if !defined(_LP64) && !defined(_WIN64)
|
||||||
|
#error You are trying to do a 32-bit build. This will all end in tears. I know it.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
void keccak(const uint8_t *in, int inlen, uint8_t *md, int mdlen);
|
||||||
|
void keccakf(uint64_t st[25], int rounds);
|
||||||
|
extern void(*const extra_hashes[4])(const void *, size_t, char *);
|
||||||
|
|
||||||
|
__m128i soft_aesenc(__m128i in, __m128i key);
|
||||||
|
__m128i soft_aeskeygenassist(__m128i key, uint8_t rcon);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This will shift and xor tmp1 into itself as 4 32-bit vals such as
|
||||||
|
// sl_xor(a1 a2 a3 a4) = a1 (a2^a1) (a3^a2^a1) (a4^a3^a2^a1)
|
||||||
|
static inline __m128i sl_xor(__m128i tmp1)
|
||||||
|
{
|
||||||
|
__m128i tmp4;
|
||||||
|
tmp4 = _mm_slli_si128(tmp1, 0x04);
|
||||||
|
tmp1 = _mm_xor_si128(tmp1, tmp4);
|
||||||
|
tmp4 = _mm_slli_si128(tmp4, 0x04);
|
||||||
|
tmp1 = _mm_xor_si128(tmp1, tmp4);
|
||||||
|
tmp4 = _mm_slli_si128(tmp4, 0x04);
|
||||||
|
tmp1 = _mm_xor_si128(tmp1, tmp4);
|
||||||
|
return tmp1;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<uint8_t rcon>
|
||||||
|
static inline void aes_genkey_sub(__m128i* xout0, __m128i* xout2)
|
||||||
|
{
|
||||||
|
__m128i xout1 = _mm_aeskeygenassist_si128(*xout2, rcon);
|
||||||
|
xout1 = _mm_shuffle_epi32(xout1, 0xFF); // see PSHUFD, set all elems to 4th elem
|
||||||
|
*xout0 = sl_xor(*xout0);
|
||||||
|
*xout0 = _mm_xor_si128(*xout0, xout1);
|
||||||
|
xout1 = _mm_aeskeygenassist_si128(*xout0, 0x00);
|
||||||
|
xout1 = _mm_shuffle_epi32(xout1, 0xAA); // see PSHUFD, set all elems to 3rd elem
|
||||||
|
*xout2 = sl_xor(*xout2);
|
||||||
|
*xout2 = _mm_xor_si128(*xout2, xout1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void soft_aes_genkey_sub(__m128i* xout0, __m128i* xout2, uint8_t rcon)
|
||||||
|
{
|
||||||
|
__m128i xout1 = soft_aeskeygenassist(*xout2, rcon);
|
||||||
|
xout1 = _mm_shuffle_epi32(xout1, 0xFF); // see PSHUFD, set all elems to 4th elem
|
||||||
|
*xout0 = sl_xor(*xout0);
|
||||||
|
*xout0 = _mm_xor_si128(*xout0, xout1);
|
||||||
|
xout1 = soft_aeskeygenassist(*xout0, 0x00);
|
||||||
|
xout1 = _mm_shuffle_epi32(xout1, 0xAA); // see PSHUFD, set all elems to 3rd elem
|
||||||
|
*xout2 = sl_xor(*xout2);
|
||||||
|
*xout2 = _mm_xor_si128(*xout2, xout1);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool SOFT_AES>
|
||||||
|
static inline void aes_genkey(const __m128i* memory, __m128i* k0, __m128i* k1, __m128i* k2, __m128i* k3,
|
||||||
|
__m128i* k4, __m128i* k5, __m128i* k6, __m128i* k7, __m128i* k8, __m128i* k9)
|
||||||
|
{
|
||||||
|
__m128i xout0, xout2;
|
||||||
|
|
||||||
|
xout0 = _mm_load_si128(memory);
|
||||||
|
xout2 = _mm_load_si128(memory+1);
|
||||||
|
*k0 = xout0;
|
||||||
|
*k1 = xout2;
|
||||||
|
|
||||||
|
if(SOFT_AES)
|
||||||
|
soft_aes_genkey_sub(&xout0, &xout2, 0x01);
|
||||||
|
else
|
||||||
|
aes_genkey_sub<0x01>(&xout0, &xout2);
|
||||||
|
*k2 = xout0;
|
||||||
|
*k3 = xout2;
|
||||||
|
|
||||||
|
if(SOFT_AES)
|
||||||
|
soft_aes_genkey_sub(&xout0, &xout2, 0x02);
|
||||||
|
else
|
||||||
|
aes_genkey_sub<0x02>(&xout0, &xout2);
|
||||||
|
*k4 = xout0;
|
||||||
|
*k5 = xout2;
|
||||||
|
|
||||||
|
if(SOFT_AES)
|
||||||
|
soft_aes_genkey_sub(&xout0, &xout2, 0x04);
|
||||||
|
else
|
||||||
|
aes_genkey_sub<0x04>(&xout0, &xout2);
|
||||||
|
*k6 = xout0;
|
||||||
|
*k7 = xout2;
|
||||||
|
|
||||||
|
if(SOFT_AES)
|
||||||
|
soft_aes_genkey_sub(&xout0, &xout2, 0x08);
|
||||||
|
else
|
||||||
|
aes_genkey_sub<0x08>(&xout0, &xout2);
|
||||||
|
*k8 = xout0;
|
||||||
|
*k9 = xout2;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2, __m128i* x3, __m128i* x4, __m128i* x5, __m128i* x6, __m128i* x7)
|
||||||
|
{
|
||||||
|
*x0 = _mm_aesenc_si128(*x0, key);
|
||||||
|
*x1 = _mm_aesenc_si128(*x1, key);
|
||||||
|
*x2 = _mm_aesenc_si128(*x2, key);
|
||||||
|
*x3 = _mm_aesenc_si128(*x3, key);
|
||||||
|
*x4 = _mm_aesenc_si128(*x4, key);
|
||||||
|
*x5 = _mm_aesenc_si128(*x5, key);
|
||||||
|
*x6 = _mm_aesenc_si128(*x6, key);
|
||||||
|
*x7 = _mm_aesenc_si128(*x7, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void soft_aes_round(__m128i key, __m128i* x0, __m128i* x1, __m128i* x2, __m128i* x3, __m128i* x4, __m128i* x5, __m128i* x6, __m128i* x7)
|
||||||
|
{
|
||||||
|
*x0 = soft_aesenc(*x0, key);
|
||||||
|
*x1 = soft_aesenc(*x1, key);
|
||||||
|
*x2 = soft_aesenc(*x2, key);
|
||||||
|
*x3 = soft_aesenc(*x3, key);
|
||||||
|
*x4 = soft_aesenc(*x4, key);
|
||||||
|
*x5 = soft_aesenc(*x5, key);
|
||||||
|
*x6 = soft_aesenc(*x6, key);
|
||||||
|
*x7 = soft_aesenc(*x7, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t MEM, bool SOFT_AES>
|
||||||
|
void cn_explode_scratchpad(const __m128i* input, __m128i* output)
|
||||||
|
{
|
||||||
|
// This is more than we have registers, compiler will assign 2 keys on the stack
|
||||||
|
__m128i xin0, xin1, xin2, xin3, xin4, xin5, xin6, xin7;
|
||||||
|
__m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9;
|
||||||
|
|
||||||
|
aes_genkey<SOFT_AES>(input, &k0, &k1, &k2, &k3, &k4, &k5, &k6, &k7, &k8, &k9);
|
||||||
|
|
||||||
|
xin0 = _mm_load_si128(input + 4);
|
||||||
|
xin1 = _mm_load_si128(input + 5);
|
||||||
|
xin2 = _mm_load_si128(input + 6);
|
||||||
|
xin3 = _mm_load_si128(input + 7);
|
||||||
|
xin4 = _mm_load_si128(input + 8);
|
||||||
|
xin5 = _mm_load_si128(input + 9);
|
||||||
|
xin6 = _mm_load_si128(input + 10);
|
||||||
|
xin7 = _mm_load_si128(input + 11);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8)
|
||||||
|
{
|
||||||
|
if(SOFT_AES)
|
||||||
|
{
|
||||||
|
soft_aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
soft_aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
soft_aes_round(k2, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
soft_aes_round(k3, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
soft_aes_round(k4, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
soft_aes_round(k5, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
soft_aes_round(k6, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
soft_aes_round(k7, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
soft_aes_round(k8, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
soft_aes_round(k9, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
aes_round(k0, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
aes_round(k1, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
aes_round(k2, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
aes_round(k3, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
aes_round(k4, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
aes_round(k5, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
aes_round(k6, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
aes_round(k7, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
aes_round(k8, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
aes_round(k9, &xin0, &xin1, &xin2, &xin3, &xin4, &xin5, &xin6, &xin7);
|
||||||
|
}
|
||||||
|
|
||||||
|
_mm_store_si128(output + i + 0, xin0);
|
||||||
|
_mm_store_si128(output + i + 1, xin1);
|
||||||
|
_mm_store_si128(output + i + 2, xin2);
|
||||||
|
_mm_store_si128(output + i + 3, xin3);
|
||||||
|
_mm_prefetch((const char*)output + i + 0, _MM_HINT_T2);
|
||||||
|
_mm_store_si128(output + i + 4, xin4);
|
||||||
|
_mm_store_si128(output + i + 5, xin5);
|
||||||
|
_mm_store_si128(output + i + 6, xin6);
|
||||||
|
_mm_store_si128(output + i + 7, xin7);
|
||||||
|
_mm_prefetch((const char*)output + i + 4, _MM_HINT_T2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t MEM, bool SOFT_AES>
|
||||||
|
void cn_implode_scratchpad(const __m128i* input, __m128i* output)
|
||||||
|
{
|
||||||
|
// This is more than we have registers, compiler will assign 2 keys on the stack
|
||||||
|
__m128i xout0, xout1, xout2, xout3, xout4, xout5, xout6, xout7;
|
||||||
|
__m128i k0, k1, k2, k3, k4, k5, k6, k7, k8, k9;
|
||||||
|
|
||||||
|
aes_genkey<SOFT_AES>(output + 2, &k0, &k1, &k2, &k3, &k4, &k5, &k6, &k7, &k8, &k9);
|
||||||
|
|
||||||
|
xout0 = _mm_load_si128(output + 4);
|
||||||
|
xout1 = _mm_load_si128(output + 5);
|
||||||
|
xout2 = _mm_load_si128(output + 6);
|
||||||
|
xout3 = _mm_load_si128(output + 7);
|
||||||
|
xout4 = _mm_load_si128(output + 8);
|
||||||
|
xout5 = _mm_load_si128(output + 9);
|
||||||
|
xout6 = _mm_load_si128(output + 10);
|
||||||
|
xout7 = _mm_load_si128(output + 11);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < MEM / sizeof(__m128i); i += 8)
|
||||||
|
{
|
||||||
|
_mm_prefetch((const char*)input + i + 0, _MM_HINT_NTA);
|
||||||
|
xout0 = _mm_xor_si128(_mm_load_si128(input + i + 0), xout0);
|
||||||
|
xout1 = _mm_xor_si128(_mm_load_si128(input + i + 1), xout1);
|
||||||
|
xout2 = _mm_xor_si128(_mm_load_si128(input + i + 2), xout2);
|
||||||
|
xout3 = _mm_xor_si128(_mm_load_si128(input + i + 3), xout3);
|
||||||
|
_mm_prefetch((const char*)input + i + 4, _MM_HINT_NTA);
|
||||||
|
xout4 = _mm_xor_si128(_mm_load_si128(input + i + 4), xout4);
|
||||||
|
xout5 = _mm_xor_si128(_mm_load_si128(input + i + 5), xout5);
|
||||||
|
xout6 = _mm_xor_si128(_mm_load_si128(input + i + 6), xout6);
|
||||||
|
xout7 = _mm_xor_si128(_mm_load_si128(input + i + 7), xout7);
|
||||||
|
|
||||||
|
if(SOFT_AES)
|
||||||
|
{
|
||||||
|
soft_aes_round(k0, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
soft_aes_round(k1, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
soft_aes_round(k2, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
soft_aes_round(k3, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
soft_aes_round(k4, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
soft_aes_round(k5, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
soft_aes_round(k6, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
soft_aes_round(k7, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
soft_aes_round(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
soft_aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
aes_round(k0, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
aes_round(k1, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
aes_round(k2, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
aes_round(k3, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
aes_round(k4, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
aes_round(k5, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
aes_round(k6, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
aes_round(k7, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
aes_round(k8, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
aes_round(k9, &xout0, &xout1, &xout2, &xout3, &xout4, &xout5, &xout6, &xout7);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_mm_store_si128(output + 4, xout0);
|
||||||
|
_mm_store_si128(output + 5, xout1);
|
||||||
|
_mm_store_si128(output + 6, xout2);
|
||||||
|
_mm_store_si128(output + 7, xout3);
|
||||||
|
_mm_store_si128(output + 8, xout4);
|
||||||
|
_mm_store_si128(output + 9, xout5);
|
||||||
|
_mm_store_si128(output + 10, xout6);
|
||||||
|
_mm_store_si128(output + 11, xout7);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t ITERATIONS, size_t MEM, bool PREFETCH, bool SOFT_AES>
|
||||||
|
void cryptonight_hash(const void* input, size_t len, void* output, cryptonight_ctx* ctx0)
|
||||||
|
{
|
||||||
|
keccak((const uint8_t *)input, len, ctx0->hash_state, 200);
|
||||||
|
|
||||||
|
// Optim - 99% time boundary
|
||||||
|
cn_explode_scratchpad<MEM, SOFT_AES>((__m128i*)ctx0->hash_state, (__m128i*)ctx0->long_state);
|
||||||
|
|
||||||
|
uint8_t* l0 = ctx0->long_state;
|
||||||
|
uint64_t* h0 = (uint64_t*)ctx0->hash_state;
|
||||||
|
|
||||||
|
uint64_t al0 = h0[0] ^ h0[4];
|
||||||
|
uint64_t ah0 = h0[1] ^ h0[5];
|
||||||
|
__m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
|
||||||
|
|
||||||
|
uint64_t idx0 = h0[0] ^ h0[4];
|
||||||
|
|
||||||
|
// Optim - 90% time boundary
|
||||||
|
for(size_t i = 0; i < ITERATIONS; i++)
|
||||||
|
{
|
||||||
|
__m128i cx;
|
||||||
|
cx = _mm_load_si128((__m128i *)&l0[idx0 & 0x1FFFF0]);
|
||||||
|
if(SOFT_AES)
|
||||||
|
cx = soft_aesenc(cx, _mm_set_epi64x(ah0, al0));
|
||||||
|
else
|
||||||
|
cx = _mm_aesenc_si128(cx, _mm_set_epi64x(ah0, al0));
|
||||||
|
_mm_store_si128((__m128i *)&l0[idx0 & 0x1FFFF0], _mm_xor_si128(bx0, cx));
|
||||||
|
idx0 = _mm_cvtsi128_si64(cx);
|
||||||
|
bx0 = cx;
|
||||||
|
if(PREFETCH)
|
||||||
|
_mm_prefetch((const char*)&l0[idx0 & 0x1FFFF0], _MM_HINT_T0);
|
||||||
|
|
||||||
|
uint64_t hi, lo, cl, ch;
|
||||||
|
cl = ((uint64_t*)&l0[idx0 & 0x1FFFF0])[0];
|
||||||
|
ch = ((uint64_t*)&l0[idx0 & 0x1FFFF0])[1];
|
||||||
|
lo = _umul128(idx0, cl, &hi);
|
||||||
|
al0 += hi;
|
||||||
|
ah0 += lo;
|
||||||
|
((uint64_t*)&l0[idx0 & 0x1FFFF0])[0] = al0;
|
||||||
|
((uint64_t*)&l0[idx0 & 0x1FFFF0])[1] = ah0;
|
||||||
|
ah0 ^= ch;
|
||||||
|
al0 ^= cl;
|
||||||
|
idx0 = al0;
|
||||||
|
if(PREFETCH)
|
||||||
|
_mm_prefetch((const char*)&l0[idx0 & 0x1FFFF0], _MM_HINT_T0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optim - 90% time boundary
|
||||||
|
cn_implode_scratchpad<MEM, SOFT_AES>((__m128i*)ctx0->long_state, (__m128i*)ctx0->hash_state);
|
||||||
|
|
||||||
|
// Optim - 99% time boundary
|
||||||
|
|
||||||
|
keccakf((uint64_t*)ctx0->hash_state, 24);
|
||||||
|
extra_hashes[ctx0->hash_state[0] & 3](ctx0->hash_state, 200, (char*)output);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This lovely creation will do 2 cn hashes at a time. We have plenty of space on silicon
|
||||||
|
// to fit temporary vars for two contexts. Function will read len*2 from input and write 64 bytes to output
|
||||||
|
// We are still limited by L3 cache, so doubling will only work with CPUs where we have more than 2MB to core (Xeons)
|
||||||
|
template<size_t ITERATIONS, size_t MEM, bool PREFETCH, bool SOFT_AES>
|
||||||
|
void cryptonight_double_hash(const void* input, size_t len, void* output, cryptonight_ctx* __restrict ctx0, cryptonight_ctx* __restrict ctx1)
|
||||||
|
{
|
||||||
|
keccak((const uint8_t *)input, len, ctx0->hash_state, 200);
|
||||||
|
keccak((const uint8_t *)input+len, len, ctx1->hash_state, 200);
|
||||||
|
|
||||||
|
// Optim - 99% time boundary
|
||||||
|
cn_explode_scratchpad<MEM, SOFT_AES>((__m128i*)ctx0->hash_state, (__m128i*)ctx0->long_state);
|
||||||
|
cn_explode_scratchpad<MEM, SOFT_AES>((__m128i*)ctx1->hash_state, (__m128i*)ctx1->long_state);
|
||||||
|
|
||||||
|
uint8_t* l0 = ctx0->long_state;
|
||||||
|
uint64_t* h0 = (uint64_t*)ctx0->hash_state;
|
||||||
|
uint8_t* l1 = ctx1->long_state;
|
||||||
|
uint64_t* h1 = (uint64_t*)ctx1->hash_state;
|
||||||
|
|
||||||
|
__m128i ax0 = _mm_set_epi64x(h0[1] ^ h0[5], h0[0] ^ h0[4]);
|
||||||
|
__m128i bx0 = _mm_set_epi64x(h0[3] ^ h0[7], h0[2] ^ h0[6]);
|
||||||
|
__m128i ax1 = _mm_set_epi64x(h1[1] ^ h1[5], h1[0] ^ h1[4]);
|
||||||
|
__m128i bx1 = _mm_set_epi64x(h1[3] ^ h1[7], h1[2] ^ h1[6]);
|
||||||
|
|
||||||
|
uint64_t idx0 = h0[0] ^ h0[4];
|
||||||
|
uint64_t idx1 = h1[0] ^ h1[4];
|
||||||
|
|
||||||
|
// Optim - 90% time boundary
|
||||||
|
for (size_t i = 0; i < ITERATIONS; i++)
|
||||||
|
{
|
||||||
|
__m128i cx;
|
||||||
|
cx = _mm_load_si128((__m128i *)&l0[idx0 & 0x1FFFF0]);
|
||||||
|
if(SOFT_AES)
|
||||||
|
cx = soft_aesenc(cx, ax0);
|
||||||
|
else
|
||||||
|
cx = _mm_aesenc_si128(cx, ax0);
|
||||||
|
_mm_store_si128((__m128i *)&l0[idx0 & 0x1FFFF0], _mm_xor_si128(bx0, cx));
|
||||||
|
idx0 = _mm_cvtsi128_si64(cx);
|
||||||
|
bx0 = cx;
|
||||||
|
if(PREFETCH)
|
||||||
|
_mm_prefetch((const char*)&l0[idx0 & 0x1FFFF0], _MM_HINT_T0);
|
||||||
|
|
||||||
|
cx = _mm_load_si128((__m128i *)&l1[idx1 & 0x1FFFF0]);
|
||||||
|
if(SOFT_AES)
|
||||||
|
cx = soft_aesenc(cx, ax1);
|
||||||
|
else
|
||||||
|
cx = _mm_aesenc_si128(cx, ax1);
|
||||||
|
_mm_store_si128((__m128i *)&l1[idx1 & 0x1FFFF0], _mm_xor_si128(bx1, cx));
|
||||||
|
idx1 = _mm_cvtsi128_si64(cx);
|
||||||
|
bx1 = cx;
|
||||||
|
if(PREFETCH)
|
||||||
|
_mm_prefetch((const char*)&l1[idx1 & 0x1FFFF0], _MM_HINT_T0);
|
||||||
|
|
||||||
|
uint64_t hi, lo;
|
||||||
|
cx = _mm_load_si128((__m128i *)&l0[idx0 & 0x1FFFF0]);
|
||||||
|
lo = _umul128(idx0, _mm_cvtsi128_si64(cx), &hi);
|
||||||
|
ax0 = _mm_add_epi64(ax0, _mm_set_epi64x(lo, hi));
|
||||||
|
_mm_store_si128((__m128i*)&l0[idx0 & 0x1FFFF0], ax0);
|
||||||
|
ax0 = _mm_xor_si128(ax0, cx);
|
||||||
|
idx0 = _mm_cvtsi128_si64(ax0);
|
||||||
|
if(PREFETCH)
|
||||||
|
_mm_prefetch((const char*)&l0[idx0 & 0x1FFFF0], _MM_HINT_T0);
|
||||||
|
|
||||||
|
cx = _mm_load_si128((__m128i *)&l1[idx1 & 0x1FFFF0]);
|
||||||
|
lo = _umul128(idx1, _mm_cvtsi128_si64(cx), &hi);
|
||||||
|
ax1 = _mm_add_epi64(ax1, _mm_set_epi64x(lo, hi));
|
||||||
|
_mm_store_si128((__m128i*)&l1[idx1 & 0x1FFFF0], ax1);
|
||||||
|
ax1 = _mm_xor_si128(ax1, cx);
|
||||||
|
idx1 = _mm_cvtsi128_si64(ax1);
|
||||||
|
if(PREFETCH)
|
||||||
|
_mm_prefetch((const char*)&l1[idx1 & 0x1FFFF0], _MM_HINT_T0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optim - 90% time boundary
|
||||||
|
cn_implode_scratchpad<MEM, SOFT_AES>((__m128i*)ctx0->long_state, (__m128i*)ctx0->hash_state);
|
||||||
|
cn_implode_scratchpad<MEM, SOFT_AES>((__m128i*)ctx1->long_state, (__m128i*)ctx1->hash_state);
|
||||||
|
|
||||||
|
// Optim - 99% time boundary
|
||||||
|
|
||||||
|
keccakf((uint64_t*)ctx0->hash_state, 24);
|
||||||
|
extra_hashes[ctx0->hash_state[0] & 3](ctx0->hash_state, 200, (char*)output);
|
||||||
|
keccakf((uint64_t*)ctx1->hash_state, 24);
|
||||||
|
extra_hashes[ctx1->hash_state[0] & 3](ctx1->hash_state, 200, (char*)output + 32);
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include "c_groestl.h"
|
||||||
|
#include "c_blake256.h"
|
||||||
|
#include "c_jh.h"
|
||||||
|
#include "c_skein.h"
|
||||||
|
}
|
||||||
|
#include "cryptonight.h"
|
||||||
|
#include "cryptonight_aesni.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#include <mm_malloc.h>
|
||||||
|
#else
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif // __GNUC__
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
void do_blake_hash(const void* input, size_t len, char* output) {
|
||||||
|
blake256_hash((uint8_t*)output, (const uint8_t*)input, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_groestl_hash(const void* input, size_t len, char* output) {
|
||||||
|
groestl((const uint8_t*)input, len * 8, (uint8_t*)output);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_jh_hash(const void* input, size_t len, char* output) {
|
||||||
|
jh_hash(32 * 8, (const uint8_t*)input, 8 * len, (uint8_t*)output);
|
||||||
|
}
|
||||||
|
|
||||||
|
void do_skein_hash(const void* input, size_t len, char* output) {
|
||||||
|
skein_hash(8 * 32, (const uint8_t*)input, 8 * len, (uint8_t*)output);
|
||||||
|
}
|
||||||
|
|
||||||
|
void (* const extra_hashes[4])(const void *, size_t, char *) = {do_blake_hash, do_groestl_hash, do_jh_hash, do_skein_hash};
|
||||||
|
|
||||||
|
|
||||||
|
void cryptonight_hash_ctx(const void* input, size_t len, void* output, cryptonight_ctx* ctx)
|
||||||
|
{
|
||||||
|
cryptonight_hash<0x80000, MEMORY, true, false>(input, len, output, ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cryptonight_hash_ctx_soft(const void* input, size_t len, void* output, cryptonight_ctx* ctx)
|
||||||
|
{
|
||||||
|
cryptonight_hash<0x80000, MEMORY, true, true>(input, len, output, ctx);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef __tables_h
|
||||||
|
#define __tables_h
|
||||||
|
|
||||||
|
|
||||||
|
const uint32_t T[512] = {0xa5f432c6, 0xc6a597f4, 0x84976ff8, 0xf884eb97, 0x99b05eee, 0xee99c7b0, 0x8d8c7af6, 0xf68df78c, 0xd17e8ff, 0xff0de517, 0xbddc0ad6, 0xd6bdb7dc, 0xb1c816de, 0xdeb1a7c8, 0x54fc6d91, 0x915439fc
|
||||||
|
, 0x50f09060, 0x6050c0f0, 0x3050702, 0x2030405, 0xa9e02ece, 0xcea987e0, 0x7d87d156, 0x567dac87, 0x192bcce7, 0xe719d52b, 0x62a613b5, 0xb56271a6, 0xe6317c4d, 0x4de69a31, 0x9ab559ec, 0xec9ac3b5
|
||||||
|
, 0x45cf408f, 0x8f4505cf, 0x9dbca31f, 0x1f9d3ebc, 0x40c04989, 0x894009c0, 0x879268fa, 0xfa87ef92, 0x153fd0ef, 0xef15c53f, 0xeb2694b2, 0xb2eb7f26, 0xc940ce8e, 0x8ec90740, 0xb1de6fb, 0xfb0bed1d
|
||||||
|
, 0xec2f6e41, 0x41ec822f, 0x67a91ab3, 0xb3677da9, 0xfd1c435f, 0x5ffdbe1c, 0xea256045, 0x45ea8a25, 0xbfdaf923, 0x23bf46da, 0xf7025153, 0x53f7a602, 0x96a145e4, 0xe496d3a1, 0x5bed769b, 0x9b5b2ded
|
||||||
|
, 0xc25d2875, 0x75c2ea5d, 0x1c24c5e1, 0xe11cd924, 0xaee9d43d, 0x3dae7ae9, 0x6abef24c, 0x4c6a98be, 0x5aee826c, 0x6c5ad8ee, 0x41c3bd7e, 0x7e41fcc3, 0x206f3f5, 0xf502f106, 0x4fd15283, 0x834f1dd1
|
||||||
|
, 0x5ce48c68, 0x685cd0e4, 0xf4075651, 0x51f4a207, 0x345c8dd1, 0xd134b95c, 0x818e1f9, 0xf908e918, 0x93ae4ce2, 0xe293dfae, 0x73953eab, 0xab734d95, 0x53f59762, 0x6253c4f5, 0x3f416b2a, 0x2a3f5441
|
||||||
|
, 0xc141c08, 0x80c1014, 0x52f66395, 0x955231f6, 0x65afe946, 0x46658caf, 0x5ee27f9d, 0x9d5e21e2, 0x28784830, 0x30286078, 0xa1f8cf37, 0x37a16ef8, 0xf111b0a, 0xa0f1411, 0xb5c4eb2f, 0x2fb55ec4
|
||||||
|
, 0x91b150e, 0xe091c1b, 0x365a7e24, 0x2436485a, 0x9bb6ad1b, 0x1b9b36b6, 0x3d4798df, 0xdf3da547, 0x266aa7cd, 0xcd26816a, 0x69bbf54e, 0x4e699cbb, 0xcd4c337f, 0x7fcdfe4c, 0x9fba50ea, 0xea9fcfba
|
||||||
|
, 0x1b2d3f12, 0x121b242d, 0x9eb9a41d, 0x1d9e3ab9, 0x749cc458, 0x5874b09c, 0x2e724634, 0x342e6872, 0x2d774136, 0x362d6c77, 0xb2cd11dc, 0xdcb2a3cd, 0xee299db4, 0xb4ee7329, 0xfb164d5b, 0x5bfbb616
|
||||||
|
, 0xf601a5a4, 0xa4f65301, 0x4dd7a176, 0x764decd7, 0x61a314b7, 0xb76175a3, 0xce49347d, 0x7dcefa49, 0x7b8ddf52, 0x527ba48d, 0x3e429fdd, 0xdd3ea142, 0x7193cd5e, 0x5e71bc93, 0x97a2b113, 0x139726a2
|
||||||
|
, 0xf504a2a6, 0xa6f55704, 0x68b801b9, 0xb96869b8, 0x0, 0x0, 0x2c74b5c1, 0xc12c9974, 0x60a0e040, 0x406080a0, 0x1f21c2e3, 0xe31fdd21, 0xc8433a79, 0x79c8f243, 0xed2c9ab6, 0xb6ed772c
|
||||||
|
, 0xbed90dd4, 0xd4beb3d9, 0x46ca478d, 0x8d4601ca, 0xd9701767, 0x67d9ce70, 0x4bddaf72, 0x724be4dd, 0xde79ed94, 0x94de3379, 0xd467ff98, 0x98d42b67, 0xe82393b0, 0xb0e87b23, 0x4ade5b85, 0x854a11de
|
||||||
|
, 0x6bbd06bb, 0xbb6b6dbd, 0x2a7ebbc5, 0xc52a917e, 0xe5347b4f, 0x4fe59e34, 0x163ad7ed, 0xed16c13a, 0xc554d286, 0x86c51754, 0xd762f89a, 0x9ad72f62, 0x55ff9966, 0x6655ccff, 0x94a7b611, 0x119422a7
|
||||||
|
, 0xcf4ac08a, 0x8acf0f4a, 0x1030d9e9, 0xe910c930, 0x60a0e04, 0x406080a, 0x819866fe, 0xfe81e798, 0xf00baba0, 0xa0f05b0b, 0x44ccb478, 0x7844f0cc, 0xbad5f025, 0x25ba4ad5, 0xe33e754b, 0x4be3963e
|
||||||
|
, 0xf30eaca2, 0xa2f35f0e, 0xfe19445d, 0x5dfeba19, 0xc05bdb80, 0x80c01b5b, 0x8a858005, 0x58a0a85, 0xadecd33f, 0x3fad7eec, 0xbcdffe21, 0x21bc42df, 0x48d8a870, 0x7048e0d8, 0x40cfdf1, 0xf104f90c
|
||||||
|
, 0xdf7a1963, 0x63dfc67a, 0xc1582f77, 0x77c1ee58, 0x759f30af, 0xaf75459f, 0x63a5e742, 0x426384a5, 0x30507020, 0x20304050, 0x1a2ecbe5, 0xe51ad12e, 0xe12effd, 0xfd0ee112, 0x6db708bf, 0xbf6d65b7
|
||||||
|
, 0x4cd45581, 0x814c19d4, 0x143c2418, 0x1814303c, 0x355f7926, 0x26354c5f, 0x2f71b2c3, 0xc32f9d71, 0xe13886be, 0xbee16738, 0xa2fdc835, 0x35a26afd, 0xcc4fc788, 0x88cc0b4f, 0x394b652e, 0x2e395c4b
|
||||||
|
, 0x57f96a93, 0x93573df9, 0xf20d5855, 0x55f2aa0d, 0x829d61fc, 0xfc82e39d, 0x47c9b37a, 0x7a47f4c9, 0xacef27c8, 0xc8ac8bef, 0xe73288ba, 0xbae76f32, 0x2b7d4f32, 0x322b647d, 0x95a442e6, 0xe695d7a4
|
||||||
|
, 0xa0fb3bc0, 0xc0a09bfb, 0x98b3aa19, 0x199832b3, 0xd168f69e, 0x9ed12768, 0x7f8122a3, 0xa37f5d81, 0x66aaee44, 0x446688aa, 0x7e82d654, 0x547ea882, 0xabe6dd3b, 0x3bab76e6, 0x839e950b, 0xb83169e
|
||||||
|
, 0xca45c98c, 0x8cca0345, 0x297bbcc7, 0xc729957b, 0xd36e056b, 0x6bd3d66e, 0x3c446c28, 0x283c5044, 0x798b2ca7, 0xa779558b, 0xe23d81bc, 0xbce2633d, 0x1d273116, 0x161d2c27, 0x769a37ad, 0xad76419a
|
||||||
|
, 0x3b4d96db, 0xdb3bad4d, 0x56fa9e64, 0x6456c8fa, 0x4ed2a674, 0x744ee8d2, 0x1e223614, 0x141e2822, 0xdb76e492, 0x92db3f76, 0xa1e120c, 0xc0a181e, 0x6cb4fc48, 0x486c90b4, 0xe4378fb8, 0xb8e46b37
|
||||||
|
, 0x5de7789f, 0x9f5d25e7, 0x6eb20fbd, 0xbd6e61b2, 0xef2a6943, 0x43ef862a, 0xa6f135c4, 0xc4a693f1, 0xa8e3da39, 0x39a872e3, 0xa4f7c631, 0x31a462f7, 0x37598ad3, 0xd337bd59, 0x8b8674f2, 0xf28bff86
|
||||||
|
, 0x325683d5, 0xd532b156, 0x43c54e8b, 0x8b430dc5, 0x59eb856e, 0x6e59dceb, 0xb7c218da, 0xdab7afc2, 0x8c8f8e01, 0x18c028f, 0x64ac1db1, 0xb16479ac, 0xd26df19c, 0x9cd2236d, 0xe03b7249, 0x49e0923b
|
||||||
|
, 0xb4c71fd8, 0xd8b4abc7, 0xfa15b9ac, 0xacfa4315, 0x709faf3, 0xf307fd09, 0x256fa0cf, 0xcf25856f, 0xafea20ca, 0xcaaf8fea, 0x8e897df4, 0xf48ef389, 0xe9206747, 0x47e98e20, 0x18283810, 0x10182028
|
||||||
|
, 0xd5640b6f, 0x6fd5de64, 0x888373f0, 0xf088fb83, 0x6fb1fb4a, 0x4a6f94b1, 0x7296ca5c, 0x5c72b896, 0x246c5438, 0x3824706c, 0xf1085f57, 0x57f1ae08, 0xc7522173, 0x73c7e652, 0x51f36497, 0x975135f3
|
||||||
|
, 0x2365aecb, 0xcb238d65, 0x7c8425a1, 0xa17c5984, 0x9cbf57e8, 0xe89ccbbf, 0x21635d3e, 0x3e217c63, 0xdd7cea96, 0x96dd377c, 0xdc7f1e61, 0x61dcc27f, 0x86919c0d, 0xd861a91, 0x85949b0f, 0xf851e94
|
||||||
|
, 0x90ab4be0, 0xe090dbab, 0x42c6ba7c, 0x7c42f8c6, 0xc4572671, 0x71c4e257, 0xaae529cc, 0xccaa83e5, 0xd873e390, 0x90d83b73, 0x50f0906, 0x6050c0f, 0x103f4f7, 0xf701f503, 0x12362a1c, 0x1c123836
|
||||||
|
, 0xa3fe3cc2, 0xc2a39ffe, 0x5fe18b6a, 0x6a5fd4e1, 0xf910beae, 0xaef94710, 0xd06b0269, 0x69d0d26b, 0x91a8bf17, 0x17912ea8, 0x58e87199, 0x995829e8, 0x2769533a, 0x3a277469, 0xb9d0f727, 0x27b94ed0
|
||||||
|
, 0x384891d9, 0xd938a948, 0x1335deeb, 0xeb13cd35, 0xb3cee52b, 0x2bb356ce, 0x33557722, 0x22334455, 0xbbd604d2, 0xd2bbbfd6, 0x709039a9, 0xa9704990, 0x89808707, 0x7890e80, 0xa7f2c133, 0x33a766f2
|
||||||
|
, 0xb6c1ec2d, 0x2db65ac1, 0x22665a3c, 0x3c227866, 0x92adb815, 0x15922aad, 0x2060a9c9, 0xc9208960, 0x49db5c87, 0x874915db, 0xff1ab0aa, 0xaaff4f1a, 0x7888d850, 0x5078a088, 0x7a8e2ba5, 0xa57a518e
|
||||||
|
, 0x8f8a8903, 0x38f068a, 0xf8134a59, 0x59f8b213, 0x809b9209, 0x980129b, 0x1739231a, 0x1a173439, 0xda751065, 0x65daca75, 0x315384d7, 0xd731b553, 0xc651d584, 0x84c61351, 0xb8d303d0, 0xd0b8bbd3
|
||||||
|
, 0xc35edc82, 0x82c31f5e, 0xb0cbe229, 0x29b052cb, 0x7799c35a, 0x5a77b499, 0x11332d1e, 0x1e113c33, 0xcb463d7b, 0x7bcbf646, 0xfc1fb7a8, 0xa8fc4b1f, 0xd6610c6d, 0x6dd6da61, 0x3a4e622c, 0x2c3a584e};
|
||||||
|
|
||||||
|
#endif /* __tables_h */
|
|
@ -0,0 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef unsigned char BitSequence;
|
||||||
|
typedef unsigned long long DataLength;
|
||||||
|
typedef enum {SUCCESS = 0, FAIL = 1, BAD_HASHLEN = 2} HashReturn;
|
|
@ -0,0 +1,153 @@
|
||||||
|
// Copyright(c) 2012 - 2013 The Cryptonote developers
|
||||||
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static inline uint32_t rol32(uint32_t x, int r) {
|
||||||
|
static_assert(sizeof(uint32_t) == sizeof(unsigned int), "this code assumes 32-bit integers");
|
||||||
|
return _rotl(x, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t rol64(uint64_t x, int r) {
|
||||||
|
return _rotl64(x, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static inline uint32_t rol32(uint32_t x, int r) {
|
||||||
|
return (x << (r & 31)) | (x >> (-r & 31));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t rol64(uint64_t x, int r) {
|
||||||
|
return (x << (r & 63)) | (x >> (-r & 63));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline uint64_t hi_dword(uint64_t val) {
|
||||||
|
return val >> 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t lo_dword(uint64_t val) {
|
||||||
|
return val & 0xFFFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint64_t div_with_reminder(uint64_t dividend, uint32_t divisor, uint32_t* remainder) {
|
||||||
|
dividend |= ((uint64_t)*remainder) << 32;
|
||||||
|
*remainder = dividend % divisor;
|
||||||
|
return dividend / divisor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Long division with 2^32 base
|
||||||
|
static inline uint32_t div128_32(uint64_t dividend_hi, uint64_t dividend_lo, uint32_t divisor, uint64_t* quotient_hi, uint64_t* quotient_lo) {
|
||||||
|
uint64_t dividend_dwords[4];
|
||||||
|
uint32_t remainder = 0;
|
||||||
|
|
||||||
|
dividend_dwords[3] = hi_dword(dividend_hi);
|
||||||
|
dividend_dwords[2] = lo_dword(dividend_hi);
|
||||||
|
dividend_dwords[1] = hi_dword(dividend_lo);
|
||||||
|
dividend_dwords[0] = lo_dword(dividend_lo);
|
||||||
|
|
||||||
|
*quotient_hi = div_with_reminder(dividend_dwords[3], divisor, &remainder) << 32;
|
||||||
|
*quotient_hi |= div_with_reminder(dividend_dwords[2], divisor, &remainder);
|
||||||
|
*quotient_lo = div_with_reminder(dividend_dwords[1], divisor, &remainder) << 32;
|
||||||
|
*quotient_lo |= div_with_reminder(dividend_dwords[0], divisor, &remainder);
|
||||||
|
|
||||||
|
return remainder;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IDENT32(x) ((uint32_t) (x))
|
||||||
|
#define IDENT64(x) ((uint64_t) (x))
|
||||||
|
|
||||||
|
#define SWAP32(x) ((((uint32_t) (x) & 0x000000ff) << 24) | \
|
||||||
|
(((uint32_t) (x) & 0x0000ff00) << 8) | \
|
||||||
|
(((uint32_t) (x) & 0x00ff0000) >> 8) | \
|
||||||
|
(((uint32_t) (x) & 0xff000000) >> 24))
|
||||||
|
#define SWAP64(x) ((((uint64_t) (x) & 0x00000000000000ff) << 56) | \
|
||||||
|
(((uint64_t) (x) & 0x000000000000ff00) << 40) | \
|
||||||
|
(((uint64_t) (x) & 0x0000000000ff0000) << 24) | \
|
||||||
|
(((uint64_t) (x) & 0x00000000ff000000) << 8) | \
|
||||||
|
(((uint64_t) (x) & 0x000000ff00000000) >> 8) | \
|
||||||
|
(((uint64_t) (x) & 0x0000ff0000000000) >> 24) | \
|
||||||
|
(((uint64_t) (x) & 0x00ff000000000000) >> 40) | \
|
||||||
|
(((uint64_t) (x) & 0xff00000000000000) >> 56))
|
||||||
|
|
||||||
|
static inline uint32_t ident32(uint32_t x) { return x; }
|
||||||
|
static inline uint64_t ident64(uint64_t x) { return x; }
|
||||||
|
|
||||||
|
static inline uint32_t swap32(uint32_t x) {
|
||||||
|
x = ((x & 0x00ff00ff) << 8) | ((x & 0xff00ff00) >> 8);
|
||||||
|
return (x << 16) | (x >> 16);
|
||||||
|
}
|
||||||
|
static inline uint64_t swap64(uint64_t x) {
|
||||||
|
x = ((x & 0x00ff00ff00ff00ff) << 8) | ((x & 0xff00ff00ff00ff00) >> 8);
|
||||||
|
x = ((x & 0x0000ffff0000ffff) << 16) | ((x & 0xffff0000ffff0000) >> 16);
|
||||||
|
return (x << 32) | (x >> 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define UNUSED __attribute__((unused))
|
||||||
|
#else
|
||||||
|
#define UNUSED
|
||||||
|
#endif
|
||||||
|
static inline void mem_inplace_ident(void *mem UNUSED, size_t n UNUSED) { }
|
||||||
|
#undef UNUSED
|
||||||
|
|
||||||
|
static inline void mem_inplace_swap32(void *mem, size_t n) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
((uint32_t *)mem)[i] = swap32(((const uint32_t *)mem)[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static inline void mem_inplace_swap64(void *mem, size_t n) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
((uint64_t *)mem)[i] = swap64(((const uint64_t *)mem)[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void memcpy_ident32(void *dst, const void *src, size_t n) {
|
||||||
|
memcpy(dst, src, 4 * n);
|
||||||
|
}
|
||||||
|
static inline void memcpy_ident64(void *dst, const void *src, size_t n) {
|
||||||
|
memcpy(dst, src, 8 * n);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void memcpy_swap32(void *dst, const void *src, size_t n) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
((uint32_t *)dst)[i] = swap32(((const uint32_t *)src)[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static inline void memcpy_swap64(void *dst, const void *src, size_t n) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
((uint64_t *)dst)[i] = swap64(((const uint64_t *)src)[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SWAP32LE IDENT32
|
||||||
|
#define SWAP32BE SWAP32
|
||||||
|
#define swap32le ident32
|
||||||
|
#define swap32be swap32
|
||||||
|
#define mem_inplace_swap32le mem_inplace_ident
|
||||||
|
#define mem_inplace_swap32be mem_inplace_swap32
|
||||||
|
#define memcpy_swap32le memcpy_ident32
|
||||||
|
#define memcpy_swap32be memcpy_swap32
|
||||||
|
#define SWAP64LE IDENT64
|
||||||
|
#define SWAP64BE SWAP64
|
||||||
|
#define swap64le ident64
|
||||||
|
#define swap64be swap64
|
||||||
|
#define mem_inplace_swap64le mem_inplace_ident
|
||||||
|
#define mem_inplace_swap64be mem_inplace_swap64
|
||||||
|
#define memcpy_swap64le memcpy_ident64
|
||||||
|
#define memcpy_swap64be memcpy_swap64
|
|
@ -0,0 +1,179 @@
|
||||||
|
#ifndef _SKEIN_PORT_H_
|
||||||
|
#define _SKEIN_PORT_H_
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifndef RETURN_VALUES
|
||||||
|
# define RETURN_VALUES
|
||||||
|
# if defined( DLL_EXPORT )
|
||||||
|
# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER )
|
||||||
|
# define VOID_RETURN __declspec( dllexport ) void __stdcall
|
||||||
|
# define INT_RETURN __declspec( dllexport ) int __stdcall
|
||||||
|
# elif defined( __GNUC__ )
|
||||||
|
# define VOID_RETURN __declspec( __dllexport__ ) void
|
||||||
|
# define INT_RETURN __declspec( __dllexport__ ) int
|
||||||
|
# else
|
||||||
|
# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
|
||||||
|
# endif
|
||||||
|
# elif defined( DLL_IMPORT )
|
||||||
|
# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER )
|
||||||
|
# define VOID_RETURN __declspec( dllimport ) void __stdcall
|
||||||
|
# define INT_RETURN __declspec( dllimport ) int __stdcall
|
||||||
|
# elif defined( __GNUC__ )
|
||||||
|
# define VOID_RETURN __declspec( __dllimport__ ) void
|
||||||
|
# define INT_RETURN __declspec( __dllimport__ ) int
|
||||||
|
# else
|
||||||
|
# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers
|
||||||
|
# endif
|
||||||
|
# elif defined( __WATCOMC__ )
|
||||||
|
# define VOID_RETURN void __cdecl
|
||||||
|
# define INT_RETURN int __cdecl
|
||||||
|
# else
|
||||||
|
# define VOID_RETURN void
|
||||||
|
# define INT_RETURN int
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* These defines are used to declare buffers in a way that allows
|
||||||
|
faster operations on longer variables to be used. In all these
|
||||||
|
defines 'size' must be a power of 2 and >= 8
|
||||||
|
|
||||||
|
dec_unit_type(size,x) declares a variable 'x' of length
|
||||||
|
'size' bits
|
||||||
|
|
||||||
|
dec_bufr_type(size,bsize,x) declares a buffer 'x' of length 'bsize'
|
||||||
|
bytes defined as an array of variables
|
||||||
|
each of 'size' bits (bsize must be a
|
||||||
|
multiple of size / 8)
|
||||||
|
|
||||||
|
ptr_cast(x,size) casts a pointer to a pointer to a
|
||||||
|
varaiable of length 'size' bits
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ui_type(size) uint##size##_t
|
||||||
|
#define dec_unit_type(size,x) typedef ui_type(size) x
|
||||||
|
#define dec_bufr_type(size,bsize,x) typedef ui_type(size) x[bsize / (size >> 3)]
|
||||||
|
#define ptr_cast(x,size) ((ui_type(size)*)(x))
|
||||||
|
|
||||||
|
typedef unsigned int uint_t; /* native unsigned integer */
|
||||||
|
typedef uint8_t u08b_t; /* 8-bit unsigned integer */
|
||||||
|
typedef uint64_t u64b_t; /* 64-bit unsigned integer */
|
||||||
|
|
||||||
|
#ifndef RotL_64
|
||||||
|
#define RotL_64(x,N) (((x) << (N)) | ((x) >> (64-(N))))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Skein is "natively" little-endian (unlike SHA-xxx), for optimal
|
||||||
|
* performance on x86 CPUs. The Skein code requires the following
|
||||||
|
* definitions for dealing with endianness:
|
||||||
|
*
|
||||||
|
* SKEIN_NEED_SWAP: 0 for little-endian, 1 for big-endian
|
||||||
|
* Skein_Put64_LSB_First
|
||||||
|
* Skein_Get64_LSB_First
|
||||||
|
* Skein_Swap64
|
||||||
|
*
|
||||||
|
* If SKEIN_NEED_SWAP is defined at compile time, it is used here
|
||||||
|
* along with the portable versions of Put64/Get64/Swap64, which
|
||||||
|
* are slow in general.
|
||||||
|
*
|
||||||
|
* Otherwise, an "auto-detect" of endianness is attempted below.
|
||||||
|
* If the default handling doesn't work well, the user may insert
|
||||||
|
* platform-specific code instead (e.g., for big-endian CPUs).
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef SKEIN_NEED_SWAP /* compile-time "override" for endianness? */
|
||||||
|
|
||||||
|
#define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||||
|
|
||||||
|
/* special handler for IA64, which may be either endianness (?) */
|
||||||
|
/* here we assume little-endian, but this may need to be changed */
|
||||||
|
#if defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
|
||||||
|
# define PLATFORM_MUST_ALIGN (1)
|
||||||
|
#ifndef PLATFORM_BYTE_ORDER
|
||||||
|
# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PLATFORM_MUST_ALIGN
|
||||||
|
# define PLATFORM_MUST_ALIGN (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if PLATFORM_BYTE_ORDER == IS_BIG_ENDIAN
|
||||||
|
/* here for big-endian CPUs */
|
||||||
|
#define SKEIN_NEED_SWAP (1)
|
||||||
|
#elif PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN
|
||||||
|
/* here for x86 and x86-64 CPUs (and other detected little-endian CPUs) */
|
||||||
|
#define SKEIN_NEED_SWAP (0)
|
||||||
|
#if PLATFORM_MUST_ALIGN == 0 /* ok to use "fast" versions? */
|
||||||
|
#define Skein_Put64_LSB_First(dst08,src64,bCnt) memcpy(dst08,src64,bCnt)
|
||||||
|
#define Skein_Get64_LSB_First(dst64,src08,wCnt) memcpy(dst64,src08,8*(wCnt))
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#error "Skein needs endianness setting!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* ifndef SKEIN_NEED_SWAP */
|
||||||
|
|
||||||
|
/*
|
||||||
|
******************************************************************
|
||||||
|
* Provide any definitions still needed.
|
||||||
|
******************************************************************
|
||||||
|
*/
|
||||||
|
#ifndef Skein_Swap64 /* swap for big-endian, nop for little-endian */
|
||||||
|
#if SKEIN_NEED_SWAP
|
||||||
|
#define Skein_Swap64(w64) \
|
||||||
|
( (( ((u64b_t)(w64)) & 0xFF) << 56) | \
|
||||||
|
(((((u64b_t)(w64)) >> 8) & 0xFF) << 48) | \
|
||||||
|
(((((u64b_t)(w64)) >>16) & 0xFF) << 40) | \
|
||||||
|
(((((u64b_t)(w64)) >>24) & 0xFF) << 32) | \
|
||||||
|
(((((u64b_t)(w64)) >>32) & 0xFF) << 24) | \
|
||||||
|
(((((u64b_t)(w64)) >>40) & 0xFF) << 16) | \
|
||||||
|
(((((u64b_t)(w64)) >>48) & 0xFF) << 8) | \
|
||||||
|
(((((u64b_t)(w64)) >>56) & 0xFF) ) )
|
||||||
|
#else
|
||||||
|
#define Skein_Swap64(w64) (w64)
|
||||||
|
#endif
|
||||||
|
#endif /* ifndef Skein_Swap64 */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef Skein_Put64_LSB_First
|
||||||
|
void Skein_Put64_LSB_First(u08b_t *dst,const u64b_t *src,size_t bCnt)
|
||||||
|
#ifdef SKEIN_PORT_CODE /* instantiate the function code here? */
|
||||||
|
{ /* this version is fully portable (big-endian or little-endian), but slow */
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
for (n=0;n<bCnt;n++)
|
||||||
|
dst[n] = (u08b_t) (src[n>>3] >> (8*(n&7)));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
; /* output only the function prototype */
|
||||||
|
#endif
|
||||||
|
#endif /* ifndef Skein_Put64_LSB_First */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef Skein_Get64_LSB_First
|
||||||
|
void Skein_Get64_LSB_First(u64b_t *dst,const u08b_t *src,size_t wCnt)
|
||||||
|
#ifdef SKEIN_PORT_CODE /* instantiate the function code here? */
|
||||||
|
{ /* this version is fully portable (big-endian or little-endian), but slow */
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
for (n=0;n<8*wCnt;n+=8)
|
||||||
|
dst[n/8] = (((u64b_t) src[n ]) ) +
|
||||||
|
(((u64b_t) src[n+1]) << 8) +
|
||||||
|
(((u64b_t) src[n+2]) << 16) +
|
||||||
|
(((u64b_t) src[n+3]) << 24) +
|
||||||
|
(((u64b_t) src[n+4]) << 32) +
|
||||||
|
(((u64b_t) src[n+5]) << 40) +
|
||||||
|
(((u64b_t) src[n+6]) << 48) +
|
||||||
|
(((u64b_t) src[n+7]) << 56) ;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
; /* output only the function prototype */
|
||||||
|
#endif
|
||||||
|
#endif /* ifndef Skein_Get64_LSB_First */
|
||||||
|
|
||||||
|
#endif /* ifndef _SKEIN_PORT_H_ */
|
|
@ -0,0 +1,197 @@
|
||||||
|
/*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The orginal author of this AES implementation is Karl Malbrain.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#include <x86intrin.h>
|
||||||
|
#else
|
||||||
|
#include <intrin.h>
|
||||||
|
#endif // __GNUC__
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#define TABLE_ALIGN 32
|
||||||
|
#define WPOLY 0x011b
|
||||||
|
#define N_COLS 4
|
||||||
|
#define AES_BLOCK_SIZE 16
|
||||||
|
#define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2))
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#define ALIGN __declspec(align(TABLE_ALIGN))
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
#define ALIGN __attribute__ ((aligned(16)))
|
||||||
|
#else
|
||||||
|
#define ALIGN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define rf1(r,c) (r)
|
||||||
|
#define word_in(x,c) (*((uint32_t*)(x)+(c)))
|
||||||
|
#define word_out(x,c,v) (*((uint32_t*)(x)+(c)) = (v))
|
||||||
|
|
||||||
|
#define s(x,c) x[c]
|
||||||
|
#define si(y,x,c) (s(y,c) = word_in(x, c))
|
||||||
|
#define so(y,x,c) word_out(y, c, s(x,c))
|
||||||
|
#define state_in(y,x) si(y,x,0); si(y,x,1); si(y,x,2); si(y,x,3)
|
||||||
|
#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3)
|
||||||
|
#define round(y,x,k) \
|
||||||
|
y[0] = (k)[0] ^ (t_fn[0][x[0] & 0xff] ^ t_fn[1][(x[1] >> 8) & 0xff] ^ t_fn[2][(x[2] >> 16) & 0xff] ^ t_fn[3][x[3] >> 24]); \
|
||||||
|
y[1] = (k)[1] ^ (t_fn[0][x[1] & 0xff] ^ t_fn[1][(x[2] >> 8) & 0xff] ^ t_fn[2][(x[3] >> 16) & 0xff] ^ t_fn[3][x[0] >> 24]); \
|
||||||
|
y[2] = (k)[2] ^ (t_fn[0][x[2] & 0xff] ^ t_fn[1][(x[3] >> 8) & 0xff] ^ t_fn[2][(x[0] >> 16) & 0xff] ^ t_fn[3][x[1] >> 24]); \
|
||||||
|
y[3] = (k)[3] ^ (t_fn[0][x[3] & 0xff] ^ t_fn[1][(x[0] >> 8) & 0xff] ^ t_fn[2][(x[1] >> 16) & 0xff] ^ t_fn[3][x[2] >> 24]);
|
||||||
|
#define to_byte(x) ((x) & 0xff)
|
||||||
|
#define bval(x,n) to_byte((x) >> (8 * (n)))
|
||||||
|
|
||||||
|
#define fwd_var(x,r,c)\
|
||||||
|
( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\
|
||||||
|
: r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\
|
||||||
|
: r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\
|
||||||
|
: ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2)))
|
||||||
|
|
||||||
|
#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c))
|
||||||
|
|
||||||
|
#define sb_data(w) {\
|
||||||
|
w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\
|
||||||
|
w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\
|
||||||
|
w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\
|
||||||
|
w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\
|
||||||
|
w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\
|
||||||
|
w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\
|
||||||
|
w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\
|
||||||
|
w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\
|
||||||
|
w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\
|
||||||
|
w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\
|
||||||
|
w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\
|
||||||
|
w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\
|
||||||
|
w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\
|
||||||
|
w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\
|
||||||
|
w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\
|
||||||
|
w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\
|
||||||
|
w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\
|
||||||
|
w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\
|
||||||
|
w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\
|
||||||
|
w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\
|
||||||
|
w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\
|
||||||
|
w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\
|
||||||
|
w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\
|
||||||
|
w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\
|
||||||
|
w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\
|
||||||
|
w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\
|
||||||
|
w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\
|
||||||
|
w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\
|
||||||
|
w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\
|
||||||
|
w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\
|
||||||
|
w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\
|
||||||
|
w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) }
|
||||||
|
|
||||||
|
#define rc_data(w) {\
|
||||||
|
w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\
|
||||||
|
w(0x1b), w(0x36) }
|
||||||
|
|
||||||
|
#define bytes2word(b0, b1, b2, b3) (((uint32_t)(b3) << 24) | \
|
||||||
|
((uint32_t)(b2) << 16) | ((uint32_t)(b1) << 8) | (b0))
|
||||||
|
|
||||||
|
#define h0(x) (x)
|
||||||
|
#define w0(p) bytes2word(p, 0, 0, 0)
|
||||||
|
#define w1(p) bytes2word(0, p, 0, 0)
|
||||||
|
#define w2(p) bytes2word(0, 0, p, 0)
|
||||||
|
#define w3(p) bytes2word(0, 0, 0, p)
|
||||||
|
|
||||||
|
#define u0(p) bytes2word(f2(p), p, p, f3(p))
|
||||||
|
#define u1(p) bytes2word(f3(p), f2(p), p, p)
|
||||||
|
#define u2(p) bytes2word(p, f3(p), f2(p), p)
|
||||||
|
#define u3(p) bytes2word(p, p, f3(p), f2(p))
|
||||||
|
|
||||||
|
#define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p))
|
||||||
|
#define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p))
|
||||||
|
#define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p))
|
||||||
|
#define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p))
|
||||||
|
|
||||||
|
#define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY))
|
||||||
|
#define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY))
|
||||||
|
#define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) ^ (((x>>5) & 4) * WPOLY))
|
||||||
|
#define f3(x) (f2(x) ^ x)
|
||||||
|
#define f9(x) (f8(x) ^ x)
|
||||||
|
#define fb(x) (f8(x) ^ f2(x) ^ x)
|
||||||
|
#define fd(x) (f8(x) ^ f4(x) ^ x)
|
||||||
|
#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
|
||||||
|
|
||||||
|
#define t_dec(m,n) t_##m##n
|
||||||
|
#define t_set(m,n) t_##m##n
|
||||||
|
#define t_use(m,n) t_##m##n
|
||||||
|
|
||||||
|
#define d_4(t,n,b,e,f,g,h) ALIGN const t n[4][256] = { b(e), b(f), b(g), b(h) }
|
||||||
|
|
||||||
|
#define four_tables(x,tab,vf,rf,c) \
|
||||||
|
(tab[0][bval(vf(x,0,c),rf(0,c))] \
|
||||||
|
^ tab[1][bval(vf(x,1,c),rf(1,c))] \
|
||||||
|
^ tab[2][bval(vf(x,2,c),rf(2,c))] \
|
||||||
|
^ tab[3][bval(vf(x,3,c),rf(3,c))])
|
||||||
|
|
||||||
|
d_4(uint32_t, t_dec(f,n), sb_data, u0, u1, u2, u3);
|
||||||
|
|
||||||
|
__m128i soft_aesenc(__m128i in, __m128i key)
|
||||||
|
{
|
||||||
|
uint32_t x0, x1, x2, x3;
|
||||||
|
x0 = _mm_cvtsi128_si32(in);
|
||||||
|
x1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(in, 0x55));
|
||||||
|
x2 = _mm_cvtsi128_si32(_mm_shuffle_epi32(in, 0xAA));
|
||||||
|
x3 = _mm_cvtsi128_si32(_mm_shuffle_epi32(in, 0xFF));
|
||||||
|
|
||||||
|
__m128i out = _mm_set_epi32(
|
||||||
|
(t_fn[0][x3 & 0xff] ^ t_fn[1][(x0 >> 8) & 0xff] ^ t_fn[2][(x1 >> 16) & 0xff] ^ t_fn[3][x2 >> 24]),
|
||||||
|
(t_fn[0][x2 & 0xff] ^ t_fn[1][(x3 >> 8) & 0xff] ^ t_fn[2][(x0 >> 16) & 0xff] ^ t_fn[3][x1 >> 24]),
|
||||||
|
(t_fn[0][x1 & 0xff] ^ t_fn[1][(x2 >> 8) & 0xff] ^ t_fn[2][(x3 >> 16) & 0xff] ^ t_fn[3][x0 >> 24]),
|
||||||
|
(t_fn[0][x0 & 0xff] ^ t_fn[1][(x1 >> 8) & 0xff] ^ t_fn[2][(x2 >> 16) & 0xff] ^ t_fn[3][x3 >> 24]));
|
||||||
|
|
||||||
|
return _mm_xor_si128(out, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t Sbox[256] = { // forward s-box
|
||||||
|
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||||
|
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||||
|
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||||
|
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||||
|
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||||
|
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||||
|
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||||
|
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||||
|
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||||
|
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||||
|
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||||
|
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||||
|
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||||
|
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||||
|
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||||
|
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};
|
||||||
|
|
||||||
|
static inline void sub_word(uint8_t* key)
|
||||||
|
{
|
||||||
|
key[0] = Sbox[key[0]];
|
||||||
|
key[1] = Sbox[key[1]];
|
||||||
|
key[2] = Sbox[key[2]];
|
||||||
|
key[3] = Sbox[key[3]];
|
||||||
|
}
|
||||||
|
|
||||||
|
__m128i soft_aeskeygenassist(__m128i key, uint8_t rcon)
|
||||||
|
{
|
||||||
|
uint32_t X1 = _mm_cvtsi128_si32(_mm_shuffle_epi32(key, 0x55));
|
||||||
|
uint32_t X3 = _mm_cvtsi128_si32(_mm_shuffle_epi32(key, 0xFF));
|
||||||
|
sub_word((uint8_t*)&X1);
|
||||||
|
sub_word((uint8_t*)&X3);
|
||||||
|
return _mm_set_epi32(_rotr(X3, 8) ^ rcon, X3,_rotr(X1, 8) ^ rcon, X1);
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Dev donation.
|
||||||
|
* Percentage of your hashing power that you want to donate to the developer, can be 0.0 if you don't want to do that.
|
||||||
|
* Example of how it works for the default setting of 1.0:
|
||||||
|
* You miner will mine into your usual pool for 99 minutes, then switch to the developer's pool for 1.0 minute.
|
||||||
|
* Switching is instant, and only happens after a successful connection, so you never loose any hashes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
constexpr double fDevDonationLevel = 1.0 / 100.0;
|
|
@ -0,0 +1,721 @@
|
||||||
|
/*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
#include <string>
|
||||||
|
#include <cmath>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "executor.h"
|
||||||
|
#include "jpsock.h"
|
||||||
|
#include "minethd.h"
|
||||||
|
#include "jconf.h"
|
||||||
|
#include "console.h"
|
||||||
|
#include "donate-level.h"
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#include <mm_malloc.h>
|
||||||
|
#else
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif // __GNUC__
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define strncasecmp _strnicmp
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
executor* executor::oInst = NULL;
|
||||||
|
|
||||||
|
executor::executor()
|
||||||
|
{
|
||||||
|
my_thd = nullptr;
|
||||||
|
cpu_ctx = (cryptonight_ctx*)_mm_malloc(sizeof(cryptonight_ctx), 4096);
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::push_timed_event(ex_event&& ev, size_t sec)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lck(timed_event_mutex);
|
||||||
|
lTimedEvents.emplace_back(std::move(ev), sec_to_ticks(sec));
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::ex_clock_thd()
|
||||||
|
{
|
||||||
|
size_t iSwitchPeriod = sec_to_ticks(iDevDonatePeriod);
|
||||||
|
size_t iDevPortion = (size_t)floor(((double)iSwitchPeriod) * fDevDonationLevel);
|
||||||
|
|
||||||
|
//No point in bothering with less than 10 sec
|
||||||
|
if(iDevPortion < sec_to_ticks(10))
|
||||||
|
iDevPortion = 0;
|
||||||
|
|
||||||
|
//Add 2 seconds to compensate for connect
|
||||||
|
if(iDevPortion != 0)
|
||||||
|
iDevPortion += sec_to_ticks(2);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(size_t(iTickTime)));
|
||||||
|
|
||||||
|
push_event(ex_event(EV_PERF_TICK));
|
||||||
|
|
||||||
|
// Service timed events
|
||||||
|
std::unique_lock<std::mutex> lck(timed_event_mutex);
|
||||||
|
std::list<timed_event>::iterator ev = lTimedEvents.begin();
|
||||||
|
while (ev != lTimedEvents.end())
|
||||||
|
{
|
||||||
|
ev->ticks_left--;
|
||||||
|
if(ev->ticks_left == 0)
|
||||||
|
{
|
||||||
|
push_event(std::move(ev->event));
|
||||||
|
ev = lTimedEvents.erase(ev);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ev++;
|
||||||
|
}
|
||||||
|
lck.unlock();
|
||||||
|
|
||||||
|
if(iDevPortion == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
iSwitchPeriod--;
|
||||||
|
if(iSwitchPeriod == 0)
|
||||||
|
{
|
||||||
|
push_event(ex_event(EV_SWITCH_POOL, usr_pool_id));
|
||||||
|
iSwitchPeriod = sec_to_ticks(iDevDonatePeriod);
|
||||||
|
}
|
||||||
|
else if(iSwitchPeriod == iDevPortion)
|
||||||
|
{
|
||||||
|
push_event(ex_event(EV_SWITCH_POOL, dev_pool_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::sched_reconnect()
|
||||||
|
{
|
||||||
|
long long unsigned int rt = jconf::inst()->GetNetRetry();
|
||||||
|
printer::inst()->print_msg(L1, "Pool connection lost. Waiting %lld s before retry.", rt);
|
||||||
|
|
||||||
|
auto work = minethd::miner_work();
|
||||||
|
minethd::switch_work(work);
|
||||||
|
|
||||||
|
push_timed_event(ex_event(EV_RECONNECT, usr_pool_id), rt);
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::log_socket_error(std::string&& sError)
|
||||||
|
{
|
||||||
|
vSocketLog.emplace_back(std::move(sError));
|
||||||
|
printer::inst()->print_msg(L1, "SOCKET ERROR - %s", vSocketLog.back().msg.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::log_result_error(std::string&& sError)
|
||||||
|
{
|
||||||
|
size_t i = 1, ln = vMineResults.size();
|
||||||
|
for(; i < ln; i++)
|
||||||
|
{
|
||||||
|
if(vMineResults[i].compare(sError))
|
||||||
|
{
|
||||||
|
vMineResults[i].increment();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(i == ln) //Not found
|
||||||
|
vMineResults.emplace_back(std::move(sError));
|
||||||
|
else
|
||||||
|
sError.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::log_result_ok(uint64_t iActualDiff)
|
||||||
|
{
|
||||||
|
iPoolHashes += iPoolDiff;
|
||||||
|
|
||||||
|
size_t ln = iTopDiff.size() - 1;
|
||||||
|
if(iActualDiff > iTopDiff[ln])
|
||||||
|
{
|
||||||
|
iTopDiff[ln] = iActualDiff;
|
||||||
|
std::sort(iTopDiff.rbegin(), iTopDiff.rend());
|
||||||
|
}
|
||||||
|
|
||||||
|
vMineResults[0].increment();
|
||||||
|
}
|
||||||
|
|
||||||
|
jpsock* executor::pick_pool_by_id(size_t pool_id)
|
||||||
|
{
|
||||||
|
assert(pool_id != invalid_pool_id);
|
||||||
|
|
||||||
|
if(pool_id == dev_pool_id)
|
||||||
|
return dev_pool;
|
||||||
|
else
|
||||||
|
return usr_pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::on_sock_ready(size_t pool_id)
|
||||||
|
{
|
||||||
|
jpsock* pool = pick_pool_by_id(pool_id);
|
||||||
|
|
||||||
|
if(pool_id == dev_pool_id)
|
||||||
|
{
|
||||||
|
if(!pool->cmd_login("", ""))
|
||||||
|
pool->disconnect();
|
||||||
|
|
||||||
|
current_pool_id = dev_pool_id;
|
||||||
|
printer::inst()->print_msg(L1, "Dev pool logged in. Switching work.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printer::inst()->print_msg(L1, "Connected. Logging in...");
|
||||||
|
|
||||||
|
if (!pool->cmd_login(jconf::inst()->GetWalletAddress(), jconf::inst()->GetPoolPwd()))
|
||||||
|
{
|
||||||
|
if(!pool->have_sock_error())
|
||||||
|
{
|
||||||
|
log_socket_error(pool->get_call_error());
|
||||||
|
pool->disconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
reset_stats();
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::on_sock_error(size_t pool_id, std::string&& sError)
|
||||||
|
{
|
||||||
|
jpsock* pool = pick_pool_by_id(pool_id);
|
||||||
|
|
||||||
|
if(pool_id == dev_pool_id)
|
||||||
|
{
|
||||||
|
pool->disconnect();
|
||||||
|
|
||||||
|
if(current_pool_id != dev_pool_id)
|
||||||
|
return;
|
||||||
|
|
||||||
|
printer::inst()->print_msg(L1, "Dev pool connection error. Switching work.");
|
||||||
|
on_switch_pool(usr_pool_id);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_socket_error(std::move(sError));
|
||||||
|
pool->disconnect();
|
||||||
|
sched_reconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::on_pool_have_job(size_t pool_id, pool_job& oPoolJob)
|
||||||
|
{
|
||||||
|
if(pool_id != current_pool_id)
|
||||||
|
return;
|
||||||
|
|
||||||
|
jpsock* pool = pick_pool_by_id(pool_id);
|
||||||
|
|
||||||
|
minethd::miner_work oWork(oPoolJob.sJobID, oPoolJob.bWorkBlob,
|
||||||
|
oPoolJob.iWorkLen, oPoolJob.iResumeCnt, oPoolJob.iTarget, pool_id);
|
||||||
|
|
||||||
|
minethd::switch_work(oWork);
|
||||||
|
|
||||||
|
if(pool_id == dev_pool_id)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(iPoolDiff != pool->get_current_diff())
|
||||||
|
{
|
||||||
|
iPoolDiff = pool->get_current_diff();
|
||||||
|
printer::inst()->print_msg(L2, "Difficulty changed. Now: %llu.", int_port(iPoolDiff));
|
||||||
|
}
|
||||||
|
|
||||||
|
printer::inst()->print_msg(L3, "New block detected.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::on_miner_result(size_t pool_id, job_result& oResult)
|
||||||
|
{
|
||||||
|
jpsock* pool = pick_pool_by_id(pool_id);
|
||||||
|
|
||||||
|
*(uint32_t*)(oResult.bWorkBlob + 39) = oResult.iNonce;
|
||||||
|
|
||||||
|
if(jconf::inst()->HaveHardwareAes())
|
||||||
|
cryptonight_hash_ctx(oResult.bWorkBlob, oResult.iWorkLen, oResult.bResult, cpu_ctx);
|
||||||
|
else
|
||||||
|
cryptonight_hash_ctx_soft(oResult.bWorkBlob, oResult.iWorkLen, oResult.bResult, cpu_ctx);
|
||||||
|
|
||||||
|
bool bVerified = ((uint32_t*)oResult.bResult)[7] < oResult.iTarget;
|
||||||
|
|
||||||
|
if(pool_id == dev_pool_id)
|
||||||
|
{
|
||||||
|
//Ignore errors silently
|
||||||
|
if(pool->is_running() && pool->is_logged_in() && bVerified)
|
||||||
|
pool->cmd_submit(oResult.sJobID, oResult.iNonce, oResult.bResult);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bVerified)
|
||||||
|
{
|
||||||
|
log_result_error("[GPU COMPUTE ERROR]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pool->is_running() || !pool->is_logged_in())
|
||||||
|
{
|
||||||
|
log_result_error("[NETWORK ERROR]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using namespace std::chrono;
|
||||||
|
size_t t_start = time_point_cast<milliseconds>(high_resolution_clock::now()).time_since_epoch().count();
|
||||||
|
bool bResult = pool->cmd_submit(oResult.sJobID, oResult.iNonce, oResult.bResult);
|
||||||
|
size_t t_len = time_point_cast<milliseconds>(high_resolution_clock::now()).time_since_epoch().count() - t_start;
|
||||||
|
|
||||||
|
if(t_len > 0xFFFF)
|
||||||
|
t_len = 0xFFFF;
|
||||||
|
iPoolCallTimes.push_back((uint16_t)t_len);
|
||||||
|
|
||||||
|
if(bResult)
|
||||||
|
{
|
||||||
|
uint64_t* targets = (uint64_t*)oResult.bResult;
|
||||||
|
log_result_ok(jpsock::t64_to_diff(targets[3]));
|
||||||
|
printer::inst()->print_msg(L3, "Result accepted by the pool.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!pool->have_sock_error())
|
||||||
|
{
|
||||||
|
printer::inst()->print_msg(L3, "Result rejected by the pool.");
|
||||||
|
|
||||||
|
std::string error = pool->get_call_error();
|
||||||
|
|
||||||
|
if(strncasecmp(error.c_str(), "Unauthenticated", 15) == 0)
|
||||||
|
{
|
||||||
|
printer::inst()->print_msg(L2, "Your miner was unable to find a share in time. Either the pool difficulty is too high, or the pool timeout is too low.");
|
||||||
|
pool->disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
log_result_error(std::move(error));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log_result_error("[NETWORK ERROR]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::on_reconnect(size_t pool_id)
|
||||||
|
{
|
||||||
|
jpsock* pool = pick_pool_by_id(pool_id);
|
||||||
|
|
||||||
|
std::string error;
|
||||||
|
if(pool_id == dev_pool_id)
|
||||||
|
return;
|
||||||
|
|
||||||
|
printer::inst()->print_msg(L1, "Connecting to pool %s ...", jconf::inst()->GetPoolAddress());
|
||||||
|
|
||||||
|
if(!pool->connect(jconf::inst()->GetPoolAddress(), error))
|
||||||
|
{
|
||||||
|
log_socket_error(std::move(error));
|
||||||
|
sched_reconnect();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::on_switch_pool(size_t pool_id)
|
||||||
|
{
|
||||||
|
if(pool_id == current_pool_id)
|
||||||
|
return;
|
||||||
|
|
||||||
|
jpsock* pool = pick_pool_by_id(pool_id);
|
||||||
|
if(pool_id == dev_pool_id)
|
||||||
|
{
|
||||||
|
std::string error;
|
||||||
|
|
||||||
|
// If it fails, it fails, we carry on on the usr pool
|
||||||
|
// as we never receive further events
|
||||||
|
printer::inst()->print_msg(L1, "Connecting to dev pool...");
|
||||||
|
if(!pool->connect("donate.xmr-stak.net:3333", error))
|
||||||
|
printer::inst()->print_msg(L1, "Error connecting to dev pool. Staying with user pool.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printer::inst()->print_msg(L1, "Switching back to user pool.");
|
||||||
|
|
||||||
|
current_pool_id = pool_id;
|
||||||
|
pool_job oPoolJob;
|
||||||
|
|
||||||
|
if(!pool->get_current_job(oPoolJob))
|
||||||
|
{
|
||||||
|
pool->disconnect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
minethd::miner_work oWork(oPoolJob.sJobID, oPoolJob.bWorkBlob,
|
||||||
|
oPoolJob.iWorkLen, oPoolJob.iResumeCnt, oPoolJob.iTarget, pool_id);
|
||||||
|
|
||||||
|
minethd::switch_work(oWork);
|
||||||
|
|
||||||
|
if(dev_pool->is_running())
|
||||||
|
push_timed_event(ex_event(EV_DEV_POOL_EXIT), 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::ex_main()
|
||||||
|
{
|
||||||
|
assert(1000 % iTickTime == 0);
|
||||||
|
|
||||||
|
minethd::miner_work oWork = minethd::miner_work();
|
||||||
|
pvThreads = minethd::thread_starter(oWork);
|
||||||
|
telem = new telemetry(pvThreads->size());
|
||||||
|
|
||||||
|
current_pool_id = usr_pool_id;
|
||||||
|
usr_pool = new jpsock(usr_pool_id);
|
||||||
|
dev_pool = new jpsock(dev_pool_id);
|
||||||
|
|
||||||
|
ex_event ev;
|
||||||
|
std::thread clock_thd(&executor::ex_clock_thd, this);
|
||||||
|
|
||||||
|
//This will connect us to the pool for the first time
|
||||||
|
push_event(ex_event(EV_RECONNECT, usr_pool_id));
|
||||||
|
|
||||||
|
// Place the default success result at postion 0, it needs to
|
||||||
|
// be here even if our first result is a failure
|
||||||
|
vMineResults.emplace_back();
|
||||||
|
|
||||||
|
// If the user requested it, start the autohash printer
|
||||||
|
if(jconf::inst()->GetVerboseLevel() >= 4)
|
||||||
|
push_timed_event(ex_event(EV_HASHRATE_LOOP), jconf::inst()->GetAutohashTime());
|
||||||
|
|
||||||
|
size_t cnt = 0, i;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
ev = oEventQ.pop();
|
||||||
|
switch (ev.iName)
|
||||||
|
{
|
||||||
|
case EV_SOCK_READY:
|
||||||
|
on_sock_ready(ev.iPoolId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_SOCK_ERROR:
|
||||||
|
on_sock_error(ev.iPoolId, std::move(ev.sSocketError));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_POOL_HAVE_JOB:
|
||||||
|
on_pool_have_job(ev.iPoolId, ev.oPoolJob);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_MINER_HAVE_RESULT:
|
||||||
|
on_miner_result(ev.iPoolId, ev.oJobResult);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_RECONNECT:
|
||||||
|
on_reconnect(ev.iPoolId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_SWITCH_POOL:
|
||||||
|
on_switch_pool(ev.iPoolId);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_DEV_POOL_EXIT:
|
||||||
|
dev_pool->disconnect();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_PERF_TICK:
|
||||||
|
for (i = 0; i < pvThreads->size(); i++)
|
||||||
|
telem->push_perf_value(i, pvThreads->at(i)->iHashCount.load(std::memory_order_relaxed),
|
||||||
|
pvThreads->at(i)->iTimestamp.load(std::memory_order_relaxed));
|
||||||
|
|
||||||
|
if((cnt++ & 0xF) == 0) //Every 16 ticks
|
||||||
|
{
|
||||||
|
double fHps = 0.0;
|
||||||
|
for (i = 0; i < pvThreads->size(); i++)
|
||||||
|
fHps += telem->calc_telemetry_data(10000, i);
|
||||||
|
|
||||||
|
if(fHighestHps < fHps)
|
||||||
|
fHighestHps = fHps;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_USR_HASHRATE:
|
||||||
|
case EV_USR_RESULTS:
|
||||||
|
case EV_USR_CONNSTAT:
|
||||||
|
print_report(ev.iName);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_HTML_HASHRATE:
|
||||||
|
case EV_HTML_RESULTS:
|
||||||
|
case EV_HTML_CONNSTAT:
|
||||||
|
http_report(ev.iName);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_HASHRATE_LOOP:
|
||||||
|
print_report(EV_USR_HASHRATE);
|
||||||
|
push_timed_event(ex_event(EV_HASHRATE_LOOP), jconf::inst()->GetAutohashTime());
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_INVALID_VAL:
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char* hps_format(double h, char* buf, size_t l)
|
||||||
|
{
|
||||||
|
if(std::isnormal(h))
|
||||||
|
{
|
||||||
|
snprintf(buf, l, " %03.1f", h);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
else if(h == 0.0) //Zero is not normal but we want it
|
||||||
|
return " 0.0";
|
||||||
|
else
|
||||||
|
return " (na)";
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::hashrate_report(std::string& out)
|
||||||
|
{
|
||||||
|
char num[32];
|
||||||
|
size_t nthd = pvThreads->size();
|
||||||
|
|
||||||
|
out.reserve(256 + nthd * 64);
|
||||||
|
|
||||||
|
double fTotal[3] = { 0.0, 0.0, 0.0};
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
out.append("HASHRATE REPORT\n");
|
||||||
|
out.append("| ID | 10s | 60s | 15m |");
|
||||||
|
if(nthd != 1)
|
||||||
|
out.append(" ID | 10s | 60s | 15m |\n");
|
||||||
|
else
|
||||||
|
out.append(1, '\n');
|
||||||
|
|
||||||
|
for (i = 0; i < nthd; i++)
|
||||||
|
{
|
||||||
|
double fHps[3];
|
||||||
|
|
||||||
|
fHps[0] = telem->calc_telemetry_data(10000, i);
|
||||||
|
fHps[1] = telem->calc_telemetry_data(60000, i);
|
||||||
|
fHps[2] = telem->calc_telemetry_data(900000, i);
|
||||||
|
|
||||||
|
snprintf(num, sizeof(num), "| %2u |", (unsigned int)i);
|
||||||
|
out.append(num);
|
||||||
|
out.append(hps_format(fHps[0], num, sizeof(num))).append(" |");
|
||||||
|
out.append(hps_format(fHps[1], num, sizeof(num))).append(" |");
|
||||||
|
out.append(hps_format(fHps[2], num, sizeof(num))).append(1, ' ');
|
||||||
|
|
||||||
|
fTotal[0] += fHps[0];
|
||||||
|
fTotal[1] += fHps[1];
|
||||||
|
fTotal[2] += fHps[2];
|
||||||
|
|
||||||
|
if((i & 0x1) == 1) //Odd i's
|
||||||
|
out.append("|\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if((i & 0x1) == 1) //We had odd number of threads
|
||||||
|
out.append("|\n");
|
||||||
|
|
||||||
|
if(nthd != 1)
|
||||||
|
out.append("-----------------------------------------------------\n");
|
||||||
|
else
|
||||||
|
out.append("---------------------------\n");
|
||||||
|
|
||||||
|
out.append("Totals: ");
|
||||||
|
out.append(hps_format(fTotal[0], num, sizeof(num)));
|
||||||
|
out.append(hps_format(fTotal[1], num, sizeof(num)));
|
||||||
|
out.append(hps_format(fTotal[2], num, sizeof(num)));
|
||||||
|
out.append(" H/s\nHighest: ");
|
||||||
|
out.append(hps_format(fHighestHps, num, sizeof(num)));
|
||||||
|
out.append(" H/s\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
char* time_format(char* buf, size_t len, std::chrono::system_clock::time_point time)
|
||||||
|
{
|
||||||
|
time_t ctime = std::chrono::system_clock::to_time_t(time);
|
||||||
|
tm stime;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Oh for god's sake... this feels like we are back to the 90's...
|
||||||
|
* and don't get me started on lack strcpy_s because NIH - use non-standard strlcpy...
|
||||||
|
* And of course C++ implements unsafe version because... reasons
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
localtime_s(&stime, &ctime);
|
||||||
|
#else
|
||||||
|
localtime_r(&ctime, &stime);
|
||||||
|
#endif // __WIN32
|
||||||
|
strftime(buf, len, "%F %T", &stime);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::result_report(std::string& out)
|
||||||
|
{
|
||||||
|
char num[128];
|
||||||
|
char date[32];
|
||||||
|
|
||||||
|
out.reserve(1024);
|
||||||
|
|
||||||
|
size_t iGoodRes = vMineResults[0].count, iTotalRes = iGoodRes;
|
||||||
|
size_t ln = vMineResults.size();
|
||||||
|
|
||||||
|
for(size_t i=1; i < ln; i++)
|
||||||
|
iTotalRes += vMineResults[i].count;
|
||||||
|
|
||||||
|
out.append("RESULT REPORT\n");
|
||||||
|
if(iTotalRes == 0)
|
||||||
|
{
|
||||||
|
out.append("You haven't found any results yet.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
double dConnSec;
|
||||||
|
{
|
||||||
|
using namespace std::chrono;
|
||||||
|
dConnSec = (double)duration_cast<seconds>(system_clock::now() - tPoolConnTime).count();
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(num, sizeof(num), " (%.1f %%)\n", 100.0 * iGoodRes / iTotalRes);
|
||||||
|
|
||||||
|
out.append("Difficulty : ").append(std::to_string(iPoolDiff)).append(1, '\n');
|
||||||
|
out.append("Good results : ").append(std::to_string(iGoodRes)).append(" / ").
|
||||||
|
append(std::to_string(iTotalRes)).append(num);
|
||||||
|
|
||||||
|
if(iPoolCallTimes.size() != 0)
|
||||||
|
{
|
||||||
|
// Here we use iPoolCallTimes since it also gets reset when we disconnect
|
||||||
|
snprintf(num, sizeof(num), "%.1f sec\n", dConnSec / iPoolCallTimes.size());
|
||||||
|
out.append("Avg result time : ").append(num);
|
||||||
|
}
|
||||||
|
out.append("Pool-side hashes : ").append(std::to_string(iPoolHashes)).append(2, '\n');
|
||||||
|
out.append("Top 10 best results found:\n");
|
||||||
|
|
||||||
|
for(size_t i=0; i < 10; i += 2)
|
||||||
|
{
|
||||||
|
snprintf(num, sizeof(num), "| %2llu | %16llu | %2llu | %16llu |\n",
|
||||||
|
int_port(i), int_port(iTopDiff[i]), int_port(i+1), int_port(iTopDiff[i+1]));
|
||||||
|
out.append(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
out.append("\nError details:\n");
|
||||||
|
if(ln > 1)
|
||||||
|
{
|
||||||
|
out.append("| Count | Error text | Last seen |\n");
|
||||||
|
for(size_t i=1; i < ln; i++)
|
||||||
|
{
|
||||||
|
snprintf(num, sizeof(num), "| %5llu | %-32.32s | %s |\n", int_port(vMineResults[i].count),
|
||||||
|
vMineResults[i].msg.c_str(), time_format(date, sizeof(date), vMineResults[i].time));
|
||||||
|
out.append(num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
out.append("Yay! No errors.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::connection_report(std::string& out)
|
||||||
|
{
|
||||||
|
char num[128];
|
||||||
|
char date[32];
|
||||||
|
|
||||||
|
out.reserve(512);
|
||||||
|
|
||||||
|
jpsock* pool = pick_pool_by_id(dev_pool_id + 1);
|
||||||
|
|
||||||
|
out.append("CONNECTION REPORT\n");
|
||||||
|
if (pool->is_running() && pool->is_logged_in())
|
||||||
|
out.append("Connected since : ").append(time_format(date, sizeof(date), tPoolConnTime)).append(1, '\n');
|
||||||
|
else
|
||||||
|
out.append("Connected since : <not connected>\n");
|
||||||
|
|
||||||
|
size_t n_calls = iPoolCallTimes.size();
|
||||||
|
if (n_calls > 1)
|
||||||
|
{
|
||||||
|
//Not-really-but-good-enough median
|
||||||
|
std::nth_element(iPoolCallTimes.begin(), iPoolCallTimes.begin() + n_calls/2, iPoolCallTimes.end());
|
||||||
|
out.append("Pool ping time : ").append(std::to_string(iPoolCallTimes[n_calls/2])).append(" ms\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
out.append("Pool ping time : (n/a)\n");
|
||||||
|
|
||||||
|
out.append("\nNetwork error log:\n");
|
||||||
|
size_t ln = vSocketLog.size();
|
||||||
|
if(ln > 0)
|
||||||
|
{
|
||||||
|
out.append("| Date | Error text |\n");
|
||||||
|
for(size_t i=0; i < ln; i++)
|
||||||
|
{
|
||||||
|
snprintf(num, sizeof(num), "| %s | %-54.54s |\n",
|
||||||
|
time_format(date, sizeof(date), vSocketLog[i].time), vSocketLog[i].msg.c_str());
|
||||||
|
out.append(num);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
out.append("Yay! No errors.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::print_report(ex_event_name ev)
|
||||||
|
{
|
||||||
|
std::string out;
|
||||||
|
switch(ev)
|
||||||
|
{
|
||||||
|
case EV_USR_HASHRATE:
|
||||||
|
hashrate_report(out);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_USR_RESULTS:
|
||||||
|
result_report(out);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_USR_CONNSTAT:
|
||||||
|
connection_report(out);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
printer::inst()->print_str(out.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::http_report(ex_event_name ev)
|
||||||
|
{
|
||||||
|
assert(pHttpString != nullptr);
|
||||||
|
|
||||||
|
switch(ev)
|
||||||
|
{
|
||||||
|
case EV_HTML_HASHRATE:
|
||||||
|
hashrate_report(*pHttpString);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_HTML_RESULTS:
|
||||||
|
result_report(*pHttpString);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case EV_HTML_CONNSTAT:
|
||||||
|
connection_report(*pHttpString);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
httpReady.set_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
void executor::get_http_report(ex_event_name ev_id, std::string& data)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lck(httpMutex);
|
||||||
|
|
||||||
|
assert(pHttpString == nullptr);
|
||||||
|
assert(ev_id == EV_HTML_HASHRATE || ev_id == EV_HTML_RESULTS || ev_id == EV_HTML_CONNSTAT);
|
||||||
|
|
||||||
|
pHttpString = &data;
|
||||||
|
httpReady = std::promise<void>();
|
||||||
|
std::future<void> ready = httpReady.get_future();
|
||||||
|
|
||||||
|
push_event(ex_event(ev_id));
|
||||||
|
|
||||||
|
ready.wait();
|
||||||
|
pHttpString = nullptr;
|
||||||
|
}
|
|
@ -0,0 +1,174 @@
|
||||||
|
#pragma once
|
||||||
|
#include "thdq.hpp"
|
||||||
|
#include "msgstruct.h"
|
||||||
|
#include <atomic>
|
||||||
|
#include <array>
|
||||||
|
#include <list>
|
||||||
|
#include <future>
|
||||||
|
|
||||||
|
#include "crypto/cryptonight.h"
|
||||||
|
|
||||||
|
class jpsock;
|
||||||
|
class minethd;
|
||||||
|
class telemetry;
|
||||||
|
|
||||||
|
class executor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static executor* inst()
|
||||||
|
{
|
||||||
|
if (oInst == nullptr) oInst = new executor;
|
||||||
|
return oInst;
|
||||||
|
};
|
||||||
|
|
||||||
|
void ex_start() { my_thd = new std::thread(&executor::ex_main, this); }
|
||||||
|
void ex_main();
|
||||||
|
|
||||||
|
void get_http_report(ex_event_name ev_id, std::string& data);
|
||||||
|
|
||||||
|
inline void push_event(ex_event&& ev) { oEventQ.push(std::move(ev)); }
|
||||||
|
void push_timed_event(ex_event&& ev, size_t sec);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct timed_event
|
||||||
|
{
|
||||||
|
ex_event event;
|
||||||
|
size_t ticks_left;
|
||||||
|
|
||||||
|
timed_event(ex_event&& ev, size_t ticks) : event(std::move(ev)), ticks_left(ticks) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
cryptonight_ctx* cpu_ctx;
|
||||||
|
|
||||||
|
// In miliseconds, has to divide a second (1000ms) into an integer number
|
||||||
|
constexpr static size_t iTickTime = 500;
|
||||||
|
|
||||||
|
// Dev donation time period in seconds. 100 minutes by default.
|
||||||
|
// We will divide up this period according to the config setting
|
||||||
|
constexpr static size_t iDevDonatePeriod = 100 * 60;
|
||||||
|
|
||||||
|
constexpr static size_t invalid_pool_id = 0;
|
||||||
|
constexpr static size_t dev_pool_id = 1;
|
||||||
|
constexpr static size_t usr_pool_id = 2;
|
||||||
|
|
||||||
|
std::list<timed_event> lTimedEvents;
|
||||||
|
std::mutex timed_event_mutex;
|
||||||
|
thdq<ex_event> oEventQ;
|
||||||
|
|
||||||
|
telemetry* telem;
|
||||||
|
std::vector<minethd*>* pvThreads;
|
||||||
|
std::thread* my_thd;
|
||||||
|
|
||||||
|
size_t current_pool_id;
|
||||||
|
|
||||||
|
jpsock* usr_pool;
|
||||||
|
jpsock* dev_pool;
|
||||||
|
|
||||||
|
jpsock* pick_pool_by_id(size_t pool_id);
|
||||||
|
|
||||||
|
bool is_dev_time;
|
||||||
|
|
||||||
|
executor();
|
||||||
|
static executor* oInst;
|
||||||
|
|
||||||
|
void ex_clock_thd();
|
||||||
|
void pool_connect(jpsock* pool);
|
||||||
|
|
||||||
|
void hashrate_report(std::string& out);
|
||||||
|
void result_report(std::string& out);
|
||||||
|
void connection_report(std::string& out);
|
||||||
|
|
||||||
|
void http_report(ex_event_name ev);
|
||||||
|
void print_report(ex_event_name ev);
|
||||||
|
|
||||||
|
std::string* pHttpString = nullptr;
|
||||||
|
std::promise<void> httpReady;
|
||||||
|
std::mutex httpMutex;
|
||||||
|
|
||||||
|
struct sck_error_log
|
||||||
|
{
|
||||||
|
std::chrono::system_clock::time_point time;
|
||||||
|
std::string msg;
|
||||||
|
|
||||||
|
sck_error_log(std::string&& err) : msg(std::move(err))
|
||||||
|
{
|
||||||
|
time = std::chrono::system_clock::now();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::vector<sck_error_log> vSocketLog;
|
||||||
|
|
||||||
|
// Element zero is always the success element.
|
||||||
|
// Keep in mind that this is a tally and not a log like above
|
||||||
|
struct result_tally
|
||||||
|
{
|
||||||
|
std::chrono::system_clock::time_point time;
|
||||||
|
std::string msg;
|
||||||
|
size_t count;
|
||||||
|
|
||||||
|
result_tally() : msg("[OK]"), count(0)
|
||||||
|
{
|
||||||
|
time = std::chrono::system_clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
result_tally(std::string&& err) : msg(std::move(err)), count(1)
|
||||||
|
{
|
||||||
|
time = std::chrono::system_clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
void increment()
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
time = std::chrono::system_clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool compare(std::string& err)
|
||||||
|
{
|
||||||
|
if(msg == err)
|
||||||
|
{
|
||||||
|
increment();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::vector<result_tally> vMineResults;
|
||||||
|
|
||||||
|
//More result statistics
|
||||||
|
std::array<size_t, 10> iTopDiff { { } }; //Initialize to zero
|
||||||
|
|
||||||
|
std::chrono::system_clock::time_point tPoolConnTime;
|
||||||
|
size_t iPoolHashes;
|
||||||
|
uint64_t iPoolDiff;
|
||||||
|
|
||||||
|
// Set it to 16 bit so that we can just let it grow
|
||||||
|
// Maximum realistic growth rate - 5MB / month
|
||||||
|
std::vector<uint16_t> iPoolCallTimes;
|
||||||
|
|
||||||
|
//Those stats are reset if we disconnect
|
||||||
|
inline void reset_stats()
|
||||||
|
{
|
||||||
|
iPoolCallTimes.clear();
|
||||||
|
tPoolConnTime = std::chrono::system_clock::now();
|
||||||
|
iPoolHashes = 0;
|
||||||
|
iPoolDiff = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double fHighestHps = 0.0;
|
||||||
|
|
||||||
|
void log_socket_error(std::string&& sError);
|
||||||
|
void log_result_error(std::string&& sError);
|
||||||
|
void log_result_ok(uint64_t iActualDiff);
|
||||||
|
|
||||||
|
void sched_reconnect();
|
||||||
|
|
||||||
|
void on_sock_ready(size_t pool_id);
|
||||||
|
void on_sock_error(size_t pool_id, std::string&& sError);
|
||||||
|
void on_pool_have_job(size_t pool_id, pool_job& oPoolJob);
|
||||||
|
void on_miner_result(size_t pool_id, job_result& oResult);
|
||||||
|
void on_reconnect(size_t pool_id);
|
||||||
|
void on_switch_pool(size_t pool_id);
|
||||||
|
|
||||||
|
inline size_t sec_to_ticks(size_t sec) { return sec * (1000 / iTickTime); }
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "msgstruct.h"
|
||||||
|
#include "httpd.h"
|
||||||
|
#include "console.h"
|
||||||
|
#include "executor.h"
|
||||||
|
#include "jconf.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include "libmicrohttpd/microhttpd.h"
|
||||||
|
#define strcasecmp _stricmp
|
||||||
|
#else
|
||||||
|
#include <microhttpd.h>
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
httpd* httpd::oInst = nullptr;
|
||||||
|
|
||||||
|
httpd::httpd()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int httpd::req_handler(void * cls,
|
||||||
|
MHD_Connection* connection,
|
||||||
|
const char* url,
|
||||||
|
const char* method,
|
||||||
|
const char* version,
|
||||||
|
const char* upload_data,
|
||||||
|
size_t* upload_data_size,
|
||||||
|
void ** ptr)
|
||||||
|
{
|
||||||
|
struct MHD_Response * rsp;
|
||||||
|
|
||||||
|
if (strcmp(method, "GET") != 0)
|
||||||
|
return MHD_NO;
|
||||||
|
|
||||||
|
*ptr = nullptr;
|
||||||
|
|
||||||
|
std::string str;
|
||||||
|
if(strcasecmp(url, "/h") == 0 || strcasecmp(url, "/hashrate") == 0)
|
||||||
|
{
|
||||||
|
str.append("<html><head><title>Hashrate Report</title></head><body><pre>");
|
||||||
|
executor::inst()->get_http_report(EV_HTML_HASHRATE, str);
|
||||||
|
str.append("</pre></body></html>");
|
||||||
|
|
||||||
|
rsp = MHD_create_response_from_buffer(str.size(), (void*)str.c_str(), MHD_RESPMEM_MUST_COPY);
|
||||||
|
}
|
||||||
|
else if(strcasecmp(url, "/c") == 0 || strcasecmp(url, "/connection") == 0)
|
||||||
|
{
|
||||||
|
str.append("<html><head><title>Connection Report</title></head><body><pre>");
|
||||||
|
executor::inst()->get_http_report(EV_HTML_CONNSTAT, str);
|
||||||
|
str.append("</pre></body></html>");
|
||||||
|
|
||||||
|
rsp = MHD_create_response_from_buffer(str.size(), (void*)str.c_str(), MHD_RESPMEM_MUST_COPY);
|
||||||
|
}
|
||||||
|
else if(strcasecmp(url, "/r") == 0 || strcasecmp(url, "/results") == 0)
|
||||||
|
{
|
||||||
|
str.append("<html><head><title>Results Report</title></head><body><pre>");
|
||||||
|
executor::inst()->get_http_report(EV_HTML_RESULTS, str);
|
||||||
|
str.append("</pre></body></html>");
|
||||||
|
|
||||||
|
rsp = MHD_create_response_from_buffer(str.size(), (void*)str.c_str(), MHD_RESPMEM_MUST_COPY);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char buffer[1024];
|
||||||
|
snprintf(buffer, sizeof(buffer), "<html><head><title>Error</title></head><body>"
|
||||||
|
"<pre>Unkown url %s - please use /h, /r or /c as url</pre></body></html>", url);
|
||||||
|
|
||||||
|
rsp = MHD_create_response_from_buffer(strlen(buffer),
|
||||||
|
(void*)buffer, MHD_RESPMEM_MUST_COPY);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret = MHD_queue_response(connection, MHD_HTTP_OK, rsp);
|
||||||
|
MHD_destroy_response(rsp);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool httpd::start_daemon()
|
||||||
|
{
|
||||||
|
d = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION,
|
||||||
|
jconf::inst()->GetHttpdPort(), NULL, NULL,
|
||||||
|
&httpd::req_handler,
|
||||||
|
NULL, MHD_OPTION_END);
|
||||||
|
|
||||||
|
if(d == nullptr)
|
||||||
|
{
|
||||||
|
printer::inst()->print_str("HTTP Daemon failed to start.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct MHD_Daemon;
|
||||||
|
struct MHD_Connection;
|
||||||
|
|
||||||
|
class httpd
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static httpd* inst()
|
||||||
|
{
|
||||||
|
if (oInst == nullptr) oInst = new httpd;
|
||||||
|
return oInst;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool start_daemon();
|
||||||
|
|
||||||
|
private:
|
||||||
|
httpd();
|
||||||
|
static httpd* oInst;
|
||||||
|
|
||||||
|
static int req_handler(void * cls,
|
||||||
|
MHD_Connection* connection,
|
||||||
|
const char* url,
|
||||||
|
const char* method,
|
||||||
|
const char* version,
|
||||||
|
const char* upload_data,
|
||||||
|
size_t* upload_data_size,
|
||||||
|
void ** ptr);
|
||||||
|
|
||||||
|
MHD_Daemon *d;
|
||||||
|
};
|
|
@ -0,0 +1,353 @@
|
||||||
|
/*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "jconf.h"
|
||||||
|
#include "console.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define strcasecmp _stricmp
|
||||||
|
#include <intrin.h>
|
||||||
|
#else
|
||||||
|
#include <cpuid.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "rapidjson/document.h"
|
||||||
|
#include "rapidjson/error/en.h"
|
||||||
|
#include "jext.h"
|
||||||
|
#include "console.h"
|
||||||
|
|
||||||
|
using namespace rapidjson;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This enum needs to match index in oConfigValues, otherwise we will get a runtime error
|
||||||
|
*/
|
||||||
|
enum configEnum { iGpuThreadNum, aGpuThreadsConf, iPlatformIdx, sPoolAddr, sWalletAddr,
|
||||||
|
sPoolPwd, iCallTimeout, iNetRetry, iVerboseLevel, iAutohashTime, iHttpdPort, bPreferIpv4 };
|
||||||
|
|
||||||
|
struct configVal {
|
||||||
|
configEnum iName;
|
||||||
|
const char* sName;
|
||||||
|
Type iType;
|
||||||
|
};
|
||||||
|
|
||||||
|
//Same order as in configEnum, as per comment above
|
||||||
|
configVal oConfigValues[] = {
|
||||||
|
{ iGpuThreadNum, "gpu_thread_num", kNumberType },
|
||||||
|
{ aGpuThreadsConf, "gpu_threads_conf", kArrayType },
|
||||||
|
{ iPlatformIdx, "platform_index", kNumberType },
|
||||||
|
{ sPoolAddr, "pool_address", kStringType },
|
||||||
|
{ sWalletAddr, "wallet_address", kStringType },
|
||||||
|
{ sPoolPwd, "pool_password", kStringType },
|
||||||
|
{ iCallTimeout, "call_timeout", kNumberType },
|
||||||
|
{ iNetRetry, "retry_time", kNumberType },
|
||||||
|
{ iVerboseLevel, "verbose_level", kNumberType },
|
||||||
|
{ iAutohashTime, "h_print_time", kNumberType },
|
||||||
|
{ iHttpdPort, "httpd_port", kNumberType },
|
||||||
|
{ bPreferIpv4, "prefer_ipv4", kTrueType }
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr size_t iConfigCnt = (sizeof(oConfigValues)/sizeof(oConfigValues[0]));
|
||||||
|
|
||||||
|
inline bool checkType(Type have, Type want)
|
||||||
|
{
|
||||||
|
if(want == have)
|
||||||
|
return true;
|
||||||
|
else if(want == kTrueType && have == kFalseType)
|
||||||
|
return true;
|
||||||
|
else if(want == kFalseType && have == kTrueType)
|
||||||
|
return true;
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct jconf::opaque_private
|
||||||
|
{
|
||||||
|
Document jsonDoc;
|
||||||
|
const Value* configValues[iConfigCnt]; //Compile time constant
|
||||||
|
|
||||||
|
opaque_private()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
jconf* jconf::oInst = nullptr;
|
||||||
|
|
||||||
|
jconf::jconf()
|
||||||
|
{
|
||||||
|
prv = new opaque_private();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool jconf::GetThreadConfig(size_t id, thd_cfg &cfg)
|
||||||
|
{
|
||||||
|
if(id >= prv->configValues[aGpuThreadsConf]->Size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const Value& oThdConf = prv->configValues[aGpuThreadsConf]->GetArray()[id];
|
||||||
|
|
||||||
|
if(!oThdConf.IsObject())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const Value *idx, *intensity, *w_size, *aff;
|
||||||
|
idx = GetObjectMember(oThdConf, "index");
|
||||||
|
intensity = GetObjectMember(oThdConf, "intensity");
|
||||||
|
w_size = GetObjectMember(oThdConf, "worksize");
|
||||||
|
aff = GetObjectMember(oThdConf, "affine_to_cpu");
|
||||||
|
|
||||||
|
if(idx == nullptr || intensity == nullptr || w_size == nullptr || aff == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!idx->IsUint64() || !intensity->IsUint64() || !w_size->IsUint64())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if(!aff->IsUint64() && !aff->IsBool())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
cfg.index = idx->GetUint64();
|
||||||
|
cfg.intensity = intensity->GetUint64();
|
||||||
|
cfg.w_size = w_size->GetUint64();
|
||||||
|
|
||||||
|
if(aff->IsNumber())
|
||||||
|
cfg.cpu_aff = aff->GetInt64();
|
||||||
|
else
|
||||||
|
cfg.cpu_aff = -1;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t jconf::GetPlatformIdx()
|
||||||
|
{
|
||||||
|
return prv->configValues[iPlatformIdx]->GetUint64();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* jconf::GetPoolAddress()
|
||||||
|
{
|
||||||
|
return prv->configValues[sPoolAddr]->GetString();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* jconf::GetPoolPwd()
|
||||||
|
{
|
||||||
|
return prv->configValues[sPoolPwd]->GetString();
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* jconf::GetWalletAddress()
|
||||||
|
{
|
||||||
|
return prv->configValues[sWalletAddr]->GetString();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool jconf::PreferIpv4()
|
||||||
|
{
|
||||||
|
return prv->configValues[bPreferIpv4]->GetBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t jconf::GetThreadCount()
|
||||||
|
{
|
||||||
|
return prv->configValues[aGpuThreadsConf]->Size();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t jconf::GetCallTimeout()
|
||||||
|
{
|
||||||
|
return prv->configValues[iCallTimeout]->GetUint64();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t jconf::GetNetRetry()
|
||||||
|
{
|
||||||
|
return prv->configValues[iNetRetry]->GetUint64();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t jconf::GetVerboseLevel()
|
||||||
|
{
|
||||||
|
return prv->configValues[iVerboseLevel]->GetUint64();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t jconf::GetAutohashTime()
|
||||||
|
{
|
||||||
|
return prv->configValues[iAutohashTime]->GetUint64();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t jconf::GetHttpdPort()
|
||||||
|
{
|
||||||
|
return prv->configValues[iHttpdPort]->GetUint();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool jconf::check_cpu_features()
|
||||||
|
{
|
||||||
|
constexpr int AESNI_BIT = 1 << 25;
|
||||||
|
constexpr int SSE2_BIT = 1 << 26;
|
||||||
|
|
||||||
|
int cpu_info[4];
|
||||||
|
#ifdef _WIN32
|
||||||
|
__cpuid(cpu_info, 1);
|
||||||
|
#else
|
||||||
|
__cpuid(1, cpu_info[0], cpu_info[1], cpu_info[2], cpu_info[3]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bHaveAes = (cpu_info[2] & AESNI_BIT) != 0;
|
||||||
|
return (cpu_info[3] & SSE2_BIT) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool jconf::parse_config(const char* sFilename)
|
||||||
|
{
|
||||||
|
FILE * pFile;
|
||||||
|
char * buffer;
|
||||||
|
size_t flen;
|
||||||
|
|
||||||
|
if(!check_cpu_features())
|
||||||
|
{
|
||||||
|
printer::inst()->print_msg(L0, "CPU support of SSE2 is required.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pFile = fopen(sFilename, "rb");
|
||||||
|
if (pFile == NULL)
|
||||||
|
{
|
||||||
|
printer::inst()->print_msg(L0, "Failed to open config file %s.", sFilename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fseek(pFile,0,SEEK_END);
|
||||||
|
flen = ftell(pFile);
|
||||||
|
rewind(pFile);
|
||||||
|
|
||||||
|
if(flen >= 64*1024)
|
||||||
|
{
|
||||||
|
fclose(pFile);
|
||||||
|
printer::inst()->print_msg(L0, "Oversized config file - %s.", sFilename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(flen <= 16)
|
||||||
|
{
|
||||||
|
printer::inst()->print_msg(L0, "File is empty or too short - %s.", sFilename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = (char*)malloc(flen + 3);
|
||||||
|
if(fread(buffer+1, flen, 1, pFile) != 1)
|
||||||
|
{
|
||||||
|
free(buffer);
|
||||||
|
fclose(pFile);
|
||||||
|
printer::inst()->print_msg(L0, "Read error while reading %s.", sFilename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
fclose(pFile);
|
||||||
|
|
||||||
|
//Replace Unicode BOM with spaces - we always use UTF-8
|
||||||
|
unsigned char* ubuffer = (unsigned char*)buffer;
|
||||||
|
if(ubuffer[1] == 0xEF && ubuffer[2] == 0xBB && ubuffer[3] == 0xBF)
|
||||||
|
{
|
||||||
|
buffer[1] = ' ';
|
||||||
|
buffer[2] = ' ';
|
||||||
|
buffer[3] = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[0] = '{';
|
||||||
|
buffer[flen] = '}';
|
||||||
|
buffer[flen + 1] = '\0';
|
||||||
|
|
||||||
|
prv->jsonDoc.Parse<kParseCommentsFlag|kParseTrailingCommasFlag>(buffer, flen+2);
|
||||||
|
free(buffer);
|
||||||
|
|
||||||
|
if(prv->jsonDoc.HasParseError())
|
||||||
|
{
|
||||||
|
printer::inst()->print_msg(L0, "JSON config parse error(offset %llu): %s",
|
||||||
|
int_port(prv->jsonDoc.GetErrorOffset()), GetParseError_En(prv->jsonDoc.GetParseError()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if(!prv->jsonDoc.IsObject())
|
||||||
|
{ //This should never happen as we created the root ourselves
|
||||||
|
printer::inst()->print_msg(L0, "Invalid config file. No root?\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(size_t i = 0; i < iConfigCnt; i++)
|
||||||
|
{
|
||||||
|
if(oConfigValues[i].iName != i)
|
||||||
|
{
|
||||||
|
printer::inst()->print_msg(L0, "Code error. oConfigValues are not in order.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
prv->configValues[i] = GetObjectMember(prv->jsonDoc, oConfigValues[i].sName);
|
||||||
|
|
||||||
|
if(prv->configValues[i] == nullptr)
|
||||||
|
{
|
||||||
|
printer::inst()->print_msg(L0, "Invalid config file. Missing value \"%s\".", oConfigValues[i].sName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!checkType(prv->configValues[i]->GetType(), oConfigValues[i].iType))
|
||||||
|
{
|
||||||
|
printer::inst()->print_msg(L0, "Invalid config file. Value \"%s\" has unexpected type.", oConfigValues[i].sName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t n_thd = prv->configValues[aGpuThreadsConf]->Size();
|
||||||
|
if(prv->configValues[iGpuThreadNum]->GetUint64() != n_thd)
|
||||||
|
{
|
||||||
|
printer::inst()->print_msg(L0,
|
||||||
|
"Invalid config file. Your GPU config array has %llu members, while you want to use %llu threads.",
|
||||||
|
int_port(n_thd), int_port(prv->configValues[iGpuThreadNum]->GetUint64()));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
thd_cfg c;
|
||||||
|
for(size_t i=0; i < n_thd; i++)
|
||||||
|
{
|
||||||
|
if(!GetThreadConfig(i, c))
|
||||||
|
{
|
||||||
|
printer::inst()->print_msg(L0, "Thread %llu has invalid config.", int_port(i));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!prv->configValues[iCallTimeout]->IsUint64() || !prv->configValues[iNetRetry]->IsUint64())
|
||||||
|
{
|
||||||
|
printer::inst()->print_msg(L0,
|
||||||
|
"Invalid config file. call_timeout and retry_time need to be positive integers.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!prv->configValues[iVerboseLevel]->IsUint64() || !prv->configValues[iAutohashTime]->IsUint64())
|
||||||
|
{
|
||||||
|
printer::inst()->print_msg(L0,
|
||||||
|
"Invalid config file. verbose_level and h_print_time need to be positive integers.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!prv->configValues[iHttpdPort]->IsUint() || prv->configValues[iHttpdPort]->GetUint() > 0xFFFF)
|
||||||
|
{
|
||||||
|
printer::inst()->print_msg(L0,
|
||||||
|
"Invalid config file. httpd_port has to be in the range 0 to 65535.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
if(GetSlowMemSetting() == no_mlck)
|
||||||
|
{
|
||||||
|
printer::inst()->print_msg(L0, "On Windows large pages need mlock. Please use another option.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
printer::inst()->set_verbose_level(prv->configValues[iVerboseLevel]->GetUint64());
|
||||||
|
return true;
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
#pragma once
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class jconf
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static jconf* inst()
|
||||||
|
{
|
||||||
|
if (oInst == nullptr) oInst = new jconf;
|
||||||
|
return oInst;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool parse_config(const char* sFilename);
|
||||||
|
|
||||||
|
struct thd_cfg {
|
||||||
|
size_t index;
|
||||||
|
size_t intensity;
|
||||||
|
size_t w_size;
|
||||||
|
long long cpu_aff;
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t GetThreadCount();
|
||||||
|
bool GetThreadConfig(size_t id, thd_cfg &cfg);
|
||||||
|
|
||||||
|
size_t GetPlatformIdx();
|
||||||
|
|
||||||
|
const char* GetPoolAddress();
|
||||||
|
const char* GetPoolPwd();
|
||||||
|
const char* GetWalletAddress();
|
||||||
|
|
||||||
|
uint64_t GetVerboseLevel();
|
||||||
|
uint64_t GetAutohashTime();
|
||||||
|
|
||||||
|
uint64_t GetCallTimeout();
|
||||||
|
uint64_t GetNetRetry();
|
||||||
|
|
||||||
|
uint16_t GetHttpdPort();
|
||||||
|
|
||||||
|
bool PreferIpv4();
|
||||||
|
|
||||||
|
inline bool HaveHardwareAes() { return bHaveAes; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
jconf();
|
||||||
|
static jconf* oInst;
|
||||||
|
|
||||||
|
bool check_cpu_features();
|
||||||
|
struct opaque_private;
|
||||||
|
opaque_private* prv;
|
||||||
|
|
||||||
|
bool bHaveAes;
|
||||||
|
};
|
|
@ -0,0 +1,13 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
using namespace rapidjson;
|
||||||
|
|
||||||
|
/* This macro brings rapidjson more in line with other libs */
|
||||||
|
inline const Value* GetObjectMember(const Value& obj, const char* key)
|
||||||
|
{
|
||||||
|
Value::ConstMemberIterator itr = obj.FindMember(key);
|
||||||
|
if (itr != obj.MemberEnd())
|
||||||
|
return &itr->value;
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
|
@ -0,0 +1,671 @@
|
||||||
|
/*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "jpsock.h"
|
||||||
|
#include "executor.h"
|
||||||
|
#include "jconf.h"
|
||||||
|
|
||||||
|
#include "rapidjson/document.h"
|
||||||
|
#include "jext.h"
|
||||||
|
#include "socks.h"
|
||||||
|
|
||||||
|
#define AGENTID_STR "xmr-stak-cpu/1.0"
|
||||||
|
|
||||||
|
using namespace rapidjson;
|
||||||
|
|
||||||
|
struct jpsock::call_rsp
|
||||||
|
{
|
||||||
|
bool bHaveResponse;
|
||||||
|
uint64_t iCallId;
|
||||||
|
Value* pCallData;
|
||||||
|
std::string sCallErr;
|
||||||
|
|
||||||
|
call_rsp(Value* val) : pCallData(val)
|
||||||
|
{
|
||||||
|
bHaveResponse = false;
|
||||||
|
iCallId = 0;
|
||||||
|
sCallErr.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef GenericDocument<UTF8<>, MemoryPoolAllocator<>, MemoryPoolAllocator<>> MemDocument;
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
* ASSUMPTION - only one calling thread. Multiple calling threads would require better
|
||||||
|
* thread safety. The calling thread is assumed to be the executor thread.
|
||||||
|
* If there is a reason to call the pool outside of the executor context, consider
|
||||||
|
* doing it via an executor event.
|
||||||
|
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
|
*
|
||||||
|
* Call values and allocators are for the calling thread (executor). When processing
|
||||||
|
* a call, the recv thread will make a copy of the call response and then erase its copy.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct jpsock::opaque_private
|
||||||
|
{
|
||||||
|
addrinfo *pSockAddr;
|
||||||
|
addrinfo *pAddrRoot;
|
||||||
|
SOCKET hSocket;
|
||||||
|
|
||||||
|
Value oCallValue;
|
||||||
|
|
||||||
|
MemoryPoolAllocator<> callAllocator;
|
||||||
|
MemoryPoolAllocator<> recvAllocator;
|
||||||
|
MemoryPoolAllocator<> parseAllocator;
|
||||||
|
MemDocument jsonDoc;
|
||||||
|
call_rsp oCallRsp;
|
||||||
|
|
||||||
|
opaque_private(uint8_t* bCallMem, uint8_t* bRecvMem, uint8_t* bParseMem) :
|
||||||
|
callAllocator(bCallMem, jpsock::iJsonMemSize),
|
||||||
|
recvAllocator(bRecvMem, jpsock::iJsonMemSize),
|
||||||
|
parseAllocator(bParseMem, jpsock::iJsonMemSize),
|
||||||
|
jsonDoc(&recvAllocator, jpsock::iJsonMemSize, &parseAllocator),
|
||||||
|
oCallRsp(nullptr)
|
||||||
|
{
|
||||||
|
hSocket = INVALID_SOCKET;
|
||||||
|
pSockAddr = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct jpsock::opq_json_val
|
||||||
|
{
|
||||||
|
const Value* val;
|
||||||
|
opq_json_val(const Value* val) : val(val) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
jpsock::jpsock(size_t id) : pool_id(id)
|
||||||
|
{
|
||||||
|
sock_init();
|
||||||
|
|
||||||
|
bJsonCallMem = (uint8_t*)malloc(iJsonMemSize);
|
||||||
|
bJsonRecvMem = (uint8_t*)malloc(iJsonMemSize);
|
||||||
|
bJsonParseMem = (uint8_t*)malloc(iJsonMemSize);
|
||||||
|
|
||||||
|
prv = new opaque_private(bJsonCallMem, bJsonRecvMem, bJsonParseMem);
|
||||||
|
|
||||||
|
oRecvThd = nullptr;
|
||||||
|
bRunning = false;
|
||||||
|
bLoggedIn = false;
|
||||||
|
iJobDiff = 0;
|
||||||
|
|
||||||
|
memset(&oCurrentJob, 0, sizeof(oCurrentJob));
|
||||||
|
}
|
||||||
|
|
||||||
|
jpsock::~jpsock()
|
||||||
|
{
|
||||||
|
delete prv;
|
||||||
|
prv = nullptr;
|
||||||
|
|
||||||
|
free(bJsonCallMem);
|
||||||
|
free(bJsonRecvMem);
|
||||||
|
free(bJsonParseMem);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string&& jpsock::get_call_error()
|
||||||
|
{
|
||||||
|
return std::move(prv->oCallRsp.sCallErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool jpsock::set_socket_error(const char* a)
|
||||||
|
{
|
||||||
|
if(!bHaveSocketError)
|
||||||
|
{
|
||||||
|
bHaveSocketError = true;
|
||||||
|
sSocketError.assign(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool jpsock::set_socket_error(const char* a, const char* b)
|
||||||
|
{
|
||||||
|
if(!bHaveSocketError)
|
||||||
|
{
|
||||||
|
bHaveSocketError = true;
|
||||||
|
size_t ln_a = strlen(a);
|
||||||
|
size_t ln_b = strlen(b);
|
||||||
|
|
||||||
|
sSocketError.reserve(ln_a + ln_b + 2);
|
||||||
|
sSocketError.assign(a, ln_a);
|
||||||
|
sSocketError.append(b, ln_b);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool jpsock::set_socket_error_strerr(const char* a)
|
||||||
|
{
|
||||||
|
char sSockErrText[512];
|
||||||
|
return set_socket_error(a, sock_strerror(sSockErrText, sizeof(sSockErrText)));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool jpsock::set_socket_error_strerr(const char* a, int res)
|
||||||
|
{
|
||||||
|
char sSockErrText[512];
|
||||||
|
return set_socket_error(a, sock_gai_strerror(res, sSockErrText, sizeof(sSockErrText)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void jpsock::jpsock_thread()
|
||||||
|
{
|
||||||
|
jpsock_thd_main();
|
||||||
|
executor::inst()->push_event(ex_event(std::move(sSocketError), pool_id));
|
||||||
|
|
||||||
|
// If a call is wating, send an error to end it
|
||||||
|
bool bCallWaiting = false;
|
||||||
|
std::unique_lock<std::mutex> mlock(call_mutex);
|
||||||
|
if(prv->oCallRsp.pCallData != nullptr)
|
||||||
|
{
|
||||||
|
prv->oCallRsp.bHaveResponse = true;
|
||||||
|
prv->oCallRsp.iCallId = 0;
|
||||||
|
prv->oCallRsp.pCallData = nullptr;
|
||||||
|
bCallWaiting = true;
|
||||||
|
}
|
||||||
|
mlock.unlock();
|
||||||
|
|
||||||
|
if(bCallWaiting)
|
||||||
|
call_cond.notify_one();
|
||||||
|
|
||||||
|
bRunning = false;
|
||||||
|
bLoggedIn = false;
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex>(job_mutex);
|
||||||
|
memset(&oCurrentJob, 0, sizeof(oCurrentJob));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool jpsock::jpsock_thd_main()
|
||||||
|
{
|
||||||
|
int ret = ::connect(prv->hSocket, prv->pSockAddr->ai_addr, (int)prv->pSockAddr->ai_addrlen);
|
||||||
|
freeaddrinfo(prv->pAddrRoot);
|
||||||
|
prv->pAddrRoot = nullptr;
|
||||||
|
|
||||||
|
if (ret != 0)
|
||||||
|
return set_socket_error_strerr("CONNECT error: ");
|
||||||
|
|
||||||
|
executor::inst()->push_event(ex_event(EV_SOCK_READY, pool_id));
|
||||||
|
|
||||||
|
char buf[iSockBufferSize];
|
||||||
|
size_t datalen = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
ret = recv(prv->hSocket, buf + datalen, sizeof(buf) - datalen, 0);
|
||||||
|
|
||||||
|
if(ret == 0)
|
||||||
|
return set_socket_error("RECEIVE error: socket closed");
|
||||||
|
if(ret == SOCKET_ERROR || ret < 0)
|
||||||
|
return set_socket_error("RECEIVE error: ");
|
||||||
|
|
||||||
|
datalen += ret;
|
||||||
|
|
||||||
|
if (datalen >= sizeof(buf))
|
||||||
|
{
|
||||||
|
sock_close(prv->hSocket);
|
||||||
|
return set_socket_error("RECEIVE error: data overflow");
|
||||||
|
}
|
||||||
|
|
||||||
|
char* lnend;
|
||||||
|
char* lnstart = buf;
|
||||||
|
while ((lnend = (char*)memchr(lnstart, '\n', datalen)) != nullptr)
|
||||||
|
{
|
||||||
|
lnend++;
|
||||||
|
int lnlen = lnend - lnstart;
|
||||||
|
|
||||||
|
if (!process_line(lnstart, lnlen))
|
||||||
|
{
|
||||||
|
sock_close(prv->hSocket);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
datalen -= lnlen;
|
||||||
|
lnstart = lnend;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Got leftover data? Move it to the front
|
||||||
|
if (datalen > 0 && buf != lnstart)
|
||||||
|
memmove(buf, lnstart, datalen);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool jpsock::process_line(char* line, size_t len)
|
||||||
|
{
|
||||||
|
prv->jsonDoc.SetNull();
|
||||||
|
prv->parseAllocator.Clear();
|
||||||
|
prv->callAllocator.Clear();
|
||||||
|
|
||||||
|
/*NULL terminate the line instead of '\n', parsing will add some more NULLs*/
|
||||||
|
line[len-1] = '\0';
|
||||||
|
|
||||||
|
//printf("RECV: %s\n", line);
|
||||||
|
|
||||||
|
if (prv->jsonDoc.ParseInsitu(line).HasParseError())
|
||||||
|
return set_socket_error("PARSE error: Invalid JSON");
|
||||||
|
|
||||||
|
if (!prv->jsonDoc.IsObject())
|
||||||
|
return set_socket_error("PARSE error: Invalid root");
|
||||||
|
|
||||||
|
const Value* mt;
|
||||||
|
if (prv->jsonDoc.HasMember("method"))
|
||||||
|
{
|
||||||
|
mt = GetObjectMember(prv->jsonDoc, "method");
|
||||||
|
|
||||||
|
if(!mt->IsString())
|
||||||
|
return set_socket_error("PARSE error: Protocol error 1");
|
||||||
|
|
||||||
|
if(strcmp(mt->GetString(), "job") != 0)
|
||||||
|
return set_socket_error("PARSE error: Unsupported server method ", mt->GetString());
|
||||||
|
|
||||||
|
mt = GetObjectMember(prv->jsonDoc, "params");
|
||||||
|
if(mt == nullptr || !mt->IsObject())
|
||||||
|
return set_socket_error("PARSE error: Protocol error 2");
|
||||||
|
|
||||||
|
opq_json_val v(mt);
|
||||||
|
return process_pool_job(&v);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint64_t iCallId;
|
||||||
|
mt = GetObjectMember(prv->jsonDoc, "id");
|
||||||
|
if (mt == nullptr || !mt->IsUint64())
|
||||||
|
return set_socket_error("PARSE error: Protocol error 3");
|
||||||
|
|
||||||
|
iCallId = mt->GetUint64();
|
||||||
|
|
||||||
|
mt = GetObjectMember(prv->jsonDoc, "error");
|
||||||
|
|
||||||
|
const char* sError = nullptr;
|
||||||
|
size_t iErrorLn = 0;
|
||||||
|
if (mt == nullptr || mt->IsNull())
|
||||||
|
{
|
||||||
|
/* If there was no error we need a result */
|
||||||
|
if ((mt = GetObjectMember(prv->jsonDoc, "result")) == nullptr)
|
||||||
|
return set_socket_error("PARSE error: Protocol error 7");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(!mt->IsObject())
|
||||||
|
return set_socket_error("PARSE error: Protocol error 5");
|
||||||
|
|
||||||
|
const Value* msg = GetObjectMember(*mt, "message");
|
||||||
|
|
||||||
|
if(msg == nullptr || !msg->IsString())
|
||||||
|
return set_socket_error("PARSE error: Protocol error 6");
|
||||||
|
|
||||||
|
iErrorLn = msg->GetStringLength();
|
||||||
|
sError = msg->GetString();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> mlock(call_mutex);
|
||||||
|
if (prv->oCallRsp.pCallData == nullptr)
|
||||||
|
{
|
||||||
|
/*Server sent us a call reply without us making a call*/
|
||||||
|
mlock.unlock();
|
||||||
|
return set_socket_error("PARSE error: Unexpected call response");
|
||||||
|
}
|
||||||
|
|
||||||
|
prv->oCallRsp.bHaveResponse = true;
|
||||||
|
prv->oCallRsp.iCallId = iCallId;
|
||||||
|
|
||||||
|
if(sError != nullptr)
|
||||||
|
{
|
||||||
|
prv->oCallRsp.pCallData = nullptr;
|
||||||
|
prv->oCallRsp.sCallErr.assign(sError, iErrorLn);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
prv->oCallRsp.pCallData->CopyFrom(*mt, prv->callAllocator);
|
||||||
|
|
||||||
|
mlock.unlock();
|
||||||
|
call_cond.notify_one();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool jpsock::process_pool_job(const opq_json_val* params)
|
||||||
|
{
|
||||||
|
if (!params->val->IsObject())
|
||||||
|
return set_socket_error("PARSE error: Job error 1");
|
||||||
|
|
||||||
|
const Value * blob, *jobid, *target;
|
||||||
|
jobid = GetObjectMember(*params->val, "job_id");
|
||||||
|
blob = GetObjectMember(*params->val, "blob");
|
||||||
|
target = GetObjectMember(*params->val, "target");
|
||||||
|
|
||||||
|
if (jobid == nullptr || blob == nullptr || target == nullptr ||
|
||||||
|
!jobid->IsString() || !blob->IsString() || !target->IsString())
|
||||||
|
{
|
||||||
|
return set_socket_error("PARSE error: Job error 2");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (jobid->GetStringLength() >= sizeof(pool_job::sJobID)) // Note >=
|
||||||
|
return set_socket_error("PARSE error: Job error 3");
|
||||||
|
|
||||||
|
uint32_t iWorkLn = blob->GetStringLength() / 2;
|
||||||
|
if (iWorkLn > sizeof(pool_job::bWorkBlob))
|
||||||
|
return set_socket_error("PARSE error: Invalid job legth. Are you sure you are mining the correct coin?");
|
||||||
|
|
||||||
|
pool_job oPoolJob;
|
||||||
|
if (!hex2bin(blob->GetString(), iWorkLn * 2, oPoolJob.bWorkBlob))
|
||||||
|
return set_socket_error("PARSE error: Job error 4");
|
||||||
|
|
||||||
|
oPoolJob.iWorkLen = iWorkLn;
|
||||||
|
memset(oPoolJob.sJobID, 0, sizeof(pool_job::sJobID));
|
||||||
|
memcpy(oPoolJob.sJobID, jobid->GetString(), jobid->GetStringLength()); //Bounds checking at proto error 3
|
||||||
|
|
||||||
|
size_t target_slen = target->GetStringLength();
|
||||||
|
if(target_slen <= 8)
|
||||||
|
{
|
||||||
|
uint32_t iTempInt;
|
||||||
|
char sTempStr[] = "00000000"; // Little-endian CPU FTW
|
||||||
|
memcpy(sTempStr, target->GetString(), target_slen);
|
||||||
|
hex2bin(sTempStr, 8, (unsigned char*)&iTempInt);
|
||||||
|
oPoolJob.iTarget = iTempInt;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return set_socket_error("PARSE error: Job error 5");
|
||||||
|
|
||||||
|
iJobDiff = t32_to_diff(oPoolJob.iTarget);
|
||||||
|
|
||||||
|
executor::inst()->push_event(ex_event(oPoolJob, pool_id));
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex>(job_mutex);
|
||||||
|
oCurrentJob = oPoolJob;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool jpsock::connect(const char* sAddr, std::string& sConnectError)
|
||||||
|
{
|
||||||
|
if(prv_connect(sAddr))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
sConnectError = std::move(sSocketError);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool jpsock::prv_connect(const char* sAddr)
|
||||||
|
{
|
||||||
|
char sAddrMb[256];
|
||||||
|
char *sTmp, *sPort;
|
||||||
|
|
||||||
|
bHaveSocketError = false;
|
||||||
|
sSocketError.clear();
|
||||||
|
iJobDiff = 0;
|
||||||
|
|
||||||
|
size_t ln = strlen(sAddr);
|
||||||
|
if (ln >= sizeof(sAddrMb))
|
||||||
|
return set_socket_error("CONNECT error: Pool address overflow.");
|
||||||
|
|
||||||
|
memcpy(sAddrMb, sAddr, ln);
|
||||||
|
sAddrMb[ln] = '\0';
|
||||||
|
|
||||||
|
if ((sTmp = strstr(sAddrMb, "//")) != nullptr)
|
||||||
|
memmove(sAddrMb, sTmp, strlen(sTmp) + 1);
|
||||||
|
|
||||||
|
if ((sPort = strchr(sAddrMb, ':')) == nullptr)
|
||||||
|
return set_socket_error("CONNECT error: Pool port number not specified, please use format <hostname>:<port>.");
|
||||||
|
|
||||||
|
sPort[0] = '\0';
|
||||||
|
sPort++;
|
||||||
|
|
||||||
|
addrinfo hints = { 0 };
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_protocol = IPPROTO_TCP;
|
||||||
|
|
||||||
|
prv->pAddrRoot = nullptr;
|
||||||
|
int err;
|
||||||
|
if ((err = getaddrinfo(sAddrMb, sPort, &hints, &prv->pAddrRoot)) != 0)
|
||||||
|
return set_socket_error_strerr("CONNECT error: GetAddrInfo: ", err);
|
||||||
|
|
||||||
|
addrinfo *ptr = prv->pAddrRoot;
|
||||||
|
addrinfo *ipv4 = nullptr, *ipv6 = nullptr;
|
||||||
|
|
||||||
|
while (ptr != nullptr)
|
||||||
|
{
|
||||||
|
if (ptr->ai_family == AF_INET)
|
||||||
|
ipv4 = ptr;
|
||||||
|
if (ptr->ai_family == AF_INET6)
|
||||||
|
ipv6 = ptr;
|
||||||
|
ptr = ptr->ai_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ipv4 == nullptr && ipv6 == nullptr)
|
||||||
|
{
|
||||||
|
freeaddrinfo(prv->pAddrRoot);
|
||||||
|
prv->pAddrRoot = nullptr;
|
||||||
|
return set_socket_error("CONNECT error: I found some DNS records but no IPv4 or IPv6 addresses.");
|
||||||
|
}
|
||||||
|
else if (ipv4 != nullptr && ipv6 == nullptr)
|
||||||
|
prv->pSockAddr = ipv4;
|
||||||
|
else if (ipv4 == nullptr && ipv6 != nullptr)
|
||||||
|
prv->pSockAddr = ipv6;
|
||||||
|
else if (ipv4 != nullptr && ipv6 != nullptr)
|
||||||
|
{
|
||||||
|
if(jconf::inst()->PreferIpv4())
|
||||||
|
prv->pSockAddr = ipv4;
|
||||||
|
else
|
||||||
|
prv->pSockAddr = ipv6;
|
||||||
|
}
|
||||||
|
|
||||||
|
prv->hSocket = socket(prv->pSockAddr->ai_family, prv->pSockAddr->ai_socktype, prv->pSockAddr->ai_protocol);
|
||||||
|
|
||||||
|
if (prv->hSocket == INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
freeaddrinfo(prv->pAddrRoot);
|
||||||
|
prv->pAddrRoot = nullptr;
|
||||||
|
return set_socket_error_strerr("CONNECT error: Socket creation failed ");
|
||||||
|
}
|
||||||
|
|
||||||
|
bRunning = true;
|
||||||
|
oRecvThd = new std::thread(&jpsock::jpsock_thread, this);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void jpsock::disconnect()
|
||||||
|
{
|
||||||
|
if(prv->hSocket != INVALID_SOCKET)
|
||||||
|
{
|
||||||
|
sock_close(prv->hSocket);
|
||||||
|
prv->hSocket = INVALID_SOCKET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(oRecvThd != nullptr)
|
||||||
|
{
|
||||||
|
oRecvThd->join();
|
||||||
|
delete oRecvThd;
|
||||||
|
oRecvThd = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool jpsock::cmd_ret_wait(const char* sPacket, opq_json_val& poResult)
|
||||||
|
{
|
||||||
|
//printf("SEND: %s\n", sPacket);
|
||||||
|
|
||||||
|
/*Set up the call rsp for the call reply*/
|
||||||
|
prv->oCallValue.SetNull();
|
||||||
|
prv->callAllocator.Clear();
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> mlock(call_mutex);
|
||||||
|
prv->oCallRsp = call_rsp(&prv->oCallValue);
|
||||||
|
mlock.unlock();
|
||||||
|
|
||||||
|
int pos = 0, slen = strlen(sPacket);
|
||||||
|
while (pos != slen)
|
||||||
|
{
|
||||||
|
int ret = send(prv->hSocket, sPacket + pos, slen - pos, 0);
|
||||||
|
if (ret == SOCKET_ERROR)
|
||||||
|
{
|
||||||
|
set_socket_error_strerr("SEND error: ");
|
||||||
|
disconnect(); //This will join the other thread;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pos += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Success is true if the server approves, result is true if there was no socket error
|
||||||
|
bool bSuccess;
|
||||||
|
mlock.lock();
|
||||||
|
bool bResult = call_cond.wait_for(mlock, std::chrono::seconds(jconf::inst()->GetCallTimeout()),
|
||||||
|
[&]() { return prv->oCallRsp.bHaveResponse; });
|
||||||
|
|
||||||
|
bSuccess = prv->oCallRsp.pCallData != nullptr;
|
||||||
|
prv->oCallRsp.pCallData = nullptr;
|
||||||
|
mlock.unlock();
|
||||||
|
|
||||||
|
if(bHaveSocketError)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
//This means that there was no socket error, but the server is not taking to us
|
||||||
|
if(!bResult)
|
||||||
|
{
|
||||||
|
set_socket_error("CALL error: Timeout while waiting for a reply");
|
||||||
|
disconnect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(bSuccess)
|
||||||
|
poResult.val = &prv->oCallValue;
|
||||||
|
|
||||||
|
return bSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool jpsock::cmd_login(const char* sLogin, const char* sPassword)
|
||||||
|
{
|
||||||
|
char cmd_buffer[1024];
|
||||||
|
|
||||||
|
snprintf(cmd_buffer, sizeof(cmd_buffer), "{\"method\":\"login\",\"params\":{\"login\":\"%s\",\"pass\":\"%s\",\"agent\":\"" AGENTID_STR "\"},\"id\":1}\n",
|
||||||
|
sLogin, sPassword);
|
||||||
|
|
||||||
|
opq_json_val oResult(nullptr);
|
||||||
|
|
||||||
|
/*Normal error conditions (failed login etc..) will end here*/
|
||||||
|
if (!cmd_ret_wait(cmd_buffer, oResult))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!oResult.val->IsObject())
|
||||||
|
{
|
||||||
|
set_socket_error("PARSE error: Login protocol error 1");
|
||||||
|
disconnect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Value* id = GetObjectMember(*oResult.val, "id");
|
||||||
|
const Value* job = GetObjectMember(*oResult.val, "job");
|
||||||
|
|
||||||
|
if (id == nullptr || job == nullptr || !id->IsString())
|
||||||
|
{
|
||||||
|
set_socket_error("PARSE error: Login protocol error 2");
|
||||||
|
disconnect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id->GetStringLength() >= sizeof(sMinerId))
|
||||||
|
{
|
||||||
|
set_socket_error("PARSE error: Login protocol error 3");
|
||||||
|
disconnect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(sMinerId, 0, sizeof(sMinerId));
|
||||||
|
memcpy(sMinerId, id->GetString(), id->GetStringLength());
|
||||||
|
|
||||||
|
opq_json_val v(job);
|
||||||
|
if(!process_pool_job(&v))
|
||||||
|
{
|
||||||
|
disconnect();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bLoggedIn = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool jpsock::cmd_submit(const char* sJobId, uint32_t iNonce, const uint8_t* bResult)
|
||||||
|
{
|
||||||
|
char cmd_buffer[1024];
|
||||||
|
char sNonce[9];
|
||||||
|
char sResult[65];
|
||||||
|
|
||||||
|
bin2hex((unsigned char*)&iNonce, 4, sNonce);
|
||||||
|
sNonce[8] = '\0';
|
||||||
|
|
||||||
|
bin2hex(bResult, 32, sResult);
|
||||||
|
sResult[64] = '\0';
|
||||||
|
|
||||||
|
snprintf(cmd_buffer, sizeof(cmd_buffer), "{\"method\":\"submit\",\"params\":{\"id\":\"%s\",\"job_id\":\"%s\",\"nonce\":\"%s\",\"result\":\"%s\"},\"id\":1}\n",
|
||||||
|
sMinerId, sJobId, sNonce, sResult);
|
||||||
|
|
||||||
|
opq_json_val oResult(nullptr);
|
||||||
|
return cmd_ret_wait(cmd_buffer, oResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool jpsock::get_current_job(pool_job& job)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex>(job_mutex);
|
||||||
|
|
||||||
|
if(oCurrentJob.iWorkLen == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
oCurrentJob.iResumeCnt++;
|
||||||
|
job = oCurrentJob;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned char hf_hex2bin(char c, bool &err)
|
||||||
|
{
|
||||||
|
if (c >= '0' && c <= '9')
|
||||||
|
return c - '0';
|
||||||
|
else if (c >= 'a' && c <= 'f')
|
||||||
|
return c - 'a' + 0xA;
|
||||||
|
else if (c >= 'A' && c <= 'F')
|
||||||
|
return c - 'A' + 0xA;
|
||||||
|
|
||||||
|
err = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool jpsock::hex2bin(const char* in, unsigned int len, unsigned char* out)
|
||||||
|
{
|
||||||
|
bool error = false;
|
||||||
|
for (unsigned int i = 0; i < len; i += 2)
|
||||||
|
{
|
||||||
|
out[i / 2] = (hf_hex2bin(in[i], error) << 4) | hf_hex2bin(in[i + 1], error);
|
||||||
|
if (error) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char hf_bin2hex(unsigned char c)
|
||||||
|
{
|
||||||
|
if (c <= 0x9)
|
||||||
|
return '0' + c;
|
||||||
|
else
|
||||||
|
return 'a' - 0xA + c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void jpsock::bin2hex(const unsigned char* in, unsigned int len, char* out)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
out[i * 2] = hf_bin2hex((in[i] & 0xF0) >> 4);
|
||||||
|
out[i * 2 + 1] = hf_bin2hex(in[i] & 0x0F);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
#pragma once
|
||||||
|
#include <mutex>
|
||||||
|
#include <atomic>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <thread>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "msgstruct.h"
|
||||||
|
|
||||||
|
/* Our pool can have two kinds of errors:
|
||||||
|
- Parsing or connection error
|
||||||
|
Those are fatal errors (we drop the connection if we encounter them).
|
||||||
|
After they are constructed from const char* strings from various places.
|
||||||
|
(can be from read-only mem), we passs them in an exectutor message
|
||||||
|
once the recv thread expires.
|
||||||
|
- Call error
|
||||||
|
This error happens when the "server says no". Usually because the job was
|
||||||
|
outdated, or we somehow got the hash wrong. It isn't fatal.
|
||||||
|
We parse it in-situ in the network buffer, after that we copy it to a
|
||||||
|
std::string. Executor will move the buffer via an r-value ref.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class jpsock
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
jpsock(size_t id);
|
||||||
|
~jpsock();
|
||||||
|
|
||||||
|
bool connect(const char* sAddr, std::string& sConnectError);
|
||||||
|
void disconnect();
|
||||||
|
|
||||||
|
bool cmd_login(const char* sLogin, const char* sPassword);
|
||||||
|
bool cmd_submit(const char* sJobId, uint32_t iNonce, const uint8_t* bResult);
|
||||||
|
|
||||||
|
static bool hex2bin(const char* in, unsigned int len, unsigned char* out);
|
||||||
|
static void bin2hex(const unsigned char* in, unsigned int len, char* out);
|
||||||
|
|
||||||
|
inline bool is_running() { return bRunning; }
|
||||||
|
inline bool is_logged_in() { return bLoggedIn; }
|
||||||
|
|
||||||
|
std::string&& get_call_error();
|
||||||
|
bool have_sock_error() { return bHaveSocketError; }
|
||||||
|
|
||||||
|
inline static uint64_t t32_to_t64(uint32_t t) { return 0xFFFFFFFFFFFFFFFFULL / (0xFFFFFFFFULL / ((uint64_t)t)); }
|
||||||
|
inline static uint64_t t64_to_diff(uint64_t t) { return 0xFFFFFFFFFFFFFFFFULL / t; }
|
||||||
|
inline static uint64_t t32_to_diff(uint32_t t) { return 0xFFFFFFFF / t; }
|
||||||
|
inline static uint64_t diff_to_t64(uint64_t d) { return 0xFFFFFFFFFFFFFFFFULL / d; }
|
||||||
|
|
||||||
|
inline uint64_t get_current_diff() { return iJobDiff; }
|
||||||
|
|
||||||
|
bool get_current_job(pool_job& job);
|
||||||
|
|
||||||
|
size_t pool_id;
|
||||||
|
private:
|
||||||
|
std::atomic<bool> bRunning;
|
||||||
|
std::atomic<bool> bLoggedIn;
|
||||||
|
|
||||||
|
uint8_t* bJsonRecvMem;
|
||||||
|
uint8_t* bJsonParseMem;
|
||||||
|
uint8_t* bJsonCallMem;
|
||||||
|
|
||||||
|
static constexpr size_t iJsonMemSize = 4096;
|
||||||
|
static constexpr size_t iSockBufferSize = 4096;
|
||||||
|
|
||||||
|
struct call_rsp;
|
||||||
|
struct opaque_private;
|
||||||
|
struct opq_json_val;
|
||||||
|
|
||||||
|
void jpsock_thread();
|
||||||
|
bool jpsock_thd_main();
|
||||||
|
bool process_line(char* line, size_t len);
|
||||||
|
bool process_pool_job(const opq_json_val* params);
|
||||||
|
bool cmd_ret_wait(const char* sPacket, opq_json_val& poResult);
|
||||||
|
|
||||||
|
char sMinerId[64];
|
||||||
|
std::atomic<uint64_t> iJobDiff;
|
||||||
|
|
||||||
|
std::string sSocketError;
|
||||||
|
std::atomic<bool> bHaveSocketError;
|
||||||
|
|
||||||
|
bool set_socket_error(const char* a);
|
||||||
|
bool set_socket_error(const char* a, const char* b);
|
||||||
|
bool set_socket_error_strerr(const char* a);
|
||||||
|
bool set_socket_error_strerr(const char* a, int res);
|
||||||
|
|
||||||
|
bool prv_connect(const char* sAddr);
|
||||||
|
|
||||||
|
std::mutex call_mutex;
|
||||||
|
std::condition_variable call_cond;
|
||||||
|
std::thread* oRecvThd;
|
||||||
|
|
||||||
|
std::mutex job_mutex;
|
||||||
|
pool_job oCurrentJob;
|
||||||
|
|
||||||
|
opaque_private* prv;
|
||||||
|
};
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,255 @@
|
||||||
|
/*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <cmath>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
#include "console.h"
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
void thd_setaffinity(std::thread::native_handle_type h, uint64_t cpu_id)
|
||||||
|
{
|
||||||
|
SetThreadAffinityMask(h, 1 << cpu_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
void thd_setaffinity(std::thread::native_handle_type h, uint64_t cpu_id)
|
||||||
|
{
|
||||||
|
cpu_set_t mn;
|
||||||
|
CPU_ZERO(&mn);
|
||||||
|
CPU_SET(cpu_id, &mn);
|
||||||
|
pthread_setaffinity_np(h, sizeof(cpu_set_t), &mn);
|
||||||
|
}
|
||||||
|
#endif // _WIN32
|
||||||
|
|
||||||
|
#include "executor.h"
|
||||||
|
#include "minethd.h"
|
||||||
|
#include "jconf.h"
|
||||||
|
#include "crypto/cryptonight.h"
|
||||||
|
|
||||||
|
telemetry::telemetry(size_t iThd)
|
||||||
|
{
|
||||||
|
ppHashCounts = new uint64_t*[iThd];
|
||||||
|
ppTimestamps = new uint64_t*[iThd];
|
||||||
|
iBucketTop = new uint32_t[iThd];
|
||||||
|
|
||||||
|
for (size_t i = 0; i < iThd; i++)
|
||||||
|
{
|
||||||
|
ppHashCounts[i] = new uint64_t[iBucketSize];
|
||||||
|
ppTimestamps[i] = new uint64_t[iBucketSize];
|
||||||
|
iBucketTop[i] = 0;
|
||||||
|
memset(ppHashCounts[0], 0, sizeof(uint64_t) * iBucketSize);
|
||||||
|
memset(ppTimestamps[0], 0, sizeof(uint64_t) * iBucketSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double telemetry::calc_telemetry_data(size_t iLastMilisec, size_t iThread)
|
||||||
|
{
|
||||||
|
using namespace std::chrono;
|
||||||
|
uint64_t iTimeNow = time_point_cast<milliseconds>(high_resolution_clock::now()).time_since_epoch().count();
|
||||||
|
|
||||||
|
uint64_t iEarliestHashCnt = 0;
|
||||||
|
uint64_t iEarliestStamp = 0;
|
||||||
|
uint64_t iLastestStamp = 0;
|
||||||
|
uint64_t iLastestHashCnt = 0;
|
||||||
|
bool bHaveFullSet = false;
|
||||||
|
|
||||||
|
//Start at 1, buckettop points to next empty
|
||||||
|
for (size_t i = 1; i < iBucketSize; i++)
|
||||||
|
{
|
||||||
|
size_t idx = (iBucketTop[iThread] - i) & iBucketMask; //overflow expected here
|
||||||
|
|
||||||
|
if (ppTimestamps[iThread][idx] == 0)
|
||||||
|
break; //That means we don't have the data yet
|
||||||
|
|
||||||
|
if (iLastestStamp == 0)
|
||||||
|
{
|
||||||
|
iLastestStamp = ppTimestamps[iThread][idx];
|
||||||
|
iLastestHashCnt = ppHashCounts[iThread][idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iTimeNow - ppTimestamps[iThread][idx] > iLastMilisec)
|
||||||
|
{
|
||||||
|
bHaveFullSet = true;
|
||||||
|
break; //We are out of the requested time period
|
||||||
|
}
|
||||||
|
|
||||||
|
iEarliestStamp = ppTimestamps[iThread][idx];
|
||||||
|
iEarliestHashCnt = ppHashCounts[iThread][idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bHaveFullSet || iEarliestStamp == 0 || iLastestStamp == 0)
|
||||||
|
return nan("");
|
||||||
|
|
||||||
|
double fHashes, fTime;
|
||||||
|
fHashes = iLastestHashCnt - iEarliestHashCnt;
|
||||||
|
fTime = iLastestStamp - iEarliestStamp;
|
||||||
|
fTime /= 1000.0;
|
||||||
|
|
||||||
|
return fHashes / fTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
void telemetry::push_perf_value(size_t iThd, uint64_t iHashCount, uint64_t iTimestamp)
|
||||||
|
{
|
||||||
|
size_t iTop = iBucketTop[iThd];
|
||||||
|
ppHashCounts[iThd][iTop] = iHashCount;
|
||||||
|
ppTimestamps[iThd][iTop] = iTimestamp;
|
||||||
|
|
||||||
|
iBucketTop[iThd] = (iTop + 1) & iBucketMask;
|
||||||
|
}
|
||||||
|
|
||||||
|
minethd::minethd(miner_work& pWork, size_t iNo, GpuContext* ctx)
|
||||||
|
{
|
||||||
|
oWork = pWork;
|
||||||
|
bQuit = 0;
|
||||||
|
iThreadNo = (uint8_t)iNo;
|
||||||
|
iJobNo = 0;
|
||||||
|
iHashCount = 0;
|
||||||
|
iTimestamp = 0;
|
||||||
|
pGpuCtx = ctx;
|
||||||
|
|
||||||
|
oWorkThd = std::thread(&minethd::work_main, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool minethd::init_gpus()
|
||||||
|
{
|
||||||
|
size_t i, n = jconf::inst()->GetThreadCount();
|
||||||
|
|
||||||
|
printer::inst()->print_msg(L1, "Compiling code and initializing GPUs. This will take a while...");
|
||||||
|
vGpuData.resize(n);
|
||||||
|
|
||||||
|
jconf::thd_cfg cfg;
|
||||||
|
for(i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
jconf::inst()->GetThreadConfig(i, cfg);
|
||||||
|
vGpuData[i].deviceIdx = cfg.index;
|
||||||
|
vGpuData[i].rawIntensity = cfg.intensity;
|
||||||
|
vGpuData[i].workSize = cfg.w_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
return InitOpenCL(vGpuData.data(), n, jconf::inst()->GetPlatformIdx()) == ERR_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::atomic<uint64_t> minethd::iGlobalJobNo;
|
||||||
|
std::atomic<uint64_t> minethd::iConsumeCnt; //Threads get jobs as they are initialized
|
||||||
|
minethd::miner_work minethd::oGlobalWork;
|
||||||
|
uint64_t minethd::iThreadCount = 0;
|
||||||
|
std::vector<GpuContext> minethd::vGpuData;
|
||||||
|
|
||||||
|
std::vector<minethd*>* minethd::thread_starter(miner_work& pWork)
|
||||||
|
{
|
||||||
|
iGlobalJobNo = 0;
|
||||||
|
iConsumeCnt = 0;
|
||||||
|
std::vector<minethd*>* pvThreads = new std::vector<minethd*>;
|
||||||
|
|
||||||
|
size_t i, n = jconf::inst()->GetThreadCount();
|
||||||
|
pvThreads->reserve(n);
|
||||||
|
|
||||||
|
jconf::thd_cfg cfg;
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
jconf::inst()->GetThreadConfig(i, cfg);
|
||||||
|
minethd* thd = new minethd(pWork, i, &vGpuData[i]);
|
||||||
|
|
||||||
|
if(cfg.cpu_aff >= 0)
|
||||||
|
thd_setaffinity(thd->oWorkThd.native_handle(), cfg.cpu_aff);
|
||||||
|
|
||||||
|
pvThreads->push_back(thd);
|
||||||
|
if(cfg.cpu_aff >= 0)
|
||||||
|
printer::inst()->print_msg(L1, "Starting GPU thread, affinity: %d.", (int)cfg.cpu_aff);
|
||||||
|
else
|
||||||
|
printer::inst()->print_msg(L1, "Starting GPU thread, no affinity.");
|
||||||
|
}
|
||||||
|
|
||||||
|
iThreadCount = n;
|
||||||
|
return pvThreads;
|
||||||
|
}
|
||||||
|
|
||||||
|
void minethd::switch_work(miner_work& pWork)
|
||||||
|
{
|
||||||
|
// iConsumeCnt is a basic lock-like polling mechanism just in case we happen to push work
|
||||||
|
// faster than threads can consume them. This should never happen in real life.
|
||||||
|
// Pool cant physically send jobs faster than every 250ms or so due to net latency.
|
||||||
|
|
||||||
|
while (iConsumeCnt.load(std::memory_order_seq_cst) < iThreadCount)
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
|
||||||
|
oGlobalWork = pWork;
|
||||||
|
iConsumeCnt.store(0, std::memory_order_seq_cst);
|
||||||
|
iGlobalJobNo++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void minethd::consume_work()
|
||||||
|
{
|
||||||
|
memcpy(&oWork, &oGlobalWork, sizeof(miner_work));
|
||||||
|
iJobNo++;
|
||||||
|
iConsumeCnt++;
|
||||||
|
|
||||||
|
if(!oWork.bStall)
|
||||||
|
{
|
||||||
|
pGpuCtx->Nonce = calc_start_nonce(oWork.iResumeCnt);
|
||||||
|
XMRSetJob(pGpuCtx, oWork.bWorkBlob, oWork.iWorkSize, oWork.iTarget);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void minethd::work_main()
|
||||||
|
{
|
||||||
|
uint64_t iCount = 0;
|
||||||
|
iConsumeCnt++;
|
||||||
|
while (bQuit == 0)
|
||||||
|
{
|
||||||
|
if (oWork.bStall)
|
||||||
|
{
|
||||||
|
/* We are stalled here because the executor didn't find a job for us yet,
|
||||||
|
either because of network latency, or a socket problem. Since we are
|
||||||
|
raison d'etre of this software it us sensible to just wait until we have something*/
|
||||||
|
|
||||||
|
while (iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo)
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
|
|
||||||
|
consume_work();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(sizeof(job_result::sJobID) == sizeof(pool_job::sJobID));
|
||||||
|
|
||||||
|
while(iGlobalJobNo.load(std::memory_order_relaxed) == iJobNo)
|
||||||
|
{
|
||||||
|
cl_uint results[0x100] = { 0 };
|
||||||
|
|
||||||
|
XMRRunJob(pGpuCtx, results);
|
||||||
|
|
||||||
|
for(size_t i = 0; i < results[0xFF]; i++)
|
||||||
|
{
|
||||||
|
executor::inst()->push_event(ex_event(job_result(oWork.sJobID, oWork.bWorkBlob,
|
||||||
|
oWork.iWorkSize, oWork.iTarget, results[i]), oWork.iPoolId));
|
||||||
|
}
|
||||||
|
|
||||||
|
iCount += pGpuCtx->rawIntensity;
|
||||||
|
using namespace std::chrono;
|
||||||
|
uint64_t iStamp = time_point_cast<milliseconds>(high_resolution_clock::now()).time_since_epoch().count();
|
||||||
|
iHashCount.store(iCount, std::memory_order_relaxed);
|
||||||
|
iTimestamp.store(iStamp, std::memory_order_relaxed);
|
||||||
|
std::this_thread::yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
consume_work();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,133 @@
|
||||||
|
#pragma once
|
||||||
|
#include <thread>
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
|
#include "amd_gpu/gpu.h"
|
||||||
|
|
||||||
|
class telemetry
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
telemetry(size_t iThd);
|
||||||
|
void push_perf_value(size_t iThd, uint64_t iHashCount, uint64_t iTimestamp);
|
||||||
|
double calc_telemetry_data(size_t iLastMilisec, size_t iThread);
|
||||||
|
|
||||||
|
private:
|
||||||
|
constexpr static size_t iBucketSize = 2 << 11; //Power of 2 to simplify calculations
|
||||||
|
constexpr static size_t iBucketMask = iBucketSize - 1;
|
||||||
|
uint32_t* iBucketTop;
|
||||||
|
uint64_t** ppHashCounts;
|
||||||
|
uint64_t** ppTimestamps;
|
||||||
|
};
|
||||||
|
|
||||||
|
class minethd
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct miner_work
|
||||||
|
{
|
||||||
|
char sJobID[64];
|
||||||
|
uint8_t bWorkBlob[88];
|
||||||
|
uint32_t iWorkSize;
|
||||||
|
uint32_t iResumeCnt;
|
||||||
|
uint32_t iTarget;
|
||||||
|
bool bStall;
|
||||||
|
size_t iPoolId;
|
||||||
|
|
||||||
|
miner_work() : iWorkSize(0), bStall(true), iPoolId(0) { }
|
||||||
|
|
||||||
|
miner_work(const char* sJobID, const uint8_t* bWork, uint32_t iWorkSize, uint32_t iResumeCnt,
|
||||||
|
uint64_t iTarget, size_t iPoolId) : iWorkSize(iWorkSize), iResumeCnt(iResumeCnt),
|
||||||
|
iTarget(iTarget), bStall(false), iPoolId(iPoolId)
|
||||||
|
{
|
||||||
|
assert(iWorkSize <= sizeof(bWorkBlob));
|
||||||
|
memcpy(this->sJobID, sJobID, sizeof(miner_work::sJobID));
|
||||||
|
memcpy(this->bWorkBlob, bWork, iWorkSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
miner_work(miner_work const&) = delete;
|
||||||
|
|
||||||
|
miner_work& operator=(miner_work const& from)
|
||||||
|
{
|
||||||
|
assert(this != &from);
|
||||||
|
|
||||||
|
iWorkSize = from.iWorkSize;
|
||||||
|
iResumeCnt = from.iResumeCnt;
|
||||||
|
iTarget = from.iTarget;
|
||||||
|
bStall = from.bStall;
|
||||||
|
iPoolId = from.iPoolId;
|
||||||
|
|
||||||
|
assert(iWorkSize <= sizeof(bWorkBlob));
|
||||||
|
memcpy(sJobID, from.sJobID, sizeof(sJobID));
|
||||||
|
memcpy(bWorkBlob, from.bWorkBlob, iWorkSize);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
miner_work(miner_work&& from) : iWorkSize(from.iWorkSize), iTarget(from.iTarget),
|
||||||
|
bStall(from.bStall), iPoolId(from.iPoolId)
|
||||||
|
{
|
||||||
|
assert(iWorkSize <= sizeof(bWorkBlob));
|
||||||
|
memcpy(sJobID, from.sJobID, sizeof(sJobID));
|
||||||
|
memcpy(bWorkBlob, from.bWorkBlob, iWorkSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
miner_work& operator=(miner_work&& from)
|
||||||
|
{
|
||||||
|
assert(this != &from);
|
||||||
|
|
||||||
|
iWorkSize = from.iWorkSize;
|
||||||
|
iResumeCnt = from.iResumeCnt;
|
||||||
|
iTarget = from.iTarget;
|
||||||
|
bStall = from.bStall;
|
||||||
|
iPoolId = from.iPoolId;
|
||||||
|
|
||||||
|
assert(iWorkSize <= sizeof(bWorkBlob));
|
||||||
|
memcpy(sJobID, from.sJobID, sizeof(sJobID));
|
||||||
|
memcpy(bWorkBlob, from.bWorkBlob, iWorkSize);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void switch_work(miner_work& pWork);
|
||||||
|
static std::vector<minethd*>* thread_starter(miner_work& pWork);
|
||||||
|
static bool init_gpus();
|
||||||
|
|
||||||
|
std::atomic<uint64_t> iHashCount;
|
||||||
|
std::atomic<uint64_t> iTimestamp;
|
||||||
|
|
||||||
|
private:
|
||||||
|
minethd(miner_work& pWork, size_t iNo, GpuContext* ctx);
|
||||||
|
|
||||||
|
// We use the top 8 bits of the nonce for thread and resume
|
||||||
|
// This allows us to resume up to 64 threads 4 times before
|
||||||
|
// we get nonce collisions
|
||||||
|
// Bottom 24 bits allow for an hour of work at 4000 H/s
|
||||||
|
inline uint32_t calc_start_nonce(uint32_t resume)
|
||||||
|
{ return (resume * iThreadCount + iThreadNo) << 24; }
|
||||||
|
|
||||||
|
void work_main();
|
||||||
|
void double_work_main();
|
||||||
|
void consume_work();
|
||||||
|
|
||||||
|
static std::atomic<uint64_t> iGlobalJobNo;
|
||||||
|
static std::atomic<uint64_t> iConsumeCnt;
|
||||||
|
static uint64_t iThreadCount;
|
||||||
|
uint64_t iJobNo;
|
||||||
|
|
||||||
|
static miner_work oGlobalWork;
|
||||||
|
miner_work oWork;
|
||||||
|
|
||||||
|
std::thread oWorkThd;
|
||||||
|
uint8_t iThreadNo;
|
||||||
|
|
||||||
|
bool bQuit;
|
||||||
|
bool bNoPrefetch;
|
||||||
|
|
||||||
|
//Mutable ptr to vector below, different for each thread
|
||||||
|
GpuContext* pGpuCtx;
|
||||||
|
|
||||||
|
// WARNING - this vector (but not its contents) must be immutable
|
||||||
|
// once the threads are started
|
||||||
|
static std::vector<GpuContext> vGpuData;
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
#pragma once
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
// Structures that we use to pass info between threads constructors are here just to make
|
||||||
|
// the stack allocation take up less space, heap is a shared resouce that needs locks too of course
|
||||||
|
|
||||||
|
struct pool_job
|
||||||
|
{
|
||||||
|
char sJobID[64];
|
||||||
|
uint8_t bWorkBlob[88];
|
||||||
|
uint32_t iTarget;
|
||||||
|
uint32_t iWorkLen;
|
||||||
|
uint32_t iResumeCnt;
|
||||||
|
|
||||||
|
pool_job() : iWorkLen(0), iResumeCnt(0) {}
|
||||||
|
pool_job(const char* sJobID, uint64_t iTarget, const uint8_t* bWorkBlob, uint32_t iWorkLen) :
|
||||||
|
iTarget(iTarget), iWorkLen(iWorkLen), iResumeCnt(0)
|
||||||
|
{
|
||||||
|
assert(iWorkLen <= sizeof(pool_job::bWorkBlob));
|
||||||
|
memcpy(this->sJobID, sJobID, sizeof(pool_job::sJobID));
|
||||||
|
memcpy(this->bWorkBlob, bWorkBlob, iWorkLen);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct job_result
|
||||||
|
{
|
||||||
|
uint8_t bResult[32];
|
||||||
|
char sJobID[64];
|
||||||
|
uint8_t bWorkBlob[88];
|
||||||
|
uint32_t iTarget;
|
||||||
|
uint32_t iWorkLen;
|
||||||
|
uint32_t iNonce;
|
||||||
|
|
||||||
|
job_result() {}
|
||||||
|
job_result(const char* sJobID, uint8_t* bWorkBlob, uint32_t iWorkLen, uint32_t iTarget, uint32_t iNonce) :
|
||||||
|
iTarget(iTarget), iWorkLen(iWorkLen), iNonce(iNonce)
|
||||||
|
{
|
||||||
|
assert(iWorkLen <= sizeof(job_result::bWorkBlob));
|
||||||
|
|
||||||
|
memcpy(this->sJobID, sJobID, sizeof(job_result::sJobID));
|
||||||
|
memcpy(this->bWorkBlob, bWorkBlob, iWorkLen);
|
||||||
|
memset(this->bResult, 0, sizeof(job_result::bResult));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ex_event_name { EV_INVALID_VAL, EV_SOCK_READY, EV_SOCK_ERROR,
|
||||||
|
EV_POOL_HAVE_JOB, EV_MINER_HAVE_RESULT, EV_PERF_TICK, EV_RECONNECT,
|
||||||
|
EV_SWITCH_POOL, EV_DEV_POOL_EXIT, EV_USR_HASHRATE, EV_USR_RESULTS, EV_USR_CONNSTAT,
|
||||||
|
EV_HASHRATE_LOOP, EV_HTML_HASHRATE, EV_HTML_RESULTS, EV_HTML_CONNSTAT };
|
||||||
|
|
||||||
|
/*
|
||||||
|
This is how I learned to stop worrying and love c++11 =).
|
||||||
|
Ghosts of endless heap allocations have finally been exorcised. Thanks
|
||||||
|
to the nifty magic of move semantics, string will only be allocated
|
||||||
|
once on the heap. Considering that it makes a jorney across stack,
|
||||||
|
heap alloced queue, to another stack before being finally processed
|
||||||
|
I think it is kind of nifty, don't you?
|
||||||
|
Also note that for non-arg events we only copy two qwords
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct ex_event
|
||||||
|
{
|
||||||
|
ex_event_name iName;
|
||||||
|
size_t iPoolId;
|
||||||
|
|
||||||
|
union
|
||||||
|
{
|
||||||
|
pool_job oPoolJob;
|
||||||
|
job_result oJobResult;
|
||||||
|
std::string sSocketError;
|
||||||
|
};
|
||||||
|
|
||||||
|
ex_event() { iName = EV_INVALID_VAL; iPoolId = 0;}
|
||||||
|
ex_event(std::string&& err, size_t id) : iName(EV_SOCK_ERROR), iPoolId(id), sSocketError(std::move(err)) { }
|
||||||
|
ex_event(job_result dat, size_t id) : iName(EV_MINER_HAVE_RESULT), iPoolId(id), oJobResult(dat) {}
|
||||||
|
ex_event(pool_job dat, size_t id) : iName(EV_POOL_HAVE_JOB), iPoolId(id), oPoolJob(dat) {}
|
||||||
|
ex_event(ex_event_name ev, size_t id = 0) : iName(ev), iPoolId(id) {}
|
||||||
|
|
||||||
|
// Delete the copy operators to make sure we are moving only what is needed
|
||||||
|
ex_event(ex_event const&) = delete;
|
||||||
|
ex_event& operator=(ex_event const&) = delete;
|
||||||
|
|
||||||
|
ex_event(ex_event&& from)
|
||||||
|
{
|
||||||
|
iName = from.iName;
|
||||||
|
iPoolId = from.iPoolId;
|
||||||
|
|
||||||
|
switch(iName)
|
||||||
|
{
|
||||||
|
case EV_SOCK_ERROR:
|
||||||
|
new (&sSocketError) std::string(std::move(from.sSocketError));
|
||||||
|
break;
|
||||||
|
case EV_MINER_HAVE_RESULT:
|
||||||
|
oJobResult = from.oJobResult;
|
||||||
|
break;
|
||||||
|
case EV_POOL_HAVE_JOB:
|
||||||
|
oPoolJob = from.oPoolJob;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ex_event& operator=(ex_event&& from)
|
||||||
|
{
|
||||||
|
assert(this != &from);
|
||||||
|
|
||||||
|
if(iName == EV_SOCK_ERROR)
|
||||||
|
sSocketError.~basic_string();
|
||||||
|
|
||||||
|
iName = from.iName;
|
||||||
|
iPoolId = from.iPoolId;
|
||||||
|
|
||||||
|
switch(iName)
|
||||||
|
{
|
||||||
|
case EV_SOCK_ERROR:
|
||||||
|
new (&sSocketError) std::string();
|
||||||
|
sSocketError = std::move(from.sSocketError);
|
||||||
|
break;
|
||||||
|
case EV_MINER_HAVE_RESULT:
|
||||||
|
oJobResult = from.oJobResult;
|
||||||
|
break;
|
||||||
|
case EV_POOL_HAVE_JOB:
|
||||||
|
oPoolJob = from.oPoolJob;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ex_event()
|
||||||
|
{
|
||||||
|
if(iName == EV_SOCK_ERROR)
|
||||||
|
sSocketError.~basic_string();
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* blake256 kernel implementation.
|
||||||
|
*
|
||||||
|
* ==========================(LICENSE BEGIN)============================
|
||||||
|
* Copyright (c) 2014 djm34
|
||||||
|
* Copyright (c) 2014 tpruvot
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* ===========================(LICENSE END)=============================
|
||||||
|
*
|
||||||
|
* @author djm34
|
||||||
|
*/
|
||||||
|
__constant static const int sigma[16][16] = {
|
||||||
|
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||||
|
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
|
||||||
|
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
|
||||||
|
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
|
||||||
|
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
|
||||||
|
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
|
||||||
|
{ 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
|
||||||
|
{ 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
|
||||||
|
{ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
|
||||||
|
{ 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
|
||||||
|
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||||
|
{ 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
|
||||||
|
{ 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
|
||||||
|
{ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
|
||||||
|
{ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
|
||||||
|
{ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
__constant static const sph_u32 c_IV256[8] = {
|
||||||
|
0x6A09E667, 0xBB67AE85,
|
||||||
|
0x3C6EF372, 0xA54FF53A,
|
||||||
|
0x510E527F, 0x9B05688C,
|
||||||
|
0x1F83D9AB, 0x5BE0CD19
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Second part (64-80) msg never change, store it */
|
||||||
|
__constant static const sph_u32 c_Padding[16] = {
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0x80000000, 0, 0, 0,
|
||||||
|
0, 0, 0, 0,
|
||||||
|
0, 1, 0, 640,
|
||||||
|
};
|
||||||
|
__constant static const sph_u32 c_u256[16] = {
|
||||||
|
0x243F6A88, 0x85A308D3,
|
||||||
|
0x13198A2E, 0x03707344,
|
||||||
|
0xA4093822, 0x299F31D0,
|
||||||
|
0x082EFA98, 0xEC4E6C89,
|
||||||
|
0x452821E6, 0x38D01377,
|
||||||
|
0xBE5466CF, 0x34E90C6C,
|
||||||
|
0xC0AC29B7, 0xC97C50DD,
|
||||||
|
0x3F84D5B5, 0xB5470917
|
||||||
|
};
|
||||||
|
|
||||||
|
#define GS(a,b,c,d,x) { \
|
||||||
|
const sph_u32 idx1 = sigma[r][x]; \
|
||||||
|
const sph_u32 idx2 = sigma[r][x+1]; \
|
||||||
|
v[a] += (m[idx1] ^ c_u256[idx2]) + v[b]; \
|
||||||
|
v[d] ^= v[a]; \
|
||||||
|
v[d] = rotate(v[d], 16U); \
|
||||||
|
v[c] += v[d]; \
|
||||||
|
v[b] ^= v[c]; \
|
||||||
|
v[b] = rotate(v[b], 20U); \
|
||||||
|
\
|
||||||
|
v[a] += (m[idx2] ^ c_u256[idx1]) + v[b]; \
|
||||||
|
v[d] ^= v[a]; \
|
||||||
|
v[d] = rotate(v[d], 24U); \
|
||||||
|
v[c] += v[d]; \
|
||||||
|
v[b] ^= v[c]; \
|
||||||
|
v[b] = rotate(v[b], 25U); \
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,912 @@
|
||||||
|
/*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma OPENCL EXTENSION cl_amd_media_ops2 : enable
|
||||||
|
|
||||||
|
#include "opencl/wolf-aes.cl"
|
||||||
|
#include "opencl/wolf-skein.cl"
|
||||||
|
#include "opencl/jh.cl"
|
||||||
|
#include "opencl/blake256.cl"
|
||||||
|
#include "opencl/groestl256.cl"
|
||||||
|
|
||||||
|
static const __constant ulong keccakf_rndc[24] =
|
||||||
|
{
|
||||||
|
0x0000000000000001, 0x0000000000008082, 0x800000000000808a,
|
||||||
|
0x8000000080008000, 0x000000000000808b, 0x0000000080000001,
|
||||||
|
0x8000000080008081, 0x8000000000008009, 0x000000000000008a,
|
||||||
|
0x0000000000000088, 0x0000000080008009, 0x000000008000000a,
|
||||||
|
0x000000008000808b, 0x800000000000008b, 0x8000000000008089,
|
||||||
|
0x8000000000008003, 0x8000000000008002, 0x8000000000000080,
|
||||||
|
0x000000000000800a, 0x800000008000000a, 0x8000000080008081,
|
||||||
|
0x8000000000008080, 0x0000000080000001, 0x8000000080008008
|
||||||
|
};
|
||||||
|
|
||||||
|
static const __constant uchar sbox[256] =
|
||||||
|
{
|
||||||
|
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
|
||||||
|
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
|
||||||
|
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
|
||||||
|
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
|
||||||
|
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
|
||||||
|
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
|
||||||
|
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
|
||||||
|
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
|
||||||
|
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
|
||||||
|
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
|
||||||
|
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
|
||||||
|
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
|
||||||
|
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
|
||||||
|
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
|
||||||
|
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
|
||||||
|
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void keccakf1600(ulong *s)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 24; ++i)
|
||||||
|
{
|
||||||
|
ulong bc[5], tmp1, tmp2;
|
||||||
|
bc[0] = s[0] ^ s[5] ^ s[10] ^ s[15] ^ s[20] ^ rotate(s[2] ^ s[7] ^ s[12] ^ s[17] ^ s[22], 1UL);
|
||||||
|
bc[1] = s[1] ^ s[6] ^ s[11] ^ s[16] ^ s[21] ^ rotate(s[3] ^ s[8] ^ s[13] ^ s[18] ^ s[23], 1UL);
|
||||||
|
bc[2] = s[2] ^ s[7] ^ s[12] ^ s[17] ^ s[22] ^ rotate(s[4] ^ s[9] ^ s[14] ^ s[19] ^ s[24], 1UL);
|
||||||
|
bc[3] = s[3] ^ s[8] ^ s[13] ^ s[18] ^ s[23] ^ rotate(s[0] ^ s[5] ^ s[10] ^ s[15] ^ s[20], 1UL);
|
||||||
|
bc[4] = s[4] ^ s[9] ^ s[14] ^ s[19] ^ s[24] ^ rotate(s[1] ^ s[6] ^ s[11] ^ s[16] ^ s[21], 1UL);
|
||||||
|
|
||||||
|
tmp1 = s[1] ^ bc[0];
|
||||||
|
|
||||||
|
s[0] ^= bc[4];
|
||||||
|
s[1] = rotate(s[6] ^ bc[0], 44UL);
|
||||||
|
s[6] = rotate(s[9] ^ bc[3], 20UL);
|
||||||
|
s[9] = rotate(s[22] ^ bc[1], 61UL);
|
||||||
|
s[22] = rotate(s[14] ^ bc[3], 39UL);
|
||||||
|
s[14] = rotate(s[20] ^ bc[4], 18UL);
|
||||||
|
s[20] = rotate(s[2] ^ bc[1], 62UL);
|
||||||
|
s[2] = rotate(s[12] ^ bc[1], 43UL);
|
||||||
|
s[12] = rotate(s[13] ^ bc[2], 25UL);
|
||||||
|
s[13] = rotate(s[19] ^ bc[3], 8UL);
|
||||||
|
s[19] = rotate(s[23] ^ bc[2], 56UL);
|
||||||
|
s[23] = rotate(s[15] ^ bc[4], 41UL);
|
||||||
|
s[15] = rotate(s[4] ^ bc[3], 27UL);
|
||||||
|
s[4] = rotate(s[24] ^ bc[3], 14UL);
|
||||||
|
s[24] = rotate(s[21] ^ bc[0], 2UL);
|
||||||
|
s[21] = rotate(s[8] ^ bc[2], 55UL);
|
||||||
|
s[8] = rotate(s[16] ^ bc[0], 35UL);
|
||||||
|
s[16] = rotate(s[5] ^ bc[4], 36UL);
|
||||||
|
s[5] = rotate(s[3] ^ bc[2], 28UL);
|
||||||
|
s[3] = rotate(s[18] ^ bc[2], 21UL);
|
||||||
|
s[18] = rotate(s[17] ^ bc[1], 15UL);
|
||||||
|
s[17] = rotate(s[11] ^ bc[0], 10UL);
|
||||||
|
s[11] = rotate(s[7] ^ bc[1], 6UL);
|
||||||
|
s[7] = rotate(s[10] ^ bc[4], 3UL);
|
||||||
|
s[10] = rotate(tmp1, 1UL);
|
||||||
|
|
||||||
|
tmp1 = s[0]; tmp2 = s[1]; s[0] = bitselect(s[0] ^ s[2], s[0], s[1]); s[1] = bitselect(s[1] ^ s[3], s[1], s[2]); s[2] = bitselect(s[2] ^ s[4], s[2], s[3]); s[3] = bitselect(s[3] ^ tmp1, s[3], s[4]); s[4] = bitselect(s[4] ^ tmp2, s[4], tmp1);
|
||||||
|
tmp1 = s[5]; tmp2 = s[6]; s[5] = bitselect(s[5] ^ s[7], s[5], s[6]); s[6] = bitselect(s[6] ^ s[8], s[6], s[7]); s[7] = bitselect(s[7] ^ s[9], s[7], s[8]); s[8] = bitselect(s[8] ^ tmp1, s[8], s[9]); s[9] = bitselect(s[9] ^ tmp2, s[9], tmp1);
|
||||||
|
tmp1 = s[10]; tmp2 = s[11]; s[10] = bitselect(s[10] ^ s[12], s[10], s[11]); s[11] = bitselect(s[11] ^ s[13], s[11], s[12]); s[12] = bitselect(s[12] ^ s[14], s[12], s[13]); s[13] = bitselect(s[13] ^ tmp1, s[13], s[14]); s[14] = bitselect(s[14] ^ tmp2, s[14], tmp1);
|
||||||
|
tmp1 = s[15]; tmp2 = s[16]; s[15] = bitselect(s[15] ^ s[17], s[15], s[16]); s[16] = bitselect(s[16] ^ s[18], s[16], s[17]); s[17] = bitselect(s[17] ^ s[19], s[17], s[18]); s[18] = bitselect(s[18] ^ tmp1, s[18], s[19]); s[19] = bitselect(s[19] ^ tmp2, s[19], tmp1);
|
||||||
|
tmp1 = s[20]; tmp2 = s[21]; s[20] = bitselect(s[20] ^ s[22], s[20], s[21]); s[21] = bitselect(s[21] ^ s[23], s[21], s[22]); s[22] = bitselect(s[22] ^ s[24], s[22], s[23]); s[23] = bitselect(s[23] ^ tmp1, s[23], s[24]); s[24] = bitselect(s[24] ^ tmp2, s[24], tmp1);
|
||||||
|
s[0] ^= keccakf_rndc[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const __constant uint keccakf_rotc[24] =
|
||||||
|
{
|
||||||
|
1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
|
||||||
|
27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44
|
||||||
|
};
|
||||||
|
|
||||||
|
static const __constant uint keccakf_piln[24] =
|
||||||
|
{
|
||||||
|
10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
|
||||||
|
15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1
|
||||||
|
};
|
||||||
|
|
||||||
|
void keccakf1600_1(ulong *st)
|
||||||
|
{
|
||||||
|
int i, round;
|
||||||
|
ulong t, bc[5];
|
||||||
|
|
||||||
|
#pragma unroll 1
|
||||||
|
for(round = 0; round < 24; ++round)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Theta
|
||||||
|
bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20];
|
||||||
|
bc[1] = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21];
|
||||||
|
bc[2] = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22];
|
||||||
|
bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23];
|
||||||
|
bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24];
|
||||||
|
|
||||||
|
#pragma unroll 1
|
||||||
|
for (i = 0; i < 5; ++i) {
|
||||||
|
t = bc[(i + 4) % 5] ^ rotate(bc[(i + 1) % 5], 1UL);
|
||||||
|
st[i ] ^= t;
|
||||||
|
st[i + 5] ^= t;
|
||||||
|
st[i + 10] ^= t;
|
||||||
|
st[i + 15] ^= t;
|
||||||
|
st[i + 20] ^= t;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Rho Pi
|
||||||
|
t = st[1];
|
||||||
|
#pragma unroll
|
||||||
|
for (i = 0; i < 24; ++i) {
|
||||||
|
bc[0] = st[keccakf_piln[i]];
|
||||||
|
st[keccakf_piln[i]] = rotate(t, (ulong)keccakf_rotc[i]);
|
||||||
|
t = bc[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
//ulong tmp1 = st[0]; ulong tmp2 = st[1]; st[0] = bitselect(st[0] ^ st[2], st[0], st[1]); st[1] = bitselect(st[1] ^ st[3], st[1], st[2]); st[2] = bitselect(st[2] ^ st[4], st[2], st[3]); st[3] = bitselect(st[3] ^ tmp1, st[3], st[4]); st[4] = bitselect(st[4] ^ tmp2, st[4], tmp1);
|
||||||
|
//tmp1 = st[5]; tmp2 = st[6]; st[5] = bitselect(st[5] ^ st[7], st[5], st[6]); st[6] = bitselect(st[6] ^ st[8], st[6], st[7]); st[7] = bitselect(st[7] ^ st[9], st[7], st[8]); st[8] = bitselect(st[8] ^ tmp1, st[8], st[9]); st[9] = bitselect(st[9] ^ tmp2, st[9], tmp1);
|
||||||
|
//tmp1 = st[10]; tmp2 = st[11]; st[10] = bitselect(st[10] ^ st[12], st[10], st[11]); st[11] = bitselect(st[11] ^ st[13], st[11], st[12]); st[12] = bitselect(st[12] ^ st[14], st[12], st[13]); st[13] = bitselect(st[13] ^ tmp1, st[13], st[14]); st[14] = bitselect(st[14] ^ tmp2, st[14], tmp1);
|
||||||
|
//tmp1 = st[15]; tmp2 = st[16]; st[15] = bitselect(st[15] ^ st[17], st[15], st[16]); st[16] = bitselect(st[16] ^ st[18], st[16], st[17]); st[17] = bitselect(st[17] ^ st[19], st[17], st[18]); st[18] = bitselect(st[18] ^ tmp1, st[18], st[19]); st[19] = bitselect(st[19] ^ tmp2, st[19], tmp1);
|
||||||
|
//tmp1 = st[20]; tmp2 = st[21]; st[20] = bitselect(st[20] ^ st[22], st[20], st[21]); st[21] = bitselect(st[21] ^ st[23], st[21], st[22]); st[22] = bitselect(st[22] ^ st[24], st[22], st[23]); st[23] = bitselect(st[23] ^ tmp1, st[23], st[24]); st[24] = bitselect(st[24] ^ tmp2, st[24], tmp1);
|
||||||
|
|
||||||
|
#pragma unroll 1
|
||||||
|
for(int i = 0; i < 25; i += 5)
|
||||||
|
{
|
||||||
|
ulong tmp[5];
|
||||||
|
|
||||||
|
#pragma unroll 1
|
||||||
|
for(int x = 0; x < 5; ++x)
|
||||||
|
tmp[x] = bitselect(st[i + x] ^ st[i + ((x + 2) % 5)], st[i + x], st[i + ((x + 1) % 5)]);
|
||||||
|
|
||||||
|
#pragma unroll 1
|
||||||
|
for(int x = 0; x < 5; ++x) st[i + x] = tmp[x];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iota
|
||||||
|
st[0] ^= keccakf_rndc[round];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void keccakf1600_2(ulong *st)
|
||||||
|
{
|
||||||
|
int i, round;
|
||||||
|
ulong t, bc[5];
|
||||||
|
|
||||||
|
#pragma unroll 1
|
||||||
|
for(round = 0; round < 24; ++round)
|
||||||
|
{
|
||||||
|
|
||||||
|
// Theta
|
||||||
|
//bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20];
|
||||||
|
//bc[1] = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21];
|
||||||
|
//bc[2] = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22];
|
||||||
|
//bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23];
|
||||||
|
//bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24];
|
||||||
|
|
||||||
|
/*
|
||||||
|
#pragma unroll
|
||||||
|
for (i = 0; i < 5; ++i) {
|
||||||
|
t = bc[(i + 4) % 5] ^ rotate(bc[(i + 1) % 5], 1UL);
|
||||||
|
st[i ] ^= t;
|
||||||
|
st[i + 5] ^= t;
|
||||||
|
st[i + 10] ^= t;
|
||||||
|
st[i + 15] ^= t;
|
||||||
|
st[i + 20] ^= t;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
bc[0] = st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20] ^ rotate(st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22], 1UL);
|
||||||
|
bc[1] = st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21] ^ rotate(st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23], 1UL);
|
||||||
|
bc[2] = st[2] ^ st[7] ^ st[12] ^ st[17] ^ st[22] ^ rotate(st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24], 1UL);
|
||||||
|
bc[3] = st[3] ^ st[8] ^ st[13] ^ st[18] ^ st[23] ^ rotate(st[0] ^ st[5] ^ st[10] ^ st[15] ^ st[20], 1UL);
|
||||||
|
bc[4] = st[4] ^ st[9] ^ st[14] ^ st[19] ^ st[24] ^ rotate(st[1] ^ st[6] ^ st[11] ^ st[16] ^ st[21], 1UL);
|
||||||
|
|
||||||
|
st[0] ^= bc[4];
|
||||||
|
st[5] ^= bc[4];
|
||||||
|
st[10] ^= bc[4];
|
||||||
|
st[15] ^= bc[4];
|
||||||
|
st[20] ^= bc[4];
|
||||||
|
|
||||||
|
st[1] ^= bc[0];
|
||||||
|
st[6] ^= bc[0];
|
||||||
|
st[11] ^= bc[0];
|
||||||
|
st[16] ^= bc[0];
|
||||||
|
st[21] ^= bc[0];
|
||||||
|
|
||||||
|
st[2] ^= bc[1];
|
||||||
|
st[7] ^= bc[1];
|
||||||
|
st[12] ^= bc[1];
|
||||||
|
st[17] ^= bc[1];
|
||||||
|
st[22] ^= bc[1];
|
||||||
|
|
||||||
|
st[3] ^= bc[2];
|
||||||
|
st[8] ^= bc[2];
|
||||||
|
st[13] ^= bc[2];
|
||||||
|
st[18] ^= bc[2];
|
||||||
|
st[23] ^= bc[2];
|
||||||
|
|
||||||
|
st[4] ^= bc[3];
|
||||||
|
st[9] ^= bc[3];
|
||||||
|
st[14] ^= bc[3];
|
||||||
|
st[19] ^= bc[3];
|
||||||
|
st[24] ^= bc[3];
|
||||||
|
|
||||||
|
// Rho Pi
|
||||||
|
t = st[1];
|
||||||
|
#pragma unroll
|
||||||
|
for (i = 0; i < 24; ++i) {
|
||||||
|
bc[0] = st[keccakf_piln[i]];
|
||||||
|
st[keccakf_piln[i]] = rotate(t, (ulong)keccakf_rotc[i]);
|
||||||
|
t = bc[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*ulong tmp1 = st[1] ^ bc[0];
|
||||||
|
|
||||||
|
st[0] ^= bc[4];
|
||||||
|
st[1] = rotate(st[6] ^ bc[0], 44UL);
|
||||||
|
st[6] = rotate(st[9] ^ bc[3], 20UL);
|
||||||
|
st[9] = rotate(st[22] ^ bc[1], 61UL);
|
||||||
|
st[22] = rotate(st[14] ^ bc[3], 39UL);
|
||||||
|
st[14] = rotate(st[20] ^ bc[4], 18UL);
|
||||||
|
st[20] = rotate(st[2] ^ bc[1], 62UL);
|
||||||
|
st[2] = rotate(st[12] ^ bc[1], 43UL);
|
||||||
|
st[12] = rotate(st[13] ^ bc[2], 25UL);
|
||||||
|
st[13] = rotate(st[19] ^ bc[3], 8UL);
|
||||||
|
st[19] = rotate(st[23] ^ bc[2], 56UL);
|
||||||
|
st[23] = rotate(st[15] ^ bc[4], 41UL);
|
||||||
|
st[15] = rotate(st[4] ^ bc[3], 27UL);
|
||||||
|
st[4] = rotate(st[24] ^ bc[3], 14UL);
|
||||||
|
st[24] = rotate(st[21] ^ bc[0], 2UL);
|
||||||
|
st[21] = rotate(st[8] ^ bc[2], 55UL);
|
||||||
|
st[8] = rotate(st[16] ^ bc[0], 35UL);
|
||||||
|
st[16] = rotate(st[5] ^ bc[4], 36UL);
|
||||||
|
st[5] = rotate(st[3] ^ bc[2], 28UL);
|
||||||
|
st[3] = rotate(st[18] ^ bc[2], 21UL);
|
||||||
|
st[18] = rotate(st[17] ^ bc[1], 15UL);
|
||||||
|
st[17] = rotate(st[11] ^ bc[0], 10UL);
|
||||||
|
st[11] = rotate(st[7] ^ bc[1], 6UL);
|
||||||
|
st[7] = rotate(st[10] ^ bc[4], 3UL);
|
||||||
|
st[10] = rotate(tmp1, 1UL);
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
//ulong tmp1 = st[0]; ulong tmp2 = st[1]; st[0] = bitselect(st[0] ^ st[2], st[0], st[1]); st[1] = bitselect(st[1] ^ st[3], st[1], st[2]); st[2] = bitselect(st[2] ^ st[4], st[2], st[3]); st[3] = bitselect(st[3] ^ tmp1, st[3], st[4]); st[4] = bitselect(st[4] ^ tmp2, st[4], tmp1);
|
||||||
|
//tmp1 = st[5]; tmp2 = st[6]; st[5] = bitselect(st[5] ^ st[7], st[5], st[6]); st[6] = bitselect(st[6] ^ st[8], st[6], st[7]); st[7] = bitselect(st[7] ^ st[9], st[7], st[8]); st[8] = bitselect(st[8] ^ tmp1, st[8], st[9]); st[9] = bitselect(st[9] ^ tmp2, st[9], tmp1);
|
||||||
|
//tmp1 = st[10]; tmp2 = st[11]; st[10] = bitselect(st[10] ^ st[12], st[10], st[11]); st[11] = bitselect(st[11] ^ st[13], st[11], st[12]); st[12] = bitselect(st[12] ^ st[14], st[12], st[13]); st[13] = bitselect(st[13] ^ tmp1, st[13], st[14]); st[14] = bitselect(st[14] ^ tmp2, st[14], tmp1);
|
||||||
|
//tmp1 = st[15]; tmp2 = st[16]; st[15] = bitselect(st[15] ^ st[17], st[15], st[16]); st[16] = bitselect(st[16] ^ st[18], st[16], st[17]); st[17] = bitselect(st[17] ^ st[19], st[17], st[18]); st[18] = bitselect(st[18] ^ tmp1, st[18], st[19]); st[19] = bitselect(st[19] ^ tmp2, st[19], tmp1);
|
||||||
|
//tmp1 = st[20]; tmp2 = st[21]; st[20] = bitselect(st[20] ^ st[22], st[20], st[21]); st[21] = bitselect(st[21] ^ st[23], st[21], st[22]); st[22] = bitselect(st[22] ^ st[24], st[22], st[23]); st[23] = bitselect(st[23] ^ tmp1, st[23], st[24]); st[24] = bitselect(st[24] ^ tmp2, st[24], tmp1);
|
||||||
|
|
||||||
|
#pragma unroll
|
||||||
|
for(int i = 0; i < 25; i += 5)
|
||||||
|
{
|
||||||
|
ulong tmp1 = st[i], tmp2 = st[i + 1];
|
||||||
|
|
||||||
|
st[i] = bitselect(st[i] ^ st[i + 2], st[i], st[i + 1]);
|
||||||
|
st[i + 1] = bitselect(st[i + 1] ^ st[i + 3], st[i + 1], st[i + 2]);
|
||||||
|
st[i + 2] = bitselect(st[i + 2] ^ st[i + 4], st[i + 2], st[i + 3]);
|
||||||
|
st[i + 3] = bitselect(st[i + 3] ^ tmp1, st[i + 3], st[i + 4]);
|
||||||
|
st[i + 4] = bitselect(st[i + 4] ^ tmp2, st[i + 4], tmp1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iota
|
||||||
|
st[0] ^= keccakf_rndc[round];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNKeccak(ulong *output, ulong *input)
|
||||||
|
{
|
||||||
|
ulong st[25];
|
||||||
|
|
||||||
|
// Copy 72 bytes
|
||||||
|
for(int i = 0; i < 9; ++i) st[i] = input[i];
|
||||||
|
|
||||||
|
// Last four and '1' bit for padding
|
||||||
|
//st[9] = as_ulong((uint2)(((uint *)input)[18], 0x00000001U));
|
||||||
|
|
||||||
|
st[9] = (input[9] & 0x00000000FFFFFFFFUL) | 0x0000000100000000UL;
|
||||||
|
|
||||||
|
for(int i = 10; i < 25; ++i) st[i] = 0x00UL;
|
||||||
|
|
||||||
|
// Last bit of padding
|
||||||
|
st[16] = 0x8000000000000000UL;
|
||||||
|
|
||||||
|
keccakf1600_1(st);
|
||||||
|
|
||||||
|
for(int i = 0; i < 25; ++i) output[i] = st[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
static const __constant uchar rcon[8] = { 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40 };
|
||||||
|
|
||||||
|
#pragma OPENCL EXTENSION cl_amd_media_ops2 : enable
|
||||||
|
|
||||||
|
#define BYTE(x, y) (amd_bfe((x), (y) << 3U, 8U))
|
||||||
|
|
||||||
|
#define SubWord(inw) ((sbox[BYTE(inw, 3)] << 24) | (sbox[BYTE(inw, 2)] << 16) | (sbox[BYTE(inw, 1)] << 8) | sbox[BYTE(inw, 0)])
|
||||||
|
|
||||||
|
void AESExpandKey256(uint *keybuf)
|
||||||
|
{
|
||||||
|
//#pragma unroll 4
|
||||||
|
for(uint c = 8, i = 1; c < 60; ++c)
|
||||||
|
{
|
||||||
|
// For 256-bit keys, an sbox permutation is done every other 4th uint generated, AND every 8th
|
||||||
|
uint t = ((!(c & 7)) || ((c & 7) == 4)) ? SubWord(keybuf[c - 1]) : keybuf[c - 1];
|
||||||
|
|
||||||
|
// If the uint we're generating has an index that is a multiple of 8, rotate and XOR with the round constant,
|
||||||
|
// then XOR this with previously generated uint. If it's 4 after a multiple of 8, only the sbox permutation
|
||||||
|
// is done, followed by the XOR. If neither are true, only the XOR with the previously generated uint is done.
|
||||||
|
keybuf[c] = keybuf[c - 8] ^ ((!(c & 7)) ? rotate(t, 24U) ^ as_uint((uchar4)(rcon[i++], 0U, 0U, 0U)) : t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define IDX(x) ((x) * (get_global_size(0)))
|
||||||
|
|
||||||
|
__attribute__((reqd_work_group_size(WORKSIZE, 8, 1)))
|
||||||
|
__kernel void cn0(__global ulong *input, __global uint4 *Scratchpad, __global ulong *states)
|
||||||
|
{
|
||||||
|
ulong State[25];
|
||||||
|
uint ExpandedKey1[256];
|
||||||
|
__local uint AES0[256], AES1[256], AES2[256], AES3[256];
|
||||||
|
uint4 text;
|
||||||
|
|
||||||
|
states += (25 * (get_global_id(0) - get_global_offset(0)));
|
||||||
|
Scratchpad += ((get_global_id(0) - get_global_offset(0)));
|
||||||
|
|
||||||
|
for(int i = get_local_id(0); i < 256; i += WORKSIZE)
|
||||||
|
{
|
||||||
|
const uint tmp = AES0_C[i];
|
||||||
|
AES0[i] = tmp;
|
||||||
|
AES1[i] = rotate(tmp, 8U);
|
||||||
|
AES2[i] = rotate(tmp, 16U);
|
||||||
|
AES3[i] = rotate(tmp, 24U);
|
||||||
|
}
|
||||||
|
|
||||||
|
((ulong8 *)State)[0] = vload8(0, input);
|
||||||
|
State[8] = input[8];
|
||||||
|
State[9] = input[9];
|
||||||
|
State[10] = input[10];
|
||||||
|
|
||||||
|
((uint *)State)[9] &= 0x00FFFFFFU;
|
||||||
|
((uint *)State)[9] |= ((get_global_id(0)) & 0xFF) << 24;
|
||||||
|
((uint *)State)[10] &= 0xFF000000U;
|
||||||
|
((uint *)State)[10] |= ((get_global_id(0) >> 8));
|
||||||
|
|
||||||
|
for(int i = 11; i < 25; ++i) State[i] = 0x00UL;
|
||||||
|
|
||||||
|
// Last bit of padding
|
||||||
|
State[16] = 0x8000000000000000UL;
|
||||||
|
|
||||||
|
keccakf1600_2(State);
|
||||||
|
|
||||||
|
mem_fence(CLK_GLOBAL_MEM_FENCE);
|
||||||
|
|
||||||
|
#pragma unroll
|
||||||
|
for(int i = 0; i < 25; ++i) states[i] = State[i];
|
||||||
|
|
||||||
|
text = vload4(get_local_id(1) + 4, (__global uint *)(states));
|
||||||
|
|
||||||
|
#pragma unroll
|
||||||
|
for(int i = 0; i < 4; ++i) ((ulong *)ExpandedKey1)[i] = states[i];
|
||||||
|
|
||||||
|
AESExpandKey256(ExpandedKey1);
|
||||||
|
|
||||||
|
mem_fence(CLK_LOCAL_MEM_FENCE);
|
||||||
|
|
||||||
|
#pragma unroll 2
|
||||||
|
for(int i = 0; i < 0x4000; ++i)
|
||||||
|
{
|
||||||
|
#pragma unroll
|
||||||
|
for(int j = 0; j < 10; ++j)
|
||||||
|
text = AES_Round(AES0, AES1, AES2, AES3, text, ((uint4 *)ExpandedKey1)[j]);
|
||||||
|
|
||||||
|
Scratchpad[IDX((i << 3) + get_local_id(1))] = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_fence(CLK_GLOBAL_MEM_FENCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((reqd_work_group_size(WORKSIZE, 1, 1)))
|
||||||
|
__kernel void cn1(__global uint4 *Scratchpad, __global ulong *states)
|
||||||
|
{
|
||||||
|
ulong a[2], b[2];
|
||||||
|
__local uint AES0[256], AES1[256], AES2[256], AES3[256];
|
||||||
|
|
||||||
|
Scratchpad += ((get_global_id(0) - get_global_offset(0)));
|
||||||
|
states += (25 * (get_global_id(0) - get_global_offset(0)));
|
||||||
|
|
||||||
|
for(int i = get_local_id(0); i < 256; i += WORKSIZE)
|
||||||
|
{
|
||||||
|
const uint tmp = AES0_C[i];
|
||||||
|
AES0[i] = tmp;
|
||||||
|
AES1[i] = rotate(tmp, 8U);
|
||||||
|
AES2[i] = rotate(tmp, 16U);
|
||||||
|
AES3[i] = rotate(tmp, 24U);
|
||||||
|
}
|
||||||
|
|
||||||
|
a[0] = states[0] ^ states[4];
|
||||||
|
b[0] = states[2] ^ states[6];
|
||||||
|
a[1] = states[1] ^ states[5];
|
||||||
|
b[1] = states[3] ^ states[7];
|
||||||
|
|
||||||
|
uint4 b_x = ((uint4 *)b)[0];
|
||||||
|
|
||||||
|
mem_fence(CLK_LOCAL_MEM_FENCE);
|
||||||
|
|
||||||
|
#pragma unroll 8
|
||||||
|
for(int i = 0; i < 0x80000; ++i)
|
||||||
|
{
|
||||||
|
ulong c[2];
|
||||||
|
|
||||||
|
((uint4 *)c)[0] = Scratchpad[IDX((a[0] & 0x1FFFF0) >> 4)];
|
||||||
|
((uint4 *)c)[0] = AES_Round(AES0, AES1, AES2, AES3, ((uint4 *)c)[0], ((uint4 *)a)[0]);
|
||||||
|
//b_x ^= ((uint4 *)c)[0];
|
||||||
|
|
||||||
|
Scratchpad[IDX((a[0] & 0x1FFFF0) >> 4)] = b_x ^ ((uint4 *)c)[0];
|
||||||
|
|
||||||
|
uint4 tmp;
|
||||||
|
tmp = Scratchpad[IDX((c[0] & 0x1FFFF0) >> 4)];
|
||||||
|
|
||||||
|
a[1] += c[0] * as_ulong2(tmp).s0;
|
||||||
|
a[0] += mul_hi(c[0], as_ulong2(tmp).s0);
|
||||||
|
|
||||||
|
Scratchpad[IDX((c[0] & 0x1FFFF0) >> 4)] = ((uint4 *)a)[0];
|
||||||
|
|
||||||
|
((uint4 *)a)[0] ^= tmp;
|
||||||
|
|
||||||
|
b_x = ((uint4 *)c)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_fence(CLK_GLOBAL_MEM_FENCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__((reqd_work_group_size(WORKSIZE, 8, 1)))
|
||||||
|
__kernel void cn2(__global uint4 *Scratchpad, __global ulong *states, __global uint *Branch0, __global uint *Branch1, __global uint *Branch2, __global uint *Branch3)
|
||||||
|
{
|
||||||
|
__local uint AES0[256], AES1[256], AES2[256], AES3[256];
|
||||||
|
uint ExpandedKey2[256];
|
||||||
|
ulong State[25];
|
||||||
|
uint4 text;
|
||||||
|
|
||||||
|
Scratchpad += ((get_global_id(0) - get_global_offset(0)));
|
||||||
|
states += (25 * (get_global_id(0) - get_global_offset(0)));
|
||||||
|
|
||||||
|
for(int i = get_local_id(0); i < 256; i += WORKSIZE)
|
||||||
|
{
|
||||||
|
const uint tmp = AES0_C[i];
|
||||||
|
AES0[i] = tmp;
|
||||||
|
AES1[i] = rotate(tmp, 8U);
|
||||||
|
AES2[i] = rotate(tmp, 16U);
|
||||||
|
AES3[i] = rotate(tmp, 24U);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__Tahiti__) || defined(__Pitcairn__)
|
||||||
|
|
||||||
|
for(int i = 0; i < 4; ++i) ((ulong *)ExpandedKey2)[i] = states[i + 4];
|
||||||
|
text = vload4(get_local_id(1) + 4, (__global uint *)states);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
text = vload4(get_local_id(1) + 4, (__global uint *)states);
|
||||||
|
((uint8 *)ExpandedKey2)[0] = vload8(1, (__global uint *)states);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
AESExpandKey256(ExpandedKey2);
|
||||||
|
|
||||||
|
barrier(CLK_LOCAL_MEM_FENCE);
|
||||||
|
|
||||||
|
#pragma unroll 2
|
||||||
|
for(int i = 0; i < 0x4000; ++i)
|
||||||
|
{
|
||||||
|
text ^= Scratchpad[IDX((i << 3) + get_local_id(1))];
|
||||||
|
|
||||||
|
#pragma unroll
|
||||||
|
for(int j = 0; j < 10; ++j)
|
||||||
|
text = AES_Round(AES0, AES1, AES2, AES3, text, ((uint4 *)ExpandedKey2)[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
vstore2(as_ulong2(text), get_local_id(1) + 4, states);
|
||||||
|
|
||||||
|
barrier(CLK_GLOBAL_MEM_FENCE);
|
||||||
|
|
||||||
|
if(!get_local_id(1))
|
||||||
|
{
|
||||||
|
for(int i = 0; i < 25; ++i) State[i] = states[i];
|
||||||
|
|
||||||
|
keccakf1600_2(State);
|
||||||
|
|
||||||
|
for(int i = 0; i < 25; ++i) states[i] = State[i];
|
||||||
|
|
||||||
|
switch(State[0] & 3)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
Branch0[atomic_inc(Branch0 + get_global_size(0))] = get_global_id(0) - get_global_offset(0);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Branch1[atomic_inc(Branch1 + get_global_size(0))] = get_global_id(0) - get_global_offset(0);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Branch2[atomic_inc(Branch2 + get_global_size(0))] = get_global_id(0) - get_global_offset(0);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
Branch3[atomic_inc(Branch3 + get_global_size(0))] = get_global_id(0) - get_global_offset(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_fence(CLK_GLOBAL_MEM_FENCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
__kernel void cryptonight(__global ulong *input, __global uint4 *Scratchpad, __global ulong *states, __global uint *Branch0, __global uint *Branch1, __global uint *Branch2, __global uint *Branch3, ulong ThreadCount)
|
||||||
|
{
|
||||||
|
uchar State[200];
|
||||||
|
__local uint AES0[256], AES1[256], AES2[256], AES3[256];
|
||||||
|
uchar ExpandedKey1[256], ExpandedKey2[256];
|
||||||
|
ulong inbuf[10], a[2], b[2];
|
||||||
|
uint4 text[8];
|
||||||
|
|
||||||
|
for(int i = 0; i < 256; ++i)
|
||||||
|
{
|
||||||
|
const uint tmp = AES0_C[i];
|
||||||
|
AES0[i] = tmp;
|
||||||
|
AES1[i] = rotate(tmp, 8U);
|
||||||
|
AES2[i] = rotate(tmp, 16U);
|
||||||
|
AES3[i] = rotate(tmp, 24U);
|
||||||
|
}
|
||||||
|
|
||||||
|
((ulong8 *)inbuf)[0] = vload8(0, input);
|
||||||
|
inbuf[8] = input[8];
|
||||||
|
inbuf[9] = (ulong)((__global uint *)input)[18];
|
||||||
|
|
||||||
|
((uint *)(((uchar *)inbuf) + 39))[0] = get_global_id(0);
|
||||||
|
CNKeccak((ulong *)State, inbuf);
|
||||||
|
|
||||||
|
a[0] = ((ulong *)State)[0] ^ ((ulong *)State)[4];
|
||||||
|
b[0] = ((ulong *)State)[2] ^ ((ulong *)State)[6];
|
||||||
|
a[1] = ((ulong *)State)[1] ^ ((ulong *)State)[5];
|
||||||
|
b[1] = ((ulong *)State)[3] ^ ((ulong *)State)[7];
|
||||||
|
|
||||||
|
for(uint i = 0; i < 8; ++i) text[i] = vload4(i + 4, (uint *)(State));
|
||||||
|
|
||||||
|
for(int i = 0; i < 4; ++i) ((ulong *)ExpandedKey1)[i] = ((ulong *)State)[i];
|
||||||
|
for(int i = 0; i < 4; ++i) ((ulong *)ExpandedKey2)[i] = ((ulong *)State)[i + 4];
|
||||||
|
|
||||||
|
AESExpandKey256(ExpandedKey1);
|
||||||
|
AESExpandKey256(ExpandedKey2);
|
||||||
|
|
||||||
|
mem_fence(CLK_LOCAL_MEM_FENCE);
|
||||||
|
|
||||||
|
Scratchpad += ((1 << 17) * (get_global_id(0) - get_global_offset(0)));
|
||||||
|
|
||||||
|
//#pragma unroll 1
|
||||||
|
for(int i = 0; i < (1 << 17); i += 8)
|
||||||
|
{
|
||||||
|
#pragma unroll
|
||||||
|
for(int j = 0; j < 10; ++j)
|
||||||
|
{
|
||||||
|
#pragma unroll
|
||||||
|
for(int x = 0; x < 8; ++x)
|
||||||
|
text[x] = AES_Round(AES0, AES1, AES2, AES3, text[x], ((uint4 *)ExpandedKey1)[j]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int j = 0; j < 8; ++j) *(Scratchpad + i + j) = text[j];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint4 b_x = ((uint4 *)b)[0];
|
||||||
|
|
||||||
|
//#pragma unroll 1
|
||||||
|
for(int i = 0; i < 0x80000; ++i)
|
||||||
|
{
|
||||||
|
ulong c[2];
|
||||||
|
|
||||||
|
((uint4 *)c)[0] = Scratchpad[(a[0] & 0x1FFFF0) >> 4];
|
||||||
|
((uint4 *)c)[0] = AES_Round(AES0, AES1, AES2, AES3, ((uint4 *)c)[0], ((uint4 *)a)[0]);
|
||||||
|
b_x ^= ((uint4 *)c)[0];
|
||||||
|
|
||||||
|
Scratchpad[(a[0] & 0x1FFFF0) >> 4] = b_x;
|
||||||
|
|
||||||
|
uint4 tmp;
|
||||||
|
tmp = Scratchpad[(c[0] & 0x1FFFF0) >> 4];
|
||||||
|
|
||||||
|
a[1] += c[0] * as_ulong2(tmp).s0;
|
||||||
|
a[0] += mul_hi(c[0], as_ulong2(tmp).s0);
|
||||||
|
|
||||||
|
Scratchpad[(c[0] & 0x1FFFF0) >> 4] = ((uint4 *)a)[0];
|
||||||
|
|
||||||
|
((uint4 *)a)[0] ^= tmp;
|
||||||
|
|
||||||
|
b_x = ((uint4 *)c)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
for(uint i = 0; i < 8; ++i) text[i] = vload4(i + 4, (uint *)(State));
|
||||||
|
|
||||||
|
for(int i = 0; i < (1 << 17); i += 8)
|
||||||
|
{
|
||||||
|
#pragma unroll
|
||||||
|
for(int j = 0; j < 8; ++j) text[j] ^= Scratchpad[i + j];
|
||||||
|
|
||||||
|
#pragma unroll 1
|
||||||
|
for(int j = 0; j < 10; ++j)
|
||||||
|
{
|
||||||
|
#pragma unroll
|
||||||
|
for(int x = 0; x < 8; ++x)
|
||||||
|
text[x] = AES_Round(AES0, AES1, AES2, AES3, text[x], ((uint4 *)ExpandedKey2)[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(uint i = 0; i < 8; ++i) vstore4(text[i], i + 4, (uint *)(State));
|
||||||
|
|
||||||
|
keccakf1600((ulong *)State);
|
||||||
|
|
||||||
|
states += (25 * (get_global_id(0) - get_global_offset(0)));
|
||||||
|
|
||||||
|
for(int i = 0; i < 25; ++i) states[i] = ((ulong *)State)[i];
|
||||||
|
|
||||||
|
switch(State[0] & 3)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
Branch0[atomic_inc(Branch0 + ThreadCount)] = get_global_id(0) - get_global_offset(0);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
Branch1[atomic_inc(Branch1 + ThreadCount)] = get_global_id(0) - get_global_offset(0);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
Branch2[atomic_inc(Branch2 + ThreadCount)] = get_global_id(0) - get_global_offset(0);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
Branch3[atomic_inc(Branch3 + ThreadCount)] = get_global_id(0) - get_global_offset(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define VSWAP8(x) (((x) >> 56) | (((x) >> 40) & 0x000000000000FF00UL) | (((x) >> 24) & 0x0000000000FF0000UL) \
|
||||||
|
| (((x) >> 8) & 0x00000000FF000000UL) | (((x) << 8) & 0x000000FF00000000UL) \
|
||||||
|
| (((x) << 24) & 0x0000FF0000000000UL) | (((x) << 40) & 0x00FF000000000000UL) | (((x) << 56) & 0xFF00000000000000UL))
|
||||||
|
|
||||||
|
#define VSWAP4(x) ((((x) >> 24) & 0xFFU) | (((x) >> 8) & 0xFF00U) | (((x) << 8) & 0xFF0000U) | (((x) << 24) & 0xFF000000U))
|
||||||
|
|
||||||
|
__kernel void Skein(__global ulong *states, __global uint *BranchBuf, __global uint *output, uint Target, ulong Threads)
|
||||||
|
{
|
||||||
|
const ulong idx = get_global_id(0) - get_global_offset(0);
|
||||||
|
|
||||||
|
if(idx >= Threads) return;
|
||||||
|
|
||||||
|
states += 25 * BranchBuf[idx];
|
||||||
|
|
||||||
|
// skein
|
||||||
|
ulong8 h = vload8(0, SKEIN512_256_IV);
|
||||||
|
|
||||||
|
// Type field begins with final bit, first bit, then six bits of type; the last 96
|
||||||
|
// bits are input processed (including in the block to be processed with that tweak)
|
||||||
|
// The output transform is only one run of UBI, since we need only 256 bits of output
|
||||||
|
// The tweak for the output transform is Type = Output with the Final bit set
|
||||||
|
// T[0] for the output is 8, and I don't know why - should be message size...
|
||||||
|
ulong t[3] = { 0x00UL, 0x7000000000000000UL, 0x00UL };
|
||||||
|
ulong8 p, m;
|
||||||
|
|
||||||
|
for(uint i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
if(i < 3) t[0] += 0x40UL;
|
||||||
|
else t[0] += 0x08UL;
|
||||||
|
|
||||||
|
t[2] = t[0] ^ t[1];
|
||||||
|
|
||||||
|
m = (i < 3) ? vload8(i, states) : (ulong8)(states[24], 0UL, 0UL, 0UL, 0UL, 0UL, 0UL, 0UL);
|
||||||
|
const ulong h8 = h.s0 ^ h.s1 ^ h.s2 ^ h.s3 ^ h.s4 ^ h.s5 ^ h.s6 ^ h.s7 ^ SKEIN_KS_PARITY;
|
||||||
|
p = Skein512Block(m, h, h8, t);
|
||||||
|
|
||||||
|
h = m ^ p;
|
||||||
|
|
||||||
|
if(i < 2) t[1] = 0x3000000000000000UL;
|
||||||
|
else t[1] = 0xB000000000000000UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
t[0] = 0x08UL;
|
||||||
|
t[1] = 0xFF00000000000000UL;
|
||||||
|
t[2] = t[0] ^ t[1];
|
||||||
|
|
||||||
|
p = (ulong8)(0);
|
||||||
|
const ulong h8 = h.s0 ^ h.s1 ^ h.s2 ^ h.s3 ^ h.s4 ^ h.s5 ^ h.s6 ^ h.s7 ^ SKEIN_KS_PARITY;
|
||||||
|
|
||||||
|
p = Skein512Block(p, h, h8, t);
|
||||||
|
|
||||||
|
//vstore8(p, 0, output);
|
||||||
|
|
||||||
|
if(as_uint16(p).s7 <= Target) output[atomic_inc(output + 0xFF)] = BranchBuf[idx] + get_global_offset(0);
|
||||||
|
|
||||||
|
mem_fence(CLK_GLOBAL_MEM_FENCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SWAP8(x) as_ulong(as_uchar8(x).s76543210)
|
||||||
|
|
||||||
|
__kernel void JH(__global ulong *states, __global uint *BranchBuf, __global uint *output, uint Target, ulong Threads)
|
||||||
|
{
|
||||||
|
const uint idx = get_global_id(0) - get_global_offset(0);
|
||||||
|
|
||||||
|
if(idx >= Threads) return;
|
||||||
|
|
||||||
|
states += 25 * BranchBuf[idx];
|
||||||
|
|
||||||
|
sph_u64 h0h = 0xEBD3202C41A398EBUL, h0l = 0xC145B29C7BBECD92UL, h1h = 0xFAC7D4609151931CUL, h1l = 0x038A507ED6820026UL, h2h = 0x45B92677269E23A4UL, h2l = 0x77941AD4481AFBE0UL, h3h = 0x7A176B0226ABB5CDUL, h3l = 0xA82FFF0F4224F056UL;
|
||||||
|
sph_u64 h4h = 0x754D2E7F8996A371UL, h4l = 0x62E27DF70849141DUL, h5h = 0x948F2476F7957627UL, h5l = 0x6C29804757B6D587UL, h6h = 0x6C0D8EAC2D275E5CUL, h6l = 0x0F7A0557C6508451UL, h7h = 0xEA12247067D3E47BUL, h7l = 0x69D71CD313ABE389UL;
|
||||||
|
sph_u64 tmp;
|
||||||
|
|
||||||
|
for(int i = 0; i < 5; ++i)
|
||||||
|
{
|
||||||
|
ulong input[8];
|
||||||
|
|
||||||
|
if(i < 3)
|
||||||
|
{
|
||||||
|
for(int x = 0; x < 8; ++x) input[x] = (states[(i << 3) + x]);
|
||||||
|
}
|
||||||
|
else if(i == 3)
|
||||||
|
{
|
||||||
|
input[0] = (states[24]);
|
||||||
|
input[1] = 0x80UL;
|
||||||
|
for(int x = 2; x < 8; ++x) input[x] = 0x00UL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
input[7] = 0x4006000000000000UL;
|
||||||
|
|
||||||
|
for(int x = 0; x < 7; ++x) input[x] = 0x00UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
h0h ^= input[0];
|
||||||
|
h0l ^= input[1];
|
||||||
|
h1h ^= input[2];
|
||||||
|
h1l ^= input[3];
|
||||||
|
h2h ^= input[4];
|
||||||
|
h2l ^= input[5];
|
||||||
|
h3h ^= input[6];
|
||||||
|
h3l ^= input[7];
|
||||||
|
|
||||||
|
E8;
|
||||||
|
|
||||||
|
h4h ^= input[0];
|
||||||
|
h4l ^= input[1];
|
||||||
|
h5h ^= input[2];
|
||||||
|
h5l ^= input[3];
|
||||||
|
h6h ^= input[4];
|
||||||
|
h6l ^= input[5];
|
||||||
|
h7h ^= input[6];
|
||||||
|
h7l ^= input[7];
|
||||||
|
}
|
||||||
|
|
||||||
|
//output[0] = h6h;
|
||||||
|
//output[1] = h6l;
|
||||||
|
//output[2] = h7h;
|
||||||
|
//output[3] = h7l;
|
||||||
|
|
||||||
|
if(as_uint2(h7l).s1 <= Target) output[atomic_inc(output + 0xFF)] = BranchBuf[idx] + get_global_offset(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SWAP4(x) as_uint(as_uchar4(x).s3210)
|
||||||
|
|
||||||
|
__kernel void Blake(__global ulong *states, __global uint *BranchBuf, __global uint *output, uint Target, ulong Threads)
|
||||||
|
{
|
||||||
|
const uint idx = get_global_id(0) - get_global_offset(0);
|
||||||
|
|
||||||
|
if(idx >= Threads) return;
|
||||||
|
|
||||||
|
states += 25 * BranchBuf[idx];
|
||||||
|
|
||||||
|
unsigned int m[16];
|
||||||
|
unsigned int v[16];
|
||||||
|
uint h[8];
|
||||||
|
|
||||||
|
((uint8 *)h)[0] = vload8(0U, c_IV256);
|
||||||
|
|
||||||
|
for(uint i = 0, bitlen = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
if(i < 3)
|
||||||
|
{
|
||||||
|
((uint16 *)m)[0] = vload16(i, (__global uint *)states);
|
||||||
|
for(int i = 0; i < 16; ++i) m[i] = SWAP4(m[i]);
|
||||||
|
bitlen += 512;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m[0] = SWAP4(((__global uint *)states)[48]);
|
||||||
|
m[1] = SWAP4(((__global uint *)states)[49]);
|
||||||
|
m[2] = 0x80000000U;
|
||||||
|
|
||||||
|
for(int i = 3; i < 13; ++i) m[i] = 0x00U;
|
||||||
|
|
||||||
|
m[13] = 1U;
|
||||||
|
m[14] = 0U;
|
||||||
|
m[15] = 0x640;
|
||||||
|
bitlen += 64;
|
||||||
|
}
|
||||||
|
|
||||||
|
((uint16 *)v)[0].lo = ((uint8 *)h)[0];
|
||||||
|
((uint16 *)v)[0].hi = vload8(0U, c_u256);
|
||||||
|
|
||||||
|
//v[12] ^= (i < 3) ? (i + 1) << 9 : 1600U;
|
||||||
|
//v[13] ^= (i < 3) ? (i + 1) << 9 : 1600U;
|
||||||
|
|
||||||
|
v[12] ^= bitlen;
|
||||||
|
v[13] ^= bitlen;
|
||||||
|
|
||||||
|
for(int r = 0; r < 14; r++)
|
||||||
|
{
|
||||||
|
GS(0, 4, 0x8, 0xC, 0x0);
|
||||||
|
GS(1, 5, 0x9, 0xD, 0x2);
|
||||||
|
GS(2, 6, 0xA, 0xE, 0x4);
|
||||||
|
GS(3, 7, 0xB, 0xF, 0x6);
|
||||||
|
GS(0, 5, 0xA, 0xF, 0x8);
|
||||||
|
GS(1, 6, 0xB, 0xC, 0xA);
|
||||||
|
GS(2, 7, 0x8, 0xD, 0xC);
|
||||||
|
GS(3, 4, 0x9, 0xE, 0xE);
|
||||||
|
}
|
||||||
|
|
||||||
|
((uint8 *)h)[0] ^= ((uint8 *)v)[0] ^ ((uint8 *)v)[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = 0; i < 8; ++i) h[i] = SWAP4(h[i]);
|
||||||
|
|
||||||
|
//for(int i = 0; i < 4; ++i) output[i] = ((ulong *)h)[i];
|
||||||
|
if(h[7] <= Target) output[atomic_inc(output + 0xFF)] = BranchBuf[idx] + get_global_offset(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
__kernel void Groestl(__global ulong *states, __global uint *BranchBuf, __global uint *output, uint Target, ulong Threads)
|
||||||
|
{
|
||||||
|
const uint idx = get_global_id(0) - get_global_offset(0);
|
||||||
|
|
||||||
|
if(idx >= Threads) return;
|
||||||
|
|
||||||
|
states += 25 * BranchBuf[idx];
|
||||||
|
|
||||||
|
ulong State[8];
|
||||||
|
|
||||||
|
for(int i = 0; i < 7; ++i) State[i] = 0UL;
|
||||||
|
|
||||||
|
State[7] = 0x0001000000000000UL;
|
||||||
|
|
||||||
|
for(uint i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
ulong H[8], M[8];
|
||||||
|
|
||||||
|
if(i < 3)
|
||||||
|
{
|
||||||
|
((ulong8 *)M)[0] = vload8(i, states);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
M[0] = states[24];
|
||||||
|
M[1] = 0x80UL;
|
||||||
|
|
||||||
|
for(int x = 2; x < 7; ++x) M[x] = 0UL;
|
||||||
|
|
||||||
|
M[7] = 0x0400000000000000UL;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int x = 0; x < 8; ++x) H[x] = M[x] ^ State[x];
|
||||||
|
|
||||||
|
PERM_SMALL_P(H);
|
||||||
|
PERM_SMALL_Q(M);
|
||||||
|
|
||||||
|
for(int x = 0; x < 8; ++x) State[x] ^= H[x] ^ M[x];
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong tmp[8];
|
||||||
|
|
||||||
|
for(int i = 0; i < 8; ++i) tmp[i] = State[i];
|
||||||
|
|
||||||
|
PERM_SMALL_P(State);
|
||||||
|
|
||||||
|
for(int i = 0; i < 8; ++i) State[i] ^= tmp[i];
|
||||||
|
|
||||||
|
//for(int i = 0; i < 4; ++i) output[i] = State[i + 4];
|
||||||
|
if(as_uint2(State[7]).s1 <= Target) output[atomic_inc(output + 0xFF)] = BranchBuf[idx] + get_global_offset(0);
|
||||||
|
}
|
|
@ -0,0 +1,289 @@
|
||||||
|
/* $Id: groestl.c 260 2011-07-21 01:02:38Z tp $ */
|
||||||
|
/*
|
||||||
|
* Groestl256
|
||||||
|
*
|
||||||
|
* ==========================(LICENSE BEGIN)============================
|
||||||
|
* Copyright (c) 2014 djm34
|
||||||
|
* Copyright (c) 2007-2010 Projet RNRT SAPHIR
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* ===========================(LICENSE END)=============================
|
||||||
|
*
|
||||||
|
* @author Thomas Pornin <thomas.pornin@cryptolog.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SPH_C64(x) x
|
||||||
|
#define SPH_ROTL64(x, y) rotate((x), (ulong)(y))
|
||||||
|
|
||||||
|
|
||||||
|
#define C64e(x) ((SPH_C64(x) >> 56) \
|
||||||
|
| ((SPH_C64(x) >> 40) & SPH_C64(0x000000000000FF00)) \
|
||||||
|
| ((SPH_C64(x) >> 24) & SPH_C64(0x0000000000FF0000)) \
|
||||||
|
| ((SPH_C64(x) >> 8) & SPH_C64(0x00000000FF000000)) \
|
||||||
|
| ((SPH_C64(x) << 8) & SPH_C64(0x000000FF00000000)) \
|
||||||
|
| ((SPH_C64(x) << 24) & SPH_C64(0x0000FF0000000000)) \
|
||||||
|
| ((SPH_C64(x) << 40) & SPH_C64(0x00FF000000000000)) \
|
||||||
|
| ((SPH_C64(x) << 56) & SPH_C64(0xFF00000000000000)))
|
||||||
|
|
||||||
|
#define B64_0(x) ((x) & 0xFF)
|
||||||
|
#define B64_1(x) (((x) >> 8) & 0xFF)
|
||||||
|
#define B64_2(x) (((x) >> 16) & 0xFF)
|
||||||
|
#define B64_3(x) (((x) >> 24) & 0xFF)
|
||||||
|
#define B64_4(x) (((x) >> 32) & 0xFF)
|
||||||
|
#define B64_5(x) (((x) >> 40) & 0xFF)
|
||||||
|
#define B64_6(x) (((x) >> 48) & 0xFF)
|
||||||
|
#define B64_7(x) ((x) >> 56)
|
||||||
|
#define R64 SPH_ROTL64
|
||||||
|
#define PC64(j, r) ((sph_u64)((j) + (r)))
|
||||||
|
#define QC64(j, r) (((sph_u64)(r) << 56) ^ (~((sph_u64)(j) << 56)))
|
||||||
|
|
||||||
|
static const __constant ulong T0_G[] =
|
||||||
|
{
|
||||||
|
0xc6a597f4a5f432c6UL, 0xf884eb9784976ff8UL, 0xee99c7b099b05eeeUL, 0xf68df78c8d8c7af6UL,
|
||||||
|
0xff0de5170d17e8ffUL, 0xd6bdb7dcbddc0ad6UL, 0xdeb1a7c8b1c816deUL, 0x915439fc54fc6d91UL,
|
||||||
|
0x6050c0f050f09060UL, 0x0203040503050702UL, 0xcea987e0a9e02eceUL, 0x567dac877d87d156UL,
|
||||||
|
0xe719d52b192bcce7UL, 0xb56271a662a613b5UL, 0x4de69a31e6317c4dUL, 0xec9ac3b59ab559ecUL,
|
||||||
|
0x8f4505cf45cf408fUL, 0x1f9d3ebc9dbca31fUL, 0x894009c040c04989UL, 0xfa87ef92879268faUL,
|
||||||
|
0xef15c53f153fd0efUL, 0xb2eb7f26eb2694b2UL, 0x8ec90740c940ce8eUL, 0xfb0bed1d0b1de6fbUL,
|
||||||
|
0x41ec822fec2f6e41UL, 0xb3677da967a91ab3UL, 0x5ffdbe1cfd1c435fUL, 0x45ea8a25ea256045UL,
|
||||||
|
0x23bf46dabfdaf923UL, 0x53f7a602f7025153UL, 0xe496d3a196a145e4UL, 0x9b5b2ded5bed769bUL,
|
||||||
|
0x75c2ea5dc25d2875UL, 0xe11cd9241c24c5e1UL, 0x3dae7ae9aee9d43dUL, 0x4c6a98be6abef24cUL,
|
||||||
|
0x6c5ad8ee5aee826cUL, 0x7e41fcc341c3bd7eUL, 0xf502f1060206f3f5UL, 0x834f1dd14fd15283UL,
|
||||||
|
0x685cd0e45ce48c68UL, 0x51f4a207f4075651UL, 0xd134b95c345c8dd1UL, 0xf908e9180818e1f9UL,
|
||||||
|
0xe293dfae93ae4ce2UL, 0xab734d9573953eabUL, 0x6253c4f553f59762UL, 0x2a3f54413f416b2aUL,
|
||||||
|
0x080c10140c141c08UL, 0x955231f652f66395UL, 0x46658caf65afe946UL, 0x9d5e21e25ee27f9dUL,
|
||||||
|
0x3028607828784830UL, 0x37a16ef8a1f8cf37UL, 0x0a0f14110f111b0aUL, 0x2fb55ec4b5c4eb2fUL,
|
||||||
|
0x0e091c1b091b150eUL, 0x2436485a365a7e24UL, 0x1b9b36b69bb6ad1bUL, 0xdf3da5473d4798dfUL,
|
||||||
|
0xcd26816a266aa7cdUL, 0x4e699cbb69bbf54eUL, 0x7fcdfe4ccd4c337fUL, 0xea9fcfba9fba50eaUL,
|
||||||
|
0x121b242d1b2d3f12UL, 0x1d9e3ab99eb9a41dUL, 0x5874b09c749cc458UL, 0x342e68722e724634UL,
|
||||||
|
0x362d6c772d774136UL, 0xdcb2a3cdb2cd11dcUL, 0xb4ee7329ee299db4UL, 0x5bfbb616fb164d5bUL,
|
||||||
|
0xa4f65301f601a5a4UL, 0x764decd74dd7a176UL, 0xb76175a361a314b7UL, 0x7dcefa49ce49347dUL,
|
||||||
|
0x527ba48d7b8ddf52UL, 0xdd3ea1423e429fddUL, 0x5e71bc937193cd5eUL, 0x139726a297a2b113UL,
|
||||||
|
0xa6f55704f504a2a6UL, 0xb96869b868b801b9UL, 0x0000000000000000UL, 0xc12c99742c74b5c1UL,
|
||||||
|
0x406080a060a0e040UL, 0xe31fdd211f21c2e3UL, 0x79c8f243c8433a79UL, 0xb6ed772ced2c9ab6UL,
|
||||||
|
0xd4beb3d9bed90dd4UL, 0x8d4601ca46ca478dUL, 0x67d9ce70d9701767UL, 0x724be4dd4bddaf72UL,
|
||||||
|
0x94de3379de79ed94UL, 0x98d42b67d467ff98UL, 0xb0e87b23e82393b0UL, 0x854a11de4ade5b85UL,
|
||||||
|
0xbb6b6dbd6bbd06bbUL, 0xc52a917e2a7ebbc5UL, 0x4fe59e34e5347b4fUL, 0xed16c13a163ad7edUL,
|
||||||
|
0x86c51754c554d286UL, 0x9ad72f62d762f89aUL, 0x6655ccff55ff9966UL, 0x119422a794a7b611UL,
|
||||||
|
0x8acf0f4acf4ac08aUL, 0xe910c9301030d9e9UL, 0x0406080a060a0e04UL, 0xfe81e798819866feUL,
|
||||||
|
0xa0f05b0bf00baba0UL, 0x7844f0cc44ccb478UL, 0x25ba4ad5bad5f025UL, 0x4be3963ee33e754bUL,
|
||||||
|
0xa2f35f0ef30eaca2UL, 0x5dfeba19fe19445dUL, 0x80c01b5bc05bdb80UL, 0x058a0a858a858005UL,
|
||||||
|
0x3fad7eecadecd33fUL, 0x21bc42dfbcdffe21UL, 0x7048e0d848d8a870UL, 0xf104f90c040cfdf1UL,
|
||||||
|
0x63dfc67adf7a1963UL, 0x77c1ee58c1582f77UL, 0xaf75459f759f30afUL, 0x426384a563a5e742UL,
|
||||||
|
0x2030405030507020UL, 0xe51ad12e1a2ecbe5UL, 0xfd0ee1120e12effdUL, 0xbf6d65b76db708bfUL,
|
||||||
|
0x814c19d44cd45581UL, 0x1814303c143c2418UL, 0x26354c5f355f7926UL, 0xc32f9d712f71b2c3UL,
|
||||||
|
0xbee16738e13886beUL, 0x35a26afda2fdc835UL, 0x88cc0b4fcc4fc788UL, 0x2e395c4b394b652eUL,
|
||||||
|
0x93573df957f96a93UL, 0x55f2aa0df20d5855UL, 0xfc82e39d829d61fcUL, 0x7a47f4c947c9b37aUL,
|
||||||
|
0xc8ac8befacef27c8UL, 0xbae76f32e73288baUL, 0x322b647d2b7d4f32UL, 0xe695d7a495a442e6UL,
|
||||||
|
0xc0a09bfba0fb3bc0UL, 0x199832b398b3aa19UL, 0x9ed12768d168f69eUL, 0xa37f5d817f8122a3UL,
|
||||||
|
0x446688aa66aaee44UL, 0x547ea8827e82d654UL, 0x3bab76e6abe6dd3bUL, 0x0b83169e839e950bUL,
|
||||||
|
0x8cca0345ca45c98cUL, 0xc729957b297bbcc7UL, 0x6bd3d66ed36e056bUL, 0x283c50443c446c28UL,
|
||||||
|
0xa779558b798b2ca7UL, 0xbce2633de23d81bcUL, 0x161d2c271d273116UL, 0xad76419a769a37adUL,
|
||||||
|
0xdb3bad4d3b4d96dbUL, 0x6456c8fa56fa9e64UL, 0x744ee8d24ed2a674UL, 0x141e28221e223614UL,
|
||||||
|
0x92db3f76db76e492UL, 0x0c0a181e0a1e120cUL, 0x486c90b46cb4fc48UL, 0xb8e46b37e4378fb8UL,
|
||||||
|
0x9f5d25e75de7789fUL, 0xbd6e61b26eb20fbdUL, 0x43ef862aef2a6943UL, 0xc4a693f1a6f135c4UL,
|
||||||
|
0x39a872e3a8e3da39UL, 0x31a462f7a4f7c631UL, 0xd337bd5937598ad3UL, 0xf28bff868b8674f2UL,
|
||||||
|
0xd532b156325683d5UL, 0x8b430dc543c54e8bUL, 0x6e59dceb59eb856eUL, 0xdab7afc2b7c218daUL,
|
||||||
|
0x018c028f8c8f8e01UL, 0xb16479ac64ac1db1UL, 0x9cd2236dd26df19cUL, 0x49e0923be03b7249UL,
|
||||||
|
0xd8b4abc7b4c71fd8UL, 0xacfa4315fa15b9acUL, 0xf307fd090709faf3UL, 0xcf25856f256fa0cfUL,
|
||||||
|
0xcaaf8feaafea20caUL, 0xf48ef3898e897df4UL, 0x47e98e20e9206747UL, 0x1018202818283810UL,
|
||||||
|
0x6fd5de64d5640b6fUL, 0xf088fb83888373f0UL, 0x4a6f94b16fb1fb4aUL, 0x5c72b8967296ca5cUL,
|
||||||
|
0x3824706c246c5438UL, 0x57f1ae08f1085f57UL, 0x73c7e652c7522173UL, 0x975135f351f36497UL,
|
||||||
|
0xcb238d652365aecbUL, 0xa17c59847c8425a1UL, 0xe89ccbbf9cbf57e8UL, 0x3e217c6321635d3eUL,
|
||||||
|
0x96dd377cdd7cea96UL, 0x61dcc27fdc7f1e61UL, 0x0d861a9186919c0dUL, 0x0f851e9485949b0fUL,
|
||||||
|
0xe090dbab90ab4be0UL, 0x7c42f8c642c6ba7cUL, 0x71c4e257c4572671UL, 0xccaa83e5aae529ccUL,
|
||||||
|
0x90d83b73d873e390UL, 0x06050c0f050f0906UL, 0xf701f5030103f4f7UL, 0x1c12383612362a1cUL,
|
||||||
|
0xc2a39ffea3fe3cc2UL, 0x6a5fd4e15fe18b6aUL, 0xaef94710f910beaeUL, 0x69d0d26bd06b0269UL,
|
||||||
|
0x17912ea891a8bf17UL, 0x995829e858e87199UL, 0x3a2774692769533aUL, 0x27b94ed0b9d0f727UL,
|
||||||
|
0xd938a948384891d9UL, 0xeb13cd351335deebUL, 0x2bb356ceb3cee52bUL, 0x2233445533557722UL,
|
||||||
|
0xd2bbbfd6bbd604d2UL, 0xa9704990709039a9UL, 0x07890e8089808707UL, 0x33a766f2a7f2c133UL,
|
||||||
|
0x2db65ac1b6c1ec2dUL, 0x3c22786622665a3cUL, 0x15922aad92adb815UL, 0xc92089602060a9c9UL,
|
||||||
|
0x874915db49db5c87UL, 0xaaff4f1aff1ab0aaUL, 0x5078a0887888d850UL, 0xa57a518e7a8e2ba5UL,
|
||||||
|
0x038f068a8f8a8903UL, 0x59f8b213f8134a59UL, 0x0980129b809b9209UL, 0x1a1734391739231aUL,
|
||||||
|
0x65daca75da751065UL, 0xd731b553315384d7UL, 0x84c61351c651d584UL, 0xd0b8bbd3b8d303d0UL,
|
||||||
|
0x82c31f5ec35edc82UL, 0x29b052cbb0cbe229UL, 0x5a77b4997799c35aUL, 0x1e113c3311332d1eUL,
|
||||||
|
0x7bcbf646cb463d7bUL, 0xa8fc4b1ffc1fb7a8UL, 0x6dd6da61d6610c6dUL, 0x2c3a584e3a4e622cUL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const __constant ulong T4_G[] =
|
||||||
|
{
|
||||||
|
0xA5F432C6C6A597F4UL, 0x84976FF8F884EB97UL, 0x99B05EEEEE99C7B0UL, 0x8D8C7AF6F68DF78CUL,
|
||||||
|
0x0D17E8FFFF0DE517UL, 0xBDDC0AD6D6BDB7DCUL, 0xB1C816DEDEB1A7C8UL, 0x54FC6D91915439FCUL,
|
||||||
|
0x50F090606050C0F0UL, 0x0305070202030405UL, 0xA9E02ECECEA987E0UL, 0x7D87D156567DAC87UL,
|
||||||
|
0x192BCCE7E719D52BUL, 0x62A613B5B56271A6UL, 0xE6317C4D4DE69A31UL, 0x9AB559ECEC9AC3B5UL,
|
||||||
|
0x45CF408F8F4505CFUL, 0x9DBCA31F1F9D3EBCUL, 0x40C04989894009C0UL, 0x879268FAFA87EF92UL,
|
||||||
|
0x153FD0EFEF15C53FUL, 0xEB2694B2B2EB7F26UL, 0xC940CE8E8EC90740UL, 0x0B1DE6FBFB0BED1DUL,
|
||||||
|
0xEC2F6E4141EC822FUL, 0x67A91AB3B3677DA9UL, 0xFD1C435F5FFDBE1CUL, 0xEA25604545EA8A25UL,
|
||||||
|
0xBFDAF92323BF46DAUL, 0xF702515353F7A602UL, 0x96A145E4E496D3A1UL, 0x5BED769B9B5B2DEDUL,
|
||||||
|
0xC25D287575C2EA5DUL, 0x1C24C5E1E11CD924UL, 0xAEE9D43D3DAE7AE9UL, 0x6ABEF24C4C6A98BEUL,
|
||||||
|
0x5AEE826C6C5AD8EEUL, 0x41C3BD7E7E41FCC3UL, 0x0206F3F5F502F106UL, 0x4FD15283834F1DD1UL,
|
||||||
|
0x5CE48C68685CD0E4UL, 0xF407565151F4A207UL, 0x345C8DD1D134B95CUL, 0x0818E1F9F908E918UL,
|
||||||
|
0x93AE4CE2E293DFAEUL, 0x73953EABAB734D95UL, 0x53F597626253C4F5UL, 0x3F416B2A2A3F5441UL,
|
||||||
|
0x0C141C08080C1014UL, 0x52F66395955231F6UL, 0x65AFE94646658CAFUL, 0x5EE27F9D9D5E21E2UL,
|
||||||
|
0x2878483030286078UL, 0xA1F8CF3737A16EF8UL, 0x0F111B0A0A0F1411UL, 0xB5C4EB2F2FB55EC4UL,
|
||||||
|
0x091B150E0E091C1BUL, 0x365A7E242436485AUL, 0x9BB6AD1B1B9B36B6UL, 0x3D4798DFDF3DA547UL,
|
||||||
|
0x266AA7CDCD26816AUL, 0x69BBF54E4E699CBBUL, 0xCD4C337F7FCDFE4CUL, 0x9FBA50EAEA9FCFBAUL,
|
||||||
|
0x1B2D3F12121B242DUL, 0x9EB9A41D1D9E3AB9UL, 0x749CC4585874B09CUL, 0x2E724634342E6872UL,
|
||||||
|
0x2D774136362D6C77UL, 0xB2CD11DCDCB2A3CDUL, 0xEE299DB4B4EE7329UL, 0xFB164D5B5BFBB616UL,
|
||||||
|
0xF601A5A4A4F65301UL, 0x4DD7A176764DECD7UL, 0x61A314B7B76175A3UL, 0xCE49347D7DCEFA49UL,
|
||||||
|
0x7B8DDF52527BA48DUL, 0x3E429FDDDD3EA142UL, 0x7193CD5E5E71BC93UL, 0x97A2B113139726A2UL,
|
||||||
|
0xF504A2A6A6F55704UL, 0x68B801B9B96869B8UL, 0x0000000000000000UL, 0x2C74B5C1C12C9974UL,
|
||||||
|
0x60A0E040406080A0UL, 0x1F21C2E3E31FDD21UL, 0xC8433A7979C8F243UL, 0xED2C9AB6B6ED772CUL,
|
||||||
|
0xBED90DD4D4BEB3D9UL, 0x46CA478D8D4601CAUL, 0xD970176767D9CE70UL, 0x4BDDAF72724BE4DDUL,
|
||||||
|
0xDE79ED9494DE3379UL, 0xD467FF9898D42B67UL, 0xE82393B0B0E87B23UL, 0x4ADE5B85854A11DEUL,
|
||||||
|
0x6BBD06BBBB6B6DBDUL, 0x2A7EBBC5C52A917EUL, 0xE5347B4F4FE59E34UL, 0x163AD7EDED16C13AUL,
|
||||||
|
0xC554D28686C51754UL, 0xD762F89A9AD72F62UL, 0x55FF99666655CCFFUL, 0x94A7B611119422A7UL,
|
||||||
|
0xCF4AC08A8ACF0F4AUL, 0x1030D9E9E910C930UL, 0x060A0E040406080AUL, 0x819866FEFE81E798UL,
|
||||||
|
0xF00BABA0A0F05B0BUL, 0x44CCB4787844F0CCUL, 0xBAD5F02525BA4AD5UL, 0xE33E754B4BE3963EUL,
|
||||||
|
0xF30EACA2A2F35F0EUL, 0xFE19445D5DFEBA19UL, 0xC05BDB8080C01B5BUL, 0x8A858005058A0A85UL,
|
||||||
|
0xADECD33F3FAD7EECUL, 0xBCDFFE2121BC42DFUL, 0x48D8A8707048E0D8UL, 0x040CFDF1F104F90CUL,
|
||||||
|
0xDF7A196363DFC67AUL, 0xC1582F7777C1EE58UL, 0x759F30AFAF75459FUL, 0x63A5E742426384A5UL,
|
||||||
|
0x3050702020304050UL, 0x1A2ECBE5E51AD12EUL, 0x0E12EFFDFD0EE112UL, 0x6DB708BFBF6D65B7UL,
|
||||||
|
0x4CD45581814C19D4UL, 0x143C24181814303CUL, 0x355F792626354C5FUL, 0x2F71B2C3C32F9D71UL,
|
||||||
|
0xE13886BEBEE16738UL, 0xA2FDC83535A26AFDUL, 0xCC4FC78888CC0B4FUL, 0x394B652E2E395C4BUL,
|
||||||
|
0x57F96A9393573DF9UL, 0xF20D585555F2AA0DUL, 0x829D61FCFC82E39DUL, 0x47C9B37A7A47F4C9UL,
|
||||||
|
0xACEF27C8C8AC8BEFUL, 0xE73288BABAE76F32UL, 0x2B7D4F32322B647DUL, 0x95A442E6E695D7A4UL,
|
||||||
|
0xA0FB3BC0C0A09BFBUL, 0x98B3AA19199832B3UL, 0xD168F69E9ED12768UL, 0x7F8122A3A37F5D81UL,
|
||||||
|
0x66AAEE44446688AAUL, 0x7E82D654547EA882UL, 0xABE6DD3B3BAB76E6UL, 0x839E950B0B83169EUL,
|
||||||
|
0xCA45C98C8CCA0345UL, 0x297BBCC7C729957BUL, 0xD36E056B6BD3D66EUL, 0x3C446C28283C5044UL,
|
||||||
|
0x798B2CA7A779558BUL, 0xE23D81BCBCE2633DUL, 0x1D273116161D2C27UL, 0x769A37ADAD76419AUL,
|
||||||
|
0x3B4D96DBDB3BAD4DUL, 0x56FA9E646456C8FAUL, 0x4ED2A674744EE8D2UL, 0x1E223614141E2822UL,
|
||||||
|
0xDB76E49292DB3F76UL, 0x0A1E120C0C0A181EUL, 0x6CB4FC48486C90B4UL, 0xE4378FB8B8E46B37UL,
|
||||||
|
0x5DE7789F9F5D25E7UL, 0x6EB20FBDBD6E61B2UL, 0xEF2A694343EF862AUL, 0xA6F135C4C4A693F1UL,
|
||||||
|
0xA8E3DA3939A872E3UL, 0xA4F7C63131A462F7UL, 0x37598AD3D337BD59UL, 0x8B8674F2F28BFF86UL,
|
||||||
|
0x325683D5D532B156UL, 0x43C54E8B8B430DC5UL, 0x59EB856E6E59DCEBUL, 0xB7C218DADAB7AFC2UL,
|
||||||
|
0x8C8F8E01018C028FUL, 0x64AC1DB1B16479ACUL, 0xD26DF19C9CD2236DUL, 0xE03B724949E0923BUL,
|
||||||
|
0xB4C71FD8D8B4ABC7UL, 0xFA15B9ACACFA4315UL, 0x0709FAF3F307FD09UL, 0x256FA0CFCF25856FUL,
|
||||||
|
0xAFEA20CACAAF8FEAUL, 0x8E897DF4F48EF389UL, 0xE920674747E98E20UL, 0x1828381010182028UL,
|
||||||
|
0xD5640B6F6FD5DE64UL, 0x888373F0F088FB83UL, 0x6FB1FB4A4A6F94B1UL, 0x7296CA5C5C72B896UL,
|
||||||
|
0x246C54383824706CUL, 0xF1085F5757F1AE08UL, 0xC752217373C7E652UL, 0x51F36497975135F3UL,
|
||||||
|
0x2365AECBCB238D65UL, 0x7C8425A1A17C5984UL, 0x9CBF57E8E89CCBBFUL, 0x21635D3E3E217C63UL,
|
||||||
|
0xDD7CEA9696DD377CUL, 0xDC7F1E6161DCC27FUL, 0x86919C0D0D861A91UL, 0x85949B0F0F851E94UL,
|
||||||
|
0x90AB4BE0E090DBABUL, 0x42C6BA7C7C42F8C6UL, 0xC457267171C4E257UL, 0xAAE529CCCCAA83E5UL,
|
||||||
|
0xD873E39090D83B73UL, 0x050F090606050C0FUL, 0x0103F4F7F701F503UL, 0x12362A1C1C123836UL,
|
||||||
|
0xA3FE3CC2C2A39FFEUL, 0x5FE18B6A6A5FD4E1UL, 0xF910BEAEAEF94710UL, 0xD06B026969D0D26BUL,
|
||||||
|
0x91A8BF1717912EA8UL, 0x58E87199995829E8UL, 0x2769533A3A277469UL, 0xB9D0F72727B94ED0UL,
|
||||||
|
0x384891D9D938A948UL, 0x1335DEEBEB13CD35UL, 0xB3CEE52B2BB356CEUL, 0x3355772222334455UL,
|
||||||
|
0xBBD604D2D2BBBFD6UL, 0x709039A9A9704990UL, 0x8980870707890E80UL, 0xA7F2C13333A766F2UL,
|
||||||
|
0xB6C1EC2D2DB65AC1UL, 0x22665A3C3C227866UL, 0x92ADB81515922AADUL, 0x2060A9C9C9208960UL,
|
||||||
|
0x49DB5C87874915DBUL, 0xFF1AB0AAAAFF4F1AUL, 0x7888D8505078A088UL, 0x7A8E2BA5A57A518EUL,
|
||||||
|
0x8F8A8903038F068AUL, 0xF8134A5959F8B213UL, 0x809B92090980129BUL, 0x1739231A1A173439UL,
|
||||||
|
0xDA75106565DACA75UL, 0x315384D7D731B553UL, 0xC651D58484C61351UL, 0xB8D303D0D0B8BBD3UL,
|
||||||
|
0xC35EDC8282C31F5EUL, 0xB0CBE22929B052CBUL, 0x7799C35A5A77B499UL, 0x11332D1E1E113C33UL,
|
||||||
|
0xCB463D7B7BCBF646UL, 0xFC1FB7A8A8FC4B1FUL, 0xD6610C6D6DD6DA61UL, 0x3A4E622C2C3A584EUL
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RSTT(d, a, b0, b1, b2, b3, b4, b5, b6, b7) do { \
|
||||||
|
t[d] = T0_G[B64_0(a[b0])] \
|
||||||
|
^ R64(T0_G[B64_1(a[b1])], 8) \
|
||||||
|
^ R64(T0_G[B64_2(a[b2])], 16) \
|
||||||
|
^ R64(T0_G[B64_3(a[b3])], 24) \
|
||||||
|
^ T4_G[B64_4(a[b4])] \
|
||||||
|
^ R64(T4_G[B64_5(a[b5])], 8) \
|
||||||
|
^ R64(T4_G[B64_6(a[b6])], 16) \
|
||||||
|
^ R64(T4_G[B64_7(a[b7])], 24); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define ROUND_SMALL_P(a, r) do { \
|
||||||
|
ulong t[8]; \
|
||||||
|
a[0] ^= PC64(0x00, r); \
|
||||||
|
a[1] ^= PC64(0x10, r); \
|
||||||
|
a[2] ^= PC64(0x20, r); \
|
||||||
|
a[3] ^= PC64(0x30, r); \
|
||||||
|
a[4] ^= PC64(0x40, r); \
|
||||||
|
a[5] ^= PC64(0x50, r); \
|
||||||
|
a[6] ^= PC64(0x60, r); \
|
||||||
|
a[7] ^= PC64(0x70, r); \
|
||||||
|
RSTT(0, a, 0, 1, 2, 3, 4, 5, 6, 7); \
|
||||||
|
RSTT(1, a, 1, 2, 3, 4, 5, 6, 7, 0); \
|
||||||
|
RSTT(2, a, 2, 3, 4, 5, 6, 7, 0, 1); \
|
||||||
|
RSTT(3, a, 3, 4, 5, 6, 7, 0, 1, 2); \
|
||||||
|
RSTT(4, a, 4, 5, 6, 7, 0, 1, 2, 3); \
|
||||||
|
RSTT(5, a, 5, 6, 7, 0, 1, 2, 3, 4); \
|
||||||
|
RSTT(6, a, 6, 7, 0, 1, 2, 3, 4, 5); \
|
||||||
|
RSTT(7, a, 7, 0, 1, 2, 3, 4, 5, 6); \
|
||||||
|
a[0] = t[0]; \
|
||||||
|
a[1] = t[1]; \
|
||||||
|
a[2] = t[2]; \
|
||||||
|
a[3] = t[3]; \
|
||||||
|
a[4] = t[4]; \
|
||||||
|
a[5] = t[5]; \
|
||||||
|
a[6] = t[6]; \
|
||||||
|
a[7] = t[7]; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define ROUND_SMALL_Pf(a,r) do { \
|
||||||
|
a[0] ^= PC64(0x00, r); \
|
||||||
|
a[1] ^= PC64(0x10, r); \
|
||||||
|
a[2] ^= PC64(0x20, r); \
|
||||||
|
a[3] ^= PC64(0x30, r); \
|
||||||
|
a[4] ^= PC64(0x40, r); \
|
||||||
|
a[5] ^= PC64(0x50, r); \
|
||||||
|
a[6] ^= PC64(0x60, r); \
|
||||||
|
a[7] ^= PC64(0x70, r); \
|
||||||
|
RSTT(7, a, 7, 0, 1, 2, 3, 4, 5, 6); \
|
||||||
|
a[7] = t[7]; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define ROUND_SMALL_Q(a, r) do { \
|
||||||
|
ulong t[8]; \
|
||||||
|
a[0] ^= QC64(0x00, r); \
|
||||||
|
a[1] ^= QC64(0x10, r); \
|
||||||
|
a[2] ^= QC64(0x20, r); \
|
||||||
|
a[3] ^= QC64(0x30, r); \
|
||||||
|
a[4] ^= QC64(0x40, r); \
|
||||||
|
a[5] ^= QC64(0x50, r); \
|
||||||
|
a[6] ^= QC64(0x60, r); \
|
||||||
|
a[7] ^= QC64(0x70, r); \
|
||||||
|
RSTT(0, a, 1, 3, 5, 7, 0, 2, 4, 6); \
|
||||||
|
RSTT(1, a, 2, 4, 6, 0, 1, 3, 5, 7); \
|
||||||
|
RSTT(2, a, 3, 5, 7, 1, 2, 4, 6, 0); \
|
||||||
|
RSTT(3, a, 4, 6, 0, 2, 3, 5, 7, 1); \
|
||||||
|
RSTT(4, a, 5, 7, 1, 3, 4, 6, 0, 2); \
|
||||||
|
RSTT(5, a, 6, 0, 2, 4, 5, 7, 1, 3); \
|
||||||
|
RSTT(6, a, 7, 1, 3, 5, 6, 0, 2, 4); \
|
||||||
|
RSTT(7, a, 0, 2, 4, 6, 7, 1, 3, 5); \
|
||||||
|
a[0] = t[0]; \
|
||||||
|
a[1] = t[1]; \
|
||||||
|
a[2] = t[2]; \
|
||||||
|
a[3] = t[3]; \
|
||||||
|
a[4] = t[4]; \
|
||||||
|
a[5] = t[5]; \
|
||||||
|
a[6] = t[6]; \
|
||||||
|
a[7] = t[7]; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define PERM_SMALL_P(a) do { \
|
||||||
|
for (int r = 0; r < 10; r ++) \
|
||||||
|
ROUND_SMALL_P(a, r); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define PERM_SMALL_Pf(a) do { \
|
||||||
|
for (int r = 0; r < 9; r ++) { \
|
||||||
|
ROUND_SMALL_P(a, r);} \
|
||||||
|
ROUND_SMALL_Pf(a,9); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define PERM_SMALL_Q(a) do { \
|
||||||
|
for (int r = 0; r < 10; r ++) \
|
||||||
|
ROUND_SMALL_Q(a, r); \
|
||||||
|
} while (0)
|
||||||
|
|
|
@ -0,0 +1,272 @@
|
||||||
|
/* $Id: jh.c 255 2011-06-07 19:50:20Z tp $ */
|
||||||
|
/*
|
||||||
|
* JH implementation.
|
||||||
|
*
|
||||||
|
* ==========================(LICENSE BEGIN)============================
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007-2010 Projet RNRT SAPHIR
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*
|
||||||
|
* ===========================(LICENSE END)=============================
|
||||||
|
*
|
||||||
|
* @author Thomas Pornin <thomas.pornin@cryptolog.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define SPH_JH_64 1
|
||||||
|
#define SPH_LITTLE_ENDIAN 1
|
||||||
|
|
||||||
|
#define SPH_C32(x) x
|
||||||
|
#define SPH_C64(x) x
|
||||||
|
typedef uint sph_u32;
|
||||||
|
typedef ulong sph_u64;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The internal bitslice representation may use either big-endian or
|
||||||
|
* little-endian (true bitslice operations do not care about the bit
|
||||||
|
* ordering, and the bit-swapping linear operations in JH happen to
|
||||||
|
* be invariant through endianness-swapping). The constants must be
|
||||||
|
* defined according to the chosen endianness; we use some
|
||||||
|
* byte-swapping macros for that.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if SPH_LITTLE_ENDIAN
|
||||||
|
|
||||||
|
#define C32e(x) ((SPH_C32(x) >> 24) \
|
||||||
|
| ((SPH_C32(x) >> 8) & SPH_C32(0x0000FF00)) \
|
||||||
|
| ((SPH_C32(x) << 8) & SPH_C32(0x00FF0000)) \
|
||||||
|
| ((SPH_C32(x) << 24) & SPH_C32(0xFF000000)))
|
||||||
|
#define dec32e_aligned sph_dec32le_aligned
|
||||||
|
#define enc32e sph_enc32le
|
||||||
|
|
||||||
|
#define C64e(x) ((SPH_C64(x) >> 56) \
|
||||||
|
| ((SPH_C64(x) >> 40) & SPH_C64(0x000000000000FF00)) \
|
||||||
|
| ((SPH_C64(x) >> 24) & SPH_C64(0x0000000000FF0000)) \
|
||||||
|
| ((SPH_C64(x) >> 8) & SPH_C64(0x00000000FF000000)) \
|
||||||
|
| ((SPH_C64(x) << 8) & SPH_C64(0x000000FF00000000)) \
|
||||||
|
| ((SPH_C64(x) << 24) & SPH_C64(0x0000FF0000000000)) \
|
||||||
|
| ((SPH_C64(x) << 40) & SPH_C64(0x00FF000000000000)) \
|
||||||
|
| ((SPH_C64(x) << 56) & SPH_C64(0xFF00000000000000)))
|
||||||
|
#define dec64e_aligned sph_dec64le_aligned
|
||||||
|
#define enc64e sph_enc64le
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define C32e(x) SPH_C32(x)
|
||||||
|
#define dec32e_aligned sph_dec32be_aligned
|
||||||
|
#define enc32e sph_enc32be
|
||||||
|
#define C64e(x) SPH_C64(x)
|
||||||
|
#define dec64e_aligned sph_dec64be_aligned
|
||||||
|
#define enc64e sph_enc64be
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define Sb(x0, x1, x2, x3, c) do { \
|
||||||
|
x3 = ~x3; \
|
||||||
|
x0 ^= (c) & ~x2; \
|
||||||
|
tmp = (c) ^ (x0 & x1); \
|
||||||
|
x0 ^= x2 & x3; \
|
||||||
|
x3 ^= ~x1 & x2; \
|
||||||
|
x1 ^= x0 & x2; \
|
||||||
|
x2 ^= x0 & ~x3; \
|
||||||
|
x0 ^= x1 | x3; \
|
||||||
|
x3 ^= x1 & x2; \
|
||||||
|
x1 ^= tmp & x0; \
|
||||||
|
x2 ^= tmp; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define Lb(x0, x1, x2, x3, x4, x5, x6, x7) do { \
|
||||||
|
x4 ^= x1; \
|
||||||
|
x5 ^= x2; \
|
||||||
|
x6 ^= x3 ^ x0; \
|
||||||
|
x7 ^= x0; \
|
||||||
|
x0 ^= x5; \
|
||||||
|
x1 ^= x6; \
|
||||||
|
x2 ^= x7 ^ x4; \
|
||||||
|
x3 ^= x4; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static const __constant ulong C[] =
|
||||||
|
{
|
||||||
|
0x67F815DFA2DED572UL, 0x571523B70A15847BUL, 0xF6875A4D90D6AB81UL, 0x402BD1C3C54F9F4EUL,
|
||||||
|
0x9CFA455CE03A98EAUL, 0x9A99B26699D2C503UL, 0x8A53BBF2B4960266UL, 0x31A2DB881A1456B5UL,
|
||||||
|
0xDB0E199A5C5AA303UL, 0x1044C1870AB23F40UL, 0x1D959E848019051CUL, 0xDCCDE75EADEB336FUL,
|
||||||
|
0x416BBF029213BA10UL, 0xD027BBF7156578DCUL, 0x5078AA3739812C0AUL, 0xD3910041D2BF1A3FUL,
|
||||||
|
0x907ECCF60D5A2D42UL, 0xCE97C0929C9F62DDUL, 0xAC442BC70BA75C18UL, 0x23FCC663D665DFD1UL,
|
||||||
|
0x1AB8E09E036C6E97UL, 0xA8EC6C447E450521UL, 0xFA618E5DBB03F1EEUL, 0x97818394B29796FDUL,
|
||||||
|
0x2F3003DB37858E4AUL, 0x956A9FFB2D8D672AUL, 0x6C69B8F88173FE8AUL, 0x14427FC04672C78AUL,
|
||||||
|
0xC45EC7BD8F15F4C5UL, 0x80BB118FA76F4475UL, 0xBC88E4AEB775DE52UL, 0xF4A3A6981E00B882UL,
|
||||||
|
0x1563A3A9338FF48EUL, 0x89F9B7D524565FAAUL, 0xFDE05A7C20EDF1B6UL, 0x362C42065AE9CA36UL,
|
||||||
|
0x3D98FE4E433529CEUL, 0xA74B9A7374F93A53UL, 0x86814E6F591FF5D0UL, 0x9F5AD8AF81AD9D0EUL,
|
||||||
|
0x6A6234EE670605A7UL, 0x2717B96EBE280B8BUL, 0x3F1080C626077447UL, 0x7B487EC66F7EA0E0UL,
|
||||||
|
0xC0A4F84AA50A550DUL, 0x9EF18E979FE7E391UL, 0xD48D605081727686UL, 0x62B0E5F3415A9E7EUL,
|
||||||
|
0x7A205440EC1F9FFCUL, 0x84C9F4CE001AE4E3UL, 0xD895FA9DF594D74FUL, 0xA554C324117E2E55UL,
|
||||||
|
0x286EFEBD2872DF5BUL, 0xB2C4A50FE27FF578UL, 0x2ED349EEEF7C8905UL, 0x7F5928EB85937E44UL,
|
||||||
|
0x4A3124B337695F70UL, 0x65E4D61DF128865EUL, 0xE720B95104771BC7UL, 0x8A87D423E843FE74UL,
|
||||||
|
0xF2947692A3E8297DUL, 0xC1D9309B097ACBDDUL, 0xE01BDC5BFB301B1DUL, 0xBF829CF24F4924DAUL,
|
||||||
|
0xFFBF70B431BAE7A4UL, 0x48BCF8DE0544320DUL, 0x39D3BB5332FCAE3BUL, 0xA08B29E0C1C39F45UL,
|
||||||
|
0x0F09AEF7FD05C9E5UL, 0x34F1904212347094UL, 0x95ED44E301B771A2UL, 0x4A982F4F368E3BE9UL,
|
||||||
|
0x15F66CA0631D4088UL, 0xFFAF52874B44C147UL, 0x30C60AE2F14ABB7EUL, 0xE68C6ECCC5B67046UL,
|
||||||
|
0x00CA4FBD56A4D5A4UL, 0xAE183EC84B849DDAUL, 0xADD1643045CE5773UL, 0x67255C1468CEA6E8UL,
|
||||||
|
0x16E10ECBF28CDAA3UL, 0x9A99949A5806E933UL, 0x7B846FC220B2601FUL, 0x1885D1A07FACCED1UL,
|
||||||
|
0xD319DD8DA15B5932UL, 0x46B4A5AAC01C9A50UL, 0xBA6B04E467633D9FUL, 0x7EEE560BAB19CAF6UL,
|
||||||
|
0x742128A9EA79B11FUL, 0xEE51363B35F7BDE9UL, 0x76D350755AAC571DUL, 0x01707DA3FEC2463AUL,
|
||||||
|
0x42D8A498AFC135F7UL, 0x79676B9E20ECED78UL, 0xA8DB3AEA15638341UL, 0x832C83324D3BC3FAUL,
|
||||||
|
0xF347271C1F3B40A7UL, 0x9A762DB734F04059UL, 0xFD4F21D26C4E3EE7UL, 0xEF5957DC398DFDB8UL,
|
||||||
|
0xDAEB492B490C9B8DUL, 0x0D70F36849D7A25BUL, 0x84558D7AD0AE3B7DUL, 0x658EF8E4F0E9A5F5UL,
|
||||||
|
0x533B1036F4A2B8A0UL, 0x5AEC3E759E07A80CUL, 0x4F88E85692946891UL, 0x4CBCBAF8555CB05BUL,
|
||||||
|
0x7B9487F3993BBBE3UL, 0x5D1C6B72D6F4DA75UL, 0x6DB334DC28ACAE64UL, 0x71DB28B850A5346CUL,
|
||||||
|
0x2A518D10F2E261F8UL, 0xFC75DD593364DBE3UL, 0xA23FCE43F1BCAC1CUL, 0xB043E8023CD1BB67UL,
|
||||||
|
0x75A12988CA5B0A33UL, 0x5C5316B44D19347FUL, 0x1E4D790EC3943B92UL, 0x3FAFEEB6D7757479UL,
|
||||||
|
0x21391ABEF7D4A8EAUL, 0x5127234C097EF45CUL, 0xD23C32BA5324A326UL, 0xADD5A66D4A17A344UL,
|
||||||
|
0x08C9F2AFA63E1DB5UL, 0x563C6B91983D5983UL, 0x4D608672A17CF84CUL, 0xF6C76E08CC3EE246UL,
|
||||||
|
0x5E76BCB1B333982FUL, 0x2AE6C4EFA566D62BUL, 0x36D4C1BEE8B6F406UL, 0x6321EFBC1582EE74UL,
|
||||||
|
0x69C953F40D4EC1FDUL, 0x26585806C45A7DA7UL, 0x16FAE0061614C17EUL, 0x3F9D63283DAF907EUL,
|
||||||
|
0x0CD29B00E3F2C9D2UL, 0x300CD4B730CEAA5FUL, 0x9832E0F216512A74UL, 0x9AF8CEE3D830EB0DUL,
|
||||||
|
0x9279F1B57B9EC54BUL, 0xD36886046EE651FFUL, 0x316796E6574D239BUL, 0x05750A17F3A6E6CCUL,
|
||||||
|
0xCE6C3213D98176B1UL, 0x62A205F88452173CUL, 0x47154778B3CB2BF4UL, 0x486A9323825446FFUL,
|
||||||
|
0x65655E4E0758DF38UL, 0x8E5086FC897CFCF2UL, 0x86CA0BD0442E7031UL, 0x4E477830A20940F0UL,
|
||||||
|
0x8338F7D139EEA065UL, 0xBD3A2CE437E95EF7UL, 0x6FF8130126B29721UL, 0xE7DE9FEFD1ED44A3UL,
|
||||||
|
0xD992257615DFA08BUL, 0xBE42DC12F6F7853CUL, 0x7EB027AB7CECA7D8UL, 0xDEA83EAADA7D8D53UL,
|
||||||
|
0xD86902BD93CE25AAUL, 0xF908731AFD43F65AUL, 0xA5194A17DAEF5FC0UL, 0x6A21FD4C33664D97UL,
|
||||||
|
0x701541DB3198B435UL, 0x9B54CDEDBB0F1EEAUL, 0x72409751A163D09AUL, 0xE26F4791BF9D75F6UL
|
||||||
|
};
|
||||||
|
|
||||||
|
#define Ceven_hi(r) (C[((r) << 2) + 0])
|
||||||
|
#define Ceven_lo(r) (C[((r) << 2) + 1])
|
||||||
|
#define Codd_hi(r) (C[((r) << 2) + 2])
|
||||||
|
#define Codd_lo(r) (C[((r) << 2) + 3])
|
||||||
|
|
||||||
|
#define S(x0, x1, x2, x3, cb, r) do { \
|
||||||
|
Sb(x0 ## h, x1 ## h, x2 ## h, x3 ## h, cb ## hi(r)); \
|
||||||
|
Sb(x0 ## l, x1 ## l, x2 ## l, x3 ## l, cb ## lo(r)); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define L(x0, x1, x2, x3, x4, x5, x6, x7) do { \
|
||||||
|
Lb(x0 ## h, x1 ## h, x2 ## h, x3 ## h, \
|
||||||
|
x4 ## h, x5 ## h, x6 ## h, x7 ## h); \
|
||||||
|
Lb(x0 ## l, x1 ## l, x2 ## l, x3 ## l, \
|
||||||
|
x4 ## l, x5 ## l, x6 ## l, x7 ## l); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define Wz(x, c, n) do { \
|
||||||
|
sph_u64 t = (x ## h & (c)) << (n); \
|
||||||
|
x ## h = ((x ## h >> (n)) & (c)) | t; \
|
||||||
|
t = (x ## l & (c)) << (n); \
|
||||||
|
x ## l = ((x ## l >> (n)) & (c)) | t; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define W0(x) Wz(x, SPH_C64(0x5555555555555555), 1)
|
||||||
|
#define W1(x) Wz(x, SPH_C64(0x3333333333333333), 2)
|
||||||
|
#define W2(x) Wz(x, SPH_C64(0x0F0F0F0F0F0F0F0F), 4)
|
||||||
|
#define W3(x) Wz(x, SPH_C64(0x00FF00FF00FF00FF), 8)
|
||||||
|
#define W4(x) Wz(x, SPH_C64(0x0000FFFF0000FFFF), 16)
|
||||||
|
#define W5(x) Wz(x, SPH_C64(0x00000000FFFFFFFF), 32)
|
||||||
|
#define W6(x) do { \
|
||||||
|
sph_u64 t = x ## h; \
|
||||||
|
x ## h = x ## l; \
|
||||||
|
x ## l = t; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define SL(ro) SLu(r + ro, ro)
|
||||||
|
|
||||||
|
#define SLu(r, ro) do { \
|
||||||
|
S(h0, h2, h4, h6, Ceven_, r); \
|
||||||
|
S(h1, h3, h5, h7, Codd_, r); \
|
||||||
|
L(h0, h2, h4, h6, h1, h3, h5, h7); \
|
||||||
|
W ## ro(h1); \
|
||||||
|
W ## ro(h3); \
|
||||||
|
W ## ro(h5); \
|
||||||
|
W ## ro(h7); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#if SPH_SMALL_FOOTPRINT_JH
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The "small footprint" 64-bit version just uses a partially unrolled
|
||||||
|
* loop.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define E8 do { \
|
||||||
|
unsigned r; \
|
||||||
|
for (r = 0; r < 42; r += 7) { \
|
||||||
|
SL(0); \
|
||||||
|
SL(1); \
|
||||||
|
SL(2); \
|
||||||
|
SL(3); \
|
||||||
|
SL(4); \
|
||||||
|
SL(5); \
|
||||||
|
SL(6); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On a "true 64-bit" architecture, we can unroll at will.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define E8 do { \
|
||||||
|
SLu( 0, 0); \
|
||||||
|
SLu( 1, 1); \
|
||||||
|
SLu( 2, 2); \
|
||||||
|
SLu( 3, 3); \
|
||||||
|
SLu( 4, 4); \
|
||||||
|
SLu( 5, 5); \
|
||||||
|
SLu( 6, 6); \
|
||||||
|
SLu( 7, 0); \
|
||||||
|
SLu( 8, 1); \
|
||||||
|
SLu( 9, 2); \
|
||||||
|
SLu(10, 3); \
|
||||||
|
SLu(11, 4); \
|
||||||
|
SLu(12, 5); \
|
||||||
|
SLu(13, 6); \
|
||||||
|
SLu(14, 0); \
|
||||||
|
SLu(15, 1); \
|
||||||
|
SLu(16, 2); \
|
||||||
|
SLu(17, 3); \
|
||||||
|
SLu(18, 4); \
|
||||||
|
SLu(19, 5); \
|
||||||
|
SLu(20, 6); \
|
||||||
|
SLu(21, 0); \
|
||||||
|
SLu(22, 1); \
|
||||||
|
SLu(23, 2); \
|
||||||
|
SLu(24, 3); \
|
||||||
|
SLu(25, 4); \
|
||||||
|
SLu(26, 5); \
|
||||||
|
SLu(27, 6); \
|
||||||
|
SLu(28, 0); \
|
||||||
|
SLu(29, 1); \
|
||||||
|
SLu(30, 2); \
|
||||||
|
SLu(31, 3); \
|
||||||
|
SLu(32, 4); \
|
||||||
|
SLu(33, 5); \
|
||||||
|
SLu(34, 6); \
|
||||||
|
SLu(35, 0); \
|
||||||
|
SLu(36, 1); \
|
||||||
|
SLu(37, 2); \
|
||||||
|
SLu(38, 3); \
|
||||||
|
SLu(39, 4); \
|
||||||
|
SLu(40, 5); \
|
||||||
|
SLu(41, 6); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,87 @@
|
||||||
|
#ifndef WOLF_AES_CL
|
||||||
|
#define WOLF_AES_CL
|
||||||
|
|
||||||
|
// AES table - the other three are generated on the fly
|
||||||
|
|
||||||
|
static const __constant uint AES0_C[256] =
|
||||||
|
{
|
||||||
|
0xA56363C6U, 0x847C7CF8U, 0x997777EEU, 0x8D7B7BF6U,
|
||||||
|
0x0DF2F2FFU, 0xBD6B6BD6U, 0xB16F6FDEU, 0x54C5C591U,
|
||||||
|
0x50303060U, 0x03010102U, 0xA96767CEU, 0x7D2B2B56U,
|
||||||
|
0x19FEFEE7U, 0x62D7D7B5U, 0xE6ABAB4DU, 0x9A7676ECU,
|
||||||
|
0x45CACA8FU, 0x9D82821FU, 0x40C9C989U, 0x877D7DFAU,
|
||||||
|
0x15FAFAEFU, 0xEB5959B2U, 0xC947478EU, 0x0BF0F0FBU,
|
||||||
|
0xECADAD41U, 0x67D4D4B3U, 0xFDA2A25FU, 0xEAAFAF45U,
|
||||||
|
0xBF9C9C23U, 0xF7A4A453U, 0x967272E4U, 0x5BC0C09BU,
|
||||||
|
0xC2B7B775U, 0x1CFDFDE1U, 0xAE93933DU, 0x6A26264CU,
|
||||||
|
0x5A36366CU, 0x413F3F7EU, 0x02F7F7F5U, 0x4FCCCC83U,
|
||||||
|
0x5C343468U, 0xF4A5A551U, 0x34E5E5D1U, 0x08F1F1F9U,
|
||||||
|
0x937171E2U, 0x73D8D8ABU, 0x53313162U, 0x3F15152AU,
|
||||||
|
0x0C040408U, 0x52C7C795U, 0x65232346U, 0x5EC3C39DU,
|
||||||
|
0x28181830U, 0xA1969637U, 0x0F05050AU, 0xB59A9A2FU,
|
||||||
|
0x0907070EU, 0x36121224U, 0x9B80801BU, 0x3DE2E2DFU,
|
||||||
|
0x26EBEBCDU, 0x6927274EU, 0xCDB2B27FU, 0x9F7575EAU,
|
||||||
|
0x1B090912U, 0x9E83831DU, 0x742C2C58U, 0x2E1A1A34U,
|
||||||
|
0x2D1B1B36U, 0xB26E6EDCU, 0xEE5A5AB4U, 0xFBA0A05BU,
|
||||||
|
0xF65252A4U, 0x4D3B3B76U, 0x61D6D6B7U, 0xCEB3B37DU,
|
||||||
|
0x7B292952U, 0x3EE3E3DDU, 0x712F2F5EU, 0x97848413U,
|
||||||
|
0xF55353A6U, 0x68D1D1B9U, 0x00000000U, 0x2CEDEDC1U,
|
||||||
|
0x60202040U, 0x1FFCFCE3U, 0xC8B1B179U, 0xED5B5BB6U,
|
||||||
|
0xBE6A6AD4U, 0x46CBCB8DU, 0xD9BEBE67U, 0x4B393972U,
|
||||||
|
0xDE4A4A94U, 0xD44C4C98U, 0xE85858B0U, 0x4ACFCF85U,
|
||||||
|
0x6BD0D0BBU, 0x2AEFEFC5U, 0xE5AAAA4FU, 0x16FBFBEDU,
|
||||||
|
0xC5434386U, 0xD74D4D9AU, 0x55333366U, 0x94858511U,
|
||||||
|
0xCF45458AU, 0x10F9F9E9U, 0x06020204U, 0x817F7FFEU,
|
||||||
|
0xF05050A0U, 0x443C3C78U, 0xBA9F9F25U, 0xE3A8A84BU,
|
||||||
|
0xF35151A2U, 0xFEA3A35DU, 0xC0404080U, 0x8A8F8F05U,
|
||||||
|
0xAD92923FU, 0xBC9D9D21U, 0x48383870U, 0x04F5F5F1U,
|
||||||
|
0xDFBCBC63U, 0xC1B6B677U, 0x75DADAAFU, 0x63212142U,
|
||||||
|
0x30101020U, 0x1AFFFFE5U, 0x0EF3F3FDU, 0x6DD2D2BFU,
|
||||||
|
0x4CCDCD81U, 0x140C0C18U, 0x35131326U, 0x2FECECC3U,
|
||||||
|
0xE15F5FBEU, 0xA2979735U, 0xCC444488U, 0x3917172EU,
|
||||||
|
0x57C4C493U, 0xF2A7A755U, 0x827E7EFCU, 0x473D3D7AU,
|
||||||
|
0xAC6464C8U, 0xE75D5DBAU, 0x2B191932U, 0x957373E6U,
|
||||||
|
0xA06060C0U, 0x98818119U, 0xD14F4F9EU, 0x7FDCDCA3U,
|
||||||
|
0x66222244U, 0x7E2A2A54U, 0xAB90903BU, 0x8388880BU,
|
||||||
|
0xCA46468CU, 0x29EEEEC7U, 0xD3B8B86BU, 0x3C141428U,
|
||||||
|
0x79DEDEA7U, 0xE25E5EBCU, 0x1D0B0B16U, 0x76DBDBADU,
|
||||||
|
0x3BE0E0DBU, 0x56323264U, 0x4E3A3A74U, 0x1E0A0A14U,
|
||||||
|
0xDB494992U, 0x0A06060CU, 0x6C242448U, 0xE45C5CB8U,
|
||||||
|
0x5DC2C29FU, 0x6ED3D3BDU, 0xEFACAC43U, 0xA66262C4U,
|
||||||
|
0xA8919139U, 0xA4959531U, 0x37E4E4D3U, 0x8B7979F2U,
|
||||||
|
0x32E7E7D5U, 0x43C8C88BU, 0x5937376EU, 0xB76D6DDAU,
|
||||||
|
0x8C8D8D01U, 0x64D5D5B1U, 0xD24E4E9CU, 0xE0A9A949U,
|
||||||
|
0xB46C6CD8U, 0xFA5656ACU, 0x07F4F4F3U, 0x25EAEACFU,
|
||||||
|
0xAF6565CAU, 0x8E7A7AF4U, 0xE9AEAE47U, 0x18080810U,
|
||||||
|
0xD5BABA6FU, 0x887878F0U, 0x6F25254AU, 0x722E2E5CU,
|
||||||
|
0x241C1C38U, 0xF1A6A657U, 0xC7B4B473U, 0x51C6C697U,
|
||||||
|
0x23E8E8CBU, 0x7CDDDDA1U, 0x9C7474E8U, 0x211F1F3EU,
|
||||||
|
0xDD4B4B96U, 0xDCBDBD61U, 0x868B8B0DU, 0x858A8A0FU,
|
||||||
|
0x907070E0U, 0x423E3E7CU, 0xC4B5B571U, 0xAA6666CCU,
|
||||||
|
0xD8484890U, 0x05030306U, 0x01F6F6F7U, 0x120E0E1CU,
|
||||||
|
0xA36161C2U, 0x5F35356AU, 0xF95757AEU, 0xD0B9B969U,
|
||||||
|
0x91868617U, 0x58C1C199U, 0x271D1D3AU, 0xB99E9E27U,
|
||||||
|
0x38E1E1D9U, 0x13F8F8EBU, 0xB398982BU, 0x33111122U,
|
||||||
|
0xBB6969D2U, 0x70D9D9A9U, 0x898E8E07U, 0xA7949433U,
|
||||||
|
0xB69B9B2DU, 0x221E1E3CU, 0x92878715U, 0x20E9E9C9U,
|
||||||
|
0x49CECE87U, 0xFF5555AAU, 0x78282850U, 0x7ADFDFA5U,
|
||||||
|
0x8F8C8C03U, 0xF8A1A159U, 0x80898909U, 0x170D0D1AU,
|
||||||
|
0xDABFBF65U, 0x31E6E6D7U, 0xC6424284U, 0xB86868D0U,
|
||||||
|
0xC3414182U, 0xB0999929U, 0x772D2D5AU, 0x110F0F1EU,
|
||||||
|
0xCBB0B07BU, 0xFC5454A8U, 0xD6BBBB6DU, 0x3A16162CU
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BYTE(x, y) (amd_bfe((x), (y) << 3U, 8U))
|
||||||
|
|
||||||
|
uint4 AES_Round(const __local uint *AES0, const __local uint *AES1, const __local uint *AES2, const __local uint *AES3, const uint4 X, const uint4 key)
|
||||||
|
{
|
||||||
|
uint4 Y;
|
||||||
|
Y.s0 = AES0[BYTE(X.s0, 0)] ^ AES1[BYTE(X.s1, 1)] ^ AES2[BYTE(X.s2, 2)] ^ AES3[BYTE(X.s3, 3)];
|
||||||
|
Y.s1 = AES0[BYTE(X.s1, 0)] ^ AES1[BYTE(X.s2, 1)] ^ AES2[BYTE(X.s3, 2)] ^ AES3[BYTE(X.s0, 3)];
|
||||||
|
Y.s2 = AES0[BYTE(X.s2, 0)] ^ AES1[BYTE(X.s3, 1)] ^ AES2[BYTE(X.s0, 2)] ^ AES3[BYTE(X.s1, 3)];
|
||||||
|
Y.s3 = AES0[BYTE(X.s3, 0)] ^ AES1[BYTE(X.s0, 1)] ^ AES2[BYTE(X.s1, 2)] ^ AES3[BYTE(X.s2, 3)];
|
||||||
|
Y ^= key;
|
||||||
|
return(Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,111 @@
|
||||||
|
#ifndef WOLF_SKEIN_CL
|
||||||
|
#define WOLF_SKEIN_CL
|
||||||
|
|
||||||
|
// Vectorized Skein implementation macros and functions by Wolf
|
||||||
|
|
||||||
|
#define SKEIN_KS_PARITY 0x1BD11BDAA9FC1A22
|
||||||
|
|
||||||
|
static const __constant ulong SKEIN256_IV[8] =
|
||||||
|
{
|
||||||
|
0xCCD044A12FDB3E13UL, 0xE83590301A79A9EBUL,
|
||||||
|
0x55AEA0614F816E6FUL, 0x2A2767A4AE9B94DBUL,
|
||||||
|
0xEC06025E74DD7683UL, 0xE7A436CDC4746251UL,
|
||||||
|
0xC36FBAF9393AD185UL, 0x3EEDBA1833EDFC13UL
|
||||||
|
};
|
||||||
|
|
||||||
|
static const __constant ulong SKEIN512_256_IV[8] =
|
||||||
|
{
|
||||||
|
0xCCD044A12FDB3E13UL, 0xE83590301A79A9EBUL,
|
||||||
|
0x55AEA0614F816E6FUL, 0x2A2767A4AE9B94DBUL,
|
||||||
|
0xEC06025E74DD7683UL, 0xE7A436CDC4746251UL,
|
||||||
|
0xC36FBAF9393AD185UL, 0x3EEDBA1833EDFC13UL
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SKEIN_INJECT_KEY(p, s) do { \
|
||||||
|
p += h; \
|
||||||
|
p.s5 += t[s % 3]; \
|
||||||
|
p.s6 += t[(s + 1) % 3]; \
|
||||||
|
p.s7 += s; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
ulong SKEIN_ROT(const uint2 x, const uint y)
|
||||||
|
{
|
||||||
|
if(y < 32) return(as_ulong(amd_bitalign(x, x.s10, 32 - y)));
|
||||||
|
else return(as_ulong(amd_bitalign(x.s10, x, 32 - (y - 32))));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SkeinMix8(ulong4 *pv0, ulong4 *pv1, const uint rc0, const uint rc1, const uint rc2, const uint rc3)
|
||||||
|
{
|
||||||
|
*pv0 += *pv1;
|
||||||
|
(*pv1).s0 = SKEIN_ROT(as_uint2((*pv1).s0), rc0);
|
||||||
|
(*pv1).s1 = SKEIN_ROT(as_uint2((*pv1).s1), rc1);
|
||||||
|
(*pv1).s2 = SKEIN_ROT(as_uint2((*pv1).s2), rc2);
|
||||||
|
(*pv1).s3 = SKEIN_ROT(as_uint2((*pv1).s3), rc3);
|
||||||
|
*pv1 ^= *pv0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong8 SkeinEvenRound(ulong8 p, const ulong8 h, const ulong *t, const uint s)
|
||||||
|
{
|
||||||
|
SKEIN_INJECT_KEY(p, s);
|
||||||
|
ulong4 pv0 = p.even, pv1 = p.odd;
|
||||||
|
|
||||||
|
SkeinMix8(&pv0, &pv1, 46, 36, 19, 37);
|
||||||
|
pv0 = shuffle(pv0, (ulong4)(1, 2, 3, 0));
|
||||||
|
pv1 = shuffle(pv1, (ulong4)(0, 3, 2, 1));
|
||||||
|
|
||||||
|
SkeinMix8(&pv0, &pv1, 33, 27, 14, 42);
|
||||||
|
pv0 = shuffle(pv0, (ulong4)(1, 2, 3, 0));
|
||||||
|
pv1 = shuffle(pv1, (ulong4)(0, 3, 2, 1));
|
||||||
|
|
||||||
|
SkeinMix8(&pv0, &pv1, 17, 49, 36, 39);
|
||||||
|
pv0 = shuffle(pv0, (ulong4)(1, 2, 3, 0));
|
||||||
|
pv1 = shuffle(pv1, (ulong4)(0, 3, 2, 1));
|
||||||
|
|
||||||
|
SkeinMix8(&pv0, &pv1, 44, 9, 54, 56);
|
||||||
|
return(shuffle2(pv0, pv1, (ulong8)(1, 4, 2, 7, 3, 6, 0, 5)));
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong8 SkeinOddRound(ulong8 p, const ulong8 h, const ulong *t, const uint s)
|
||||||
|
{
|
||||||
|
SKEIN_INJECT_KEY(p, s);
|
||||||
|
ulong4 pv0 = p.even, pv1 = p.odd;
|
||||||
|
|
||||||
|
SkeinMix8(&pv0, &pv1, 39, 30, 34, 24);
|
||||||
|
pv0 = shuffle(pv0, (ulong4)(1, 2, 3, 0));
|
||||||
|
pv1 = shuffle(pv1, (ulong4)(0, 3, 2, 1));
|
||||||
|
|
||||||
|
SkeinMix8(&pv0, &pv1, 13, 50, 10, 17);
|
||||||
|
pv0 = shuffle(pv0, (ulong4)(1, 2, 3, 0));
|
||||||
|
pv1 = shuffle(pv1, (ulong4)(0, 3, 2, 1));
|
||||||
|
|
||||||
|
SkeinMix8(&pv0, &pv1, 25, 29, 39, 43);
|
||||||
|
pv0 = shuffle(pv0, (ulong4)(1, 2, 3, 0));
|
||||||
|
pv1 = shuffle(pv1, (ulong4)(0, 3, 2, 1));
|
||||||
|
|
||||||
|
SkeinMix8(&pv0, &pv1, 8, 35, 56, 22);
|
||||||
|
return(shuffle2(pv0, pv1, (ulong8)(1, 4, 2, 7, 3, 6, 0, 5)));
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong8 Skein512Block(ulong8 p, ulong8 h, ulong h8, const ulong *t)
|
||||||
|
{
|
||||||
|
#pragma unroll
|
||||||
|
for(int i = 0; i < 18; ++i)
|
||||||
|
{
|
||||||
|
p = SkeinEvenRound(p, h, t, i);
|
||||||
|
++i;
|
||||||
|
ulong tmp = h.s0;
|
||||||
|
h = shuffle(h, (ulong8)(1, 2, 3, 4, 5, 6, 7, 0));
|
||||||
|
h.s7 = h8;
|
||||||
|
h8 = tmp;
|
||||||
|
p = SkeinOddRound(p, h, t, i);
|
||||||
|
tmp = h.s0;
|
||||||
|
h = shuffle(h, (ulong8)(1, 2, 3, 4, 5, 6, 7, 0));
|
||||||
|
h.s7 = h8;
|
||||||
|
h8 = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
SKEIN_INJECT_KEY(p, 18);
|
||||||
|
return(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,271 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ALLOCATORS_H_
|
||||||
|
#define RAPIDJSON_ALLOCATORS_H_
|
||||||
|
|
||||||
|
#include "rapidjson.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Allocator
|
||||||
|
|
||||||
|
/*! \class rapidjson::Allocator
|
||||||
|
\brief Concept for allocating, resizing and freeing memory block.
|
||||||
|
|
||||||
|
Note that Malloc() and Realloc() are non-static but Free() is static.
|
||||||
|
|
||||||
|
So if an allocator need to support Free(), it needs to put its pointer in
|
||||||
|
the header of memory block.
|
||||||
|
|
||||||
|
\code
|
||||||
|
concept Allocator {
|
||||||
|
static const bool kNeedFree; //!< Whether this allocator needs to call Free().
|
||||||
|
|
||||||
|
// Allocate a memory block.
|
||||||
|
// \param size of the memory block in bytes.
|
||||||
|
// \returns pointer to the memory block.
|
||||||
|
void* Malloc(size_t size);
|
||||||
|
|
||||||
|
// Resize a memory block.
|
||||||
|
// \param originalPtr The pointer to current memory block. Null pointer is permitted.
|
||||||
|
// \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
|
||||||
|
// \param newSize the new size in bytes.
|
||||||
|
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
|
||||||
|
|
||||||
|
// Free a memory block.
|
||||||
|
// \param pointer to the memory block. Null pointer is permitted.
|
||||||
|
static void Free(void *ptr);
|
||||||
|
};
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// CrtAllocator
|
||||||
|
|
||||||
|
//! C-runtime library allocator.
|
||||||
|
/*! This class is just wrapper for standard C library memory routines.
|
||||||
|
\note implements Allocator concept
|
||||||
|
*/
|
||||||
|
class CrtAllocator {
|
||||||
|
public:
|
||||||
|
static const bool kNeedFree = true;
|
||||||
|
void* Malloc(size_t size) {
|
||||||
|
if (size) // behavior of malloc(0) is implementation defined.
|
||||||
|
return std::malloc(size);
|
||||||
|
else
|
||||||
|
return NULL; // standardize to returning NULL.
|
||||||
|
}
|
||||||
|
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
||||||
|
(void)originalSize;
|
||||||
|
if (newSize == 0) {
|
||||||
|
std::free(originalPtr);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return std::realloc(originalPtr, newSize);
|
||||||
|
}
|
||||||
|
static void Free(void *ptr) { std::free(ptr); }
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// MemoryPoolAllocator
|
||||||
|
|
||||||
|
//! Default memory allocator used by the parser and DOM.
|
||||||
|
/*! This allocator allocate memory blocks from pre-allocated memory chunks.
|
||||||
|
|
||||||
|
It does not free memory blocks. And Realloc() only allocate new memory.
|
||||||
|
|
||||||
|
The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
|
||||||
|
|
||||||
|
User may also supply a buffer as the first chunk.
|
||||||
|
|
||||||
|
If the user-buffer is full then additional chunks are allocated by BaseAllocator.
|
||||||
|
|
||||||
|
The user-buffer is not deallocated by this allocator.
|
||||||
|
|
||||||
|
\tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
|
||||||
|
\note implements Allocator concept
|
||||||
|
*/
|
||||||
|
template <typename BaseAllocator = CrtAllocator>
|
||||||
|
class MemoryPoolAllocator {
|
||||||
|
public:
|
||||||
|
static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
|
||||||
|
|
||||||
|
//! Constructor with chunkSize.
|
||||||
|
/*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||||
|
\param baseAllocator The allocator for allocating memory chunks.
|
||||||
|
*/
|
||||||
|
MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||||
|
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Constructor with user-supplied buffer.
|
||||||
|
/*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
|
||||||
|
|
||||||
|
The user buffer will not be deallocated when this allocator is destructed.
|
||||||
|
|
||||||
|
\param buffer User supplied buffer.
|
||||||
|
\param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
|
||||||
|
\param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
|
||||||
|
\param baseAllocator The allocator for allocating memory chunks.
|
||||||
|
*/
|
||||||
|
MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
|
||||||
|
chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
|
||||||
|
{
|
||||||
|
RAPIDJSON_ASSERT(buffer != 0);
|
||||||
|
RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
|
||||||
|
chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
|
||||||
|
chunkHead_->capacity = size - sizeof(ChunkHeader);
|
||||||
|
chunkHead_->size = 0;
|
||||||
|
chunkHead_->next = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Destructor.
|
||||||
|
/*! This deallocates all memory chunks, excluding the user-supplied buffer.
|
||||||
|
*/
|
||||||
|
~MemoryPoolAllocator() {
|
||||||
|
Clear();
|
||||||
|
RAPIDJSON_DELETE(ownBaseAllocator_);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Deallocates all memory chunks, excluding the user-supplied buffer.
|
||||||
|
void Clear() {
|
||||||
|
while (chunkHead_ && chunkHead_ != userBuffer_) {
|
||||||
|
ChunkHeader* next = chunkHead_->next;
|
||||||
|
baseAllocator_->Free(chunkHead_);
|
||||||
|
chunkHead_ = next;
|
||||||
|
}
|
||||||
|
if (chunkHead_ && chunkHead_ == userBuffer_)
|
||||||
|
chunkHead_->size = 0; // Clear user buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Computes the total capacity of allocated memory chunks.
|
||||||
|
/*! \return total capacity in bytes.
|
||||||
|
*/
|
||||||
|
size_t Capacity() const {
|
||||||
|
size_t capacity = 0;
|
||||||
|
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||||
|
capacity += c->capacity;
|
||||||
|
return capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Computes the memory blocks allocated.
|
||||||
|
/*! \return total used bytes.
|
||||||
|
*/
|
||||||
|
size_t Size() const {
|
||||||
|
size_t size = 0;
|
||||||
|
for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
|
||||||
|
size += c->size;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Allocates a memory block. (concept Allocator)
|
||||||
|
void* Malloc(size_t size) {
|
||||||
|
if (!size)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
size = RAPIDJSON_ALIGN(size);
|
||||||
|
if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
|
||||||
|
if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
|
||||||
|
chunkHead_->size += size;
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Resizes a memory block (concept Allocator)
|
||||||
|
void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
|
||||||
|
if (originalPtr == 0)
|
||||||
|
return Malloc(newSize);
|
||||||
|
|
||||||
|
if (newSize == 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
originalSize = RAPIDJSON_ALIGN(originalSize);
|
||||||
|
newSize = RAPIDJSON_ALIGN(newSize);
|
||||||
|
|
||||||
|
// Do not shrink if new size is smaller than original
|
||||||
|
if (originalSize >= newSize)
|
||||||
|
return originalPtr;
|
||||||
|
|
||||||
|
// Simply expand it if it is the last allocation and there is sufficient space
|
||||||
|
if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
|
||||||
|
size_t increment = static_cast<size_t>(newSize - originalSize);
|
||||||
|
if (chunkHead_->size + increment <= chunkHead_->capacity) {
|
||||||
|
chunkHead_->size += increment;
|
||||||
|
return originalPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Realloc process: allocate and copy memory, do not free original buffer.
|
||||||
|
if (void* newBuffer = Malloc(newSize)) {
|
||||||
|
if (originalSize)
|
||||||
|
std::memcpy(newBuffer, originalPtr, originalSize);
|
||||||
|
return newBuffer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Frees a memory block (concept Allocator)
|
||||||
|
static void Free(void *ptr) { (void)ptr; } // Do nothing
|
||||||
|
|
||||||
|
private:
|
||||||
|
//! Copy constructor is not permitted.
|
||||||
|
MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||||
|
//! Copy assignment operator is not permitted.
|
||||||
|
MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
|
||||||
|
|
||||||
|
//! Creates a new chunk.
|
||||||
|
/*! \param capacity Capacity of the chunk in bytes.
|
||||||
|
\return true if success.
|
||||||
|
*/
|
||||||
|
bool AddChunk(size_t capacity) {
|
||||||
|
if (!baseAllocator_)
|
||||||
|
ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
|
||||||
|
if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
|
||||||
|
chunk->capacity = capacity;
|
||||||
|
chunk->size = 0;
|
||||||
|
chunk->next = chunkHead_;
|
||||||
|
chunkHead_ = chunk;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
|
||||||
|
|
||||||
|
//! Chunk header for perpending to each chunk.
|
||||||
|
/*! Chunks are stored as a singly linked list.
|
||||||
|
*/
|
||||||
|
struct ChunkHeader {
|
||||||
|
size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself).
|
||||||
|
size_t size; //!< Current size of allocated memory in bytes.
|
||||||
|
ChunkHeader *next; //!< Next chunk in the linked list.
|
||||||
|
};
|
||||||
|
|
||||||
|
ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation.
|
||||||
|
size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated.
|
||||||
|
void *userBuffer_; //!< User supplied buffer.
|
||||||
|
BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks.
|
||||||
|
BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object.
|
||||||
|
};
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ENCODINGS_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,299 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ENCODEDSTREAM_H_
|
||||||
|
#define RAPIDJSON_ENCODEDSTREAM_H_
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
#include "memorystream.h"
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Input byte stream wrapper with a statically bound encoding.
|
||||||
|
/*!
|
||||||
|
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
|
||||||
|
\tparam InputByteStream Type of input byte stream. For example, FileReadStream.
|
||||||
|
*/
|
||||||
|
template <typename Encoding, typename InputByteStream>
|
||||||
|
class EncodedInputStream {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
public:
|
||||||
|
typedef typename Encoding::Ch Ch;
|
||||||
|
|
||||||
|
EncodedInputStream(InputByteStream& is) : is_(is) {
|
||||||
|
current_ = Encoding::TakeBOM(is_);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ch Peek() const { return current_; }
|
||||||
|
Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
|
||||||
|
size_t Tell() const { return is_.Tell(); }
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||||
|
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
EncodedInputStream(const EncodedInputStream&);
|
||||||
|
EncodedInputStream& operator=(const EncodedInputStream&);
|
||||||
|
|
||||||
|
InputByteStream& is_;
|
||||||
|
Ch current_;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Specialized for UTF8 MemoryStream.
|
||||||
|
template <>
|
||||||
|
class EncodedInputStream<UTF8<>, MemoryStream> {
|
||||||
|
public:
|
||||||
|
typedef UTF8<>::Ch Ch;
|
||||||
|
|
||||||
|
EncodedInputStream(MemoryStream& is) : is_(is) {
|
||||||
|
if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();
|
||||||
|
if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();
|
||||||
|
if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();
|
||||||
|
}
|
||||||
|
Ch Peek() const { return is_.Peek(); }
|
||||||
|
Ch Take() { return is_.Take(); }
|
||||||
|
size_t Tell() const { return is_.Tell(); }
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
void Put(Ch) {}
|
||||||
|
void Flush() {}
|
||||||
|
Ch* PutBegin() { return 0; }
|
||||||
|
size_t PutEnd(Ch*) { return 0; }
|
||||||
|
|
||||||
|
MemoryStream& is_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
EncodedInputStream(const EncodedInputStream&);
|
||||||
|
EncodedInputStream& operator=(const EncodedInputStream&);
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Output byte stream wrapper with statically bound encoding.
|
||||||
|
/*!
|
||||||
|
\tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
|
||||||
|
\tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
|
||||||
|
*/
|
||||||
|
template <typename Encoding, typename OutputByteStream>
|
||||||
|
class EncodedOutputStream {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
public:
|
||||||
|
typedef typename Encoding::Ch Ch;
|
||||||
|
|
||||||
|
EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) {
|
||||||
|
if (putBOM)
|
||||||
|
Encoding::PutBOM(os_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Put(Ch c) { Encoding::Put(os_, c); }
|
||||||
|
void Flush() { os_.Flush(); }
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
|
||||||
|
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
|
||||||
|
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
EncodedOutputStream(const EncodedOutputStream&);
|
||||||
|
EncodedOutputStream& operator=(const EncodedOutputStream&);
|
||||||
|
|
||||||
|
OutputByteStream& os_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
|
||||||
|
|
||||||
|
//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
|
||||||
|
/*!
|
||||||
|
\tparam CharType Type of character for reading.
|
||||||
|
\tparam InputByteStream type of input byte stream to be wrapped.
|
||||||
|
*/
|
||||||
|
template <typename CharType, typename InputByteStream>
|
||||||
|
class AutoUTFInputStream {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
public:
|
||||||
|
typedef CharType Ch;
|
||||||
|
|
||||||
|
//! Constructor.
|
||||||
|
/*!
|
||||||
|
\param is input stream to be wrapped.
|
||||||
|
\param type UTF encoding type if it is not detected from the stream.
|
||||||
|
*/
|
||||||
|
AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
|
||||||
|
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
|
||||||
|
DetectType();
|
||||||
|
static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
|
||||||
|
takeFunc_ = f[type_];
|
||||||
|
current_ = takeFunc_(*is_);
|
||||||
|
}
|
||||||
|
|
||||||
|
UTFType GetType() const { return type_; }
|
||||||
|
bool HasBOM() const { return hasBOM_; }
|
||||||
|
|
||||||
|
Ch Peek() const { return current_; }
|
||||||
|
Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
|
||||||
|
size_t Tell() const { return is_->Tell(); }
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||||
|
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
AutoUTFInputStream(const AutoUTFInputStream&);
|
||||||
|
AutoUTFInputStream& operator=(const AutoUTFInputStream&);
|
||||||
|
|
||||||
|
// Detect encoding type with BOM or RFC 4627
|
||||||
|
void DetectType() {
|
||||||
|
// BOM (Byte Order Mark):
|
||||||
|
// 00 00 FE FF UTF-32BE
|
||||||
|
// FF FE 00 00 UTF-32LE
|
||||||
|
// FE FF UTF-16BE
|
||||||
|
// FF FE UTF-16LE
|
||||||
|
// EF BB BF UTF-8
|
||||||
|
|
||||||
|
const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());
|
||||||
|
if (!c)
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
|
||||||
|
hasBOM_ = false;
|
||||||
|
if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||||
|
else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
|
||||||
|
else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||||
|
else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); }
|
||||||
|
else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); }
|
||||||
|
|
||||||
|
// RFC 4627: Section 3
|
||||||
|
// "Since the first two characters of a JSON text will always be ASCII
|
||||||
|
// characters [RFC0020], it is possible to determine whether an octet
|
||||||
|
// stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
|
||||||
|
// at the pattern of nulls in the first four octets."
|
||||||
|
// 00 00 00 xx UTF-32BE
|
||||||
|
// 00 xx 00 xx UTF-16BE
|
||||||
|
// xx 00 00 00 UTF-32LE
|
||||||
|
// xx 00 xx 00 UTF-16LE
|
||||||
|
// xx xx xx xx UTF-8
|
||||||
|
|
||||||
|
if (!hasBOM_) {
|
||||||
|
unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
|
||||||
|
switch (pattern) {
|
||||||
|
case 0x08: type_ = kUTF32BE; break;
|
||||||
|
case 0x0A: type_ = kUTF16BE; break;
|
||||||
|
case 0x01: type_ = kUTF32LE; break;
|
||||||
|
case 0x05: type_ = kUTF16LE; break;
|
||||||
|
case 0x0F: type_ = kUTF8; break;
|
||||||
|
default: break; // Use type defined by user.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||||
|
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||||
|
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef Ch (*TakeFunc)(InputByteStream& is);
|
||||||
|
InputByteStream* is_;
|
||||||
|
UTFType type_;
|
||||||
|
Ch current_;
|
||||||
|
TakeFunc takeFunc_;
|
||||||
|
bool hasBOM_;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
|
||||||
|
/*!
|
||||||
|
\tparam CharType Type of character for writing.
|
||||||
|
\tparam OutputByteStream type of output byte stream to be wrapped.
|
||||||
|
*/
|
||||||
|
template <typename CharType, typename OutputByteStream>
|
||||||
|
class AutoUTFOutputStream {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
public:
|
||||||
|
typedef CharType Ch;
|
||||||
|
|
||||||
|
//! Constructor.
|
||||||
|
/*!
|
||||||
|
\param os output stream to be wrapped.
|
||||||
|
\param type UTF encoding type.
|
||||||
|
\param putBOM Whether to write BOM at the beginning of the stream.
|
||||||
|
*/
|
||||||
|
AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
|
||||||
|
RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
|
||||||
|
|
||||||
|
// Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
|
||||||
|
if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
|
||||||
|
if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
|
||||||
|
|
||||||
|
static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
|
||||||
|
putFunc_ = f[type_];
|
||||||
|
|
||||||
|
if (putBOM)
|
||||||
|
PutBOM();
|
||||||
|
}
|
||||||
|
|
||||||
|
UTFType GetType() const { return type_; }
|
||||||
|
|
||||||
|
void Put(Ch c) { putFunc_(*os_, c); }
|
||||||
|
void Flush() { os_->Flush(); }
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
|
||||||
|
Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
|
||||||
|
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
AutoUTFOutputStream(const AutoUTFOutputStream&);
|
||||||
|
AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
|
||||||
|
|
||||||
|
void PutBOM() {
|
||||||
|
typedef void (*PutBOMFunc)(OutputByteStream&);
|
||||||
|
static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
|
||||||
|
f[type_](*os_);
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef void (*PutFunc)(OutputByteStream&, Ch);
|
||||||
|
|
||||||
|
OutputByteStream* os_;
|
||||||
|
UTFType type_;
|
||||||
|
PutFunc putFunc_;
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef RAPIDJSON_ENCODINGS_FUNC
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_FILESTREAM_H_
|
|
@ -0,0 +1,716 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ENCODINGS_H_
|
||||||
|
#define RAPIDJSON_ENCODINGS_H_
|
||||||
|
|
||||||
|
#include "rapidjson.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
|
||||||
|
RAPIDJSON_DIAG_OFF(4702) // unreachable code
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
RAPIDJSON_DIAG_OFF(overflow)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Encoding
|
||||||
|
|
||||||
|
/*! \class rapidjson::Encoding
|
||||||
|
\brief Concept for encoding of Unicode characters.
|
||||||
|
|
||||||
|
\code
|
||||||
|
concept Encoding {
|
||||||
|
typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition.
|
||||||
|
|
||||||
|
enum { supportUnicode = 1 }; // or 0 if not supporting unicode
|
||||||
|
|
||||||
|
//! \brief Encode a Unicode codepoint to an output stream.
|
||||||
|
//! \param os Output stream.
|
||||||
|
//! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void Encode(OutputStream& os, unsigned codepoint);
|
||||||
|
|
||||||
|
//! \brief Decode a Unicode codepoint from an input stream.
|
||||||
|
//! \param is Input stream.
|
||||||
|
//! \param codepoint Output of the unicode codepoint.
|
||||||
|
//! \return true if a valid codepoint can be decoded from the stream.
|
||||||
|
template <typename InputStream>
|
||||||
|
static bool Decode(InputStream& is, unsigned* codepoint);
|
||||||
|
|
||||||
|
//! \brief Validate one Unicode codepoint from an encoded stream.
|
||||||
|
//! \param is Input stream to obtain codepoint.
|
||||||
|
//! \param os Output for copying one codepoint.
|
||||||
|
//! \return true if it is valid.
|
||||||
|
//! \note This function just validating and copying the codepoint without actually decode it.
|
||||||
|
template <typename InputStream, typename OutputStream>
|
||||||
|
static bool Validate(InputStream& is, OutputStream& os);
|
||||||
|
|
||||||
|
// The following functions are deal with byte streams.
|
||||||
|
|
||||||
|
//! Take a character from input byte stream, skip BOM if exist.
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is);
|
||||||
|
|
||||||
|
//! Take a character from input byte stream.
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static Ch Take(InputByteStream& is);
|
||||||
|
|
||||||
|
//! Put BOM to output byte stream.
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os);
|
||||||
|
|
||||||
|
//! Put a character to output byte stream.
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, Ch c);
|
||||||
|
};
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// UTF8
|
||||||
|
|
||||||
|
//! UTF-8 encoding.
|
||||||
|
/*! http://en.wikipedia.org/wiki/UTF-8
|
||||||
|
http://tools.ietf.org/html/rfc3629
|
||||||
|
\tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
|
||||||
|
\note implements Encoding concept
|
||||||
|
*/
|
||||||
|
template<typename CharType = char>
|
||||||
|
struct UTF8 {
|
||||||
|
typedef CharType Ch;
|
||||||
|
|
||||||
|
enum { supportUnicode = 1 };
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||||
|
if (codepoint <= 0x7F)
|
||||||
|
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
||||||
|
else if (codepoint <= 0x7FF) {
|
||||||
|
os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
|
||||||
|
os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
|
||||||
|
}
|
||||||
|
else if (codepoint <= 0xFFFF) {
|
||||||
|
os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
|
||||||
|
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||||
|
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||||
|
os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
|
||||||
|
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
|
||||||
|
os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||||
|
os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||||
|
if (codepoint <= 0x7F)
|
||||||
|
PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
|
||||||
|
else if (codepoint <= 0x7FF) {
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
|
||||||
|
}
|
||||||
|
else if (codepoint <= 0xFFFF) {
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
|
||||||
|
PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
|
#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
|
||||||
|
#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
|
||||||
|
#define TAIL() COPY(); TRANS(0x70)
|
||||||
|
typename InputStream::Ch c = is.Take();
|
||||||
|
if (!(c & 0x80)) {
|
||||||
|
*codepoint = static_cast<unsigned char>(c);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char type = GetRange(static_cast<unsigned char>(c));
|
||||||
|
if (type >= 32) {
|
||||||
|
*codepoint = 0;
|
||||||
|
} else {
|
||||||
|
*codepoint = (0xFF >> type) & static_cast<unsigned char>(c);
|
||||||
|
}
|
||||||
|
bool result = true;
|
||||||
|
switch (type) {
|
||||||
|
case 2: TAIL(); return result;
|
||||||
|
case 3: TAIL(); TAIL(); return result;
|
||||||
|
case 4: COPY(); TRANS(0x50); TAIL(); return result;
|
||||||
|
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
|
||||||
|
case 6: TAIL(); TAIL(); TAIL(); return result;
|
||||||
|
case 10: COPY(); TRANS(0x20); TAIL(); return result;
|
||||||
|
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
#undef COPY
|
||||||
|
#undef TRANS
|
||||||
|
#undef TAIL
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream, typename OutputStream>
|
||||||
|
static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
#define COPY() os.Put(c = is.Take())
|
||||||
|
#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
|
||||||
|
#define TAIL() COPY(); TRANS(0x70)
|
||||||
|
Ch c;
|
||||||
|
COPY();
|
||||||
|
if (!(c & 0x80))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool result = true;
|
||||||
|
switch (GetRange(static_cast<unsigned char>(c))) {
|
||||||
|
case 2: TAIL(); return result;
|
||||||
|
case 3: TAIL(); TAIL(); return result;
|
||||||
|
case 4: COPY(); TRANS(0x50); TAIL(); return result;
|
||||||
|
case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
|
||||||
|
case 6: TAIL(); TAIL(); TAIL(); return result;
|
||||||
|
case 10: COPY(); TRANS(0x20); TAIL(); return result;
|
||||||
|
case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
#undef COPY
|
||||||
|
#undef TRANS
|
||||||
|
#undef TAIL
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned char GetRange(unsigned char c) {
|
||||||
|
// Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
|
||||||
|
// With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
|
||||||
|
static const unsigned char type[] = {
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||||
|
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
|
||||||
|
0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
|
||||||
|
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
|
||||||
|
0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
|
||||||
|
8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
|
||||||
|
10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
|
||||||
|
};
|
||||||
|
return type[c];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
typename InputByteStream::Ch c = Take(is);
|
||||||
|
if (static_cast<unsigned char>(c) != 0xEFu) return c;
|
||||||
|
c = is.Take();
|
||||||
|
if (static_cast<unsigned char>(c) != 0xBBu) return c;
|
||||||
|
c = is.Take();
|
||||||
|
if (static_cast<unsigned char>(c) != 0xBFu) return c;
|
||||||
|
c = is.Take();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static Ch Take(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
return static_cast<Ch>(is.Take());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, Ch c) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(c));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// UTF16
|
||||||
|
|
||||||
|
//! UTF-16 encoding.
|
||||||
|
/*! http://en.wikipedia.org/wiki/UTF-16
|
||||||
|
http://tools.ietf.org/html/rfc2781
|
||||||
|
\tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
|
||||||
|
\note implements Encoding concept
|
||||||
|
|
||||||
|
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
|
||||||
|
For streaming, use UTF16LE and UTF16BE, which handle endianness.
|
||||||
|
*/
|
||||||
|
template<typename CharType = wchar_t>
|
||||||
|
struct UTF16 {
|
||||||
|
typedef CharType Ch;
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
|
||||||
|
|
||||||
|
enum { supportUnicode = 1 };
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||||
|
if (codepoint <= 0xFFFF) {
|
||||||
|
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
|
||||||
|
os.Put(static_cast<typename OutputStream::Ch>(codepoint));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||||
|
unsigned v = codepoint - 0x10000;
|
||||||
|
os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
|
||||||
|
os.Put((v & 0x3FF) | 0xDC00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||||
|
if (codepoint <= 0xFFFF) {
|
||||||
|
RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair
|
||||||
|
PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||||
|
unsigned v = codepoint - 0x10000;
|
||||||
|
PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
|
||||||
|
PutUnsafe(os, (v & 0x3FF) | 0xDC00);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||||
|
typename InputStream::Ch c = is.Take();
|
||||||
|
if (c < 0xD800 || c > 0xDFFF) {
|
||||||
|
*codepoint = static_cast<unsigned>(c);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (c <= 0xDBFF) {
|
||||||
|
*codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;
|
||||||
|
c = is.Take();
|
||||||
|
*codepoint |= (static_cast<unsigned>(c) & 0x3FF);
|
||||||
|
*codepoint += 0x10000;
|
||||||
|
return c >= 0xDC00 && c <= 0xDFFF;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream, typename OutputStream>
|
||||||
|
static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
|
||||||
|
typename InputStream::Ch c;
|
||||||
|
os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));
|
||||||
|
if (c < 0xD800 || c > 0xDFFF)
|
||||||
|
return true;
|
||||||
|
else if (c <= 0xDBFF) {
|
||||||
|
os.Put(c = is.Take());
|
||||||
|
return c >= 0xDC00 && c <= 0xDFFF;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! UTF-16 little endian encoding.
|
||||||
|
template<typename CharType = wchar_t>
|
||||||
|
struct UTF16LE : UTF16<CharType> {
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
CharType c = Take(is);
|
||||||
|
return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType Take(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
unsigned c = static_cast<uint8_t>(is.Take());
|
||||||
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||||
|
return static_cast<CharType>(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, CharType c) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! UTF-16 big endian encoding.
|
||||||
|
template<typename CharType = wchar_t>
|
||||||
|
struct UTF16BE : UTF16<CharType> {
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
CharType c = Take(is);
|
||||||
|
return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType Take(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||||
|
c |= static_cast<uint8_t>(is.Take());
|
||||||
|
return static_cast<CharType>(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, CharType c) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// UTF32
|
||||||
|
|
||||||
|
//! UTF-32 encoding.
|
||||||
|
/*! http://en.wikipedia.org/wiki/UTF-32
|
||||||
|
\tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
|
||||||
|
\note implements Encoding concept
|
||||||
|
|
||||||
|
\note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
|
||||||
|
For streaming, use UTF32LE and UTF32BE, which handle endianness.
|
||||||
|
*/
|
||||||
|
template<typename CharType = unsigned>
|
||||||
|
struct UTF32 {
|
||||||
|
typedef CharType Ch;
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
|
||||||
|
|
||||||
|
enum { supportUnicode = 1 };
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||||
|
os.Put(codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
|
||||||
|
PutUnsafe(os, codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
|
||||||
|
Ch c = is.Take();
|
||||||
|
*codepoint = c;
|
||||||
|
return c <= 0x10FFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream, typename OutputStream>
|
||||||
|
static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
|
||||||
|
Ch c;
|
||||||
|
os.Put(c = is.Take());
|
||||||
|
return c <= 0x10FFFF;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! UTF-32 little endian enocoding.
|
||||||
|
template<typename CharType = unsigned>
|
||||||
|
struct UTF32LE : UTF32<CharType> {
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
CharType c = Take(is);
|
||||||
|
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType Take(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
unsigned c = static_cast<uint8_t>(is.Take());
|
||||||
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||||
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
|
||||||
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
|
||||||
|
return static_cast<CharType>(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, CharType c) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! UTF-32 big endian encoding.
|
||||||
|
template<typename CharType = unsigned>
|
||||||
|
struct UTF32BE : UTF32<CharType> {
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
CharType c = Take(is);
|
||||||
|
return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType Take(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
|
||||||
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
|
||||||
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
|
||||||
|
c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
|
||||||
|
return static_cast<CharType>(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, CharType c) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// ASCII
|
||||||
|
|
||||||
|
//! ASCII encoding.
|
||||||
|
/*! http://en.wikipedia.org/wiki/ASCII
|
||||||
|
\tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
|
||||||
|
\note implements Encoding concept
|
||||||
|
*/
|
||||||
|
template<typename CharType = char>
|
||||||
|
struct ASCII {
|
||||||
|
typedef CharType Ch;
|
||||||
|
|
||||||
|
enum { supportUnicode = 0 };
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void Encode(OutputStream& os, unsigned codepoint) {
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x7F);
|
||||||
|
os.Put(static_cast<Ch>(codepoint & 0xFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||||
|
RAPIDJSON_ASSERT(codepoint <= 0x7F);
|
||||||
|
PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
|
uint8_t c = static_cast<uint8_t>(is.Take());
|
||||||
|
*codepoint = c;
|
||||||
|
return c <= 0X7F;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream, typename OutputStream>
|
||||||
|
static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
uint8_t c = static_cast<uint8_t>(is.Take());
|
||||||
|
os.Put(static_cast<typename OutputStream::Ch>(c));
|
||||||
|
return c <= 0x7F;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static CharType TakeBOM(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
uint8_t c = static_cast<uint8_t>(Take(is));
|
||||||
|
return static_cast<Ch>(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputByteStream>
|
||||||
|
static Ch Take(InputByteStream& is) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
|
||||||
|
return static_cast<Ch>(is.Take());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void PutBOM(OutputByteStream& os) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
(void)os;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename OutputByteStream>
|
||||||
|
static void Put(OutputByteStream& os, Ch c) {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
|
||||||
|
os.Put(static_cast<typename OutputByteStream::Ch>(c));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// AutoUTF
|
||||||
|
|
||||||
|
//! Runtime-specified UTF encoding type of a stream.
|
||||||
|
enum UTFType {
|
||||||
|
kUTF8 = 0, //!< UTF-8.
|
||||||
|
kUTF16LE = 1, //!< UTF-16 little endian.
|
||||||
|
kUTF16BE = 2, //!< UTF-16 big endian.
|
||||||
|
kUTF32LE = 3, //!< UTF-32 little endian.
|
||||||
|
kUTF32BE = 4 //!< UTF-32 big endian.
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
|
||||||
|
/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
|
||||||
|
*/
|
||||||
|
template<typename CharType>
|
||||||
|
struct AutoUTF {
|
||||||
|
typedef CharType Ch;
|
||||||
|
|
||||||
|
enum { supportUnicode = 1 };
|
||||||
|
|
||||||
|
#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {
|
||||||
|
typedef void (*EncodeFunc)(OutputStream&, unsigned);
|
||||||
|
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
|
||||||
|
(*f[os.GetType()])(os, codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
|
||||||
|
typedef void (*EncodeFunc)(OutputStream&, unsigned);
|
||||||
|
static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };
|
||||||
|
(*f[os.GetType()])(os, codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
|
||||||
|
typedef bool (*DecodeFunc)(InputStream&, unsigned*);
|
||||||
|
static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
|
||||||
|
return (*f[is.GetType()])(is, codepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
|
||||||
|
static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
|
||||||
|
return (*f[is.GetType()])(is, os);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef RAPIDJSON_ENCODINGS_FUNC
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Transcoder
|
||||||
|
|
||||||
|
//! Encoding conversion.
|
||||||
|
template<typename SourceEncoding, typename TargetEncoding>
|
||||||
|
struct Transcoder {
|
||||||
|
//! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
|
||||||
|
template<typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
|
||||||
|
unsigned codepoint;
|
||||||
|
if (!SourceEncoding::Decode(is, &codepoint))
|
||||||
|
return false;
|
||||||
|
TargetEncoding::Encode(os, codepoint);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
|
||||||
|
unsigned codepoint;
|
||||||
|
if (!SourceEncoding::Decode(is, &codepoint))
|
||||||
|
return false;
|
||||||
|
TargetEncoding::EncodeUnsafe(os, codepoint);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Validate one Unicode codepoint from an encoded stream.
|
||||||
|
template<typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
return Transcode(is, os); // Since source/target encoding is different, must transcode.
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Forward declaration.
|
||||||
|
template<typename Stream>
|
||||||
|
inline void PutUnsafe(Stream& stream, typename Stream::Ch c);
|
||||||
|
|
||||||
|
//! Specialization of Transcoder with same source and target encoding.
|
||||||
|
template<typename Encoding>
|
||||||
|
struct Transcoder<Encoding, Encoding> {
|
||||||
|
template<typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
|
||||||
|
os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
|
||||||
|
PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename InputStream, typename OutputStream>
|
||||||
|
RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
|
||||||
|
return Encoding::Validate(is, os); // source/target encoding are the same
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ENCODINGS_H_
|
|
@ -0,0 +1,74 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ERROR_EN_H_
|
||||||
|
#define RAPIDJSON_ERROR_EN_H_
|
||||||
|
|
||||||
|
#include "error.h"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||||
|
RAPIDJSON_DIAG_OFF(covered-switch-default)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Maps error code of parsing into error message.
|
||||||
|
/*!
|
||||||
|
\ingroup RAPIDJSON_ERRORS
|
||||||
|
\param parseErrorCode Error code obtained in parsing.
|
||||||
|
\return the error message.
|
||||||
|
\note User can make a copy of this function for localization.
|
||||||
|
Using switch-case is safer for future modification of error codes.
|
||||||
|
*/
|
||||||
|
inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
|
||||||
|
switch (parseErrorCode) {
|
||||||
|
case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error.");
|
||||||
|
|
||||||
|
case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty.");
|
||||||
|
case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
|
||||||
|
|
||||||
|
case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value.");
|
||||||
|
|
||||||
|
case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
|
||||||
|
case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
|
||||||
|
case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
|
||||||
|
|
||||||
|
case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
|
||||||
|
|
||||||
|
case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
|
||||||
|
case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
|
||||||
|
case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
|
||||||
|
case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
|
||||||
|
case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
|
||||||
|
|
||||||
|
case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
|
||||||
|
case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
|
||||||
|
case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
|
||||||
|
|
||||||
|
case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
|
||||||
|
case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
|
||||||
|
|
||||||
|
default: return RAPIDJSON_ERROR_STRING("Unknown error.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ERROR_EN_H_
|
|
@ -0,0 +1,155 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ERROR_ERROR_H_
|
||||||
|
#define RAPIDJSON_ERROR_ERROR_H_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! \file error.h */
|
||||||
|
|
||||||
|
/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_ERROR_CHARTYPE
|
||||||
|
|
||||||
|
//! Character type of error messages.
|
||||||
|
/*! \ingroup RAPIDJSON_ERRORS
|
||||||
|
The default character type is \c char.
|
||||||
|
On Windows, user can define this macro as \c TCHAR for supporting both
|
||||||
|
unicode/non-unicode settings.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_ERROR_CHARTYPE
|
||||||
|
#define RAPIDJSON_ERROR_CHARTYPE char
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_ERROR_STRING
|
||||||
|
|
||||||
|
//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
|
||||||
|
/*! \ingroup RAPIDJSON_ERRORS
|
||||||
|
By default this conversion macro does nothing.
|
||||||
|
On Windows, user can define this macro as \c _T(x) for supporting both
|
||||||
|
unicode/non-unicode settings.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_ERROR_STRING
|
||||||
|
#define RAPIDJSON_ERROR_STRING(x) x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// ParseErrorCode
|
||||||
|
|
||||||
|
//! Error code of parsing.
|
||||||
|
/*! \ingroup RAPIDJSON_ERRORS
|
||||||
|
\see GenericReader::Parse, GenericReader::GetParseErrorCode
|
||||||
|
*/
|
||||||
|
enum ParseErrorCode {
|
||||||
|
kParseErrorNone = 0, //!< No error.
|
||||||
|
|
||||||
|
kParseErrorDocumentEmpty, //!< The document is empty.
|
||||||
|
kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
|
||||||
|
|
||||||
|
kParseErrorValueInvalid, //!< Invalid value.
|
||||||
|
|
||||||
|
kParseErrorObjectMissName, //!< Missing a name for object member.
|
||||||
|
kParseErrorObjectMissColon, //!< Missing a colon after a name of object member.
|
||||||
|
kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member.
|
||||||
|
|
||||||
|
kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element.
|
||||||
|
|
||||||
|
kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string.
|
||||||
|
kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid.
|
||||||
|
kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
|
||||||
|
kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string.
|
||||||
|
kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
|
||||||
|
|
||||||
|
kParseErrorNumberTooBig, //!< Number too big to be stored in double.
|
||||||
|
kParseErrorNumberMissFraction, //!< Miss fraction part in number.
|
||||||
|
kParseErrorNumberMissExponent, //!< Miss exponent in number.
|
||||||
|
|
||||||
|
kParseErrorTermination, //!< Parsing was terminated.
|
||||||
|
kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Result of parsing (wraps ParseErrorCode)
|
||||||
|
/*!
|
||||||
|
\ingroup RAPIDJSON_ERRORS
|
||||||
|
\code
|
||||||
|
Document doc;
|
||||||
|
ParseResult ok = doc.Parse("[42]");
|
||||||
|
if (!ok) {
|
||||||
|
fprintf(stderr, "JSON parse error: %s (%u)",
|
||||||
|
GetParseError_En(ok.Code()), ok.Offset());
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
\see GenericReader::Parse, GenericDocument::Parse
|
||||||
|
*/
|
||||||
|
struct ParseResult {
|
||||||
|
public:
|
||||||
|
//! Default constructor, no error.
|
||||||
|
ParseResult() : code_(kParseErrorNone), offset_(0) {}
|
||||||
|
//! Constructor to set an error.
|
||||||
|
ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
|
||||||
|
|
||||||
|
//! Get the error code.
|
||||||
|
ParseErrorCode Code() const { return code_; }
|
||||||
|
//! Get the error offset, if \ref IsError(), 0 otherwise.
|
||||||
|
size_t Offset() const { return offset_; }
|
||||||
|
|
||||||
|
//! Conversion to \c bool, returns \c true, iff !\ref IsError().
|
||||||
|
operator bool() const { return !IsError(); }
|
||||||
|
//! Whether the result is an error.
|
||||||
|
bool IsError() const { return code_ != kParseErrorNone; }
|
||||||
|
|
||||||
|
bool operator==(const ParseResult& that) const { return code_ == that.code_; }
|
||||||
|
bool operator==(ParseErrorCode code) const { return code_ == code; }
|
||||||
|
friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
|
||||||
|
|
||||||
|
//! Reset error code.
|
||||||
|
void Clear() { Set(kParseErrorNone); }
|
||||||
|
//! Update error code and offset.
|
||||||
|
void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
ParseErrorCode code_;
|
||||||
|
size_t offset_;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Function pointer type of GetParseError().
|
||||||
|
/*! \ingroup RAPIDJSON_ERRORS
|
||||||
|
|
||||||
|
This is the prototype for \c GetParseError_X(), where \c X is a locale.
|
||||||
|
User can dynamically change locale in runtime, e.g.:
|
||||||
|
\code
|
||||||
|
GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
|
||||||
|
const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ERROR_ERROR_H_
|
|
@ -0,0 +1,99 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_FILEREADSTREAM_H_
|
||||||
|
#define RAPIDJSON_FILEREADSTREAM_H_
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||||
|
RAPIDJSON_DIAG_OFF(missing-noreturn)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! File byte stream for input using fread().
|
||||||
|
/*!
|
||||||
|
\note implements Stream concept
|
||||||
|
*/
|
||||||
|
class FileReadStream {
|
||||||
|
public:
|
||||||
|
typedef char Ch; //!< Character type (byte).
|
||||||
|
|
||||||
|
//! Constructor.
|
||||||
|
/*!
|
||||||
|
\param fp File pointer opened for read.
|
||||||
|
\param buffer user-supplied buffer.
|
||||||
|
\param bufferSize size of buffer in bytes. Must >=4 bytes.
|
||||||
|
*/
|
||||||
|
FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
|
||||||
|
RAPIDJSON_ASSERT(fp_ != 0);
|
||||||
|
RAPIDJSON_ASSERT(bufferSize >= 4);
|
||||||
|
Read();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ch Peek() const { return *current_; }
|
||||||
|
Ch Take() { Ch c = *current_; Read(); return c; }
|
||||||
|
size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||||
|
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
// For encoding detection only.
|
||||||
|
const Ch* Peek4() const {
|
||||||
|
return (current_ + 4 <= bufferLast_) ? current_ : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Read() {
|
||||||
|
if (current_ < bufferLast_)
|
||||||
|
++current_;
|
||||||
|
else if (!eof_) {
|
||||||
|
count_ += readCount_;
|
||||||
|
readCount_ = fread(buffer_, 1, bufferSize_, fp_);
|
||||||
|
bufferLast_ = buffer_ + readCount_ - 1;
|
||||||
|
current_ = buffer_;
|
||||||
|
|
||||||
|
if (readCount_ < bufferSize_) {
|
||||||
|
buffer_[readCount_] = '\0';
|
||||||
|
++bufferLast_;
|
||||||
|
eof_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::FILE* fp_;
|
||||||
|
Ch *buffer_;
|
||||||
|
size_t bufferSize_;
|
||||||
|
Ch *bufferLast_;
|
||||||
|
Ch *current_;
|
||||||
|
size_t readCount_;
|
||||||
|
size_t count_; //!< Number of characters read
|
||||||
|
bool eof_;
|
||||||
|
};
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_FILESTREAM_H_
|
|
@ -0,0 +1,104 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_FILEWRITESTREAM_H_
|
||||||
|
#define RAPIDJSON_FILEWRITESTREAM_H_
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Wrapper of C file stream for input using fread().
|
||||||
|
/*!
|
||||||
|
\note implements Stream concept
|
||||||
|
*/
|
||||||
|
class FileWriteStream {
|
||||||
|
public:
|
||||||
|
typedef char Ch; //!< Character type. Only support char.
|
||||||
|
|
||||||
|
FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) {
|
||||||
|
RAPIDJSON_ASSERT(fp_ != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Put(char c) {
|
||||||
|
if (current_ >= bufferEnd_)
|
||||||
|
Flush();
|
||||||
|
|
||||||
|
*current_++ = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PutN(char c, size_t n) {
|
||||||
|
size_t avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||||
|
while (n > avail) {
|
||||||
|
std::memset(current_, c, avail);
|
||||||
|
current_ += avail;
|
||||||
|
Flush();
|
||||||
|
n -= avail;
|
||||||
|
avail = static_cast<size_t>(bufferEnd_ - current_);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n > 0) {
|
||||||
|
std::memset(current_, c, n);
|
||||||
|
current_ += n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Flush() {
|
||||||
|
if (current_ != buffer_) {
|
||||||
|
size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
|
||||||
|
if (result < static_cast<size_t>(current_ - buffer_)) {
|
||||||
|
// failure deliberately ignored at this time
|
||||||
|
// added to avoid warn_unused_result build errors
|
||||||
|
}
|
||||||
|
current_ = buffer_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
char Take() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Prohibit copy constructor & assignment operator.
|
||||||
|
FileWriteStream(const FileWriteStream&);
|
||||||
|
FileWriteStream& operator=(const FileWriteStream&);
|
||||||
|
|
||||||
|
std::FILE* fp_;
|
||||||
|
char *buffer_;
|
||||||
|
char *bufferEnd_;
|
||||||
|
char *current_;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Implement specialized version of PutN() with memset() for better performance.
|
||||||
|
template<>
|
||||||
|
inline void PutN(FileWriteStream& stream, char c, size_t n) {
|
||||||
|
stream.PutN(c, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_FILESTREAM_H_
|
|
@ -0,0 +1,151 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_FWD_H_
|
||||||
|
#define RAPIDJSON_FWD_H_
|
||||||
|
|
||||||
|
#include "rapidjson.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
// encodings.h
|
||||||
|
|
||||||
|
template<typename CharType> struct UTF8;
|
||||||
|
template<typename CharType> struct UTF16;
|
||||||
|
template<typename CharType> struct UTF16BE;
|
||||||
|
template<typename CharType> struct UTF16LE;
|
||||||
|
template<typename CharType> struct UTF32;
|
||||||
|
template<typename CharType> struct UTF32BE;
|
||||||
|
template<typename CharType> struct UTF32LE;
|
||||||
|
template<typename CharType> struct ASCII;
|
||||||
|
template<typename CharType> struct AutoUTF;
|
||||||
|
|
||||||
|
template<typename SourceEncoding, typename TargetEncoding>
|
||||||
|
struct Transcoder;
|
||||||
|
|
||||||
|
// allocators.h
|
||||||
|
|
||||||
|
class CrtAllocator;
|
||||||
|
|
||||||
|
template <typename BaseAllocator>
|
||||||
|
class MemoryPoolAllocator;
|
||||||
|
|
||||||
|
// stream.h
|
||||||
|
|
||||||
|
template <typename Encoding>
|
||||||
|
struct GenericStringStream;
|
||||||
|
|
||||||
|
typedef GenericStringStream<UTF8<char> > StringStream;
|
||||||
|
|
||||||
|
template <typename Encoding>
|
||||||
|
struct GenericInsituStringStream;
|
||||||
|
|
||||||
|
typedef GenericInsituStringStream<UTF8<char> > InsituStringStream;
|
||||||
|
|
||||||
|
// stringbuffer.h
|
||||||
|
|
||||||
|
template <typename Encoding, typename Allocator>
|
||||||
|
class GenericStringBuffer;
|
||||||
|
|
||||||
|
typedef GenericStringBuffer<UTF8<char>, CrtAllocator> StringBuffer;
|
||||||
|
|
||||||
|
// filereadstream.h
|
||||||
|
|
||||||
|
class FileReadStream;
|
||||||
|
|
||||||
|
// filewritestream.h
|
||||||
|
|
||||||
|
class FileWriteStream;
|
||||||
|
|
||||||
|
// memorybuffer.h
|
||||||
|
|
||||||
|
template <typename Allocator>
|
||||||
|
struct GenericMemoryBuffer;
|
||||||
|
|
||||||
|
typedef GenericMemoryBuffer<CrtAllocator> MemoryBuffer;
|
||||||
|
|
||||||
|
// memorystream.h
|
||||||
|
|
||||||
|
struct MemoryStream;
|
||||||
|
|
||||||
|
// reader.h
|
||||||
|
|
||||||
|
template<typename Encoding, typename Derived>
|
||||||
|
struct BaseReaderHandler;
|
||||||
|
|
||||||
|
template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator>
|
||||||
|
class GenericReader;
|
||||||
|
|
||||||
|
typedef GenericReader<UTF8<char>, UTF8<char>, CrtAllocator> Reader;
|
||||||
|
|
||||||
|
// writer.h
|
||||||
|
|
||||||
|
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
|
||||||
|
class Writer;
|
||||||
|
|
||||||
|
// prettywriter.h
|
||||||
|
|
||||||
|
template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
|
||||||
|
class PrettyWriter;
|
||||||
|
|
||||||
|
// document.h
|
||||||
|
|
||||||
|
template <typename Encoding, typename Allocator>
|
||||||
|
struct GenericMember;
|
||||||
|
|
||||||
|
template <bool Const, typename Encoding, typename Allocator>
|
||||||
|
class GenericMemberIterator;
|
||||||
|
|
||||||
|
template<typename CharType>
|
||||||
|
struct GenericStringRef;
|
||||||
|
|
||||||
|
template <typename Encoding, typename Allocator>
|
||||||
|
class GenericValue;
|
||||||
|
|
||||||
|
typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value;
|
||||||
|
|
||||||
|
template <typename Encoding, typename Allocator, typename StackAllocator>
|
||||||
|
class GenericDocument;
|
||||||
|
|
||||||
|
typedef GenericDocument<UTF8<char>, MemoryPoolAllocator<CrtAllocator>, CrtAllocator> Document;
|
||||||
|
|
||||||
|
// pointer.h
|
||||||
|
|
||||||
|
template <typename ValueType, typename Allocator>
|
||||||
|
class GenericPointer;
|
||||||
|
|
||||||
|
typedef GenericPointer<Value, CrtAllocator> Pointer;
|
||||||
|
|
||||||
|
// schema.h
|
||||||
|
|
||||||
|
template <typename SchemaDocumentType>
|
||||||
|
class IGenericRemoteSchemaDocumentProvider;
|
||||||
|
|
||||||
|
template <typename ValueT, typename Allocator>
|
||||||
|
class GenericSchemaDocument;
|
||||||
|
|
||||||
|
typedef GenericSchemaDocument<Value, CrtAllocator> SchemaDocument;
|
||||||
|
typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename SchemaDocumentType,
|
||||||
|
typename OutputHandler,
|
||||||
|
typename StateAllocator>
|
||||||
|
class GenericSchemaValidator;
|
||||||
|
|
||||||
|
typedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator> SchemaValidator;
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_RAPIDJSONFWD_H_
|
|
@ -0,0 +1,290 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_BIGINTEGER_H_
|
||||||
|
#define RAPIDJSON_BIGINTEGER_H_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
|
#include <intrin.h> // for _umul128
|
||||||
|
#pragma intrinsic(_umul128)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
class BigInteger {
|
||||||
|
public:
|
||||||
|
typedef uint64_t Type;
|
||||||
|
|
||||||
|
BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
|
||||||
|
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit BigInteger(uint64_t u) : count_(1) {
|
||||||
|
digits_[0] = u;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger(const char* decimals, size_t length) : count_(1) {
|
||||||
|
RAPIDJSON_ASSERT(length > 0);
|
||||||
|
digits_[0] = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19
|
||||||
|
while (length >= kMaxDigitPerIteration) {
|
||||||
|
AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
|
||||||
|
length -= kMaxDigitPerIteration;
|
||||||
|
i += kMaxDigitPerIteration;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length > 0)
|
||||||
|
AppendDecimal64(decimals + i, decimals + i + length);
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& operator=(const BigInteger &rhs)
|
||||||
|
{
|
||||||
|
if (this != &rhs) {
|
||||||
|
count_ = rhs.count_;
|
||||||
|
std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& operator=(uint64_t u) {
|
||||||
|
digits_[0] = u;
|
||||||
|
count_ = 1;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& operator+=(uint64_t u) {
|
||||||
|
Type backup = digits_[0];
|
||||||
|
digits_[0] += u;
|
||||||
|
for (size_t i = 0; i < count_ - 1; i++) {
|
||||||
|
if (digits_[i] >= backup)
|
||||||
|
return *this; // no carry
|
||||||
|
backup = digits_[i + 1];
|
||||||
|
digits_[i + 1] += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last carry
|
||||||
|
if (digits_[count_ - 1] < backup)
|
||||||
|
PushBack(1);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& operator*=(uint64_t u) {
|
||||||
|
if (u == 0) return *this = 0;
|
||||||
|
if (u == 1) return *this;
|
||||||
|
if (*this == 1) return *this = u;
|
||||||
|
|
||||||
|
uint64_t k = 0;
|
||||||
|
for (size_t i = 0; i < count_; i++) {
|
||||||
|
uint64_t hi;
|
||||||
|
digits_[i] = MulAdd64(digits_[i], u, k, &hi);
|
||||||
|
k = hi;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k > 0)
|
||||||
|
PushBack(k);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& operator*=(uint32_t u) {
|
||||||
|
if (u == 0) return *this = 0;
|
||||||
|
if (u == 1) return *this;
|
||||||
|
if (*this == 1) return *this = u;
|
||||||
|
|
||||||
|
uint64_t k = 0;
|
||||||
|
for (size_t i = 0; i < count_; i++) {
|
||||||
|
const uint64_t c = digits_[i] >> 32;
|
||||||
|
const uint64_t d = digits_[i] & 0xFFFFFFFF;
|
||||||
|
const uint64_t uc = u * c;
|
||||||
|
const uint64_t ud = u * d;
|
||||||
|
const uint64_t p0 = ud + k;
|
||||||
|
const uint64_t p1 = uc + (p0 >> 32);
|
||||||
|
digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
|
||||||
|
k = p1 >> 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k > 0)
|
||||||
|
PushBack(k);
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& operator<<=(size_t shift) {
|
||||||
|
if (IsZero() || shift == 0) return *this;
|
||||||
|
|
||||||
|
size_t offset = shift / kTypeBit;
|
||||||
|
size_t interShift = shift % kTypeBit;
|
||||||
|
RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
|
||||||
|
|
||||||
|
if (interShift == 0) {
|
||||||
|
std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));
|
||||||
|
count_ += offset;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
digits_[count_] = 0;
|
||||||
|
for (size_t i = count_; i > 0; i--)
|
||||||
|
digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
|
||||||
|
digits_[offset] = digits_[0] << interShift;
|
||||||
|
count_ += offset;
|
||||||
|
if (digits_[count_])
|
||||||
|
count_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memset(digits_, 0, offset * sizeof(Type));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const BigInteger& rhs) const {
|
||||||
|
return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const Type rhs) const {
|
||||||
|
return count_ == 1 && digits_[0] == rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
BigInteger& MultiplyPow5(unsigned exp) {
|
||||||
|
static const uint32_t kPow5[12] = {
|
||||||
|
5,
|
||||||
|
5 * 5,
|
||||||
|
5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
|
||||||
|
5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
|
||||||
|
};
|
||||||
|
if (exp == 0) return *this;
|
||||||
|
for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
|
||||||
|
for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
|
||||||
|
if (exp > 0) *this *= kPow5[exp - 1];
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute absolute difference of this and rhs.
|
||||||
|
// Assume this != rhs
|
||||||
|
bool Difference(const BigInteger& rhs, BigInteger* out) const {
|
||||||
|
int cmp = Compare(rhs);
|
||||||
|
RAPIDJSON_ASSERT(cmp != 0);
|
||||||
|
const BigInteger *a, *b; // Makes a > b
|
||||||
|
bool ret;
|
||||||
|
if (cmp < 0) { a = &rhs; b = this; ret = true; }
|
||||||
|
else { a = this; b = &rhs; ret = false; }
|
||||||
|
|
||||||
|
Type borrow = 0;
|
||||||
|
for (size_t i = 0; i < a->count_; i++) {
|
||||||
|
Type d = a->digits_[i] - borrow;
|
||||||
|
if (i < b->count_)
|
||||||
|
d -= b->digits_[i];
|
||||||
|
borrow = (d > a->digits_[i]) ? 1 : 0;
|
||||||
|
out->digits_[i] = d;
|
||||||
|
if (d != 0)
|
||||||
|
out->count_ = i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Compare(const BigInteger& rhs) const {
|
||||||
|
if (count_ != rhs.count_)
|
||||||
|
return count_ < rhs.count_ ? -1 : 1;
|
||||||
|
|
||||||
|
for (size_t i = count_; i-- > 0;)
|
||||||
|
if (digits_[i] != rhs.digits_[i])
|
||||||
|
return digits_[i] < rhs.digits_[i] ? -1 : 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetCount() const { return count_; }
|
||||||
|
Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }
|
||||||
|
bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void AppendDecimal64(const char* begin, const char* end) {
|
||||||
|
uint64_t u = ParseUint64(begin, end);
|
||||||
|
if (IsZero())
|
||||||
|
*this = u;
|
||||||
|
else {
|
||||||
|
unsigned exp = static_cast<unsigned>(end - begin);
|
||||||
|
(MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushBack(Type digit) {
|
||||||
|
RAPIDJSON_ASSERT(count_ < kCapacity);
|
||||||
|
digits_[count_++] = digit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t ParseUint64(const char* begin, const char* end) {
|
||||||
|
uint64_t r = 0;
|
||||||
|
for (const char* p = begin; p != end; ++p) {
|
||||||
|
RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
|
||||||
|
r = r * 10u + static_cast<unsigned>(*p - '0');
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assume a * b + k < 2^128
|
||||||
|
static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {
|
||||||
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
|
uint64_t low = _umul128(a, b, outHigh) + k;
|
||||||
|
if (low < k)
|
||||||
|
(*outHigh)++;
|
||||||
|
return low;
|
||||||
|
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
|
||||||
|
__extension__ typedef unsigned __int128 uint128;
|
||||||
|
uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
|
||||||
|
p += k;
|
||||||
|
*outHigh = static_cast<uint64_t>(p >> 64);
|
||||||
|
return static_cast<uint64_t>(p);
|
||||||
|
#else
|
||||||
|
const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
|
||||||
|
uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
|
||||||
|
x1 += (x0 >> 32); // can't give carry
|
||||||
|
x1 += x2;
|
||||||
|
if (x1 < x2)
|
||||||
|
x3 += (static_cast<uint64_t>(1) << 32);
|
||||||
|
uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
|
||||||
|
uint64_t hi = x3 + (x1 >> 32);
|
||||||
|
|
||||||
|
lo += k;
|
||||||
|
if (lo < k)
|
||||||
|
hi++;
|
||||||
|
*outHigh = hi;
|
||||||
|
return lo;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000
|
||||||
|
static const size_t kCapacity = kBitCount / sizeof(Type);
|
||||||
|
static const size_t kTypeBit = sizeof(Type) * 8;
|
||||||
|
|
||||||
|
Type digits_[kCapacity];
|
||||||
|
size_t count_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_BIGINTEGER_H_
|
|
@ -0,0 +1,258 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
|
||||||
|
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
|
||||||
|
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_DIYFP_H_
|
||||||
|
#define RAPIDJSON_DIYFP_H_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
|
#include <intrin.h>
|
||||||
|
#pragma intrinsic(_BitScanReverse64)
|
||||||
|
#pragma intrinsic(_umul128)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct DiyFp {
|
||||||
|
DiyFp() : f(), e() {}
|
||||||
|
|
||||||
|
DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
|
||||||
|
|
||||||
|
explicit DiyFp(double d) {
|
||||||
|
union {
|
||||||
|
double d;
|
||||||
|
uint64_t u64;
|
||||||
|
} u = { d };
|
||||||
|
|
||||||
|
int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
|
||||||
|
uint64_t significand = (u.u64 & kDpSignificandMask);
|
||||||
|
if (biased_e != 0) {
|
||||||
|
f = significand + kDpHiddenBit;
|
||||||
|
e = biased_e - kDpExponentBias;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
f = significand;
|
||||||
|
e = kDpMinExponent + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyFp operator-(const DiyFp& rhs) const {
|
||||||
|
return DiyFp(f - rhs.f, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyFp operator*(const DiyFp& rhs) const {
|
||||||
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
|
uint64_t h;
|
||||||
|
uint64_t l = _umul128(f, rhs.f, &h);
|
||||||
|
if (l & (uint64_t(1) << 63)) // rounding
|
||||||
|
h++;
|
||||||
|
return DiyFp(h, e + rhs.e + 64);
|
||||||
|
#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
|
||||||
|
__extension__ typedef unsigned __int128 uint128;
|
||||||
|
uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
|
||||||
|
uint64_t h = static_cast<uint64_t>(p >> 64);
|
||||||
|
uint64_t l = static_cast<uint64_t>(p);
|
||||||
|
if (l & (uint64_t(1) << 63)) // rounding
|
||||||
|
h++;
|
||||||
|
return DiyFp(h, e + rhs.e + 64);
|
||||||
|
#else
|
||||||
|
const uint64_t M32 = 0xFFFFFFFF;
|
||||||
|
const uint64_t a = f >> 32;
|
||||||
|
const uint64_t b = f & M32;
|
||||||
|
const uint64_t c = rhs.f >> 32;
|
||||||
|
const uint64_t d = rhs.f & M32;
|
||||||
|
const uint64_t ac = a * c;
|
||||||
|
const uint64_t bc = b * c;
|
||||||
|
const uint64_t ad = a * d;
|
||||||
|
const uint64_t bd = b * d;
|
||||||
|
uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
|
||||||
|
tmp += 1U << 31; /// mult_round
|
||||||
|
return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyFp Normalize() const {
|
||||||
|
#if defined(_MSC_VER) && defined(_M_AMD64)
|
||||||
|
unsigned long index;
|
||||||
|
_BitScanReverse64(&index, f);
|
||||||
|
return DiyFp(f << (63 - index), e - (63 - index));
|
||||||
|
#elif defined(__GNUC__) && __GNUC__ >= 4
|
||||||
|
int s = __builtin_clzll(f);
|
||||||
|
return DiyFp(f << s, e - s);
|
||||||
|
#else
|
||||||
|
DiyFp res = *this;
|
||||||
|
while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
|
||||||
|
res.f <<= 1;
|
||||||
|
res.e--;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyFp NormalizeBoundary() const {
|
||||||
|
DiyFp res = *this;
|
||||||
|
while (!(res.f & (kDpHiddenBit << 1))) {
|
||||||
|
res.f <<= 1;
|
||||||
|
res.e--;
|
||||||
|
}
|
||||||
|
res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
|
||||||
|
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
|
||||||
|
DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
|
||||||
|
DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
|
||||||
|
mi.f <<= mi.e - pl.e;
|
||||||
|
mi.e = pl.e;
|
||||||
|
*plus = pl;
|
||||||
|
*minus = mi;
|
||||||
|
}
|
||||||
|
|
||||||
|
double ToDouble() const {
|
||||||
|
union {
|
||||||
|
double d;
|
||||||
|
uint64_t u64;
|
||||||
|
}u;
|
||||||
|
const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
|
||||||
|
static_cast<uint64_t>(e + kDpExponentBias);
|
||||||
|
u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
|
||||||
|
return u.d;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const int kDiySignificandSize = 64;
|
||||||
|
static const int kDpSignificandSize = 52;
|
||||||
|
static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
|
||||||
|
static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
|
||||||
|
static const int kDpMinExponent = -kDpExponentBias;
|
||||||
|
static const int kDpDenormalExponent = -kDpExponentBias + 1;
|
||||||
|
static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
|
||||||
|
static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
|
||||||
|
static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
|
||||||
|
|
||||||
|
uint64_t f;
|
||||||
|
int e;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline DiyFp GetCachedPowerByIndex(size_t index) {
|
||||||
|
// 10^-348, 10^-340, ..., 10^340
|
||||||
|
static const uint64_t kCachedPowers_F[] = {
|
||||||
|
RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
|
||||||
|
RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
|
||||||
|
RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
|
||||||
|
RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
|
||||||
|
RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
|
||||||
|
RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
|
||||||
|
RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
|
||||||
|
RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
|
||||||
|
RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
|
||||||
|
RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
|
||||||
|
RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
|
||||||
|
RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
|
||||||
|
RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
|
||||||
|
RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
|
||||||
|
RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
|
||||||
|
RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
|
||||||
|
RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
|
||||||
|
RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
|
||||||
|
RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
|
||||||
|
RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
|
||||||
|
RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
|
||||||
|
RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
|
||||||
|
RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
|
||||||
|
RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
|
||||||
|
RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
|
||||||
|
RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
|
||||||
|
RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
|
||||||
|
RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
|
||||||
|
RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
|
||||||
|
RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
|
||||||
|
RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
|
||||||
|
RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
|
||||||
|
RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
|
||||||
|
RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
|
||||||
|
RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
|
||||||
|
RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
|
||||||
|
RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
|
||||||
|
RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
|
||||||
|
RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
|
||||||
|
RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
|
||||||
|
RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
|
||||||
|
RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
|
||||||
|
RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
|
||||||
|
RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
|
||||||
|
};
|
||||||
|
static const int16_t kCachedPowers_E[] = {
|
||||||
|
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
|
||||||
|
-954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
|
||||||
|
-688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
|
||||||
|
-422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
|
||||||
|
-157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
|
||||||
|
109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
|
||||||
|
375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
|
||||||
|
641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
|
||||||
|
907, 933, 960, 986, 1013, 1039, 1066
|
||||||
|
};
|
||||||
|
return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DiyFp GetCachedPower(int e, int* K) {
|
||||||
|
|
||||||
|
//int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
|
||||||
|
double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
|
||||||
|
int k = static_cast<int>(dk);
|
||||||
|
if (dk - k > 0.0)
|
||||||
|
k++;
|
||||||
|
|
||||||
|
unsigned index = static_cast<unsigned>((k >> 3) + 1);
|
||||||
|
*K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
|
||||||
|
|
||||||
|
return GetCachedPowerByIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DiyFp GetCachedPower10(int exp, int *outExp) {
|
||||||
|
unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
|
||||||
|
*outExp = -348 + static_cast<int>(index) * 8;
|
||||||
|
return GetCachedPowerByIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_DIYFP_H_
|
|
@ -0,0 +1,245 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
|
||||||
|
// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
|
||||||
|
// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_DTOA_
|
||||||
|
#define RAPIDJSON_DTOA_
|
||||||
|
|
||||||
|
#include "itoa.h" // GetDigitsLut()
|
||||||
|
#include "diyfp.h"
|
||||||
|
#include "ieee754.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
|
||||||
|
while (rest < wp_w && delta - rest >= ten_kappa &&
|
||||||
|
(rest + ten_kappa < wp_w || /// closer
|
||||||
|
wp_w - rest > rest + ten_kappa - wp_w)) {
|
||||||
|
buffer[len - 1]--;
|
||||||
|
rest += ten_kappa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned CountDecimalDigit32(uint32_t n) {
|
||||||
|
// Simple pure C++ implementation was faster than __builtin_clz version in this situation.
|
||||||
|
if (n < 10) return 1;
|
||||||
|
if (n < 100) return 2;
|
||||||
|
if (n < 1000) return 3;
|
||||||
|
if (n < 10000) return 4;
|
||||||
|
if (n < 100000) return 5;
|
||||||
|
if (n < 1000000) return 6;
|
||||||
|
if (n < 10000000) return 7;
|
||||||
|
if (n < 100000000) return 8;
|
||||||
|
// Will not reach 10 digits in DigitGen()
|
||||||
|
//if (n < 1000000000) return 9;
|
||||||
|
//return 10;
|
||||||
|
return 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
|
||||||
|
static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
|
||||||
|
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
|
||||||
|
const DiyFp wp_w = Mp - W;
|
||||||
|
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
|
||||||
|
uint64_t p2 = Mp.f & (one.f - 1);
|
||||||
|
unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
|
||||||
|
*len = 0;
|
||||||
|
|
||||||
|
while (kappa > 0) {
|
||||||
|
uint32_t d = 0;
|
||||||
|
switch (kappa) {
|
||||||
|
case 9: d = p1 / 100000000; p1 %= 100000000; break;
|
||||||
|
case 8: d = p1 / 10000000; p1 %= 10000000; break;
|
||||||
|
case 7: d = p1 / 1000000; p1 %= 1000000; break;
|
||||||
|
case 6: d = p1 / 100000; p1 %= 100000; break;
|
||||||
|
case 5: d = p1 / 10000; p1 %= 10000; break;
|
||||||
|
case 4: d = p1 / 1000; p1 %= 1000; break;
|
||||||
|
case 3: d = p1 / 100; p1 %= 100; break;
|
||||||
|
case 2: d = p1 / 10; p1 %= 10; break;
|
||||||
|
case 1: d = p1; p1 = 0; break;
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
if (d || *len)
|
||||||
|
buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
|
||||||
|
kappa--;
|
||||||
|
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
|
||||||
|
if (tmp <= delta) {
|
||||||
|
*K += kappa;
|
||||||
|
GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// kappa = 0
|
||||||
|
for (;;) {
|
||||||
|
p2 *= 10;
|
||||||
|
delta *= 10;
|
||||||
|
char d = static_cast<char>(p2 >> -one.e);
|
||||||
|
if (d || *len)
|
||||||
|
buffer[(*len)++] = static_cast<char>('0' + d);
|
||||||
|
p2 &= one.f - 1;
|
||||||
|
kappa--;
|
||||||
|
if (p2 < delta) {
|
||||||
|
*K += kappa;
|
||||||
|
int index = -static_cast<int>(kappa);
|
||||||
|
GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast<int>(kappa)] : 0));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void Grisu2(double value, char* buffer, int* length, int* K) {
|
||||||
|
const DiyFp v(value);
|
||||||
|
DiyFp w_m, w_p;
|
||||||
|
v.NormalizedBoundaries(&w_m, &w_p);
|
||||||
|
|
||||||
|
const DiyFp c_mk = GetCachedPower(w_p.e, K);
|
||||||
|
const DiyFp W = v.Normalize() * c_mk;
|
||||||
|
DiyFp Wp = w_p * c_mk;
|
||||||
|
DiyFp Wm = w_m * c_mk;
|
||||||
|
Wm.f++;
|
||||||
|
Wp.f--;
|
||||||
|
DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* WriteExponent(int K, char* buffer) {
|
||||||
|
if (K < 0) {
|
||||||
|
*buffer++ = '-';
|
||||||
|
K = -K;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (K >= 100) {
|
||||||
|
*buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
|
||||||
|
K %= 100;
|
||||||
|
const char* d = GetDigitsLut() + K * 2;
|
||||||
|
*buffer++ = d[0];
|
||||||
|
*buffer++ = d[1];
|
||||||
|
}
|
||||||
|
else if (K >= 10) {
|
||||||
|
const char* d = GetDigitsLut() + K * 2;
|
||||||
|
*buffer++ = d[0];
|
||||||
|
*buffer++ = d[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*buffer++ = static_cast<char>('0' + static_cast<char>(K));
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
|
||||||
|
const int kk = length + k; // 10^(kk-1) <= v < 10^kk
|
||||||
|
|
||||||
|
if (0 <= k && kk <= 21) {
|
||||||
|
// 1234e7 -> 12340000000
|
||||||
|
for (int i = length; i < kk; i++)
|
||||||
|
buffer[i] = '0';
|
||||||
|
buffer[kk] = '.';
|
||||||
|
buffer[kk + 1] = '0';
|
||||||
|
return &buffer[kk + 2];
|
||||||
|
}
|
||||||
|
else if (0 < kk && kk <= 21) {
|
||||||
|
// 1234e-2 -> 12.34
|
||||||
|
std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
|
||||||
|
buffer[kk] = '.';
|
||||||
|
if (0 > k + maxDecimalPlaces) {
|
||||||
|
// When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
|
||||||
|
// Remove extra trailing zeros (at least one) after truncation.
|
||||||
|
for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
|
||||||
|
if (buffer[i] != '0')
|
||||||
|
return &buffer[i + 1];
|
||||||
|
return &buffer[kk + 2]; // Reserve one zero
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return &buffer[length + 1];
|
||||||
|
}
|
||||||
|
else if (-6 < kk && kk <= 0) {
|
||||||
|
// 1234e-6 -> 0.001234
|
||||||
|
const int offset = 2 - kk;
|
||||||
|
std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
|
||||||
|
buffer[0] = '0';
|
||||||
|
buffer[1] = '.';
|
||||||
|
for (int i = 2; i < offset; i++)
|
||||||
|
buffer[i] = '0';
|
||||||
|
if (length - kk > maxDecimalPlaces) {
|
||||||
|
// When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
|
||||||
|
// Remove extra trailing zeros (at least one) after truncation.
|
||||||
|
for (int i = maxDecimalPlaces + 1; i > 2; i--)
|
||||||
|
if (buffer[i] != '0')
|
||||||
|
return &buffer[i + 1];
|
||||||
|
return &buffer[3]; // Reserve one zero
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return &buffer[length + offset];
|
||||||
|
}
|
||||||
|
else if (kk < -maxDecimalPlaces) {
|
||||||
|
// Truncate to zero
|
||||||
|
buffer[0] = '0';
|
||||||
|
buffer[1] = '.';
|
||||||
|
buffer[2] = '0';
|
||||||
|
return &buffer[3];
|
||||||
|
}
|
||||||
|
else if (length == 1) {
|
||||||
|
// 1e30
|
||||||
|
buffer[1] = 'e';
|
||||||
|
return WriteExponent(kk - 1, &buffer[2]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// 1234e30 -> 1.234e33
|
||||||
|
std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
|
||||||
|
buffer[1] = '.';
|
||||||
|
buffer[length + 1] = 'e';
|
||||||
|
return WriteExponent(kk - 1, &buffer[0 + length + 2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {
|
||||||
|
RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
|
||||||
|
Double d(value);
|
||||||
|
if (d.IsZero()) {
|
||||||
|
if (d.Sign())
|
||||||
|
*buffer++ = '-'; // -0.0, Issue #289
|
||||||
|
buffer[0] = '0';
|
||||||
|
buffer[1] = '.';
|
||||||
|
buffer[2] = '0';
|
||||||
|
return &buffer[3];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (value < 0) {
|
||||||
|
*buffer++ = '-';
|
||||||
|
value = -value;
|
||||||
|
}
|
||||||
|
int length, K;
|
||||||
|
Grisu2(value, buffer, &length, &K);
|
||||||
|
return Prettify(buffer, length, K, maxDecimalPlaces);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_DTOA_
|
|
@ -0,0 +1,78 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_IEEE754_
|
||||||
|
#define RAPIDJSON_IEEE754_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
class Double {
|
||||||
|
public:
|
||||||
|
Double() {}
|
||||||
|
Double(double d) : d_(d) {}
|
||||||
|
Double(uint64_t u) : u_(u) {}
|
||||||
|
|
||||||
|
double Value() const { return d_; }
|
||||||
|
uint64_t Uint64Value() const { return u_; }
|
||||||
|
|
||||||
|
double NextPositiveDouble() const {
|
||||||
|
RAPIDJSON_ASSERT(!Sign());
|
||||||
|
return Double(u_ + 1).Value();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Sign() const { return (u_ & kSignMask) != 0; }
|
||||||
|
uint64_t Significand() const { return u_ & kSignificandMask; }
|
||||||
|
int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
|
||||||
|
|
||||||
|
bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
|
||||||
|
bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
|
||||||
|
bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }
|
||||||
|
bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
|
||||||
|
bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
|
||||||
|
|
||||||
|
uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
|
||||||
|
int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
|
||||||
|
uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
|
||||||
|
|
||||||
|
static unsigned EffectiveSignificandSize(int order) {
|
||||||
|
if (order >= -1021)
|
||||||
|
return 53;
|
||||||
|
else if (order <= -1074)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return static_cast<unsigned>(order) + 1074;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const int kSignificandSize = 52;
|
||||||
|
static const int kExponentBias = 0x3FF;
|
||||||
|
static const int kDenormalExponent = 1 - kExponentBias;
|
||||||
|
static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
|
||||||
|
static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
|
||||||
|
static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
|
||||||
|
static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
|
||||||
|
|
||||||
|
union {
|
||||||
|
double d_;
|
||||||
|
uint64_t u_;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_IEEE754_
|
|
@ -0,0 +1,304 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ITOA_
|
||||||
|
#define RAPIDJSON_ITOA_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
inline const char* GetDigitsLut() {
|
||||||
|
static const char cDigitsLut[200] = {
|
||||||
|
'0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',
|
||||||
|
'1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',
|
||||||
|
'2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',
|
||||||
|
'3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',
|
||||||
|
'4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',
|
||||||
|
'5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',
|
||||||
|
'6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',
|
||||||
|
'7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',
|
||||||
|
'8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',
|
||||||
|
'9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'
|
||||||
|
};
|
||||||
|
return cDigitsLut;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* u32toa(uint32_t value, char* buffer) {
|
||||||
|
const char* cDigitsLut = GetDigitsLut();
|
||||||
|
|
||||||
|
if (value < 10000) {
|
||||||
|
const uint32_t d1 = (value / 100) << 1;
|
||||||
|
const uint32_t d2 = (value % 100) << 1;
|
||||||
|
|
||||||
|
if (value >= 1000)
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
if (value >= 100)
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
if (value >= 10)
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
}
|
||||||
|
else if (value < 100000000) {
|
||||||
|
// value = bbbbcccc
|
||||||
|
const uint32_t b = value / 10000;
|
||||||
|
const uint32_t c = value % 10000;
|
||||||
|
|
||||||
|
const uint32_t d1 = (b / 100) << 1;
|
||||||
|
const uint32_t d2 = (b % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d3 = (c / 100) << 1;
|
||||||
|
const uint32_t d4 = (c % 100) << 1;
|
||||||
|
|
||||||
|
if (value >= 10000000)
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
if (value >= 1000000)
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
if (value >= 100000)
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
|
||||||
|
*buffer++ = cDigitsLut[d3];
|
||||||
|
*buffer++ = cDigitsLut[d3 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d4];
|
||||||
|
*buffer++ = cDigitsLut[d4 + 1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// value = aabbbbcccc in decimal
|
||||||
|
|
||||||
|
const uint32_t a = value / 100000000; // 1 to 42
|
||||||
|
value %= 100000000;
|
||||||
|
|
||||||
|
if (a >= 10) {
|
||||||
|
const unsigned i = a << 1;
|
||||||
|
*buffer++ = cDigitsLut[i];
|
||||||
|
*buffer++ = cDigitsLut[i + 1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
|
||||||
|
|
||||||
|
const uint32_t b = value / 10000; // 0 to 9999
|
||||||
|
const uint32_t c = value % 10000; // 0 to 9999
|
||||||
|
|
||||||
|
const uint32_t d1 = (b / 100) << 1;
|
||||||
|
const uint32_t d2 = (b % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d3 = (c / 100) << 1;
|
||||||
|
const uint32_t d4 = (c % 100) << 1;
|
||||||
|
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d3];
|
||||||
|
*buffer++ = cDigitsLut[d3 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d4];
|
||||||
|
*buffer++ = cDigitsLut[d4 + 1];
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* i32toa(int32_t value, char* buffer) {
|
||||||
|
uint32_t u = static_cast<uint32_t>(value);
|
||||||
|
if (value < 0) {
|
||||||
|
*buffer++ = '-';
|
||||||
|
u = ~u + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return u32toa(u, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* u64toa(uint64_t value, char* buffer) {
|
||||||
|
const char* cDigitsLut = GetDigitsLut();
|
||||||
|
const uint64_t kTen8 = 100000000;
|
||||||
|
const uint64_t kTen9 = kTen8 * 10;
|
||||||
|
const uint64_t kTen10 = kTen8 * 100;
|
||||||
|
const uint64_t kTen11 = kTen8 * 1000;
|
||||||
|
const uint64_t kTen12 = kTen8 * 10000;
|
||||||
|
const uint64_t kTen13 = kTen8 * 100000;
|
||||||
|
const uint64_t kTen14 = kTen8 * 1000000;
|
||||||
|
const uint64_t kTen15 = kTen8 * 10000000;
|
||||||
|
const uint64_t kTen16 = kTen8 * kTen8;
|
||||||
|
|
||||||
|
if (value < kTen8) {
|
||||||
|
uint32_t v = static_cast<uint32_t>(value);
|
||||||
|
if (v < 10000) {
|
||||||
|
const uint32_t d1 = (v / 100) << 1;
|
||||||
|
const uint32_t d2 = (v % 100) << 1;
|
||||||
|
|
||||||
|
if (v >= 1000)
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
if (v >= 100)
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
if (v >= 10)
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// value = bbbbcccc
|
||||||
|
const uint32_t b = v / 10000;
|
||||||
|
const uint32_t c = v % 10000;
|
||||||
|
|
||||||
|
const uint32_t d1 = (b / 100) << 1;
|
||||||
|
const uint32_t d2 = (b % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d3 = (c / 100) << 1;
|
||||||
|
const uint32_t d4 = (c % 100) << 1;
|
||||||
|
|
||||||
|
if (value >= 10000000)
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
if (value >= 1000000)
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
if (value >= 100000)
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
|
||||||
|
*buffer++ = cDigitsLut[d3];
|
||||||
|
*buffer++ = cDigitsLut[d3 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d4];
|
||||||
|
*buffer++ = cDigitsLut[d4 + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (value < kTen16) {
|
||||||
|
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
|
||||||
|
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
|
||||||
|
|
||||||
|
const uint32_t b0 = v0 / 10000;
|
||||||
|
const uint32_t c0 = v0 % 10000;
|
||||||
|
|
||||||
|
const uint32_t d1 = (b0 / 100) << 1;
|
||||||
|
const uint32_t d2 = (b0 % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d3 = (c0 / 100) << 1;
|
||||||
|
const uint32_t d4 = (c0 % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t b1 = v1 / 10000;
|
||||||
|
const uint32_t c1 = v1 % 10000;
|
||||||
|
|
||||||
|
const uint32_t d5 = (b1 / 100) << 1;
|
||||||
|
const uint32_t d6 = (b1 % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d7 = (c1 / 100) << 1;
|
||||||
|
const uint32_t d8 = (c1 % 100) << 1;
|
||||||
|
|
||||||
|
if (value >= kTen15)
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
if (value >= kTen14)
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
if (value >= kTen13)
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
if (value >= kTen12)
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
if (value >= kTen11)
|
||||||
|
*buffer++ = cDigitsLut[d3];
|
||||||
|
if (value >= kTen10)
|
||||||
|
*buffer++ = cDigitsLut[d3 + 1];
|
||||||
|
if (value >= kTen9)
|
||||||
|
*buffer++ = cDigitsLut[d4];
|
||||||
|
if (value >= kTen8)
|
||||||
|
*buffer++ = cDigitsLut[d4 + 1];
|
||||||
|
|
||||||
|
*buffer++ = cDigitsLut[d5];
|
||||||
|
*buffer++ = cDigitsLut[d5 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d6];
|
||||||
|
*buffer++ = cDigitsLut[d6 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d7];
|
||||||
|
*buffer++ = cDigitsLut[d7 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d8];
|
||||||
|
*buffer++ = cDigitsLut[d8 + 1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
|
||||||
|
value %= kTen16;
|
||||||
|
|
||||||
|
if (a < 10)
|
||||||
|
*buffer++ = static_cast<char>('0' + static_cast<char>(a));
|
||||||
|
else if (a < 100) {
|
||||||
|
const uint32_t i = a << 1;
|
||||||
|
*buffer++ = cDigitsLut[i];
|
||||||
|
*buffer++ = cDigitsLut[i + 1];
|
||||||
|
}
|
||||||
|
else if (a < 1000) {
|
||||||
|
*buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
|
||||||
|
|
||||||
|
const uint32_t i = (a % 100) << 1;
|
||||||
|
*buffer++ = cDigitsLut[i];
|
||||||
|
*buffer++ = cDigitsLut[i + 1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const uint32_t i = (a / 100) << 1;
|
||||||
|
const uint32_t j = (a % 100) << 1;
|
||||||
|
*buffer++ = cDigitsLut[i];
|
||||||
|
*buffer++ = cDigitsLut[i + 1];
|
||||||
|
*buffer++ = cDigitsLut[j];
|
||||||
|
*buffer++ = cDigitsLut[j + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
|
||||||
|
const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
|
||||||
|
|
||||||
|
const uint32_t b0 = v0 / 10000;
|
||||||
|
const uint32_t c0 = v0 % 10000;
|
||||||
|
|
||||||
|
const uint32_t d1 = (b0 / 100) << 1;
|
||||||
|
const uint32_t d2 = (b0 % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d3 = (c0 / 100) << 1;
|
||||||
|
const uint32_t d4 = (c0 % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t b1 = v1 / 10000;
|
||||||
|
const uint32_t c1 = v1 % 10000;
|
||||||
|
|
||||||
|
const uint32_t d5 = (b1 / 100) << 1;
|
||||||
|
const uint32_t d6 = (b1 % 100) << 1;
|
||||||
|
|
||||||
|
const uint32_t d7 = (c1 / 100) << 1;
|
||||||
|
const uint32_t d8 = (c1 % 100) << 1;
|
||||||
|
|
||||||
|
*buffer++ = cDigitsLut[d1];
|
||||||
|
*buffer++ = cDigitsLut[d1 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d2];
|
||||||
|
*buffer++ = cDigitsLut[d2 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d3];
|
||||||
|
*buffer++ = cDigitsLut[d3 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d4];
|
||||||
|
*buffer++ = cDigitsLut[d4 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d5];
|
||||||
|
*buffer++ = cDigitsLut[d5 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d6];
|
||||||
|
*buffer++ = cDigitsLut[d6 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d7];
|
||||||
|
*buffer++ = cDigitsLut[d7 + 1];
|
||||||
|
*buffer++ = cDigitsLut[d8];
|
||||||
|
*buffer++ = cDigitsLut[d8 + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline char* i64toa(int64_t value, char* buffer) {
|
||||||
|
uint64_t u = static_cast<uint64_t>(value);
|
||||||
|
if (value < 0) {
|
||||||
|
*buffer++ = '-';
|
||||||
|
u = ~u + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return u64toa(u, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ITOA_
|
|
@ -0,0 +1,181 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_INTERNAL_META_H_
|
||||||
|
#define RAPIDJSON_INTERNAL_META_H_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
#endif
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(6334)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||||
|
#include <type_traits>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//@cond RAPIDJSON_INTERNAL
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
|
||||||
|
template <typename T> struct Void { typedef void Type; };
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// BoolType, TrueType, FalseType
|
||||||
|
//
|
||||||
|
template <bool Cond> struct BoolType {
|
||||||
|
static const bool Value = Cond;
|
||||||
|
typedef BoolType Type;
|
||||||
|
};
|
||||||
|
typedef BoolType<true> TrueType;
|
||||||
|
typedef BoolType<false> FalseType;
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
|
||||||
|
//
|
||||||
|
|
||||||
|
template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
|
||||||
|
template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
|
||||||
|
template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
|
||||||
|
template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
|
||||||
|
|
||||||
|
template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
|
||||||
|
template <> struct AndExprCond<true, true> : TrueType {};
|
||||||
|
template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
|
||||||
|
template <> struct OrExprCond<false, false> : FalseType {};
|
||||||
|
|
||||||
|
template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
|
||||||
|
template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {};
|
||||||
|
template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
|
||||||
|
template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// AddConst, MaybeAddConst, RemoveConst
|
||||||
|
template <typename T> struct AddConst { typedef const T Type; };
|
||||||
|
template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
|
||||||
|
template <typename T> struct RemoveConst { typedef T Type; };
|
||||||
|
template <typename T> struct RemoveConst<const T> { typedef T Type; };
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// IsSame, IsConst, IsMoreConst, IsPointer
|
||||||
|
//
|
||||||
|
template <typename T, typename U> struct IsSame : FalseType {};
|
||||||
|
template <typename T> struct IsSame<T, T> : TrueType {};
|
||||||
|
|
||||||
|
template <typename T> struct IsConst : FalseType {};
|
||||||
|
template <typename T> struct IsConst<const T> : TrueType {};
|
||||||
|
|
||||||
|
template <typename CT, typename T>
|
||||||
|
struct IsMoreConst
|
||||||
|
: AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
|
||||||
|
BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
|
||||||
|
|
||||||
|
template <typename T> struct IsPointer : FalseType {};
|
||||||
|
template <typename T> struct IsPointer<T*> : TrueType {};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// IsBaseOf
|
||||||
|
//
|
||||||
|
#if RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||||
|
|
||||||
|
template <typename B, typename D> struct IsBaseOf
|
||||||
|
: BoolType< ::std::is_base_of<B,D>::value> {};
|
||||||
|
|
||||||
|
#else // simplified version adopted from Boost
|
||||||
|
|
||||||
|
template<typename B, typename D> struct IsBaseOfImpl {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
|
||||||
|
|
||||||
|
typedef char (&Yes)[1];
|
||||||
|
typedef char (&No) [2];
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static Yes Check(const D*, T);
|
||||||
|
static No Check(const B*, int);
|
||||||
|
|
||||||
|
struct Host {
|
||||||
|
operator const B*() const;
|
||||||
|
operator const D*();
|
||||||
|
};
|
||||||
|
|
||||||
|
enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename B, typename D> struct IsBaseOf
|
||||||
|
: OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// EnableIf / DisableIf
|
||||||
|
//
|
||||||
|
template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; };
|
||||||
|
template <typename T> struct EnableIfCond<false, T> { /* empty */ };
|
||||||
|
|
||||||
|
template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
|
||||||
|
template <typename T> struct DisableIfCond<true, T> { /* empty */ };
|
||||||
|
|
||||||
|
template <typename Condition, typename T = void>
|
||||||
|
struct EnableIf : EnableIfCond<Condition::Value, T> {};
|
||||||
|
|
||||||
|
template <typename Condition, typename T = void>
|
||||||
|
struct DisableIf : DisableIfCond<Condition::Value, T> {};
|
||||||
|
|
||||||
|
// SFINAE helpers
|
||||||
|
struct SfinaeTag {};
|
||||||
|
template <typename T> struct RemoveSfinaeTag;
|
||||||
|
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
|
||||||
|
|
||||||
|
#define RAPIDJSON_REMOVEFPTR_(type) \
|
||||||
|
typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
|
||||||
|
< ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
|
||||||
|
|
||||||
|
#define RAPIDJSON_ENABLEIF(cond) \
|
||||||
|
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
|
||||||
|
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||||
|
|
||||||
|
#define RAPIDJSON_DISABLEIF(cond) \
|
||||||
|
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
|
||||||
|
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||||
|
|
||||||
|
#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
|
||||||
|
typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
|
||||||
|
<RAPIDJSON_REMOVEFPTR_(cond), \
|
||||||
|
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||||
|
|
||||||
|
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
|
||||||
|
typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
|
||||||
|
<RAPIDJSON_REMOVEFPTR_(cond), \
|
||||||
|
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
//@endcond
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_INTERNAL_META_H_
|
|
@ -0,0 +1,55 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_POW10_
|
||||||
|
#define RAPIDJSON_POW10_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
//! Computes integer powers of 10 in double (10.0^n).
|
||||||
|
/*! This function uses lookup table for fast and accurate results.
|
||||||
|
\param n non-negative exponent. Must <= 308.
|
||||||
|
\return 10.0^n
|
||||||
|
*/
|
||||||
|
inline double Pow10(int n) {
|
||||||
|
static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
|
||||||
|
1e+0,
|
||||||
|
1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
|
||||||
|
1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
|
||||||
|
1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
|
||||||
|
1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
|
||||||
|
1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
|
||||||
|
1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
|
||||||
|
1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
|
||||||
|
1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
|
||||||
|
1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
|
||||||
|
1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
|
||||||
|
1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
|
||||||
|
1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
|
||||||
|
1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
|
||||||
|
1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
|
||||||
|
1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
|
||||||
|
1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
|
||||||
|
};
|
||||||
|
RAPIDJSON_ASSERT(n >= 0 && n <= 308);
|
||||||
|
return e[n];
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_POW10_
|
|
@ -0,0 +1,731 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_INTERNAL_REGEX_H_
|
||||||
|
#define RAPIDJSON_INTERNAL_REGEX_H_
|
||||||
|
|
||||||
|
#include "../allocators.h"
|
||||||
|
#include "../stream.h"
|
||||||
|
#include "stack.h"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
RAPIDJSON_DIAG_OFF(switch-enum)
|
||||||
|
RAPIDJSON_DIAG_OFF(implicit-fallthrough)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_REGEX_VERBOSE
|
||||||
|
#define RAPIDJSON_REGEX_VERBOSE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// DecodedStream
|
||||||
|
|
||||||
|
template <typename SourceStream, typename Encoding>
|
||||||
|
class DecodedStream {
|
||||||
|
public:
|
||||||
|
DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
|
||||||
|
unsigned Peek() { return codepoint_; }
|
||||||
|
unsigned Take() {
|
||||||
|
unsigned c = codepoint_;
|
||||||
|
if (c) // No further decoding when '\0'
|
||||||
|
Decode();
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Decode() {
|
||||||
|
if (!Encoding::Decode(ss_, &codepoint_))
|
||||||
|
codepoint_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SourceStream& ss_;
|
||||||
|
unsigned codepoint_;
|
||||||
|
};
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// GenericRegex
|
||||||
|
|
||||||
|
static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1
|
||||||
|
static const SizeType kRegexInvalidRange = ~SizeType(0);
|
||||||
|
|
||||||
|
template <typename Encoding, typename Allocator>
|
||||||
|
class GenericRegexSearch;
|
||||||
|
|
||||||
|
//! Regular expression engine with subset of ECMAscript grammar.
|
||||||
|
/*!
|
||||||
|
Supported regular expression syntax:
|
||||||
|
- \c ab Concatenation
|
||||||
|
- \c a|b Alternation
|
||||||
|
- \c a? Zero or one
|
||||||
|
- \c a* Zero or more
|
||||||
|
- \c a+ One or more
|
||||||
|
- \c a{3} Exactly 3 times
|
||||||
|
- \c a{3,} At least 3 times
|
||||||
|
- \c a{3,5} 3 to 5 times
|
||||||
|
- \c (ab) Grouping
|
||||||
|
- \c ^a At the beginning
|
||||||
|
- \c a$ At the end
|
||||||
|
- \c . Any character
|
||||||
|
- \c [abc] Character classes
|
||||||
|
- \c [a-c] Character class range
|
||||||
|
- \c [a-z0-9_] Character class combination
|
||||||
|
- \c [^abc] Negated character classes
|
||||||
|
- \c [^a-c] Negated character class range
|
||||||
|
- \c [\b] Backspace (U+0008)
|
||||||
|
- \c \\| \\\\ ... Escape characters
|
||||||
|
- \c \\f Form feed (U+000C)
|
||||||
|
- \c \\n Line feed (U+000A)
|
||||||
|
- \c \\r Carriage return (U+000D)
|
||||||
|
- \c \\t Tab (U+0009)
|
||||||
|
- \c \\v Vertical tab (U+000B)
|
||||||
|
|
||||||
|
\note This is a Thompson NFA engine, implemented with reference to
|
||||||
|
Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).",
|
||||||
|
https://swtch.com/~rsc/regexp/regexp1.html
|
||||||
|
*/
|
||||||
|
template <typename Encoding, typename Allocator = CrtAllocator>
|
||||||
|
class GenericRegex {
|
||||||
|
public:
|
||||||
|
typedef Encoding EncodingType;
|
||||||
|
typedef typename Encoding::Ch Ch;
|
||||||
|
template <typename, typename> friend class GenericRegexSearch;
|
||||||
|
|
||||||
|
GenericRegex(const Ch* source, Allocator* allocator = 0) :
|
||||||
|
states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
|
||||||
|
anchorBegin_(), anchorEnd_()
|
||||||
|
{
|
||||||
|
GenericStringStream<Encoding> ss(source);
|
||||||
|
DecodedStream<GenericStringStream<Encoding>, Encoding> ds(ss);
|
||||||
|
Parse(ds);
|
||||||
|
}
|
||||||
|
|
||||||
|
~GenericRegex() {}
|
||||||
|
|
||||||
|
bool IsValid() const {
|
||||||
|
return root_ != kRegexInvalidState;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum Operator {
|
||||||
|
kZeroOrOne,
|
||||||
|
kZeroOrMore,
|
||||||
|
kOneOrMore,
|
||||||
|
kConcatenation,
|
||||||
|
kAlternation,
|
||||||
|
kLeftParenthesis
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.'
|
||||||
|
static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
|
||||||
|
static const unsigned kRangeNegationFlag = 0x80000000;
|
||||||
|
|
||||||
|
struct Range {
|
||||||
|
unsigned start; //
|
||||||
|
unsigned end;
|
||||||
|
SizeType next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct State {
|
||||||
|
SizeType out; //!< Equals to kInvalid for matching state
|
||||||
|
SizeType out1; //!< Equals to non-kInvalid for split
|
||||||
|
SizeType rangeStart;
|
||||||
|
unsigned codepoint;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Frag {
|
||||||
|
Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}
|
||||||
|
SizeType start;
|
||||||
|
SizeType out; //!< link-list of all output states
|
||||||
|
SizeType minIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
State& GetState(SizeType index) {
|
||||||
|
RAPIDJSON_ASSERT(index < stateCount_);
|
||||||
|
return states_.template Bottom<State>()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const State& GetState(SizeType index) const {
|
||||||
|
RAPIDJSON_ASSERT(index < stateCount_);
|
||||||
|
return states_.template Bottom<State>()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
Range& GetRange(SizeType index) {
|
||||||
|
RAPIDJSON_ASSERT(index < rangeCount_);
|
||||||
|
return ranges_.template Bottom<Range>()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
const Range& GetRange(SizeType index) const {
|
||||||
|
RAPIDJSON_ASSERT(index < rangeCount_);
|
||||||
|
return ranges_.template Bottom<Range>()[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
void Parse(DecodedStream<InputStream, Encoding>& ds) {
|
||||||
|
Allocator allocator;
|
||||||
|
Stack<Allocator> operandStack(&allocator, 256); // Frag
|
||||||
|
Stack<Allocator> operatorStack(&allocator, 256); // Operator
|
||||||
|
Stack<Allocator> atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis)
|
||||||
|
|
||||||
|
*atomCountStack.template Push<unsigned>() = 0;
|
||||||
|
|
||||||
|
unsigned codepoint;
|
||||||
|
while (ds.Peek() != 0) {
|
||||||
|
switch (codepoint = ds.Take()) {
|
||||||
|
case '^':
|
||||||
|
anchorBegin_ = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '$':
|
||||||
|
anchorEnd_ = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '|':
|
||||||
|
while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)
|
||||||
|
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
|
||||||
|
return;
|
||||||
|
*operatorStack.template Push<Operator>() = kAlternation;
|
||||||
|
*atomCountStack.template Top<unsigned>() = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '(':
|
||||||
|
*operatorStack.template Push<Operator>() = kLeftParenthesis;
|
||||||
|
*atomCountStack.template Push<unsigned>() = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ')':
|
||||||
|
while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)
|
||||||
|
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
|
||||||
|
return;
|
||||||
|
if (operatorStack.Empty())
|
||||||
|
return;
|
||||||
|
operatorStack.template Pop<Operator>(1);
|
||||||
|
atomCountStack.template Pop<unsigned>(1);
|
||||||
|
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '?':
|
||||||
|
if (!Eval(operandStack, kZeroOrOne))
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '*':
|
||||||
|
if (!Eval(operandStack, kZeroOrMore))
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '+':
|
||||||
|
if (!Eval(operandStack, kOneOrMore))
|
||||||
|
return;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '{':
|
||||||
|
{
|
||||||
|
unsigned n, m;
|
||||||
|
if (!ParseUnsigned(ds, &n))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ds.Peek() == ',') {
|
||||||
|
ds.Take();
|
||||||
|
if (ds.Peek() == '}')
|
||||||
|
m = kInfinityQuantifier;
|
||||||
|
else if (!ParseUnsigned(ds, &m) || m < n)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
m = n;
|
||||||
|
|
||||||
|
if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
|
||||||
|
return;
|
||||||
|
ds.Take();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '.':
|
||||||
|
PushOperand(operandStack, kAnyCharacterClass);
|
||||||
|
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '[':
|
||||||
|
{
|
||||||
|
SizeType range;
|
||||||
|
if (!ParseRange(ds, &range))
|
||||||
|
return;
|
||||||
|
SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
|
||||||
|
GetState(s).rangeStart = range;
|
||||||
|
*operandStack.template Push<Frag>() = Frag(s, s, s);
|
||||||
|
}
|
||||||
|
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\\': // Escape character
|
||||||
|
if (!CharacterEscape(ds, &codepoint))
|
||||||
|
return; // Unsupported escape character
|
||||||
|
// fall through to default
|
||||||
|
|
||||||
|
default: // Pattern character
|
||||||
|
PushOperand(operandStack, codepoint);
|
||||||
|
ImplicitConcatenation(atomCountStack, operatorStack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!operatorStack.Empty())
|
||||||
|
if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Link the operand to matching state.
|
||||||
|
if (operandStack.GetSize() == sizeof(Frag)) {
|
||||||
|
Frag* e = operandStack.template Pop<Frag>(1);
|
||||||
|
Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
|
||||||
|
root_ = e->start;
|
||||||
|
|
||||||
|
#if RAPIDJSON_REGEX_VERBOSE
|
||||||
|
printf("root: %d\n", root_);
|
||||||
|
for (SizeType i = 0; i < stateCount_ ; i++) {
|
||||||
|
State& s = GetState(i);
|
||||||
|
printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
|
||||||
|
State* s = states_.template Push<State>();
|
||||||
|
s->out = out;
|
||||||
|
s->out1 = out1;
|
||||||
|
s->codepoint = codepoint;
|
||||||
|
s->rangeStart = kRegexInvalidRange;
|
||||||
|
return stateCount_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) {
|
||||||
|
SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
|
||||||
|
*operandStack.template Push<Frag>() = Frag(s, s, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) {
|
||||||
|
if (*atomCountStack.template Top<unsigned>())
|
||||||
|
*operatorStack.template Push<Operator>() = kConcatenation;
|
||||||
|
(*atomCountStack.template Top<unsigned>())++;
|
||||||
|
}
|
||||||
|
|
||||||
|
SizeType Append(SizeType l1, SizeType l2) {
|
||||||
|
SizeType old = l1;
|
||||||
|
while (GetState(l1).out != kRegexInvalidState)
|
||||||
|
l1 = GetState(l1).out;
|
||||||
|
GetState(l1).out = l2;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Patch(SizeType l, SizeType s) {
|
||||||
|
for (SizeType next; l != kRegexInvalidState; l = next) {
|
||||||
|
next = GetState(l).out;
|
||||||
|
GetState(l).out = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Eval(Stack<Allocator>& operandStack, Operator op) {
|
||||||
|
switch (op) {
|
||||||
|
case kConcatenation:
|
||||||
|
RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);
|
||||||
|
{
|
||||||
|
Frag e2 = *operandStack.template Pop<Frag>(1);
|
||||||
|
Frag e1 = *operandStack.template Pop<Frag>(1);
|
||||||
|
Patch(e1.out, e2.start);
|
||||||
|
*operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case kAlternation:
|
||||||
|
if (operandStack.GetSize() >= sizeof(Frag) * 2) {
|
||||||
|
Frag e2 = *operandStack.template Pop<Frag>(1);
|
||||||
|
Frag e1 = *operandStack.template Pop<Frag>(1);
|
||||||
|
SizeType s = NewState(e1.start, e2.start, 0);
|
||||||
|
*operandStack.template Push<Frag>() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case kZeroOrOne:
|
||||||
|
if (operandStack.GetSize() >= sizeof(Frag)) {
|
||||||
|
Frag e = *operandStack.template Pop<Frag>(1);
|
||||||
|
SizeType s = NewState(kRegexInvalidState, e.start, 0);
|
||||||
|
*operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case kZeroOrMore:
|
||||||
|
if (operandStack.GetSize() >= sizeof(Frag)) {
|
||||||
|
Frag e = *operandStack.template Pop<Frag>(1);
|
||||||
|
SizeType s = NewState(kRegexInvalidState, e.start, 0);
|
||||||
|
Patch(e.out, s);
|
||||||
|
*operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
default:
|
||||||
|
RAPIDJSON_ASSERT(op == kOneOrMore);
|
||||||
|
if (operandStack.GetSize() >= sizeof(Frag)) {
|
||||||
|
Frag e = *operandStack.template Pop<Frag>(1);
|
||||||
|
SizeType s = NewState(kRegexInvalidState, e.start, 0);
|
||||||
|
Patch(e.out, s);
|
||||||
|
*operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {
|
||||||
|
RAPIDJSON_ASSERT(n <= m);
|
||||||
|
RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));
|
||||||
|
|
||||||
|
if (n == 0) {
|
||||||
|
if (m == 0) // a{0} not support
|
||||||
|
return false;
|
||||||
|
else if (m == kInfinityQuantifier)
|
||||||
|
Eval(operandStack, kZeroOrMore); // a{0,} -> a*
|
||||||
|
else {
|
||||||
|
Eval(operandStack, kZeroOrOne); // a{0,5} -> a?
|
||||||
|
for (unsigned i = 0; i < m - 1; i++)
|
||||||
|
CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a?
|
||||||
|
for (unsigned i = 0; i < m - 1; i++)
|
||||||
|
Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a
|
||||||
|
CloneTopOperand(operandStack);
|
||||||
|
|
||||||
|
if (m == kInfinityQuantifier)
|
||||||
|
Eval(operandStack, kOneOrMore); // a{3,} -> a a a+
|
||||||
|
else if (m > n) {
|
||||||
|
CloneTopOperand(operandStack); // a{3,5} -> a a a a
|
||||||
|
Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a?
|
||||||
|
for (unsigned i = n; i < m - 1; i++)
|
||||||
|
CloneTopOperand(operandStack); // a{3,5} -> a a a a? a?
|
||||||
|
for (unsigned i = n; i < m; i++)
|
||||||
|
Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < n - 1; i++)
|
||||||
|
Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }
|
||||||
|
|
||||||
|
void CloneTopOperand(Stack<Allocator>& operandStack) {
|
||||||
|
const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation
|
||||||
|
SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)
|
||||||
|
State* s = states_.template Push<State>(count);
|
||||||
|
memcpy(s, &GetState(src.minIndex), count * sizeof(State));
|
||||||
|
for (SizeType j = 0; j < count; j++) {
|
||||||
|
if (s[j].out != kRegexInvalidState)
|
||||||
|
s[j].out += count;
|
||||||
|
if (s[j].out1 != kRegexInvalidState)
|
||||||
|
s[j].out1 += count;
|
||||||
|
}
|
||||||
|
*operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count);
|
||||||
|
stateCount_ += count;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
bool ParseUnsigned(DecodedStream<InputStream, Encoding>& ds, unsigned* u) {
|
||||||
|
unsigned r = 0;
|
||||||
|
if (ds.Peek() < '0' || ds.Peek() > '9')
|
||||||
|
return false;
|
||||||
|
while (ds.Peek() >= '0' && ds.Peek() <= '9') {
|
||||||
|
if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
|
||||||
|
return false; // overflow
|
||||||
|
r = r * 10 + (ds.Take() - '0');
|
||||||
|
}
|
||||||
|
*u = r;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
bool ParseRange(DecodedStream<InputStream, Encoding>& ds, SizeType* range) {
|
||||||
|
bool isBegin = true;
|
||||||
|
bool negate = false;
|
||||||
|
int step = 0;
|
||||||
|
SizeType start = kRegexInvalidRange;
|
||||||
|
SizeType current = kRegexInvalidRange;
|
||||||
|
unsigned codepoint;
|
||||||
|
while ((codepoint = ds.Take()) != 0) {
|
||||||
|
if (isBegin) {
|
||||||
|
isBegin = false;
|
||||||
|
if (codepoint == '^') {
|
||||||
|
negate = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (codepoint) {
|
||||||
|
case ']':
|
||||||
|
if (start == kRegexInvalidRange)
|
||||||
|
return false; // Error: nothing inside []
|
||||||
|
if (step == 2) { // Add trailing '-'
|
||||||
|
SizeType r = NewRange('-');
|
||||||
|
RAPIDJSON_ASSERT(current != kRegexInvalidRange);
|
||||||
|
GetRange(current).next = r;
|
||||||
|
}
|
||||||
|
if (negate)
|
||||||
|
GetRange(start).start |= kRangeNegationFlag;
|
||||||
|
*range = start;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case '\\':
|
||||||
|
if (ds.Peek() == 'b') {
|
||||||
|
ds.Take();
|
||||||
|
codepoint = 0x0008; // Escape backspace character
|
||||||
|
}
|
||||||
|
else if (!CharacterEscape(ds, &codepoint))
|
||||||
|
return false;
|
||||||
|
// fall through to default
|
||||||
|
|
||||||
|
default:
|
||||||
|
switch (step) {
|
||||||
|
case 1:
|
||||||
|
if (codepoint == '-') {
|
||||||
|
step++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// fall through to step 0 for other characters
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
SizeType r = NewRange(codepoint);
|
||||||
|
if (current != kRegexInvalidRange)
|
||||||
|
GetRange(current).next = r;
|
||||||
|
if (start == kRegexInvalidRange)
|
||||||
|
start = r;
|
||||||
|
current = r;
|
||||||
|
}
|
||||||
|
step = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
RAPIDJSON_ASSERT(step == 2);
|
||||||
|
GetRange(current).end = codepoint;
|
||||||
|
step = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SizeType NewRange(unsigned codepoint) {
|
||||||
|
Range* r = ranges_.template Push<Range>();
|
||||||
|
r->start = r->end = codepoint;
|
||||||
|
r->next = kRegexInvalidRange;
|
||||||
|
return rangeCount_++;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
bool CharacterEscape(DecodedStream<InputStream, Encoding>& ds, unsigned* escapedCodepoint) {
|
||||||
|
unsigned codepoint;
|
||||||
|
switch (codepoint = ds.Take()) {
|
||||||
|
case '^':
|
||||||
|
case '$':
|
||||||
|
case '|':
|
||||||
|
case '(':
|
||||||
|
case ')':
|
||||||
|
case '?':
|
||||||
|
case '*':
|
||||||
|
case '+':
|
||||||
|
case '.':
|
||||||
|
case '[':
|
||||||
|
case ']':
|
||||||
|
case '{':
|
||||||
|
case '}':
|
||||||
|
case '\\':
|
||||||
|
*escapedCodepoint = codepoint; return true;
|
||||||
|
case 'f': *escapedCodepoint = 0x000C; return true;
|
||||||
|
case 'n': *escapedCodepoint = 0x000A; return true;
|
||||||
|
case 'r': *escapedCodepoint = 0x000D; return true;
|
||||||
|
case 't': *escapedCodepoint = 0x0009; return true;
|
||||||
|
case 'v': *escapedCodepoint = 0x000B; return true;
|
||||||
|
default:
|
||||||
|
return false; // Unsupported escape character
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Stack<Allocator> states_;
|
||||||
|
Stack<Allocator> ranges_;
|
||||||
|
SizeType root_;
|
||||||
|
SizeType stateCount_;
|
||||||
|
SizeType rangeCount_;
|
||||||
|
|
||||||
|
static const unsigned kInfinityQuantifier = ~0u;
|
||||||
|
|
||||||
|
// For SearchWithAnchoring()
|
||||||
|
bool anchorBegin_;
|
||||||
|
bool anchorEnd_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename RegexType, typename Allocator = CrtAllocator>
|
||||||
|
class GenericRegexSearch {
|
||||||
|
public:
|
||||||
|
typedef typename RegexType::EncodingType Encoding;
|
||||||
|
typedef typename Encoding::Ch Ch;
|
||||||
|
|
||||||
|
GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) :
|
||||||
|
regex_(regex), allocator_(allocator), ownAllocator_(0),
|
||||||
|
state0_(allocator, 0), state1_(allocator, 0), stateSet_()
|
||||||
|
{
|
||||||
|
RAPIDJSON_ASSERT(regex_.IsValid());
|
||||||
|
if (!allocator_)
|
||||||
|
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
|
||||||
|
stateSet_ = static_cast<unsigned*>(allocator_->Malloc(GetStateSetSize()));
|
||||||
|
state0_.template Reserve<SizeType>(regex_.stateCount_);
|
||||||
|
state1_.template Reserve<SizeType>(regex_.stateCount_);
|
||||||
|
}
|
||||||
|
|
||||||
|
~GenericRegexSearch() {
|
||||||
|
Allocator::Free(stateSet_);
|
||||||
|
RAPIDJSON_DELETE(ownAllocator_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
bool Match(InputStream& is) {
|
||||||
|
return SearchWithAnchoring(is, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Match(const Ch* s) {
|
||||||
|
GenericStringStream<Encoding> is(s);
|
||||||
|
return Match(is);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
bool Search(InputStream& is) {
|
||||||
|
return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Search(const Ch* s) {
|
||||||
|
GenericStringStream<Encoding> is(s);
|
||||||
|
return Search(is);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef typename RegexType::State State;
|
||||||
|
typedef typename RegexType::Range Range;
|
||||||
|
|
||||||
|
template <typename InputStream>
|
||||||
|
bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) {
|
||||||
|
DecodedStream<InputStream, Encoding> ds(is);
|
||||||
|
|
||||||
|
state0_.Clear();
|
||||||
|
Stack<Allocator> *current = &state0_, *next = &state1_;
|
||||||
|
const size_t stateSetSize = GetStateSetSize();
|
||||||
|
std::memset(stateSet_, 0, stateSetSize);
|
||||||
|
|
||||||
|
bool matched = AddState(*current, regex_.root_);
|
||||||
|
unsigned codepoint;
|
||||||
|
while (!current->Empty() && (codepoint = ds.Take()) != 0) {
|
||||||
|
std::memset(stateSet_, 0, stateSetSize);
|
||||||
|
next->Clear();
|
||||||
|
matched = false;
|
||||||
|
for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
|
||||||
|
const State& sr = regex_.GetState(*s);
|
||||||
|
if (sr.codepoint == codepoint ||
|
||||||
|
sr.codepoint == RegexType::kAnyCharacterClass ||
|
||||||
|
(sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
|
||||||
|
{
|
||||||
|
matched = AddState(*next, sr.out) || matched;
|
||||||
|
if (!anchorEnd && matched)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!anchorBegin)
|
||||||
|
AddState(*next, regex_.root_);
|
||||||
|
}
|
||||||
|
internal::Swap(current, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
return matched;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetStateSetSize() const {
|
||||||
|
return (regex_.stateCount_ + 31) / 32 * 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return whether the added states is a match state
|
||||||
|
bool AddState(Stack<Allocator>& l, SizeType index) {
|
||||||
|
RAPIDJSON_ASSERT(index != kRegexInvalidState);
|
||||||
|
|
||||||
|
const State& s = regex_.GetState(index);
|
||||||
|
if (s.out1 != kRegexInvalidState) { // Split
|
||||||
|
bool matched = AddState(l, s.out);
|
||||||
|
return AddState(l, s.out1) || matched;
|
||||||
|
}
|
||||||
|
else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) {
|
||||||
|
stateSet_[index >> 5] |= (1 << (index & 31));
|
||||||
|
*l.template PushUnsafe<SizeType>() = index;
|
||||||
|
}
|
||||||
|
return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
|
||||||
|
bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0;
|
||||||
|
while (rangeIndex != kRegexInvalidRange) {
|
||||||
|
const Range& r = regex_.GetRange(rangeIndex);
|
||||||
|
if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end)
|
||||||
|
return yes;
|
||||||
|
rangeIndex = r.next;
|
||||||
|
}
|
||||||
|
return !yes;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RegexType& regex_;
|
||||||
|
Allocator* allocator_;
|
||||||
|
Allocator* ownAllocator_;
|
||||||
|
Stack<Allocator> state0_;
|
||||||
|
Stack<Allocator> state1_;
|
||||||
|
uint32_t* stateSet_;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef GenericRegex<UTF8<> > Regex;
|
||||||
|
typedef GenericRegexSearch<Regex> RegexSearch;
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_INTERNAL_REGEX_H_
|
|
@ -0,0 +1,230 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_INTERNAL_STACK_H_
|
||||||
|
#define RAPIDJSON_INTERNAL_STACK_H_
|
||||||
|
|
||||||
|
#include "../allocators.h"
|
||||||
|
#include "swap.h"
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Stack
|
||||||
|
|
||||||
|
//! A type-unsafe stack for storing different types of data.
|
||||||
|
/*! \tparam Allocator Allocator for allocating stack memory.
|
||||||
|
*/
|
||||||
|
template <typename Allocator>
|
||||||
|
class Stack {
|
||||||
|
public:
|
||||||
|
// Optimization note: Do not allocate memory for stack_ in constructor.
|
||||||
|
// Do it lazily when first Push() -> Expand() -> Resize().
|
||||||
|
Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
|
||||||
|
}
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
Stack(Stack&& rhs)
|
||||||
|
: allocator_(rhs.allocator_),
|
||||||
|
ownAllocator_(rhs.ownAllocator_),
|
||||||
|
stack_(rhs.stack_),
|
||||||
|
stackTop_(rhs.stackTop_),
|
||||||
|
stackEnd_(rhs.stackEnd_),
|
||||||
|
initialCapacity_(rhs.initialCapacity_)
|
||||||
|
{
|
||||||
|
rhs.allocator_ = 0;
|
||||||
|
rhs.ownAllocator_ = 0;
|
||||||
|
rhs.stack_ = 0;
|
||||||
|
rhs.stackTop_ = 0;
|
||||||
|
rhs.stackEnd_ = 0;
|
||||||
|
rhs.initialCapacity_ = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
~Stack() {
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
Stack& operator=(Stack&& rhs) {
|
||||||
|
if (&rhs != this)
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
|
||||||
|
allocator_ = rhs.allocator_;
|
||||||
|
ownAllocator_ = rhs.ownAllocator_;
|
||||||
|
stack_ = rhs.stack_;
|
||||||
|
stackTop_ = rhs.stackTop_;
|
||||||
|
stackEnd_ = rhs.stackEnd_;
|
||||||
|
initialCapacity_ = rhs.initialCapacity_;
|
||||||
|
|
||||||
|
rhs.allocator_ = 0;
|
||||||
|
rhs.ownAllocator_ = 0;
|
||||||
|
rhs.stack_ = 0;
|
||||||
|
rhs.stackTop_ = 0;
|
||||||
|
rhs.stackEnd_ = 0;
|
||||||
|
rhs.initialCapacity_ = 0;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
|
||||||
|
internal::Swap(allocator_, rhs.allocator_);
|
||||||
|
internal::Swap(ownAllocator_, rhs.ownAllocator_);
|
||||||
|
internal::Swap(stack_, rhs.stack_);
|
||||||
|
internal::Swap(stackTop_, rhs.stackTop_);
|
||||||
|
internal::Swap(stackEnd_, rhs.stackEnd_);
|
||||||
|
internal::Swap(initialCapacity_, rhs.initialCapacity_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear() { stackTop_ = stack_; }
|
||||||
|
|
||||||
|
void ShrinkToFit() {
|
||||||
|
if (Empty()) {
|
||||||
|
// If the stack is empty, completely deallocate the memory.
|
||||||
|
Allocator::Free(stack_);
|
||||||
|
stack_ = 0;
|
||||||
|
stackTop_ = 0;
|
||||||
|
stackEnd_ = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Resize(GetSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optimization note: try to minimize the size of this function for force inline.
|
||||||
|
// Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
|
||||||
|
template<typename T>
|
||||||
|
RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
|
||||||
|
// Expand the stack if needed
|
||||||
|
if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))
|
||||||
|
Expand<T>(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
|
||||||
|
Reserve<T>(count);
|
||||||
|
return PushUnsafe<T>(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
|
||||||
|
RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);
|
||||||
|
T* ret = reinterpret_cast<T*>(stackTop_);
|
||||||
|
stackTop_ += sizeof(T) * count;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* Pop(size_t count) {
|
||||||
|
RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
|
||||||
|
stackTop_ -= count * sizeof(T);
|
||||||
|
return reinterpret_cast<T*>(stackTop_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* Top() {
|
||||||
|
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||||
|
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const T* Top() const {
|
||||||
|
RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
|
||||||
|
return reinterpret_cast<T*>(stackTop_ - sizeof(T));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* End() { return reinterpret_cast<T*>(stackTop_); }
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const T* End() const { return reinterpret_cast<T*>(stackTop_); }
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
T* Bottom() { return reinterpret_cast<T*>(stack_); }
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
|
||||||
|
|
||||||
|
bool HasAllocator() const {
|
||||||
|
return allocator_ != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Allocator& GetAllocator() {
|
||||||
|
RAPIDJSON_ASSERT(allocator_);
|
||||||
|
return *allocator_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Empty() const { return stackTop_ == stack_; }
|
||||||
|
size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
|
||||||
|
size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<typename T>
|
||||||
|
void Expand(size_t count) {
|
||||||
|
// Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
|
||||||
|
size_t newCapacity;
|
||||||
|
if (stack_ == 0) {
|
||||||
|
if (!allocator_)
|
||||||
|
ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
|
||||||
|
newCapacity = initialCapacity_;
|
||||||
|
} else {
|
||||||
|
newCapacity = GetCapacity();
|
||||||
|
newCapacity += (newCapacity + 1) / 2;
|
||||||
|
}
|
||||||
|
size_t newSize = GetSize() + sizeof(T) * count;
|
||||||
|
if (newCapacity < newSize)
|
||||||
|
newCapacity = newSize;
|
||||||
|
|
||||||
|
Resize(newCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Resize(size_t newCapacity) {
|
||||||
|
const size_t size = GetSize(); // Backup the current size
|
||||||
|
stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
|
||||||
|
stackTop_ = stack_ + size;
|
||||||
|
stackEnd_ = stack_ + newCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Destroy() {
|
||||||
|
Allocator::Free(stack_);
|
||||||
|
RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prohibit copy constructor & assignment operator.
|
||||||
|
Stack(const Stack&);
|
||||||
|
Stack& operator=(const Stack&);
|
||||||
|
|
||||||
|
Allocator* allocator_;
|
||||||
|
Allocator* ownAllocator_;
|
||||||
|
char *stack_;
|
||||||
|
char *stackTop_;
|
||||||
|
char *stackEnd_;
|
||||||
|
size_t initialCapacity_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_STACK_H_
|
|
@ -0,0 +1,58 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||||
|
#define RAPIDJSON_INTERNAL_STRFUNC_H_
|
||||||
|
|
||||||
|
#include "../stream.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
//! Custom strlen() which works on different character types.
|
||||||
|
/*! \tparam Ch Character type (e.g. char, wchar_t, short)
|
||||||
|
\param s Null-terminated input string.
|
||||||
|
\return Number of characters in the string.
|
||||||
|
\note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
|
||||||
|
*/
|
||||||
|
template <typename Ch>
|
||||||
|
inline SizeType StrLen(const Ch* s) {
|
||||||
|
RAPIDJSON_ASSERT(s != 0);
|
||||||
|
const Ch* p = s;
|
||||||
|
while (*p) ++p;
|
||||||
|
return SizeType(p - s);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Returns number of code points in a encoded string.
|
||||||
|
template<typename Encoding>
|
||||||
|
bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
|
||||||
|
RAPIDJSON_ASSERT(s != 0);
|
||||||
|
RAPIDJSON_ASSERT(outCount != 0);
|
||||||
|
GenericStringStream<Encoding> is(s);
|
||||||
|
const typename Encoding::Ch* end = s + length;
|
||||||
|
SizeType count = 0;
|
||||||
|
while (is.src_ < end) {
|
||||||
|
unsigned codepoint;
|
||||||
|
if (!Encoding::Decode(is, &codepoint))
|
||||||
|
return false;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
*outCount = count;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
|
|
@ -0,0 +1,269 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_STRTOD_
|
||||||
|
#define RAPIDJSON_STRTOD_
|
||||||
|
|
||||||
|
#include "ieee754.h"
|
||||||
|
#include "biginteger.h"
|
||||||
|
#include "diyfp.h"
|
||||||
|
#include "pow10.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
inline double FastPath(double significand, int exp) {
|
||||||
|
if (exp < -308)
|
||||||
|
return 0.0;
|
||||||
|
else if (exp >= 0)
|
||||||
|
return significand * internal::Pow10(exp);
|
||||||
|
else
|
||||||
|
return significand / internal::Pow10(-exp);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double StrtodNormalPrecision(double d, int p) {
|
||||||
|
if (p < -308) {
|
||||||
|
// Prevent expSum < -308, making Pow10(p) = 0
|
||||||
|
d = FastPath(d, -308);
|
||||||
|
d = FastPath(d, p + 308);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
d = FastPath(d, p);
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
inline T Min3(T a, T b, T c) {
|
||||||
|
T m = a;
|
||||||
|
if (m > b) m = b;
|
||||||
|
if (m > c) m = c;
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
|
||||||
|
const Double db(b);
|
||||||
|
const uint64_t bInt = db.IntegerSignificand();
|
||||||
|
const int bExp = db.IntegerExponent();
|
||||||
|
const int hExp = bExp - 1;
|
||||||
|
|
||||||
|
int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
|
||||||
|
|
||||||
|
// Adjust for decimal exponent
|
||||||
|
if (dExp >= 0) {
|
||||||
|
dS_Exp2 += dExp;
|
||||||
|
dS_Exp5 += dExp;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bS_Exp2 -= dExp;
|
||||||
|
bS_Exp5 -= dExp;
|
||||||
|
hS_Exp2 -= dExp;
|
||||||
|
hS_Exp5 -= dExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust for binary exponent
|
||||||
|
if (bExp >= 0)
|
||||||
|
bS_Exp2 += bExp;
|
||||||
|
else {
|
||||||
|
dS_Exp2 -= bExp;
|
||||||
|
hS_Exp2 -= bExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust for half ulp exponent
|
||||||
|
if (hExp >= 0)
|
||||||
|
hS_Exp2 += hExp;
|
||||||
|
else {
|
||||||
|
dS_Exp2 -= hExp;
|
||||||
|
bS_Exp2 -= hExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove common power of two factor from all three scaled values
|
||||||
|
int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
|
||||||
|
dS_Exp2 -= common_Exp2;
|
||||||
|
bS_Exp2 -= common_Exp2;
|
||||||
|
hS_Exp2 -= common_Exp2;
|
||||||
|
|
||||||
|
BigInteger dS = d;
|
||||||
|
dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
|
||||||
|
|
||||||
|
BigInteger bS(bInt);
|
||||||
|
bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
|
||||||
|
|
||||||
|
BigInteger hS(1);
|
||||||
|
hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
|
||||||
|
|
||||||
|
BigInteger delta(0);
|
||||||
|
dS.Difference(bS, &delta);
|
||||||
|
|
||||||
|
return delta.Compare(hS);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool StrtodFast(double d, int p, double* result) {
|
||||||
|
// Use fast path for string-to-double conversion if possible
|
||||||
|
// see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
|
||||||
|
if (p > 22 && p < 22 + 16) {
|
||||||
|
// Fast Path Cases In Disguise
|
||||||
|
d *= internal::Pow10(p - 22);
|
||||||
|
p = 22;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
|
||||||
|
*result = FastPath(d, p);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute an approximation and see if it is within 1/2 ULP
|
||||||
|
inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {
|
||||||
|
uint64_t significand = 0;
|
||||||
|
size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
|
||||||
|
for (; i < length; i++) {
|
||||||
|
if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
|
||||||
|
(significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
|
||||||
|
break;
|
||||||
|
significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < length && decimals[i] >= '5') // Rounding
|
||||||
|
significand++;
|
||||||
|
|
||||||
|
size_t remaining = length - i;
|
||||||
|
const unsigned kUlpShift = 3;
|
||||||
|
const unsigned kUlp = 1 << kUlpShift;
|
||||||
|
int64_t error = (remaining == 0) ? 0 : kUlp / 2;
|
||||||
|
|
||||||
|
DiyFp v(significand, 0);
|
||||||
|
v = v.Normalize();
|
||||||
|
error <<= -v.e;
|
||||||
|
|
||||||
|
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(i) + exp;
|
||||||
|
|
||||||
|
int actualExp;
|
||||||
|
DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
|
||||||
|
if (actualExp != dExp) {
|
||||||
|
static const DiyFp kPow10[] = {
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6
|
||||||
|
DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7
|
||||||
|
};
|
||||||
|
int adjustment = dExp - actualExp - 1;
|
||||||
|
RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
|
||||||
|
v = v * kPow10[adjustment];
|
||||||
|
if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit
|
||||||
|
error += kUlp / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
v = v * cachedPower;
|
||||||
|
|
||||||
|
error += kUlp + (error == 0 ? 0 : 1);
|
||||||
|
|
||||||
|
const int oldExp = v.e;
|
||||||
|
v = v.Normalize();
|
||||||
|
error <<= oldExp - v.e;
|
||||||
|
|
||||||
|
const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
|
||||||
|
unsigned precisionSize = 64 - effectiveSignificandSize;
|
||||||
|
if (precisionSize + kUlpShift >= 64) {
|
||||||
|
unsigned scaleExp = (precisionSize + kUlpShift) - 63;
|
||||||
|
v.f >>= scaleExp;
|
||||||
|
v.e += scaleExp;
|
||||||
|
error = (error >> scaleExp) + 1 + static_cast<int>(kUlp);
|
||||||
|
precisionSize -= scaleExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize));
|
||||||
|
const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
|
||||||
|
const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
|
||||||
|
if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
|
||||||
|
rounded.f++;
|
||||||
|
if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
|
||||||
|
rounded.f >>= 1;
|
||||||
|
rounded.e++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*result = rounded.ToDouble();
|
||||||
|
|
||||||
|
return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
|
||||||
|
const BigInteger dInt(decimals, length);
|
||||||
|
const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp;
|
||||||
|
Double a(approx);
|
||||||
|
int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
|
||||||
|
if (cmp < 0)
|
||||||
|
return a.Value(); // within half ULP
|
||||||
|
else if (cmp == 0) {
|
||||||
|
// Round towards even
|
||||||
|
if (a.Significand() & 1)
|
||||||
|
return a.NextPositiveDouble();
|
||||||
|
else
|
||||||
|
return a.Value();
|
||||||
|
}
|
||||||
|
else // adjustment
|
||||||
|
return a.NextPositiveDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
|
||||||
|
RAPIDJSON_ASSERT(d >= 0.0);
|
||||||
|
RAPIDJSON_ASSERT(length >= 1);
|
||||||
|
|
||||||
|
double result;
|
||||||
|
if (StrtodFast(d, p, &result))
|
||||||
|
return result;
|
||||||
|
|
||||||
|
// Trim leading zeros
|
||||||
|
while (*decimals == '0' && length > 1) {
|
||||||
|
length--;
|
||||||
|
decimals++;
|
||||||
|
decimalPosition--;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim trailing zeros
|
||||||
|
while (decimals[length - 1] == '0' && length > 1) {
|
||||||
|
length--;
|
||||||
|
decimalPosition--;
|
||||||
|
exp++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trim right-most digits
|
||||||
|
const int kMaxDecimalDigit = 780;
|
||||||
|
if (static_cast<int>(length) > kMaxDecimalDigit) {
|
||||||
|
int delta = (static_cast<int>(length) - kMaxDecimalDigit);
|
||||||
|
exp += delta;
|
||||||
|
decimalPosition -= static_cast<unsigned>(delta);
|
||||||
|
length = kMaxDecimalDigit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If too small, underflow to zero
|
||||||
|
if (int(length) + exp < -324)
|
||||||
|
return 0.0;
|
||||||
|
|
||||||
|
if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
|
||||||
|
return result;
|
||||||
|
|
||||||
|
// Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
|
||||||
|
return StrtodBigInteger(result, decimals, length, decimalPosition, exp);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_STRTOD_
|
|
@ -0,0 +1,46 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_INTERNAL_SWAP_H_
|
||||||
|
#define RAPIDJSON_INTERNAL_SWAP_H_
|
||||||
|
|
||||||
|
#include "../rapidjson.h"
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
namespace internal {
|
||||||
|
|
||||||
|
//! Custom swap() to avoid dependency on C++ <algorithm> header
|
||||||
|
/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
|
||||||
|
\note This has the same semantics as std::swap().
|
||||||
|
*/
|
||||||
|
template <typename T>
|
||||||
|
inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
|
||||||
|
T tmp = a;
|
||||||
|
a = b;
|
||||||
|
b = tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace internal
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_INTERNAL_SWAP_H_
|
|
@ -0,0 +1,115 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_ISTREAMWRAPPER_H_
|
||||||
|
#define RAPIDJSON_ISTREAMWRAPPER_H_
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
#include <iosfwd>
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept.
|
||||||
|
/*!
|
||||||
|
The classes can be wrapped including but not limited to:
|
||||||
|
|
||||||
|
- \c std::istringstream
|
||||||
|
- \c std::stringstream
|
||||||
|
- \c std::wistringstream
|
||||||
|
- \c std::wstringstream
|
||||||
|
- \c std::ifstream
|
||||||
|
- \c std::fstream
|
||||||
|
- \c std::wifstream
|
||||||
|
- \c std::wfstream
|
||||||
|
|
||||||
|
\tparam StreamType Class derived from \c std::basic_istream.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <typename StreamType>
|
||||||
|
class BasicIStreamWrapper {
|
||||||
|
public:
|
||||||
|
typedef typename StreamType::char_type Ch;
|
||||||
|
BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {}
|
||||||
|
|
||||||
|
Ch Peek() const {
|
||||||
|
typename StreamType::int_type c = stream_.peek();
|
||||||
|
return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast<Ch>(c) : '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
Ch Take() {
|
||||||
|
typename StreamType::int_type c = stream_.get();
|
||||||
|
if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) {
|
||||||
|
count_++;
|
||||||
|
return static_cast<Ch>(c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
// tellg() may return -1 when failed. So we count by ourself.
|
||||||
|
size_t Tell() const { return count_; }
|
||||||
|
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||||
|
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
// For encoding detection only.
|
||||||
|
const Ch* Peek4() const {
|
||||||
|
RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream.
|
||||||
|
int i;
|
||||||
|
bool hasError = false;
|
||||||
|
for (i = 0; i < 4; ++i) {
|
||||||
|
typename StreamType::int_type c = stream_.get();
|
||||||
|
if (c == StreamType::traits_type::eof()) {
|
||||||
|
hasError = true;
|
||||||
|
stream_.clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
peekBuffer_[i] = static_cast<Ch>(c);
|
||||||
|
}
|
||||||
|
for (--i; i >= 0; --i)
|
||||||
|
stream_.putback(peekBuffer_[i]);
|
||||||
|
return !hasError ? peekBuffer_ : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BasicIStreamWrapper(const BasicIStreamWrapper&);
|
||||||
|
BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
|
||||||
|
|
||||||
|
StreamType& stream_;
|
||||||
|
size_t count_; //!< Number of characters read. Note:
|
||||||
|
mutable Ch peekBuffer_[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
|
||||||
|
typedef BasicIStreamWrapper<std::wistream> WIStreamWrapper;
|
||||||
|
|
||||||
|
#if defined(__clang__) || defined(_MSC_VER)
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_ISTREAMWRAPPER_H_
|
|
@ -0,0 +1,70 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_MEMORYBUFFER_H_
|
||||||
|
#define RAPIDJSON_MEMORYBUFFER_H_
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
#include "internal/stack.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Represents an in-memory output byte stream.
|
||||||
|
/*!
|
||||||
|
This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.
|
||||||
|
|
||||||
|
It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.
|
||||||
|
|
||||||
|
Differences between MemoryBuffer and StringBuffer:
|
||||||
|
1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer.
|
||||||
|
2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.
|
||||||
|
|
||||||
|
\tparam Allocator type for allocating memory buffer.
|
||||||
|
\note implements Stream concept
|
||||||
|
*/
|
||||||
|
template <typename Allocator = CrtAllocator>
|
||||||
|
struct GenericMemoryBuffer {
|
||||||
|
typedef char Ch; // byte
|
||||||
|
|
||||||
|
GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
|
||||||
|
|
||||||
|
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
|
||||||
|
void Flush() {}
|
||||||
|
|
||||||
|
void Clear() { stack_.Clear(); }
|
||||||
|
void ShrinkToFit() { stack_.ShrinkToFit(); }
|
||||||
|
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
|
||||||
|
void Pop(size_t count) { stack_.template Pop<Ch>(count); }
|
||||||
|
|
||||||
|
const Ch* GetBuffer() const {
|
||||||
|
return stack_.template Bottom<Ch>();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t GetSize() const { return stack_.GetSize(); }
|
||||||
|
|
||||||
|
static const size_t kDefaultCapacity = 256;
|
||||||
|
mutable internal::Stack<Allocator> stack_;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef GenericMemoryBuffer<> MemoryBuffer;
|
||||||
|
|
||||||
|
//! Implement specialized version of PutN() with memset() for better performance.
|
||||||
|
template<>
|
||||||
|
inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
|
||||||
|
std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_MEMORYBUFFER_H_
|
|
@ -0,0 +1,71 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_MEMORYSTREAM_H_
|
||||||
|
#define RAPIDJSON_MEMORYSTREAM_H_
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||||
|
RAPIDJSON_DIAG_OFF(missing-noreturn)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Represents an in-memory input byte stream.
|
||||||
|
/*!
|
||||||
|
This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.
|
||||||
|
|
||||||
|
It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.
|
||||||
|
|
||||||
|
Differences between MemoryStream and StringStream:
|
||||||
|
1. StringStream has encoding but MemoryStream is a byte stream.
|
||||||
|
2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.
|
||||||
|
3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().
|
||||||
|
\note implements Stream concept
|
||||||
|
*/
|
||||||
|
struct MemoryStream {
|
||||||
|
typedef char Ch; // byte
|
||||||
|
|
||||||
|
MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
|
||||||
|
|
||||||
|
Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; }
|
||||||
|
Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; }
|
||||||
|
size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
|
||||||
|
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||||
|
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
// For encoding detection only.
|
||||||
|
const Ch* Peek4() const {
|
||||||
|
return Tell() + 4 <= size_ ? src_ : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Ch* src_; //!< Current read position.
|
||||||
|
const Ch* begin_; //!< Original head of the string.
|
||||||
|
const Ch* end_; //!< End of stream.
|
||||||
|
size_t size_; //!< Size of the stream.
|
||||||
|
};
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_MEMORYBUFFER_H_
|
|
@ -0,0 +1,316 @@
|
||||||
|
// ISO C9x compliant inttypes.h for Microsoft Visual Studio
|
||||||
|
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2013 Alexander Chemeris
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the product 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 AUTHOR ``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 AUTHOR 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// The above software in this distribution may have been modified by
|
||||||
|
// THL A29 Limited ("Tencent Modifications").
|
||||||
|
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
|
||||||
|
|
||||||
|
#ifndef _MSC_VER // [
|
||||||
|
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||||
|
#endif // _MSC_VER ]
|
||||||
|
|
||||||
|
#ifndef _MSC_INTTYPES_H_ // [
|
||||||
|
#define _MSC_INTTYPES_H_
|
||||||
|
|
||||||
|
#if _MSC_VER > 1000
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
|
||||||
|
// miloyip: VC supports inttypes.h since VC2013
|
||||||
|
#if _MSC_VER >= 1800
|
||||||
|
#include <inttypes.h>
|
||||||
|
#else
|
||||||
|
|
||||||
|
// 7.8 Format conversion of integer types
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
intmax_t quot;
|
||||||
|
intmax_t rem;
|
||||||
|
} imaxdiv_t;
|
||||||
|
|
||||||
|
// 7.8.1 Macros for format specifiers
|
||||||
|
|
||||||
|
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198
|
||||||
|
|
||||||
|
// The fprintf macros for signed integers are:
|
||||||
|
#define PRId8 "d"
|
||||||
|
#define PRIi8 "i"
|
||||||
|
#define PRIdLEAST8 "d"
|
||||||
|
#define PRIiLEAST8 "i"
|
||||||
|
#define PRIdFAST8 "d"
|
||||||
|
#define PRIiFAST8 "i"
|
||||||
|
|
||||||
|
#define PRId16 "hd"
|
||||||
|
#define PRIi16 "hi"
|
||||||
|
#define PRIdLEAST16 "hd"
|
||||||
|
#define PRIiLEAST16 "hi"
|
||||||
|
#define PRIdFAST16 "hd"
|
||||||
|
#define PRIiFAST16 "hi"
|
||||||
|
|
||||||
|
#define PRId32 "I32d"
|
||||||
|
#define PRIi32 "I32i"
|
||||||
|
#define PRIdLEAST32 "I32d"
|
||||||
|
#define PRIiLEAST32 "I32i"
|
||||||
|
#define PRIdFAST32 "I32d"
|
||||||
|
#define PRIiFAST32 "I32i"
|
||||||
|
|
||||||
|
#define PRId64 "I64d"
|
||||||
|
#define PRIi64 "I64i"
|
||||||
|
#define PRIdLEAST64 "I64d"
|
||||||
|
#define PRIiLEAST64 "I64i"
|
||||||
|
#define PRIdFAST64 "I64d"
|
||||||
|
#define PRIiFAST64 "I64i"
|
||||||
|
|
||||||
|
#define PRIdMAX "I64d"
|
||||||
|
#define PRIiMAX "I64i"
|
||||||
|
|
||||||
|
#define PRIdPTR "Id"
|
||||||
|
#define PRIiPTR "Ii"
|
||||||
|
|
||||||
|
// The fprintf macros for unsigned integers are:
|
||||||
|
#define PRIo8 "o"
|
||||||
|
#define PRIu8 "u"
|
||||||
|
#define PRIx8 "x"
|
||||||
|
#define PRIX8 "X"
|
||||||
|
#define PRIoLEAST8 "o"
|
||||||
|
#define PRIuLEAST8 "u"
|
||||||
|
#define PRIxLEAST8 "x"
|
||||||
|
#define PRIXLEAST8 "X"
|
||||||
|
#define PRIoFAST8 "o"
|
||||||
|
#define PRIuFAST8 "u"
|
||||||
|
#define PRIxFAST8 "x"
|
||||||
|
#define PRIXFAST8 "X"
|
||||||
|
|
||||||
|
#define PRIo16 "ho"
|
||||||
|
#define PRIu16 "hu"
|
||||||
|
#define PRIx16 "hx"
|
||||||
|
#define PRIX16 "hX"
|
||||||
|
#define PRIoLEAST16 "ho"
|
||||||
|
#define PRIuLEAST16 "hu"
|
||||||
|
#define PRIxLEAST16 "hx"
|
||||||
|
#define PRIXLEAST16 "hX"
|
||||||
|
#define PRIoFAST16 "ho"
|
||||||
|
#define PRIuFAST16 "hu"
|
||||||
|
#define PRIxFAST16 "hx"
|
||||||
|
#define PRIXFAST16 "hX"
|
||||||
|
|
||||||
|
#define PRIo32 "I32o"
|
||||||
|
#define PRIu32 "I32u"
|
||||||
|
#define PRIx32 "I32x"
|
||||||
|
#define PRIX32 "I32X"
|
||||||
|
#define PRIoLEAST32 "I32o"
|
||||||
|
#define PRIuLEAST32 "I32u"
|
||||||
|
#define PRIxLEAST32 "I32x"
|
||||||
|
#define PRIXLEAST32 "I32X"
|
||||||
|
#define PRIoFAST32 "I32o"
|
||||||
|
#define PRIuFAST32 "I32u"
|
||||||
|
#define PRIxFAST32 "I32x"
|
||||||
|
#define PRIXFAST32 "I32X"
|
||||||
|
|
||||||
|
#define PRIo64 "I64o"
|
||||||
|
#define PRIu64 "I64u"
|
||||||
|
#define PRIx64 "I64x"
|
||||||
|
#define PRIX64 "I64X"
|
||||||
|
#define PRIoLEAST64 "I64o"
|
||||||
|
#define PRIuLEAST64 "I64u"
|
||||||
|
#define PRIxLEAST64 "I64x"
|
||||||
|
#define PRIXLEAST64 "I64X"
|
||||||
|
#define PRIoFAST64 "I64o"
|
||||||
|
#define PRIuFAST64 "I64u"
|
||||||
|
#define PRIxFAST64 "I64x"
|
||||||
|
#define PRIXFAST64 "I64X"
|
||||||
|
|
||||||
|
#define PRIoMAX "I64o"
|
||||||
|
#define PRIuMAX "I64u"
|
||||||
|
#define PRIxMAX "I64x"
|
||||||
|
#define PRIXMAX "I64X"
|
||||||
|
|
||||||
|
#define PRIoPTR "Io"
|
||||||
|
#define PRIuPTR "Iu"
|
||||||
|
#define PRIxPTR "Ix"
|
||||||
|
#define PRIXPTR "IX"
|
||||||
|
|
||||||
|
// The fscanf macros for signed integers are:
|
||||||
|
#define SCNd8 "d"
|
||||||
|
#define SCNi8 "i"
|
||||||
|
#define SCNdLEAST8 "d"
|
||||||
|
#define SCNiLEAST8 "i"
|
||||||
|
#define SCNdFAST8 "d"
|
||||||
|
#define SCNiFAST8 "i"
|
||||||
|
|
||||||
|
#define SCNd16 "hd"
|
||||||
|
#define SCNi16 "hi"
|
||||||
|
#define SCNdLEAST16 "hd"
|
||||||
|
#define SCNiLEAST16 "hi"
|
||||||
|
#define SCNdFAST16 "hd"
|
||||||
|
#define SCNiFAST16 "hi"
|
||||||
|
|
||||||
|
#define SCNd32 "ld"
|
||||||
|
#define SCNi32 "li"
|
||||||
|
#define SCNdLEAST32 "ld"
|
||||||
|
#define SCNiLEAST32 "li"
|
||||||
|
#define SCNdFAST32 "ld"
|
||||||
|
#define SCNiFAST32 "li"
|
||||||
|
|
||||||
|
#define SCNd64 "I64d"
|
||||||
|
#define SCNi64 "I64i"
|
||||||
|
#define SCNdLEAST64 "I64d"
|
||||||
|
#define SCNiLEAST64 "I64i"
|
||||||
|
#define SCNdFAST64 "I64d"
|
||||||
|
#define SCNiFAST64 "I64i"
|
||||||
|
|
||||||
|
#define SCNdMAX "I64d"
|
||||||
|
#define SCNiMAX "I64i"
|
||||||
|
|
||||||
|
#ifdef _WIN64 // [
|
||||||
|
# define SCNdPTR "I64d"
|
||||||
|
# define SCNiPTR "I64i"
|
||||||
|
#else // _WIN64 ][
|
||||||
|
# define SCNdPTR "ld"
|
||||||
|
# define SCNiPTR "li"
|
||||||
|
#endif // _WIN64 ]
|
||||||
|
|
||||||
|
// The fscanf macros for unsigned integers are:
|
||||||
|
#define SCNo8 "o"
|
||||||
|
#define SCNu8 "u"
|
||||||
|
#define SCNx8 "x"
|
||||||
|
#define SCNX8 "X"
|
||||||
|
#define SCNoLEAST8 "o"
|
||||||
|
#define SCNuLEAST8 "u"
|
||||||
|
#define SCNxLEAST8 "x"
|
||||||
|
#define SCNXLEAST8 "X"
|
||||||
|
#define SCNoFAST8 "o"
|
||||||
|
#define SCNuFAST8 "u"
|
||||||
|
#define SCNxFAST8 "x"
|
||||||
|
#define SCNXFAST8 "X"
|
||||||
|
|
||||||
|
#define SCNo16 "ho"
|
||||||
|
#define SCNu16 "hu"
|
||||||
|
#define SCNx16 "hx"
|
||||||
|
#define SCNX16 "hX"
|
||||||
|
#define SCNoLEAST16 "ho"
|
||||||
|
#define SCNuLEAST16 "hu"
|
||||||
|
#define SCNxLEAST16 "hx"
|
||||||
|
#define SCNXLEAST16 "hX"
|
||||||
|
#define SCNoFAST16 "ho"
|
||||||
|
#define SCNuFAST16 "hu"
|
||||||
|
#define SCNxFAST16 "hx"
|
||||||
|
#define SCNXFAST16 "hX"
|
||||||
|
|
||||||
|
#define SCNo32 "lo"
|
||||||
|
#define SCNu32 "lu"
|
||||||
|
#define SCNx32 "lx"
|
||||||
|
#define SCNX32 "lX"
|
||||||
|
#define SCNoLEAST32 "lo"
|
||||||
|
#define SCNuLEAST32 "lu"
|
||||||
|
#define SCNxLEAST32 "lx"
|
||||||
|
#define SCNXLEAST32 "lX"
|
||||||
|
#define SCNoFAST32 "lo"
|
||||||
|
#define SCNuFAST32 "lu"
|
||||||
|
#define SCNxFAST32 "lx"
|
||||||
|
#define SCNXFAST32 "lX"
|
||||||
|
|
||||||
|
#define SCNo64 "I64o"
|
||||||
|
#define SCNu64 "I64u"
|
||||||
|
#define SCNx64 "I64x"
|
||||||
|
#define SCNX64 "I64X"
|
||||||
|
#define SCNoLEAST64 "I64o"
|
||||||
|
#define SCNuLEAST64 "I64u"
|
||||||
|
#define SCNxLEAST64 "I64x"
|
||||||
|
#define SCNXLEAST64 "I64X"
|
||||||
|
#define SCNoFAST64 "I64o"
|
||||||
|
#define SCNuFAST64 "I64u"
|
||||||
|
#define SCNxFAST64 "I64x"
|
||||||
|
#define SCNXFAST64 "I64X"
|
||||||
|
|
||||||
|
#define SCNoMAX "I64o"
|
||||||
|
#define SCNuMAX "I64u"
|
||||||
|
#define SCNxMAX "I64x"
|
||||||
|
#define SCNXMAX "I64X"
|
||||||
|
|
||||||
|
#ifdef _WIN64 // [
|
||||||
|
# define SCNoPTR "I64o"
|
||||||
|
# define SCNuPTR "I64u"
|
||||||
|
# define SCNxPTR "I64x"
|
||||||
|
# define SCNXPTR "I64X"
|
||||||
|
#else // _WIN64 ][
|
||||||
|
# define SCNoPTR "lo"
|
||||||
|
# define SCNuPTR "lu"
|
||||||
|
# define SCNxPTR "lx"
|
||||||
|
# define SCNXPTR "lX"
|
||||||
|
#endif // _WIN64 ]
|
||||||
|
|
||||||
|
#endif // __STDC_FORMAT_MACROS ]
|
||||||
|
|
||||||
|
// 7.8.2 Functions for greatest-width integer types
|
||||||
|
|
||||||
|
// 7.8.2.1 The imaxabs function
|
||||||
|
#define imaxabs _abs64
|
||||||
|
|
||||||
|
// 7.8.2.2 The imaxdiv function
|
||||||
|
|
||||||
|
// This is modified version of div() function from Microsoft's div.c found
|
||||||
|
// in %MSVC.NET%\crt\src\div.c
|
||||||
|
#ifdef STATIC_IMAXDIV // [
|
||||||
|
static
|
||||||
|
#else // STATIC_IMAXDIV ][
|
||||||
|
_inline
|
||||||
|
#endif // STATIC_IMAXDIV ]
|
||||||
|
imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
|
||||||
|
{
|
||||||
|
imaxdiv_t result;
|
||||||
|
|
||||||
|
result.quot = numer / denom;
|
||||||
|
result.rem = numer % denom;
|
||||||
|
|
||||||
|
if (numer < 0 && result.rem > 0) {
|
||||||
|
// did division wrong; must fix up
|
||||||
|
++result.quot;
|
||||||
|
result.rem -= denom;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7.8.2.3 The strtoimax and strtoumax functions
|
||||||
|
#define strtoimax _strtoi64
|
||||||
|
#define strtoumax _strtoui64
|
||||||
|
|
||||||
|
// 7.8.2.4 The wcstoimax and wcstoumax functions
|
||||||
|
#define wcstoimax _wcstoi64
|
||||||
|
#define wcstoumax _wcstoui64
|
||||||
|
|
||||||
|
#endif // _MSC_VER >= 1800
|
||||||
|
|
||||||
|
#endif // _MSC_INTTYPES_H_ ]
|
|
@ -0,0 +1,300 @@
|
||||||
|
// ISO C9x compliant stdint.h for Microsoft Visual Studio
|
||||||
|
// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
|
||||||
|
//
|
||||||
|
// Copyright (c) 2006-2013 Alexander Chemeris
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//
|
||||||
|
// 3. Neither the name of the product 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 AUTHOR ``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 AUTHOR 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.
|
||||||
|
//
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// The above software in this distribution may have been modified by
|
||||||
|
// THL A29 Limited ("Tencent Modifications").
|
||||||
|
// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
|
||||||
|
|
||||||
|
#ifndef _MSC_VER // [
|
||||||
|
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||||
|
#endif // _MSC_VER ]
|
||||||
|
|
||||||
|
#ifndef _MSC_STDINT_H_ // [
|
||||||
|
#define _MSC_STDINT_H_
|
||||||
|
|
||||||
|
#if _MSC_VER > 1000
|
||||||
|
#pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010.
|
||||||
|
#if _MSC_VER >= 1600 // [
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
|
||||||
|
|
||||||
|
#undef INT8_C
|
||||||
|
#undef INT16_C
|
||||||
|
#undef INT32_C
|
||||||
|
#undef INT64_C
|
||||||
|
#undef UINT8_C
|
||||||
|
#undef UINT16_C
|
||||||
|
#undef UINT32_C
|
||||||
|
#undef UINT64_C
|
||||||
|
|
||||||
|
// 7.18.4.1 Macros for minimum-width integer constants
|
||||||
|
|
||||||
|
#define INT8_C(val) val##i8
|
||||||
|
#define INT16_C(val) val##i16
|
||||||
|
#define INT32_C(val) val##i32
|
||||||
|
#define INT64_C(val) val##i64
|
||||||
|
|
||||||
|
#define UINT8_C(val) val##ui8
|
||||||
|
#define UINT16_C(val) val##ui16
|
||||||
|
#define UINT32_C(val) val##ui32
|
||||||
|
#define UINT64_C(val) val##ui64
|
||||||
|
|
||||||
|
// 7.18.4.2 Macros for greatest-width integer constants
|
||||||
|
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
|
||||||
|
// Check out Issue 9 for the details.
|
||||||
|
#ifndef INTMAX_C // [
|
||||||
|
# define INTMAX_C INT64_C
|
||||||
|
#endif // INTMAX_C ]
|
||||||
|
#ifndef UINTMAX_C // [
|
||||||
|
# define UINTMAX_C UINT64_C
|
||||||
|
#endif // UINTMAX_C ]
|
||||||
|
|
||||||
|
#endif // __STDC_CONSTANT_MACROS ]
|
||||||
|
|
||||||
|
#else // ] _MSC_VER >= 1700 [
|
||||||
|
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
|
// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
|
||||||
|
// compiling for ARM we have to wrap <wchar.h> include with 'extern "C++" {}'
|
||||||
|
// or compiler would give many errors like this:
|
||||||
|
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
||||||
|
#if defined(__cplusplus) && !defined(_M_ARM)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
# include <wchar.h>
|
||||||
|
#if defined(__cplusplus) && !defined(_M_ARM)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Define _W64 macros to mark types changing their size, like intptr_t.
|
||||||
|
#ifndef _W64
|
||||||
|
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
|
||||||
|
# define _W64 __w64
|
||||||
|
# else
|
||||||
|
# define _W64
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// 7.18.1 Integer types
|
||||||
|
|
||||||
|
// 7.18.1.1 Exact-width integer types
|
||||||
|
|
||||||
|
// Visual Studio 6 and Embedded Visual C++ 4 doesn't
|
||||||
|
// realize that, e.g. char has the same size as __int8
|
||||||
|
// so we give up on __intX for them.
|
||||||
|
#if (_MSC_VER < 1300)
|
||||||
|
typedef signed char int8_t;
|
||||||
|
typedef signed short int16_t;
|
||||||
|
typedef signed int int32_t;
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
typedef unsigned short uint16_t;
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
#else
|
||||||
|
typedef signed __int8 int8_t;
|
||||||
|
typedef signed __int16 int16_t;
|
||||||
|
typedef signed __int32 int32_t;
|
||||||
|
typedef unsigned __int8 uint8_t;
|
||||||
|
typedef unsigned __int16 uint16_t;
|
||||||
|
typedef unsigned __int32 uint32_t;
|
||||||
|
#endif
|
||||||
|
typedef signed __int64 int64_t;
|
||||||
|
typedef unsigned __int64 uint64_t;
|
||||||
|
|
||||||
|
|
||||||
|
// 7.18.1.2 Minimum-width integer types
|
||||||
|
typedef int8_t int_least8_t;
|
||||||
|
typedef int16_t int_least16_t;
|
||||||
|
typedef int32_t int_least32_t;
|
||||||
|
typedef int64_t int_least64_t;
|
||||||
|
typedef uint8_t uint_least8_t;
|
||||||
|
typedef uint16_t uint_least16_t;
|
||||||
|
typedef uint32_t uint_least32_t;
|
||||||
|
typedef uint64_t uint_least64_t;
|
||||||
|
|
||||||
|
// 7.18.1.3 Fastest minimum-width integer types
|
||||||
|
typedef int8_t int_fast8_t;
|
||||||
|
typedef int16_t int_fast16_t;
|
||||||
|
typedef int32_t int_fast32_t;
|
||||||
|
typedef int64_t int_fast64_t;
|
||||||
|
typedef uint8_t uint_fast8_t;
|
||||||
|
typedef uint16_t uint_fast16_t;
|
||||||
|
typedef uint32_t uint_fast32_t;
|
||||||
|
typedef uint64_t uint_fast64_t;
|
||||||
|
|
||||||
|
// 7.18.1.4 Integer types capable of holding object pointers
|
||||||
|
#ifdef _WIN64 // [
|
||||||
|
typedef signed __int64 intptr_t;
|
||||||
|
typedef unsigned __int64 uintptr_t;
|
||||||
|
#else // _WIN64 ][
|
||||||
|
typedef _W64 signed int intptr_t;
|
||||||
|
typedef _W64 unsigned int uintptr_t;
|
||||||
|
#endif // _WIN64 ]
|
||||||
|
|
||||||
|
// 7.18.1.5 Greatest-width integer types
|
||||||
|
typedef int64_t intmax_t;
|
||||||
|
typedef uint64_t uintmax_t;
|
||||||
|
|
||||||
|
|
||||||
|
// 7.18.2 Limits of specified-width integer types
|
||||||
|
|
||||||
|
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
|
||||||
|
|
||||||
|
// 7.18.2.1 Limits of exact-width integer types
|
||||||
|
#define INT8_MIN ((int8_t)_I8_MIN)
|
||||||
|
#define INT8_MAX _I8_MAX
|
||||||
|
#define INT16_MIN ((int16_t)_I16_MIN)
|
||||||
|
#define INT16_MAX _I16_MAX
|
||||||
|
#define INT32_MIN ((int32_t)_I32_MIN)
|
||||||
|
#define INT32_MAX _I32_MAX
|
||||||
|
#define INT64_MIN ((int64_t)_I64_MIN)
|
||||||
|
#define INT64_MAX _I64_MAX
|
||||||
|
#define UINT8_MAX _UI8_MAX
|
||||||
|
#define UINT16_MAX _UI16_MAX
|
||||||
|
#define UINT32_MAX _UI32_MAX
|
||||||
|
#define UINT64_MAX _UI64_MAX
|
||||||
|
|
||||||
|
// 7.18.2.2 Limits of minimum-width integer types
|
||||||
|
#define INT_LEAST8_MIN INT8_MIN
|
||||||
|
#define INT_LEAST8_MAX INT8_MAX
|
||||||
|
#define INT_LEAST16_MIN INT16_MIN
|
||||||
|
#define INT_LEAST16_MAX INT16_MAX
|
||||||
|
#define INT_LEAST32_MIN INT32_MIN
|
||||||
|
#define INT_LEAST32_MAX INT32_MAX
|
||||||
|
#define INT_LEAST64_MIN INT64_MIN
|
||||||
|
#define INT_LEAST64_MAX INT64_MAX
|
||||||
|
#define UINT_LEAST8_MAX UINT8_MAX
|
||||||
|
#define UINT_LEAST16_MAX UINT16_MAX
|
||||||
|
#define UINT_LEAST32_MAX UINT32_MAX
|
||||||
|
#define UINT_LEAST64_MAX UINT64_MAX
|
||||||
|
|
||||||
|
// 7.18.2.3 Limits of fastest minimum-width integer types
|
||||||
|
#define INT_FAST8_MIN INT8_MIN
|
||||||
|
#define INT_FAST8_MAX INT8_MAX
|
||||||
|
#define INT_FAST16_MIN INT16_MIN
|
||||||
|
#define INT_FAST16_MAX INT16_MAX
|
||||||
|
#define INT_FAST32_MIN INT32_MIN
|
||||||
|
#define INT_FAST32_MAX INT32_MAX
|
||||||
|
#define INT_FAST64_MIN INT64_MIN
|
||||||
|
#define INT_FAST64_MAX INT64_MAX
|
||||||
|
#define UINT_FAST8_MAX UINT8_MAX
|
||||||
|
#define UINT_FAST16_MAX UINT16_MAX
|
||||||
|
#define UINT_FAST32_MAX UINT32_MAX
|
||||||
|
#define UINT_FAST64_MAX UINT64_MAX
|
||||||
|
|
||||||
|
// 7.18.2.4 Limits of integer types capable of holding object pointers
|
||||||
|
#ifdef _WIN64 // [
|
||||||
|
# define INTPTR_MIN INT64_MIN
|
||||||
|
# define INTPTR_MAX INT64_MAX
|
||||||
|
# define UINTPTR_MAX UINT64_MAX
|
||||||
|
#else // _WIN64 ][
|
||||||
|
# define INTPTR_MIN INT32_MIN
|
||||||
|
# define INTPTR_MAX INT32_MAX
|
||||||
|
# define UINTPTR_MAX UINT32_MAX
|
||||||
|
#endif // _WIN64 ]
|
||||||
|
|
||||||
|
// 7.18.2.5 Limits of greatest-width integer types
|
||||||
|
#define INTMAX_MIN INT64_MIN
|
||||||
|
#define INTMAX_MAX INT64_MAX
|
||||||
|
#define UINTMAX_MAX UINT64_MAX
|
||||||
|
|
||||||
|
// 7.18.3 Limits of other integer types
|
||||||
|
|
||||||
|
#ifdef _WIN64 // [
|
||||||
|
# define PTRDIFF_MIN _I64_MIN
|
||||||
|
# define PTRDIFF_MAX _I64_MAX
|
||||||
|
#else // _WIN64 ][
|
||||||
|
# define PTRDIFF_MIN _I32_MIN
|
||||||
|
# define PTRDIFF_MAX _I32_MAX
|
||||||
|
#endif // _WIN64 ]
|
||||||
|
|
||||||
|
#define SIG_ATOMIC_MIN INT_MIN
|
||||||
|
#define SIG_ATOMIC_MAX INT_MAX
|
||||||
|
|
||||||
|
#ifndef SIZE_MAX // [
|
||||||
|
# ifdef _WIN64 // [
|
||||||
|
# define SIZE_MAX _UI64_MAX
|
||||||
|
# else // _WIN64 ][
|
||||||
|
# define SIZE_MAX _UI32_MAX
|
||||||
|
# endif // _WIN64 ]
|
||||||
|
#endif // SIZE_MAX ]
|
||||||
|
|
||||||
|
// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
|
||||||
|
#ifndef WCHAR_MIN // [
|
||||||
|
# define WCHAR_MIN 0
|
||||||
|
#endif // WCHAR_MIN ]
|
||||||
|
#ifndef WCHAR_MAX // [
|
||||||
|
# define WCHAR_MAX _UI16_MAX
|
||||||
|
#endif // WCHAR_MAX ]
|
||||||
|
|
||||||
|
#define WINT_MIN 0
|
||||||
|
#define WINT_MAX _UI16_MAX
|
||||||
|
|
||||||
|
#endif // __STDC_LIMIT_MACROS ]
|
||||||
|
|
||||||
|
|
||||||
|
// 7.18.4 Limits of other integer types
|
||||||
|
|
||||||
|
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
|
||||||
|
|
||||||
|
// 7.18.4.1 Macros for minimum-width integer constants
|
||||||
|
|
||||||
|
#define INT8_C(val) val##i8
|
||||||
|
#define INT16_C(val) val##i16
|
||||||
|
#define INT32_C(val) val##i32
|
||||||
|
#define INT64_C(val) val##i64
|
||||||
|
|
||||||
|
#define UINT8_C(val) val##ui8
|
||||||
|
#define UINT16_C(val) val##ui16
|
||||||
|
#define UINT32_C(val) val##ui32
|
||||||
|
#define UINT64_C(val) val##ui64
|
||||||
|
|
||||||
|
// 7.18.4.2 Macros for greatest-width integer constants
|
||||||
|
// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
|
||||||
|
// Check out Issue 9 for the details.
|
||||||
|
#ifndef INTMAX_C // [
|
||||||
|
# define INTMAX_C INT64_C
|
||||||
|
#endif // INTMAX_C ]
|
||||||
|
#ifndef UINTMAX_C // [
|
||||||
|
# define UINTMAX_C UINT64_C
|
||||||
|
#endif // UINTMAX_C ]
|
||||||
|
|
||||||
|
#endif // __STDC_CONSTANT_MACROS ]
|
||||||
|
|
||||||
|
#endif // _MSC_VER >= 1600 ]
|
||||||
|
|
||||||
|
#endif // _MSC_STDINT_H_ ]
|
|
@ -0,0 +1,81 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_OSTREAMWRAPPER_H_
|
||||||
|
#define RAPIDJSON_OSTREAMWRAPPER_H_
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
#include <iosfwd>
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept.
|
||||||
|
/*!
|
||||||
|
The classes can be wrapped including but not limited to:
|
||||||
|
|
||||||
|
- \c std::ostringstream
|
||||||
|
- \c std::stringstream
|
||||||
|
- \c std::wpstringstream
|
||||||
|
- \c std::wstringstream
|
||||||
|
- \c std::ifstream
|
||||||
|
- \c std::fstream
|
||||||
|
- \c std::wofstream
|
||||||
|
- \c std::wfstream
|
||||||
|
|
||||||
|
\tparam StreamType Class derived from \c std::basic_ostream.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template <typename StreamType>
|
||||||
|
class BasicOStreamWrapper {
|
||||||
|
public:
|
||||||
|
typedef typename StreamType::char_type Ch;
|
||||||
|
BasicOStreamWrapper(StreamType& stream) : stream_(stream) {}
|
||||||
|
|
||||||
|
void Put(Ch c) {
|
||||||
|
stream_.put(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Flush() {
|
||||||
|
stream_.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not implemented
|
||||||
|
char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
char Take() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
BasicOStreamWrapper(const BasicOStreamWrapper&);
|
||||||
|
BasicOStreamWrapper& operator=(const BasicOStreamWrapper&);
|
||||||
|
|
||||||
|
StreamType& stream_;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef BasicOStreamWrapper<std::ostream> OStreamWrapper;
|
||||||
|
typedef BasicOStreamWrapper<std::wostream> WOStreamWrapper;
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_OSTREAMWRAPPER_H_
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,275 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_PRETTYWRITER_H_
|
||||||
|
#define RAPIDJSON_PRETTYWRITER_H_
|
||||||
|
|
||||||
|
#include "writer.h"
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Combination of PrettyWriter format flags.
|
||||||
|
/*! \see PrettyWriter::SetFormatOptions
|
||||||
|
*/
|
||||||
|
enum PrettyFormatOptions {
|
||||||
|
kFormatDefault = 0, //!< Default pretty formatting.
|
||||||
|
kFormatSingleLineArray = 1 //!< Format arrays on a single line.
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Writer with indentation and spacing.
|
||||||
|
/*!
|
||||||
|
\tparam OutputStream Type of ouptut os.
|
||||||
|
\tparam SourceEncoding Encoding of source string.
|
||||||
|
\tparam TargetEncoding Encoding of output stream.
|
||||||
|
\tparam StackAllocator Type of allocator for allocating memory of stack.
|
||||||
|
*/
|
||||||
|
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
|
||||||
|
class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
|
||||||
|
public:
|
||||||
|
typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base;
|
||||||
|
typedef typename Base::Ch Ch;
|
||||||
|
|
||||||
|
//! Constructor
|
||||||
|
/*! \param os Output stream.
|
||||||
|
\param allocator User supplied allocator. If it is null, it will create a private one.
|
||||||
|
\param levelDepth Initial capacity of stack.
|
||||||
|
*/
|
||||||
|
explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
|
||||||
|
Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
|
||||||
|
|
||||||
|
|
||||||
|
explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
|
||||||
|
Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
PrettyWriter(PrettyWriter&& rhs) :
|
||||||
|
Base(std::forward<PrettyWriter>(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! Set custom indentation.
|
||||||
|
/*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
|
||||||
|
\param indentCharCount Number of indent characters for each indentation level.
|
||||||
|
\note The default indentation is 4 spaces.
|
||||||
|
*/
|
||||||
|
PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
|
||||||
|
RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
|
||||||
|
indentChar_ = indentChar;
|
||||||
|
indentCharCount_ = indentCharCount;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Set pretty writer formatting options.
|
||||||
|
/*! \param options Formatting options.
|
||||||
|
*/
|
||||||
|
PrettyWriter& SetFormatOptions(PrettyFormatOptions options) {
|
||||||
|
formatOptions_ = options;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! @name Implementation of Handler
|
||||||
|
\see Handler
|
||||||
|
*/
|
||||||
|
//@{
|
||||||
|
|
||||||
|
bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); }
|
||||||
|
bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }
|
||||||
|
bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); }
|
||||||
|
bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); }
|
||||||
|
bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }
|
||||||
|
bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
|
||||||
|
bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
|
||||||
|
|
||||||
|
bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
|
||||||
|
RAPIDJSON_ASSERT(str != 0);
|
||||||
|
(void)copy;
|
||||||
|
PrettyPrefix(kNumberType);
|
||||||
|
return Base::WriteString(str, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String(const Ch* str, SizeType length, bool copy = false) {
|
||||||
|
RAPIDJSON_ASSERT(str != 0);
|
||||||
|
(void)copy;
|
||||||
|
PrettyPrefix(kStringType);
|
||||||
|
return Base::WriteString(str, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_STDSTRING
|
||||||
|
bool String(const std::basic_string<Ch>& str) {
|
||||||
|
return String(str.data(), SizeType(str.size()));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool StartObject() {
|
||||||
|
PrettyPrefix(kObjectType);
|
||||||
|
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
|
||||||
|
return Base::WriteStartObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_STDSTRING
|
||||||
|
bool Key(const std::basic_string<Ch>& str) {
|
||||||
|
return Key(str.data(), SizeType(str.size()));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool EndObject(SizeType memberCount = 0) {
|
||||||
|
(void)memberCount;
|
||||||
|
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
|
||||||
|
RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
|
||||||
|
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
|
||||||
|
|
||||||
|
if (!empty) {
|
||||||
|
Base::os_->Put('\n');
|
||||||
|
WriteIndent();
|
||||||
|
}
|
||||||
|
bool ret = Base::WriteEndObject();
|
||||||
|
(void)ret;
|
||||||
|
RAPIDJSON_ASSERT(ret == true);
|
||||||
|
if (Base::level_stack_.Empty()) // end of json text
|
||||||
|
Base::os_->Flush();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StartArray() {
|
||||||
|
PrettyPrefix(kArrayType);
|
||||||
|
new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
|
||||||
|
return Base::WriteStartArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EndArray(SizeType memberCount = 0) {
|
||||||
|
(void)memberCount;
|
||||||
|
RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
|
||||||
|
RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
|
||||||
|
bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
|
||||||
|
|
||||||
|
if (!empty && !(formatOptions_ & kFormatSingleLineArray)) {
|
||||||
|
Base::os_->Put('\n');
|
||||||
|
WriteIndent();
|
||||||
|
}
|
||||||
|
bool ret = Base::WriteEndArray();
|
||||||
|
(void)ret;
|
||||||
|
RAPIDJSON_ASSERT(ret == true);
|
||||||
|
if (Base::level_stack_.Empty()) // end of json text
|
||||||
|
Base::os_->Flush();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
/*! @name Convenience extensions */
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Simpler but slower overload.
|
||||||
|
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||||
|
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
//! Write a raw JSON value.
|
||||||
|
/*!
|
||||||
|
For user to write a stringified JSON as a value.
|
||||||
|
|
||||||
|
\param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
|
||||||
|
\param length Length of the json.
|
||||||
|
\param type Type of the root of json.
|
||||||
|
\note When using PrettyWriter::RawValue(), the result json may not be indented correctly.
|
||||||
|
*/
|
||||||
|
bool RawValue(const Ch* json, size_t length, Type type) {
|
||||||
|
RAPIDJSON_ASSERT(json != 0);
|
||||||
|
PrettyPrefix(type);
|
||||||
|
return Base::WriteRawValue(json, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void PrettyPrefix(Type type) {
|
||||||
|
(void)type;
|
||||||
|
if (Base::level_stack_.GetSize() != 0) { // this value is not at root
|
||||||
|
typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
|
||||||
|
|
||||||
|
if (level->inArray) {
|
||||||
|
if (level->valueCount > 0) {
|
||||||
|
Base::os_->Put(','); // add comma if it is not the first element in array
|
||||||
|
if (formatOptions_ & kFormatSingleLineArray)
|
||||||
|
Base::os_->Put(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(formatOptions_ & kFormatSingleLineArray)) {
|
||||||
|
Base::os_->Put('\n');
|
||||||
|
WriteIndent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { // in object
|
||||||
|
if (level->valueCount > 0) {
|
||||||
|
if (level->valueCount % 2 == 0) {
|
||||||
|
Base::os_->Put(',');
|
||||||
|
Base::os_->Put('\n');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Base::os_->Put(':');
|
||||||
|
Base::os_->Put(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Base::os_->Put('\n');
|
||||||
|
|
||||||
|
if (level->valueCount % 2 == 0)
|
||||||
|
WriteIndent();
|
||||||
|
}
|
||||||
|
if (!level->inArray && level->valueCount % 2 == 0)
|
||||||
|
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
|
||||||
|
level->valueCount++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root.
|
||||||
|
Base::hasRoot_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WriteIndent() {
|
||||||
|
size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
|
||||||
|
PutN(*Base::os_, static_cast<typename TargetEncoding::Ch>(indentChar_), count);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ch indentChar_;
|
||||||
|
unsigned indentCharCount_;
|
||||||
|
PrettyFormatOptions formatOptions_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Prohibit copy constructor & assignment operator.
|
||||||
|
PrettyWriter(const PrettyWriter&);
|
||||||
|
PrettyWriter& operator=(const PrettyWriter&);
|
||||||
|
};
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_RAPIDJSON_H_
|
|
@ -0,0 +1,615 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_RAPIDJSON_H_
|
||||||
|
#define RAPIDJSON_RAPIDJSON_H_
|
||||||
|
|
||||||
|
/*!\file rapidjson.h
|
||||||
|
\brief common definitions and configuration
|
||||||
|
|
||||||
|
\see RAPIDJSON_CONFIG
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration
|
||||||
|
\brief Configuration macros for library features
|
||||||
|
|
||||||
|
Some RapidJSON features are configurable to adapt the library to a wide
|
||||||
|
variety of platforms, environments and usage scenarios. Most of the
|
||||||
|
features can be configured in terms of overriden or predefined
|
||||||
|
preprocessor macros at compile-time.
|
||||||
|
|
||||||
|
Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs.
|
||||||
|
|
||||||
|
\note These macros should be given on the compiler command-line
|
||||||
|
(where applicable) to avoid inconsistent values when compiling
|
||||||
|
different translation units of a single application.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstdlib> // malloc(), realloc(), free(), size_t
|
||||||
|
#include <cstring> // memset(), memcpy(), memmove(), memcmp()
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_VERSION_STRING
|
||||||
|
//
|
||||||
|
// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt.
|
||||||
|
//
|
||||||
|
|
||||||
|
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||||
|
// token stringification
|
||||||
|
#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
|
||||||
|
#define RAPIDJSON_DO_STRINGIFY(x) #x
|
||||||
|
//!@endcond
|
||||||
|
|
||||||
|
/*! \def RAPIDJSON_MAJOR_VERSION
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\brief Major version of RapidJSON in integer.
|
||||||
|
*/
|
||||||
|
/*! \def RAPIDJSON_MINOR_VERSION
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\brief Minor version of RapidJSON in integer.
|
||||||
|
*/
|
||||||
|
/*! \def RAPIDJSON_PATCH_VERSION
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\brief Patch version of RapidJSON in integer.
|
||||||
|
*/
|
||||||
|
/*! \def RAPIDJSON_VERSION_STRING
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\brief Version of RapidJSON in "<major>.<minor>.<patch>" string format.
|
||||||
|
*/
|
||||||
|
#define RAPIDJSON_MAJOR_VERSION 1
|
||||||
|
#define RAPIDJSON_MINOR_VERSION 1
|
||||||
|
#define RAPIDJSON_PATCH_VERSION 0
|
||||||
|
#define RAPIDJSON_VERSION_STRING \
|
||||||
|
RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION)
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_NAMESPACE_(BEGIN|END)
|
||||||
|
/*! \def RAPIDJSON_NAMESPACE
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\brief provide custom rapidjson namespace
|
||||||
|
|
||||||
|
In order to avoid symbol clashes and/or "One Definition Rule" errors
|
||||||
|
between multiple inclusions of (different versions of) RapidJSON in
|
||||||
|
a single binary, users can customize the name of the main RapidJSON
|
||||||
|
namespace.
|
||||||
|
|
||||||
|
In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE
|
||||||
|
to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple
|
||||||
|
levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref
|
||||||
|
RAPIDJSON_NAMESPACE_END need to be defined as well:
|
||||||
|
|
||||||
|
\code
|
||||||
|
// in some .cpp file
|
||||||
|
#define RAPIDJSON_NAMESPACE my::rapidjson
|
||||||
|
#define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson {
|
||||||
|
#define RAPIDJSON_NAMESPACE_END } }
|
||||||
|
#include "rapidjson/..."
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\see rapidjson
|
||||||
|
*/
|
||||||
|
/*! \def RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\brief provide custom rapidjson namespace (opening expression)
|
||||||
|
\see RAPIDJSON_NAMESPACE
|
||||||
|
*/
|
||||||
|
/*! \def RAPIDJSON_NAMESPACE_END
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\brief provide custom rapidjson namespace (closing expression)
|
||||||
|
\see RAPIDJSON_NAMESPACE
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_NAMESPACE
|
||||||
|
#define RAPIDJSON_NAMESPACE rapidjson
|
||||||
|
#endif
|
||||||
|
#ifndef RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE {
|
||||||
|
#endif
|
||||||
|
#ifndef RAPIDJSON_NAMESPACE_END
|
||||||
|
#define RAPIDJSON_NAMESPACE_END }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_HAS_STDSTRING
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_HAS_STDSTRING
|
||||||
|
#ifdef RAPIDJSON_DOXYGEN_RUNNING
|
||||||
|
#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default
|
||||||
|
#endif
|
||||||
|
/*! \def RAPIDJSON_HAS_STDSTRING
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\brief Enable RapidJSON support for \c std::string
|
||||||
|
|
||||||
|
By defining this preprocessor symbol to \c 1, several convenience functions for using
|
||||||
|
\ref rapidjson::GenericValue with \c std::string are enabled, especially
|
||||||
|
for construction and comparison.
|
||||||
|
|
||||||
|
\hideinitializer
|
||||||
|
*/
|
||||||
|
#endif // !defined(RAPIDJSON_HAS_STDSTRING)
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_STDSTRING
|
||||||
|
#include <string>
|
||||||
|
#endif // RAPIDJSON_HAS_STDSTRING
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_NO_INT64DEFINE
|
||||||
|
|
||||||
|
/*! \def RAPIDJSON_NO_INT64DEFINE
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\brief Use external 64-bit integer types.
|
||||||
|
|
||||||
|
RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types
|
||||||
|
to be available at global scope.
|
||||||
|
|
||||||
|
If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to
|
||||||
|
prevent RapidJSON from defining its own types.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_NO_INT64DEFINE
|
||||||
|
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||||
|
#if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013
|
||||||
|
#include "msinttypes/stdint.h"
|
||||||
|
#include "msinttypes/inttypes.h"
|
||||||
|
#else
|
||||||
|
// Other compilers should have this.
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#endif
|
||||||
|
//!@endcond
|
||||||
|
#ifdef RAPIDJSON_DOXYGEN_RUNNING
|
||||||
|
#define RAPIDJSON_NO_INT64DEFINE
|
||||||
|
#endif
|
||||||
|
#endif // RAPIDJSON_NO_INT64TYPEDEF
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_FORCEINLINE
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_FORCEINLINE
|
||||||
|
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||||
|
#if defined(_MSC_VER) && defined(NDEBUG)
|
||||||
|
#define RAPIDJSON_FORCEINLINE __forceinline
|
||||||
|
#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG)
|
||||||
|
#define RAPIDJSON_FORCEINLINE __attribute__((always_inline))
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_FORCEINLINE
|
||||||
|
#endif
|
||||||
|
//!@endcond
|
||||||
|
#endif // RAPIDJSON_FORCEINLINE
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_ENDIAN
|
||||||
|
#define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine
|
||||||
|
#define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine
|
||||||
|
|
||||||
|
//! Endianness of the machine.
|
||||||
|
/*!
|
||||||
|
\def RAPIDJSON_ENDIAN
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
|
||||||
|
GCC 4.6 provided macro for detecting endianness of the target machine. But other
|
||||||
|
compilers may not have this. User can define RAPIDJSON_ENDIAN to either
|
||||||
|
\ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN.
|
||||||
|
|
||||||
|
Default detection implemented with reference to
|
||||||
|
\li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html
|
||||||
|
\li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_ENDIAN
|
||||||
|
// Detect with GCC 4.6's macro
|
||||||
|
# ifdef __BYTE_ORDER__
|
||||||
|
# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||||
|
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||||
|
# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
||||||
|
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||||
|
# else
|
||||||
|
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
|
||||||
|
# endif // __BYTE_ORDER__
|
||||||
|
// Detect with GLIBC's endian.h
|
||||||
|
# elif defined(__GLIBC__)
|
||||||
|
# include <endian.h>
|
||||||
|
# if (__BYTE_ORDER == __LITTLE_ENDIAN)
|
||||||
|
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||||
|
# elif (__BYTE_ORDER == __BIG_ENDIAN)
|
||||||
|
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||||
|
# else
|
||||||
|
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
|
||||||
|
# endif // __GLIBC__
|
||||||
|
// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro
|
||||||
|
# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
|
||||||
|
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||||
|
# elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
|
||||||
|
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||||
|
// Detect with architecture macros
|
||||||
|
# elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)
|
||||||
|
# define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
|
||||||
|
# elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
|
||||||
|
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||||
|
# elif defined(_MSC_VER) && defined(_M_ARM)
|
||||||
|
# define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
|
||||||
|
# elif defined(RAPIDJSON_DOXYGEN_RUNNING)
|
||||||
|
# define RAPIDJSON_ENDIAN
|
||||||
|
# else
|
||||||
|
# error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
|
||||||
|
# endif
|
||||||
|
#endif // RAPIDJSON_ENDIAN
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_64BIT
|
||||||
|
|
||||||
|
//! Whether using 64-bit architecture
|
||||||
|
#ifndef RAPIDJSON_64BIT
|
||||||
|
#if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__)
|
||||||
|
#define RAPIDJSON_64BIT 1
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_64BIT 0
|
||||||
|
#endif
|
||||||
|
#endif // RAPIDJSON_64BIT
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_ALIGN
|
||||||
|
|
||||||
|
//! Data alignment of the machine.
|
||||||
|
/*! \ingroup RAPIDJSON_CONFIG
|
||||||
|
\param x pointer to align
|
||||||
|
|
||||||
|
Some machines require strict data alignment. Currently the default uses 4 bytes
|
||||||
|
alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms.
|
||||||
|
User can customize by defining the RAPIDJSON_ALIGN function macro.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_ALIGN
|
||||||
|
#if RAPIDJSON_64BIT == 1
|
||||||
|
#define RAPIDJSON_ALIGN(x) (((x) + static_cast<uint64_t>(7u)) & ~static_cast<uint64_t>(7u))
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_UINT64_C2
|
||||||
|
|
||||||
|
//! Construct a 64-bit literal by a pair of 32-bit integer.
|
||||||
|
/*!
|
||||||
|
64-bit literal with or without ULL suffix is prone to compiler warnings.
|
||||||
|
UINT64_C() is C macro which cause compilation problems.
|
||||||
|
Use this macro to define 64-bit constants by a pair of 32-bit integer.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_UINT64_C2
|
||||||
|
#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_48BITPOINTER_OPTIMIZATION
|
||||||
|
|
||||||
|
//! Use only lower 48-bit address for some pointers.
|
||||||
|
/*!
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
|
||||||
|
This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address.
|
||||||
|
The higher 16-bit can be used for storing other data.
|
||||||
|
\c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION
|
||||||
|
#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
|
||||||
|
#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0
|
||||||
|
#endif
|
||||||
|
#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION
|
||||||
|
|
||||||
|
#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1
|
||||||
|
#if RAPIDJSON_64BIT != 1
|
||||||
|
#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1
|
||||||
|
#endif
|
||||||
|
#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))
|
||||||
|
#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF))))
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x))
|
||||||
|
#define RAPIDJSON_GETPOINTER(type, p) (p)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
|
||||||
|
|
||||||
|
/*! \def RAPIDJSON_SIMD
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\brief Enable SSE2/SSE4.2 optimization.
|
||||||
|
|
||||||
|
RapidJSON supports optimized implementations for some parsing operations
|
||||||
|
based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible
|
||||||
|
processors.
|
||||||
|
|
||||||
|
To enable these optimizations, two different symbols can be defined;
|
||||||
|
\code
|
||||||
|
// Enable SSE2 optimization.
|
||||||
|
#define RAPIDJSON_SSE2
|
||||||
|
|
||||||
|
// Enable SSE4.2 optimization.
|
||||||
|
#define RAPIDJSON_SSE42
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\c RAPIDJSON_SSE42 takes precedence, if both are defined.
|
||||||
|
|
||||||
|
If any of these symbols is defined, RapidJSON defines the macro
|
||||||
|
\c RAPIDJSON_SIMD to indicate the availability of the optimized code.
|
||||||
|
*/
|
||||||
|
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \
|
||||||
|
|| defined(RAPIDJSON_DOXYGEN_RUNNING)
|
||||||
|
#define RAPIDJSON_SIMD
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_NO_SIZETYPEDEFINE
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_NO_SIZETYPEDEFINE
|
||||||
|
/*! \def RAPIDJSON_NO_SIZETYPEDEFINE
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\brief User-provided \c SizeType definition.
|
||||||
|
|
||||||
|
In order to avoid using 32-bit size types for indexing strings and arrays,
|
||||||
|
define this preprocessor symbol and provide the type rapidjson::SizeType
|
||||||
|
before including RapidJSON:
|
||||||
|
\code
|
||||||
|
#define RAPIDJSON_NO_SIZETYPEDEFINE
|
||||||
|
namespace rapidjson { typedef ::std::size_t SizeType; }
|
||||||
|
#include "rapidjson/..."
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
\see rapidjson::SizeType
|
||||||
|
*/
|
||||||
|
#ifdef RAPIDJSON_DOXYGEN_RUNNING
|
||||||
|
#define RAPIDJSON_NO_SIZETYPEDEFINE
|
||||||
|
#endif
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
//! Size type (for string lengths, array sizes, etc.)
|
||||||
|
/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms,
|
||||||
|
instead of using \c size_t. Users may override the SizeType by defining
|
||||||
|
\ref RAPIDJSON_NO_SIZETYPEDEFINE.
|
||||||
|
*/
|
||||||
|
typedef unsigned SizeType;
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// always import std::size_t to rapidjson namespace
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
using std::size_t;
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_ASSERT
|
||||||
|
|
||||||
|
//! Assertion.
|
||||||
|
/*! \ingroup RAPIDJSON_CONFIG
|
||||||
|
By default, rapidjson uses C \c assert() for internal assertions.
|
||||||
|
User can override it by defining RAPIDJSON_ASSERT(x) macro.
|
||||||
|
|
||||||
|
\note Parsing errors are handled and can be customized by the
|
||||||
|
\ref RAPIDJSON_ERRORS APIs.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_ASSERT
|
||||||
|
#include <cassert>
|
||||||
|
#define RAPIDJSON_ASSERT(x) assert(x)
|
||||||
|
#endif // RAPIDJSON_ASSERT
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_STATIC_ASSERT
|
||||||
|
|
||||||
|
// Adopt from boost
|
||||||
|
#ifndef RAPIDJSON_STATIC_ASSERT
|
||||||
|
#ifndef __clang__
|
||||||
|
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||||
|
#endif
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
template <bool x> struct STATIC_ASSERTION_FAILURE;
|
||||||
|
template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
|
||||||
|
template<int x> struct StaticAssertTest {};
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)
|
||||||
|
#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)
|
||||||
|
#define RAPIDJSON_DO_JOIN2(X, Y) X##Y
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
|
||||||
|
#endif
|
||||||
|
#ifndef __clang__
|
||||||
|
//!@endcond
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*! \def RAPIDJSON_STATIC_ASSERT
|
||||||
|
\brief (Internal) macro to check for conditions at compile-time
|
||||||
|
\param x compile-time condition
|
||||||
|
\hideinitializer
|
||||||
|
*/
|
||||||
|
#define RAPIDJSON_STATIC_ASSERT(x) \
|
||||||
|
typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \
|
||||||
|
sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \
|
||||||
|
RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY
|
||||||
|
|
||||||
|
//! Compiler branching hint for expression with high probability to be true.
|
||||||
|
/*!
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\param x Boolean expression likely to be true.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_LIKELY
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_LIKELY(x) (x)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! Compiler branching hint for expression with low probability to be true.
|
||||||
|
/*!
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\param x Boolean expression unlikely to be true.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_UNLIKELY
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_UNLIKELY(x) (x)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Helpers
|
||||||
|
|
||||||
|
//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
|
||||||
|
|
||||||
|
#define RAPIDJSON_MULTILINEMACRO_BEGIN do {
|
||||||
|
#define RAPIDJSON_MULTILINEMACRO_END \
|
||||||
|
} while((void)0, 0)
|
||||||
|
|
||||||
|
// adopted from Boost
|
||||||
|
#define RAPIDJSON_VERSION_CODE(x,y,z) \
|
||||||
|
(((x)*100000) + ((y)*100) + (z))
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#define RAPIDJSON_GNUC \
|
||||||
|
RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0))
|
||||||
|
|
||||||
|
#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x))
|
||||||
|
#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x)
|
||||||
|
#define RAPIDJSON_DIAG_OFF(x) \
|
||||||
|
RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x)))
|
||||||
|
|
||||||
|
// push/pop support in Clang and GCC>=4.6
|
||||||
|
#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0))
|
||||||
|
#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
|
||||||
|
#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
|
||||||
|
#else // GCC >= 4.2, < 4.6
|
||||||
|
#define RAPIDJSON_DIAG_PUSH /* ignored */
|
||||||
|
#define RAPIDJSON_DIAG_POP /* ignored */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
|
||||||
|
// pragma (MSVC specific)
|
||||||
|
#define RAPIDJSON_PRAGMA(x) __pragma(x)
|
||||||
|
#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x))
|
||||||
|
|
||||||
|
#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x)
|
||||||
|
#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
|
||||||
|
#define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define RAPIDJSON_DIAG_OFF(x) /* ignored */
|
||||||
|
#define RAPIDJSON_DIAG_PUSH /* ignored */
|
||||||
|
#define RAPIDJSON_DIAG_POP /* ignored */
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_DIAG_*
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// C++11 features
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
#if defined(__clang__)
|
||||||
|
#if __has_feature(cxx_rvalue_references) && \
|
||||||
|
(defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
|
||||||
|
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
|
||||||
|
#endif
|
||||||
|
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
|
||||||
|
(defined(_MSC_VER) && _MSC_VER >= 1600)
|
||||||
|
|
||||||
|
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
|
||||||
|
#endif
|
||||||
|
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||||
|
#if defined(__clang__)
|
||||||
|
#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
|
||||||
|
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__))
|
||||||
|
// (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported
|
||||||
|
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||||
|
#define RAPIDJSON_NOEXCEPT noexcept
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_NOEXCEPT /* noexcept */
|
||||||
|
#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
|
||||||
|
|
||||||
|
// no automatic detection, yet
|
||||||
|
#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||||
|
#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR
|
||||||
|
#if defined(__clang__)
|
||||||
|
#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for)
|
||||||
|
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
|
||||||
|
(defined(_MSC_VER) && _MSC_VER >= 1700)
|
||||||
|
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1
|
||||||
|
#else
|
||||||
|
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0
|
||||||
|
#endif
|
||||||
|
#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR
|
||||||
|
|
||||||
|
//!@endcond
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// new/delete
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_NEW
|
||||||
|
///! customization point for global \c new
|
||||||
|
#define RAPIDJSON_NEW(x) new x
|
||||||
|
#endif
|
||||||
|
#ifndef RAPIDJSON_DELETE
|
||||||
|
///! customization point for global \c delete
|
||||||
|
#define RAPIDJSON_DELETE(x) delete x
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Type
|
||||||
|
|
||||||
|
/*! \namespace rapidjson
|
||||||
|
\brief main RapidJSON namespace
|
||||||
|
\see RAPIDJSON_NAMESPACE
|
||||||
|
*/
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Type of JSON value
|
||||||
|
enum Type {
|
||||||
|
kNullType = 0, //!< null
|
||||||
|
kFalseType = 1, //!< false
|
||||||
|
kTrueType = 2, //!< true
|
||||||
|
kObjectType = 3, //!< object
|
||||||
|
kArrayType = 4, //!< array
|
||||||
|
kStringType = 5, //!< string
|
||||||
|
kNumberType = 6 //!< number
|
||||||
|
};
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_RAPIDJSON_H_
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,179 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#include "rapidjson.h"
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_STREAM_H_
|
||||||
|
#define RAPIDJSON_STREAM_H_
|
||||||
|
|
||||||
|
#include "encodings.h"
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Stream
|
||||||
|
|
||||||
|
/*! \class rapidjson::Stream
|
||||||
|
\brief Concept for reading and writing characters.
|
||||||
|
|
||||||
|
For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd().
|
||||||
|
|
||||||
|
For write-only stream, only need to implement Put() and Flush().
|
||||||
|
|
||||||
|
\code
|
||||||
|
concept Stream {
|
||||||
|
typename Ch; //!< Character type of the stream.
|
||||||
|
|
||||||
|
//! Read the current character from stream without moving the read cursor.
|
||||||
|
Ch Peek() const;
|
||||||
|
|
||||||
|
//! Read the current character from stream and moving the read cursor to next character.
|
||||||
|
Ch Take();
|
||||||
|
|
||||||
|
//! Get the current read cursor.
|
||||||
|
//! \return Number of characters read from start.
|
||||||
|
size_t Tell();
|
||||||
|
|
||||||
|
//! Begin writing operation at the current read pointer.
|
||||||
|
//! \return The begin writer pointer.
|
||||||
|
Ch* PutBegin();
|
||||||
|
|
||||||
|
//! Write a character.
|
||||||
|
void Put(Ch c);
|
||||||
|
|
||||||
|
//! Flush the buffer.
|
||||||
|
void Flush();
|
||||||
|
|
||||||
|
//! End the writing operation.
|
||||||
|
//! \param begin The begin write pointer returned by PutBegin().
|
||||||
|
//! \return Number of characters written.
|
||||||
|
size_t PutEnd(Ch* begin);
|
||||||
|
}
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
|
||||||
|
//! Provides additional information for stream.
|
||||||
|
/*!
|
||||||
|
By using traits pattern, this type provides a default configuration for stream.
|
||||||
|
For custom stream, this type can be specialized for other configuration.
|
||||||
|
See TEST(Reader, CustomStringStream) in readertest.cpp for example.
|
||||||
|
*/
|
||||||
|
template<typename Stream>
|
||||||
|
struct StreamTraits {
|
||||||
|
//! Whether to make local copy of stream for optimization during parsing.
|
||||||
|
/*!
|
||||||
|
By default, for safety, streams do not use local copy optimization.
|
||||||
|
Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.
|
||||||
|
*/
|
||||||
|
enum { copyOptimization = 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Reserve n characters for writing to a stream.
|
||||||
|
template<typename Stream>
|
||||||
|
inline void PutReserve(Stream& stream, size_t count) {
|
||||||
|
(void)stream;
|
||||||
|
(void)count;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Write character to a stream, presuming buffer is reserved.
|
||||||
|
template<typename Stream>
|
||||||
|
inline void PutUnsafe(Stream& stream, typename Stream::Ch c) {
|
||||||
|
stream.Put(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Put N copies of a character to a stream.
|
||||||
|
template<typename Stream, typename Ch>
|
||||||
|
inline void PutN(Stream& stream, Ch c, size_t n) {
|
||||||
|
PutReserve(stream, n);
|
||||||
|
for (size_t i = 0; i < n; i++)
|
||||||
|
PutUnsafe(stream, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// StringStream
|
||||||
|
|
||||||
|
//! Read-only string stream.
|
||||||
|
/*! \note implements Stream concept
|
||||||
|
*/
|
||||||
|
template <typename Encoding>
|
||||||
|
struct GenericStringStream {
|
||||||
|
typedef typename Encoding::Ch Ch;
|
||||||
|
|
||||||
|
GenericStringStream(const Ch *src) : src_(src), head_(src) {}
|
||||||
|
|
||||||
|
Ch Peek() const { return *src_; }
|
||||||
|
Ch Take() { return *src_++; }
|
||||||
|
size_t Tell() const { return static_cast<size_t>(src_ - head_); }
|
||||||
|
|
||||||
|
Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
void Put(Ch) { RAPIDJSON_ASSERT(false); }
|
||||||
|
void Flush() { RAPIDJSON_ASSERT(false); }
|
||||||
|
size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
|
||||||
|
|
||||||
|
const Ch* src_; //!< Current read position.
|
||||||
|
const Ch* head_; //!< Original head of the string.
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Encoding>
|
||||||
|
struct StreamTraits<GenericStringStream<Encoding> > {
|
||||||
|
enum { copyOptimization = 1 };
|
||||||
|
};
|
||||||
|
|
||||||
|
//! String stream with UTF8 encoding.
|
||||||
|
typedef GenericStringStream<UTF8<> > StringStream;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// InsituStringStream
|
||||||
|
|
||||||
|
//! A read-write string stream.
|
||||||
|
/*! This string stream is particularly designed for in-situ parsing.
|
||||||
|
\note implements Stream concept
|
||||||
|
*/
|
||||||
|
template <typename Encoding>
|
||||||
|
struct GenericInsituStringStream {
|
||||||
|
typedef typename Encoding::Ch Ch;
|
||||||
|
|
||||||
|
GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}
|
||||||
|
|
||||||
|
// Read
|
||||||
|
Ch Peek() { return *src_; }
|
||||||
|
Ch Take() { return *src_++; }
|
||||||
|
size_t Tell() { return static_cast<size_t>(src_ - head_); }
|
||||||
|
|
||||||
|
// Write
|
||||||
|
void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
|
||||||
|
|
||||||
|
Ch* PutBegin() { return dst_ = src_; }
|
||||||
|
size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }
|
||||||
|
void Flush() {}
|
||||||
|
|
||||||
|
Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; }
|
||||||
|
void Pop(size_t count) { dst_ -= count; }
|
||||||
|
|
||||||
|
Ch* src_;
|
||||||
|
Ch* dst_;
|
||||||
|
Ch* head_;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Encoding>
|
||||||
|
struct StreamTraits<GenericInsituStringStream<Encoding> > {
|
||||||
|
enum { copyOptimization = 1 };
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Insitu string stream with UTF8 encoding.
|
||||||
|
typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_STREAM_H_
|
|
@ -0,0 +1,121 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_STRINGBUFFER_H_
|
||||||
|
#define RAPIDJSON_STRINGBUFFER_H_
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
#include "internal/stack.h"
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
#include <utility> // std::move
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "internal/stack.h"
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
//! Represents an in-memory output stream.
|
||||||
|
/*!
|
||||||
|
\tparam Encoding Encoding of the stream.
|
||||||
|
\tparam Allocator type for allocating memory buffer.
|
||||||
|
\note implements Stream concept
|
||||||
|
*/
|
||||||
|
template <typename Encoding, typename Allocator = CrtAllocator>
|
||||||
|
class GenericStringBuffer {
|
||||||
|
public:
|
||||||
|
typedef typename Encoding::Ch Ch;
|
||||||
|
|
||||||
|
GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}
|
||||||
|
GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {
|
||||||
|
if (&rhs != this)
|
||||||
|
stack_ = std::move(rhs.stack_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void Put(Ch c) { *stack_.template Push<Ch>() = c; }
|
||||||
|
void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; }
|
||||||
|
void Flush() {}
|
||||||
|
|
||||||
|
void Clear() { stack_.Clear(); }
|
||||||
|
void ShrinkToFit() {
|
||||||
|
// Push and pop a null terminator. This is safe.
|
||||||
|
*stack_.template Push<Ch>() = '\0';
|
||||||
|
stack_.ShrinkToFit();
|
||||||
|
stack_.template Pop<Ch>(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Reserve(size_t count) { stack_.template Reserve<Ch>(count); }
|
||||||
|
Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
|
||||||
|
Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<Ch>(count); }
|
||||||
|
void Pop(size_t count) { stack_.template Pop<Ch>(count); }
|
||||||
|
|
||||||
|
const Ch* GetString() const {
|
||||||
|
// Push and pop a null terminator. This is safe.
|
||||||
|
*stack_.template Push<Ch>() = '\0';
|
||||||
|
stack_.template Pop<Ch>(1);
|
||||||
|
|
||||||
|
return stack_.template Bottom<Ch>();
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Get the size of string in bytes in the string buffer.
|
||||||
|
size_t GetSize() const { return stack_.GetSize(); }
|
||||||
|
|
||||||
|
//! Get the length of string in Ch in the string buffer.
|
||||||
|
size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); }
|
||||||
|
|
||||||
|
static const size_t kDefaultCapacity = 256;
|
||||||
|
mutable internal::Stack<Allocator> stack_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Prohibit copy constructor & assignment operator.
|
||||||
|
GenericStringBuffer(const GenericStringBuffer&);
|
||||||
|
GenericStringBuffer& operator=(const GenericStringBuffer&);
|
||||||
|
};
|
||||||
|
|
||||||
|
//! String buffer with UTF8 encoding
|
||||||
|
typedef GenericStringBuffer<UTF8<> > StringBuffer;
|
||||||
|
|
||||||
|
template<typename Encoding, typename Allocator>
|
||||||
|
inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) {
|
||||||
|
stream.Reserve(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Encoding, typename Allocator>
|
||||||
|
inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) {
|
||||||
|
stream.PutUnsafe(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Implement specialized version of PutN() with memset() for better performance.
|
||||||
|
template<>
|
||||||
|
inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
|
||||||
|
std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
|
||||||
|
}
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_STRINGBUFFER_H_
|
|
@ -0,0 +1,624 @@
|
||||||
|
// Tencent is pleased to support the open source community by making RapidJSON available.
|
||||||
|
//
|
||||||
|
// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the MIT License (the "License"); you may not use this file except
|
||||||
|
// in compliance with the License. You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://opensource.org/licenses/MIT
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software distributed
|
||||||
|
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
// specific language governing permissions and limitations under the License.
|
||||||
|
|
||||||
|
#ifndef RAPIDJSON_WRITER_H_
|
||||||
|
#define RAPIDJSON_WRITER_H_
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
#include "internal/stack.h"
|
||||||
|
#include "internal/strfunc.h"
|
||||||
|
#include "internal/dtoa.h"
|
||||||
|
#include "internal/itoa.h"
|
||||||
|
#include "stringbuffer.h"
|
||||||
|
#include <new> // placement new
|
||||||
|
|
||||||
|
#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
|
||||||
|
#include <intrin.h>
|
||||||
|
#pragma intrinsic(_BitScanForward)
|
||||||
|
#endif
|
||||||
|
#ifdef RAPIDJSON_SSE42
|
||||||
|
#include <nmmintrin.h>
|
||||||
|
#elif defined(RAPIDJSON_SSE2)
|
||||||
|
#include <emmintrin.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(padded)
|
||||||
|
RAPIDJSON_DIAG_OFF(unreachable-code)
|
||||||
|
RAPIDJSON_DIAG_OFF(c++98-compat)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// WriteFlag
|
||||||
|
|
||||||
|
/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS
|
||||||
|
\ingroup RAPIDJSON_CONFIG
|
||||||
|
\brief User-defined kWriteDefaultFlags definition.
|
||||||
|
|
||||||
|
User can define this as any \c WriteFlag combinations.
|
||||||
|
*/
|
||||||
|
#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
|
||||||
|
#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! Combination of writeFlags
|
||||||
|
enum WriteFlag {
|
||||||
|
kWriteNoFlags = 0, //!< No flags are set.
|
||||||
|
kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.
|
||||||
|
kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN.
|
||||||
|
kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS
|
||||||
|
};
|
||||||
|
|
||||||
|
//! JSON writer
|
||||||
|
/*! Writer implements the concept Handler.
|
||||||
|
It generates JSON text by events to an output os.
|
||||||
|
|
||||||
|
User may programmatically calls the functions of a writer to generate JSON text.
|
||||||
|
|
||||||
|
On the other side, a writer can also be passed to objects that generates events,
|
||||||
|
|
||||||
|
for example Reader::Parse() and Document::Accept().
|
||||||
|
|
||||||
|
\tparam OutputStream Type of output stream.
|
||||||
|
\tparam SourceEncoding Encoding of source string.
|
||||||
|
\tparam TargetEncoding Encoding of output stream.
|
||||||
|
\tparam StackAllocator Type of allocator for allocating memory of stack.
|
||||||
|
\note implements Handler concept
|
||||||
|
*/
|
||||||
|
template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
|
||||||
|
class Writer {
|
||||||
|
public:
|
||||||
|
typedef typename SourceEncoding::Ch Ch;
|
||||||
|
|
||||||
|
static const int kDefaultMaxDecimalPlaces = 324;
|
||||||
|
|
||||||
|
//! Constructor
|
||||||
|
/*! \param os Output stream.
|
||||||
|
\param stackAllocator User supplied allocator. If it is null, it will create a private one.
|
||||||
|
\param levelDepth Initial capacity of stack.
|
||||||
|
*/
|
||||||
|
explicit
|
||||||
|
Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
|
||||||
|
os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
|
||||||
|
|
||||||
|
explicit
|
||||||
|
Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
|
||||||
|
os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
|
||||||
|
Writer(Writer&& rhs) :
|
||||||
|
os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) {
|
||||||
|
rhs.os_ = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! Reset the writer with a new stream.
|
||||||
|
/*!
|
||||||
|
This function reset the writer with a new stream and default settings,
|
||||||
|
in order to make a Writer object reusable for output multiple JSONs.
|
||||||
|
|
||||||
|
\param os New output stream.
|
||||||
|
\code
|
||||||
|
Writer<OutputStream> writer(os1);
|
||||||
|
writer.StartObject();
|
||||||
|
// ...
|
||||||
|
writer.EndObject();
|
||||||
|
|
||||||
|
writer.Reset(os2);
|
||||||
|
writer.StartObject();
|
||||||
|
// ...
|
||||||
|
writer.EndObject();
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
void Reset(OutputStream& os) {
|
||||||
|
os_ = &os;
|
||||||
|
hasRoot_ = false;
|
||||||
|
level_stack_.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Checks whether the output is a complete JSON.
|
||||||
|
/*!
|
||||||
|
A complete JSON has a complete root object or array.
|
||||||
|
*/
|
||||||
|
bool IsComplete() const {
|
||||||
|
return hasRoot_ && level_stack_.Empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetMaxDecimalPlaces() const {
|
||||||
|
return maxDecimalPlaces_;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Sets the maximum number of decimal places for double output.
|
||||||
|
/*!
|
||||||
|
This setting truncates the output with specified number of decimal places.
|
||||||
|
|
||||||
|
For example,
|
||||||
|
|
||||||
|
\code
|
||||||
|
writer.SetMaxDecimalPlaces(3);
|
||||||
|
writer.StartArray();
|
||||||
|
writer.Double(0.12345); // "0.123"
|
||||||
|
writer.Double(0.0001); // "0.0"
|
||||||
|
writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent)
|
||||||
|
writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent)
|
||||||
|
writer.EndArray();
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
The default setting does not truncate any decimal places. You can restore to this setting by calling
|
||||||
|
\code
|
||||||
|
writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces);
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
void SetMaxDecimalPlaces(int maxDecimalPlaces) {
|
||||||
|
maxDecimalPlaces_ = maxDecimalPlaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!@name Implementation of Handler
|
||||||
|
\see Handler
|
||||||
|
*/
|
||||||
|
//@{
|
||||||
|
|
||||||
|
bool Null() { Prefix(kNullType); return EndValue(WriteNull()); }
|
||||||
|
bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); }
|
||||||
|
bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); }
|
||||||
|
bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); }
|
||||||
|
bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); }
|
||||||
|
bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); }
|
||||||
|
|
||||||
|
//! Writes the given \c double value to the stream
|
||||||
|
/*!
|
||||||
|
\param d The value to be written.
|
||||||
|
\return Whether it is succeed.
|
||||||
|
*/
|
||||||
|
bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); }
|
||||||
|
|
||||||
|
bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
|
||||||
|
RAPIDJSON_ASSERT(str != 0);
|
||||||
|
(void)copy;
|
||||||
|
Prefix(kNumberType);
|
||||||
|
return EndValue(WriteString(str, length));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool String(const Ch* str, SizeType length, bool copy = false) {
|
||||||
|
RAPIDJSON_ASSERT(str != 0);
|
||||||
|
(void)copy;
|
||||||
|
Prefix(kStringType);
|
||||||
|
return EndValue(WriteString(str, length));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if RAPIDJSON_HAS_STDSTRING
|
||||||
|
bool String(const std::basic_string<Ch>& str) {
|
||||||
|
return String(str.data(), SizeType(str.size()));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool StartObject() {
|
||||||
|
Prefix(kObjectType);
|
||||||
|
new (level_stack_.template Push<Level>()) Level(false);
|
||||||
|
return WriteStartObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
|
||||||
|
|
||||||
|
bool EndObject(SizeType memberCount = 0) {
|
||||||
|
(void)memberCount;
|
||||||
|
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
|
||||||
|
RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
|
||||||
|
level_stack_.template Pop<Level>(1);
|
||||||
|
return EndValue(WriteEndObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StartArray() {
|
||||||
|
Prefix(kArrayType);
|
||||||
|
new (level_stack_.template Push<Level>()) Level(true);
|
||||||
|
return WriteStartArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EndArray(SizeType elementCount = 0) {
|
||||||
|
(void)elementCount;
|
||||||
|
RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
|
||||||
|
RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
|
||||||
|
level_stack_.template Pop<Level>(1);
|
||||||
|
return EndValue(WriteEndArray());
|
||||||
|
}
|
||||||
|
//@}
|
||||||
|
|
||||||
|
/*! @name Convenience extensions */
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Simpler but slower overload.
|
||||||
|
bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
|
||||||
|
bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
//! Write a raw JSON value.
|
||||||
|
/*!
|
||||||
|
For user to write a stringified JSON as a value.
|
||||||
|
|
||||||
|
\param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
|
||||||
|
\param length Length of the json.
|
||||||
|
\param type Type of the root of json.
|
||||||
|
*/
|
||||||
|
bool RawValue(const Ch* json, size_t length, Type type) {
|
||||||
|
RAPIDJSON_ASSERT(json != 0);
|
||||||
|
Prefix(type);
|
||||||
|
return EndValue(WriteRawValue(json, length));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//! Information for each nested level
|
||||||
|
struct Level {
|
||||||
|
Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
|
||||||
|
size_t valueCount; //!< number of values in this level
|
||||||
|
bool inArray; //!< true if in array, otherwise in object
|
||||||
|
};
|
||||||
|
|
||||||
|
static const size_t kDefaultLevelDepth = 32;
|
||||||
|
|
||||||
|
bool WriteNull() {
|
||||||
|
PutReserve(*os_, 4);
|
||||||
|
PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteBool(bool b) {
|
||||||
|
if (b) {
|
||||||
|
PutReserve(*os_, 4);
|
||||||
|
PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PutReserve(*os_, 5);
|
||||||
|
PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e');
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteInt(int i) {
|
||||||
|
char buffer[11];
|
||||||
|
const char* end = internal::i32toa(i, buffer);
|
||||||
|
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||||
|
for (const char* p = buffer; p != end; ++p)
|
||||||
|
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteUint(unsigned u) {
|
||||||
|
char buffer[10];
|
||||||
|
const char* end = internal::u32toa(u, buffer);
|
||||||
|
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||||
|
for (const char* p = buffer; p != end; ++p)
|
||||||
|
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteInt64(int64_t i64) {
|
||||||
|
char buffer[21];
|
||||||
|
const char* end = internal::i64toa(i64, buffer);
|
||||||
|
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||||
|
for (const char* p = buffer; p != end; ++p)
|
||||||
|
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteUint64(uint64_t u64) {
|
||||||
|
char buffer[20];
|
||||||
|
char* end = internal::u64toa(u64, buffer);
|
||||||
|
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||||
|
for (char* p = buffer; p != end; ++p)
|
||||||
|
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteDouble(double d) {
|
||||||
|
if (internal::Double(d).IsNanOrInf()) {
|
||||||
|
if (!(writeFlags & kWriteNanAndInfFlag))
|
||||||
|
return false;
|
||||||
|
if (internal::Double(d).IsNan()) {
|
||||||
|
PutReserve(*os_, 3);
|
||||||
|
PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (internal::Double(d).Sign()) {
|
||||||
|
PutReserve(*os_, 9);
|
||||||
|
PutUnsafe(*os_, '-');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PutReserve(*os_, 8);
|
||||||
|
PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
|
||||||
|
PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buffer[25];
|
||||||
|
char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
|
||||||
|
PutReserve(*os_, static_cast<size_t>(end - buffer));
|
||||||
|
for (char* p = buffer; p != end; ++p)
|
||||||
|
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteString(const Ch* str, SizeType length) {
|
||||||
|
static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
|
||||||
|
static const char escape[256] = {
|
||||||
|
#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||||
|
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||||
|
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
|
||||||
|
'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
|
||||||
|
0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
|
||||||
|
Z16, Z16, // 30~4F
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
|
||||||
|
Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
|
||||||
|
#undef Z16
|
||||||
|
};
|
||||||
|
|
||||||
|
if (TargetEncoding::supportUnicode)
|
||||||
|
PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
|
||||||
|
else
|
||||||
|
PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..."
|
||||||
|
|
||||||
|
PutUnsafe(*os_, '\"');
|
||||||
|
GenericStringStream<SourceEncoding> is(str);
|
||||||
|
while (ScanWriteUnescapedString(is, length)) {
|
||||||
|
const Ch c = is.Peek();
|
||||||
|
if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
|
||||||
|
// Unicode escaping
|
||||||
|
unsigned codepoint;
|
||||||
|
if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))
|
||||||
|
return false;
|
||||||
|
PutUnsafe(*os_, '\\');
|
||||||
|
PutUnsafe(*os_, 'u');
|
||||||
|
if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
|
||||||
|
PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);
|
||||||
|
PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]);
|
||||||
|
PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]);
|
||||||
|
PutUnsafe(*os_, hexDigits[(codepoint ) & 15]);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
|
||||||
|
// Surrogate pair
|
||||||
|
unsigned s = codepoint - 0x010000;
|
||||||
|
unsigned lead = (s >> 10) + 0xD800;
|
||||||
|
unsigned trail = (s & 0x3FF) + 0xDC00;
|
||||||
|
PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);
|
||||||
|
PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]);
|
||||||
|
PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]);
|
||||||
|
PutUnsafe(*os_, hexDigits[(lead ) & 15]);
|
||||||
|
PutUnsafe(*os_, '\\');
|
||||||
|
PutUnsafe(*os_, 'u');
|
||||||
|
PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);
|
||||||
|
PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]);
|
||||||
|
PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]);
|
||||||
|
PutUnsafe(*os_, hexDigits[(trail ) & 15]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
|
||||||
|
is.Take();
|
||||||
|
PutUnsafe(*os_, '\\');
|
||||||
|
PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(escape[static_cast<unsigned char>(c)]));
|
||||||
|
if (escape[static_cast<unsigned char>(c)] == 'u') {
|
||||||
|
PutUnsafe(*os_, '0');
|
||||||
|
PutUnsafe(*os_, '0');
|
||||||
|
PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);
|
||||||
|
PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
|
||||||
|
Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
|
||||||
|
Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
PutUnsafe(*os_, '\"');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
|
||||||
|
return RAPIDJSON_LIKELY(is.Tell() < length);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WriteStartObject() { os_->Put('{'); return true; }
|
||||||
|
bool WriteEndObject() { os_->Put('}'); return true; }
|
||||||
|
bool WriteStartArray() { os_->Put('['); return true; }
|
||||||
|
bool WriteEndArray() { os_->Put(']'); return true; }
|
||||||
|
|
||||||
|
bool WriteRawValue(const Ch* json, size_t length) {
|
||||||
|
PutReserve(*os_, length);
|
||||||
|
for (size_t i = 0; i < length; i++) {
|
||||||
|
RAPIDJSON_ASSERT(json[i] != '\0');
|
||||||
|
PutUnsafe(*os_, json[i]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Prefix(Type type) {
|
||||||
|
(void)type;
|
||||||
|
if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
|
||||||
|
Level* level = level_stack_.template Top<Level>();
|
||||||
|
if (level->valueCount > 0) {
|
||||||
|
if (level->inArray)
|
||||||
|
os_->Put(','); // add comma if it is not the first element in array
|
||||||
|
else // in object
|
||||||
|
os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
|
||||||
|
}
|
||||||
|
if (!level->inArray && level->valueCount % 2 == 0)
|
||||||
|
RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
|
||||||
|
level->valueCount++;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
|
||||||
|
hasRoot_ = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Flush the value if it is the top level one.
|
||||||
|
bool EndValue(bool ret) {
|
||||||
|
if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
|
||||||
|
os_->Flush();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
OutputStream* os_;
|
||||||
|
internal::Stack<StackAllocator> level_stack_;
|
||||||
|
int maxDecimalPlaces_;
|
||||||
|
bool hasRoot_;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Prohibit copy constructor & assignment operator.
|
||||||
|
Writer(const Writer&);
|
||||||
|
Writer& operator=(const Writer&);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Full specialization for StringStream to prevent memory copying
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool Writer<StringBuffer>::WriteInt(int i) {
|
||||||
|
char *buffer = os_->Push(11);
|
||||||
|
const char* end = internal::i32toa(i, buffer);
|
||||||
|
os_->Pop(static_cast<size_t>(11 - (end - buffer)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
|
||||||
|
char *buffer = os_->Push(10);
|
||||||
|
const char* end = internal::u32toa(u, buffer);
|
||||||
|
os_->Pop(static_cast<size_t>(10 - (end - buffer)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
|
||||||
|
char *buffer = os_->Push(21);
|
||||||
|
const char* end = internal::i64toa(i64, buffer);
|
||||||
|
os_->Pop(static_cast<size_t>(21 - (end - buffer)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
|
||||||
|
char *buffer = os_->Push(20);
|
||||||
|
const char* end = internal::u64toa(u, buffer);
|
||||||
|
os_->Pop(static_cast<size_t>(20 - (end - buffer)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
inline bool Writer<StringBuffer>::WriteDouble(double d) {
|
||||||
|
if (internal::Double(d).IsNanOrInf()) {
|
||||||
|
// Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
|
||||||
|
if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))
|
||||||
|
return false;
|
||||||
|
if (internal::Double(d).IsNan()) {
|
||||||
|
PutReserve(*os_, 3);
|
||||||
|
PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (internal::Double(d).Sign()) {
|
||||||
|
PutReserve(*os_, 9);
|
||||||
|
PutUnsafe(*os_, '-');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
PutReserve(*os_, 8);
|
||||||
|
PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
|
||||||
|
PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *buffer = os_->Push(25);
|
||||||
|
char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
|
||||||
|
os_->Pop(static_cast<size_t>(25 - (end - buffer)));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
|
||||||
|
template<>
|
||||||
|
inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
|
||||||
|
if (length < 16)
|
||||||
|
return RAPIDJSON_LIKELY(is.Tell() < length);
|
||||||
|
|
||||||
|
if (!RAPIDJSON_LIKELY(is.Tell() < length))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const char* p = is.src_;
|
||||||
|
const char* end = is.head_ + length;
|
||||||
|
const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
|
||||||
|
const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
|
||||||
|
if (nextAligned > end)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
while (p != nextAligned)
|
||||||
|
if (*p < 0x20 || *p == '\"' || *p == '\\') {
|
||||||
|
is.src_ = p;
|
||||||
|
return RAPIDJSON_LIKELY(is.Tell() < length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
os_->PutUnsafe(*p++);
|
||||||
|
|
||||||
|
// The rest of string using SIMD
|
||||||
|
static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
|
||||||
|
static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
|
||||||
|
static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
|
||||||
|
const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
|
||||||
|
const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
|
||||||
|
const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
|
||||||
|
|
||||||
|
for (; p != endAligned; p += 16) {
|
||||||
|
const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
|
||||||
|
const __m128i t1 = _mm_cmpeq_epi8(s, dq);
|
||||||
|
const __m128i t2 = _mm_cmpeq_epi8(s, bs);
|
||||||
|
const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
|
||||||
|
const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
|
||||||
|
unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
|
||||||
|
if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
|
||||||
|
SizeType len;
|
||||||
|
#ifdef _MSC_VER // Find the index of first escaped
|
||||||
|
unsigned long offset;
|
||||||
|
_BitScanForward(&offset, r);
|
||||||
|
len = offset;
|
||||||
|
#else
|
||||||
|
len = static_cast<SizeType>(__builtin_ffs(r) - 1);
|
||||||
|
#endif
|
||||||
|
char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
q[i] = p[i];
|
||||||
|
|
||||||
|
p += len;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s);
|
||||||
|
}
|
||||||
|
|
||||||
|
is.src_ = p;
|
||||||
|
return RAPIDJSON_LIKELY(is.Tell() < length);
|
||||||
|
}
|
||||||
|
#endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
|
||||||
|
|
||||||
|
RAPIDJSON_NAMESPACE_END
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __clang__
|
||||||
|
RAPIDJSON_DIAG_POP
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_RAPIDJSON_H_
|
|
@ -0,0 +1,87 @@
|
||||||
|
#pragma once
|
||||||
|
#ifdef _WIN32
|
||||||
|
#ifndef _WIN32_WINNT
|
||||||
|
#define _WIN32_WINNT 0x0601 /* Windows 7 */
|
||||||
|
#endif
|
||||||
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
inline void sock_init()
|
||||||
|
{
|
||||||
|
static bool bWSAInit = false;
|
||||||
|
|
||||||
|
if (!bWSAInit)
|
||||||
|
{
|
||||||
|
WSADATA wsaData;
|
||||||
|
WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||||
|
bWSAInit = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void sock_close(SOCKET s)
|
||||||
|
{
|
||||||
|
shutdown(s, SD_BOTH);
|
||||||
|
closesocket(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char* sock_strerror(char* buf, size_t len)
|
||||||
|
{
|
||||||
|
buf[0] = '\0';
|
||||||
|
|
||||||
|
FormatMessageA(
|
||||||
|
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
|
||||||
|
NULL, WSAGetLastError(),
|
||||||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
|
(LPSTR)buf, len, NULL);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char* sock_gai_strerror(int err, char* buf, size_t len)
|
||||||
|
{
|
||||||
|
buf[0] = '\0';
|
||||||
|
|
||||||
|
FormatMessageA(
|
||||||
|
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK,
|
||||||
|
NULL, (DWORD)err,
|
||||||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
|
(LPSTR)buf, len, NULL);
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Assume that any non-Windows platform uses POSIX-style sockets instead. */
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h> /* Needed for getaddrinfo() and freeaddrinfo() */
|
||||||
|
#include <unistd.h> /* Needed for close() */
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
inline void sock_init() {}
|
||||||
|
typedef int SOCKET;
|
||||||
|
|
||||||
|
#define INVALID_SOCKET (-1)
|
||||||
|
#define SOCKET_ERROR (-1)
|
||||||
|
|
||||||
|
inline void sock_close(SOCKET s)
|
||||||
|
{
|
||||||
|
shutdown(s, SHUT_RDWR);
|
||||||
|
close(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char* sock_strerror(char* buf, size_t len)
|
||||||
|
{
|
||||||
|
buf[0] = '\0';
|
||||||
|
return strerror_r(errno, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const char* sock_gai_strerror(int err, char* buf, size_t len)
|
||||||
|
{
|
||||||
|
buf[0] = '\0';
|
||||||
|
return gai_strerror(err);
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,49 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <queue>
|
||||||
|
#include <thread>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class thdq
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
T pop()
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> mlock(mutex_);
|
||||||
|
while (queue_.empty()) { cond_.wait(mlock); }
|
||||||
|
auto item = std::move(queue_.front());
|
||||||
|
queue_.pop();
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pop(T& item)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> mlock(mutex_);
|
||||||
|
while (queue_.empty()) { cond_.wait(mlock); }
|
||||||
|
item = queue_.front();
|
||||||
|
queue_.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
void push(const T& item)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> mlock(mutex_);
|
||||||
|
queue_.push(item);
|
||||||
|
mlock.unlock();
|
||||||
|
cond_.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
void push(T&& item)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> mlock(mutex_);
|
||||||
|
queue_.push(std::move(item));
|
||||||
|
mlock.unlock();
|
||||||
|
cond_.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::queue<T> queue_;
|
||||||
|
std::mutex mutex_;
|
||||||
|
std::condition_variable cond_;
|
||||||
|
};
|
|
@ -0,0 +1,164 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
|
||||||
|
<CodeBlocks_project_file>
|
||||||
|
<FileVersion major="1" minor="6" />
|
||||||
|
<Project>
|
||||||
|
<Option title="xmr-stak-amd" />
|
||||||
|
<Option pch_mode="2" />
|
||||||
|
<Option compiler="gcc" />
|
||||||
|
<Build>
|
||||||
|
<Target title="Debug">
|
||||||
|
<Option output="bin/Debug/miner" prefix_auto="1" extension_auto="1" />
|
||||||
|
<Option object_output="obj/Debug/" />
|
||||||
|
<Option type="1" />
|
||||||
|
<Option compiler="gcc" />
|
||||||
|
<Option parameters="config-debug.txt" />
|
||||||
|
<Compiler>
|
||||||
|
<Add option="-march=corei7-avx" />
|
||||||
|
<Add option="-std=c++11" />
|
||||||
|
<Add option="-m64" />
|
||||||
|
<Add option="-g" />
|
||||||
|
<Add directory="include" />
|
||||||
|
</Compiler>
|
||||||
|
<Linker>
|
||||||
|
<Add option="-m64" />
|
||||||
|
</Linker>
|
||||||
|
</Target>
|
||||||
|
<Target title="Release">
|
||||||
|
<Option output="bin/Release/miner" prefix_auto="1" extension_auto="1" />
|
||||||
|
<Option object_output="obj/Release/" />
|
||||||
|
<Option type="1" />
|
||||||
|
<Option compiler="gcc" />
|
||||||
|
<Option parameters="config-debug.txt" />
|
||||||
|
<Compiler>
|
||||||
|
<Add option="-march=westmere" />
|
||||||
|
<Add option="-O3" />
|
||||||
|
<Add option="-std=c++11" />
|
||||||
|
<Add option="-m64" />
|
||||||
|
<Add option="-DNDEBUG" />
|
||||||
|
<Add directory="include" />
|
||||||
|
</Compiler>
|
||||||
|
<Linker>
|
||||||
|
<Add option="-s" />
|
||||||
|
<Add option="-m64" />
|
||||||
|
</Linker>
|
||||||
|
</Target>
|
||||||
|
<Target title="Release_test">
|
||||||
|
<Option output="bin/Release_test/miner" prefix_auto="1" extension_auto="1" />
|
||||||
|
<Option object_output="obj/Release_test/" />
|
||||||
|
<Option type="1" />
|
||||||
|
<Option compiler="gcc" />
|
||||||
|
<Option parameters="config-debug.txt" />
|
||||||
|
<Compiler>
|
||||||
|
<Add option="-march=westmere" />
|
||||||
|
<Add option="-O3" />
|
||||||
|
<Add option="-std=c++11" />
|
||||||
|
<Add option="-m64" />
|
||||||
|
<Add directory="include" />
|
||||||
|
</Compiler>
|
||||||
|
<Linker>
|
||||||
|
<Add option="-s" />
|
||||||
|
<Add option="-m64" />
|
||||||
|
</Linker>
|
||||||
|
</Target>
|
||||||
|
</Build>
|
||||||
|
<Compiler>
|
||||||
|
<Add option="-Wall" />
|
||||||
|
</Compiler>
|
||||||
|
<Linker>
|
||||||
|
<Add library="pthread" />
|
||||||
|
<Add library="libmicrohttpd" />
|
||||||
|
<Add library="OpenCL" />
|
||||||
|
</Linker>
|
||||||
|
<Unit filename="amd_gpu/gpu.c">
|
||||||
|
<Option compilerVar="CC" />
|
||||||
|
</Unit>
|
||||||
|
<Unit filename="amd_gpu/gpu.h" />
|
||||||
|
<Unit filename="cli-miner.cpp" />
|
||||||
|
<Unit filename="console.cpp" />
|
||||||
|
<Unit filename="console.h" />
|
||||||
|
<Unit filename="crypto/c_blake256.c">
|
||||||
|
<Option compilerVar="CC" />
|
||||||
|
</Unit>
|
||||||
|
<Unit filename="crypto/c_blake256.h" />
|
||||||
|
<Unit filename="crypto/c_groestl.c">
|
||||||
|
<Option compilerVar="CC" />
|
||||||
|
</Unit>
|
||||||
|
<Unit filename="crypto/c_groestl.h" />
|
||||||
|
<Unit filename="crypto/c_jh.c">
|
||||||
|
<Option compilerVar="CC" />
|
||||||
|
</Unit>
|
||||||
|
<Unit filename="crypto/c_jh.h" />
|
||||||
|
<Unit filename="crypto/c_keccak.c">
|
||||||
|
<Option compilerVar="CC" />
|
||||||
|
</Unit>
|
||||||
|
<Unit filename="crypto/c_keccak.h" />
|
||||||
|
<Unit filename="crypto/c_skein.c">
|
||||||
|
<Option compilerVar="CC" />
|
||||||
|
</Unit>
|
||||||
|
<Unit filename="crypto/c_skein.h" />
|
||||||
|
<Unit filename="crypto/cryptonight.h" />
|
||||||
|
<Unit filename="crypto/cryptonight_aesni.h" />
|
||||||
|
<Unit filename="crypto/cryptonight_common.cpp" />
|
||||||
|
<Unit filename="crypto/groestl_tables.h" />
|
||||||
|
<Unit filename="crypto/hash.h" />
|
||||||
|
<Unit filename="crypto/int-util.h" />
|
||||||
|
<Unit filename="crypto/skein_port.h" />
|
||||||
|
<Unit filename="crypto/soft_aes.c">
|
||||||
|
<Option compilerVar="CC" />
|
||||||
|
</Unit>
|
||||||
|
<Unit filename="donate-level.h" />
|
||||||
|
<Unit filename="executor.cpp" />
|
||||||
|
<Unit filename="executor.h" />
|
||||||
|
<Unit filename="httpd.cpp" />
|
||||||
|
<Unit filename="httpd.h" />
|
||||||
|
<Unit filename="jconf.cpp" />
|
||||||
|
<Unit filename="jconf.h" />
|
||||||
|
<Unit filename="jext.h" />
|
||||||
|
<Unit filename="jpsock.cpp" />
|
||||||
|
<Unit filename="jpsock.h" />
|
||||||
|
<Unit filename="minethd.cpp" />
|
||||||
|
<Unit filename="minethd.h" />
|
||||||
|
<Unit filename="msgstruct.h" />
|
||||||
|
<Unit filename="rapidjson/allocators.h" />
|
||||||
|
<Unit filename="rapidjson/document.h" />
|
||||||
|
<Unit filename="rapidjson/encodedstream.h" />
|
||||||
|
<Unit filename="rapidjson/encodings.h" />
|
||||||
|
<Unit filename="rapidjson/error/en.h" />
|
||||||
|
<Unit filename="rapidjson/error/error.h" />
|
||||||
|
<Unit filename="rapidjson/filereadstream.h" />
|
||||||
|
<Unit filename="rapidjson/filewritestream.h" />
|
||||||
|
<Unit filename="rapidjson/fwd.h" />
|
||||||
|
<Unit filename="rapidjson/internal/biginteger.h" />
|
||||||
|
<Unit filename="rapidjson/internal/diyfp.h" />
|
||||||
|
<Unit filename="rapidjson/internal/dtoa.h" />
|
||||||
|
<Unit filename="rapidjson/internal/ieee754.h" />
|
||||||
|
<Unit filename="rapidjson/internal/itoa.h" />
|
||||||
|
<Unit filename="rapidjson/internal/meta.h" />
|
||||||
|
<Unit filename="rapidjson/internal/pow10.h" />
|
||||||
|
<Unit filename="rapidjson/internal/regex.h" />
|
||||||
|
<Unit filename="rapidjson/internal/stack.h" />
|
||||||
|
<Unit filename="rapidjson/internal/strfunc.h" />
|
||||||
|
<Unit filename="rapidjson/internal/strtod.h" />
|
||||||
|
<Unit filename="rapidjson/internal/swap.h" />
|
||||||
|
<Unit filename="rapidjson/istreamwrapper.h" />
|
||||||
|
<Unit filename="rapidjson/memorybuffer.h" />
|
||||||
|
<Unit filename="rapidjson/memorystream.h" />
|
||||||
|
<Unit filename="rapidjson/msinttypes/inttypes.h" />
|
||||||
|
<Unit filename="rapidjson/msinttypes/stdint.h" />
|
||||||
|
<Unit filename="rapidjson/ostreamwrapper.h" />
|
||||||
|
<Unit filename="rapidjson/pointer.h" />
|
||||||
|
<Unit filename="rapidjson/prettywriter.h" />
|
||||||
|
<Unit filename="rapidjson/rapidjson.h" />
|
||||||
|
<Unit filename="rapidjson/reader.h" />
|
||||||
|
<Unit filename="rapidjson/schema.h" />
|
||||||
|
<Unit filename="rapidjson/stream.h" />
|
||||||
|
<Unit filename="rapidjson/stringbuffer.h" />
|
||||||
|
<Unit filename="rapidjson/writer.h" />
|
||||||
|
<Unit filename="socks.h" />
|
||||||
|
<Unit filename="thdq.hpp" />
|
||||||
|
<Extensions>
|
||||||
|
<code_completion />
|
||||||
|
<debugger />
|
||||||
|
</Extensions>
|
||||||
|
</Project>
|
||||||
|
</CodeBlocks_project_file>
|
Loading…
Reference in New Issue