1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-08 00:37:15 +01:00

Dumped the old implementation. Started with a more simple approach.

This commit is contained in:
Sandu Liviu Catalin 2016-02-21 00:25:00 +02:00
parent 96ded94026
commit 06e598acfb
293 changed files with 37439 additions and 92564 deletions

1
bin/bootstrap.nut Normal file
View File

@ -0,0 +1 @@
print("Hello World");

1
bin/plugins/placeholder Normal file
View File

@ -0,0 +1 @@
Keep me!

7
bin/sqmod.ini Normal file
View File

@ -0,0 +1,7 @@
[Config]
StackSize=2048
[Scripts]
Source=bootstrap.nut
[Options]

View File

@ -1,121 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="Common" />
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Win32 Debug Static">
<Option output="../lib/mingw32/common-d" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/win32-d/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-g" />
<Add option="-D_DEBUG" />
<Add option="-DWIN32" />
<Add directory="../config/mingw32" />
</Compiler>
</Target>
<Target title="Win32 Release Static">
<Option output="../lib/mingw32/common" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/win32/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-fexpensive-optimizations" />
<Add option="-O3" />
<Add option="-DNDEBUG" />
<Add option="-DWIN32" />
<Add directory="../config/mingw32" />
</Compiler>
<Linker>
<Add option="-s" />
</Linker>
</Target>
<Target title="Win64 Debug Static">
<Option output="../lib/mingw64/common-d" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/win64-d/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-g" />
<Add option="-D_DEBUG" />
<Add option="-DWIN32" />
<Add option="-DWIN64" />
<Add option="-D_SQ64" />
<Add directory="../config/mingw64" />
</Compiler>
</Target>
<Target title="Win64 Release Static">
<Option output="../lib/mingw64/common" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/win64/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-fexpensive-optimizations" />
<Add option="-O3" />
<Add option="-DNDEBUG" />
<Add option="-DWIN32" />
<Add option="-DWIN64" />
<Add option="-D_SQ64" />
<Add directory="../config/mingw64" />
</Compiler>
<Linker>
<Add option="-s" />
</Linker>
</Target>
</Build>
<Compiler>
<Add option="-Wall" />
<Add option="-std=c++11" />
<Add option="-DFMT_USE_VARIADIC_TEMPLATES" />
<Add option="-DFMT_USE_RVALUE_REFERENCES" />
<Add directory="../include" />
<Add directory="../config/common" />
<Add directory="../external/Common" />
<Add directory="../external/IRC" />
</Compiler>
<Unit filename="../external/Common/crc32.cpp" />
<Unit filename="../external/Common/crc32.h" />
<Unit filename="../external/Common/digest.cpp" />
<Unit filename="../external/Common/endian.h" />
<Unit filename="../external/Common/hash.h" />
<Unit filename="../external/Common/hmac.h" />
<Unit filename="../external/Common/keccak.cpp" />
<Unit filename="../external/Common/keccak.h" />
<Unit filename="../external/Common/md5.cpp" />
<Unit filename="../external/Common/md5.h" />
<Unit filename="../external/Common/posix.cc" />
<Unit filename="../external/Common/posix.h" />
<Unit filename="../external/Common/sha1.cpp" />
<Unit filename="../external/Common/sha1.h" />
<Unit filename="../external/Common/sha256.cpp" />
<Unit filename="../external/Common/sha256.h" />
<Unit filename="../external/Common/sha3.cpp" />
<Unit filename="../external/Common/sha3.h" />
<Unit filename="../external/CppFormat/format.cc" />
<Unit filename="../external/IRC/libircclient.c">
<Option compilerVar="CC" />
</Unit>
<Unit filename="../external/PUGIXML/pugixml.cpp" />
<Unit filename="../external/SimpleINI/ConvertUTF.c">
<Option compilerVar="CC" />
</Unit>
<Extensions>
<code_completion />
<envvars />
<debugger />
<lib_finder disable_auto="1" />
</Extensions>
</Project>
</CodeBlocks_project_file>

182
cbp/Hash.cbp Normal file
View File

@ -0,0 +1,182 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<CodeBlocks_project_file>
<FileVersion major="1" minor="6" />
<Project>
<Option title="Hash" />
<Option pch_mode="2" />
<Option compiler="gcc" />
<Build>
<Target title="Win32 Debug Static">
<Option output="../lib/mingw32-d/hash" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/mingw32-d/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-m32" />
<Add option="-g" />
<Add option="-D_DEBUG" />
<Add directory="../config/mingw32" />
</Compiler>
<Linker>
<Add option="-m32" />
</Linker>
</Target>
<Target title="Win32 Release Static">
<Option output="../lib/mingw32/hash" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/mingw32/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-O3" />
<Add option="-m32" />
<Add option="-DNDEBUG" />
<Add directory="../config/mingw32" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-m32" />
</Linker>
</Target>
<Target title="Win64 Debug Static">
<Option output="../lib/mingw64-d/hash" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/mingw64-d/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-m64" />
<Add option="-g" />
<Add option="-D_DEBUG" />
<Add directory="../config/mingw64" />
</Compiler>
<Linker>
<Add option="-m64" />
</Linker>
</Target>
<Target title="Win64 Release Static">
<Option output="../lib/mingw64/hash" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/mingw64/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-O3" />
<Add option="-m64" />
<Add option="-DNDEBUG" />
<Add directory="../config/mingw64" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-m64" />
</Linker>
</Target>
<Target title="Linux32 Debug Static">
<Option output="../lib/gcc32-d/hash" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/gcc32-d/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-m32" />
<Add option="-g" />
<Add option="-fPIC" />
<Add option="-D_DEBUG" />
<Add directory="../config/gcc32" />
</Compiler>
<Linker>
<Add option="-m32" />
</Linker>
</Target>
<Target title="Linux32 Release Static">
<Option output="../lib/gcc32/hash" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/gcc32/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-O3" />
<Add option="-m32" />
<Add option="-fPIC" />
<Add option="-DNDEBUG" />
<Add directory="../config/gcc32" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-m32" />
</Linker>
</Target>
<Target title="Linux64 Debug Static">
<Option output="../lib/gcc64-d/hash" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/gcc64-d/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-m64" />
<Add option="-g" />
<Add option="-fPIC" />
<Add option="-D_DEBUG" />
<Add directory="../config/gcc64" />
</Compiler>
<Linker>
<Add option="-m64" />
</Linker>
</Target>
<Target title="Linux64 Release Static">
<Option output="../lib/gcc64/hash" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/gcc64/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-O3" />
<Add option="-m64" />
<Add option="-fPIC" />
<Add option="-DNDEBUG" />
<Add directory="../config/gcc64" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-m64" />
</Linker>
</Target>
</Build>
<Compiler>
<Add option="-Wall" />
<Add directory="../include" />
<Add directory="../config/common" />
<Add directory="../external/Hash" />
</Compiler>
<Unit filename="../external/Hash/crc32.cpp" />
<Unit filename="../external/Hash/crc32.h" />
<Unit filename="../external/Hash/digest.cpp" />
<Unit filename="../external/Hash/endian.h" />
<Unit filename="../external/Hash/hash.h" />
<Unit filename="../external/Hash/hmac.h" />
<Unit filename="../external/Hash/keccak.cpp" />
<Unit filename="../external/Hash/keccak.h" />
<Unit filename="../external/Hash/md5.cpp" />
<Unit filename="../external/Hash/md5.h" />
<Unit filename="../external/Hash/sha1.cpp" />
<Unit filename="../external/Hash/sha1.h" />
<Unit filename="../external/Hash/sha256.cpp" />
<Unit filename="../external/Hash/sha256.h" />
<Unit filename="../external/Hash/sha3.cpp" />
<Unit filename="../external/Hash/sha3.h" />
<Extensions>
<code_completion />
<envvars />
<debugger />
</Extensions>
</Project>
</CodeBlocks_project_file>

View File

@ -7,124 +7,195 @@
<Option compiler="gcc" /> <Option compiler="gcc" />
<Build> <Build>
<Target title="Win32 Debug Dynamic"> <Target title="Win32 Debug Dynamic">
<Option output="../bin/win32-d/sqmod" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" /> <Option output="../bin/win32-d/sqmod32" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="0" extension_auto="1" />
<Option working_dir="../bin/win32-d/" /> <Option working_dir="../bin/win32-d/" />
<Option object_output="../obj/win32-d/" /> <Option object_output="../obj/mingw32-d/" />
<Option type="3" /> <Option type="3" />
<Option compiler="gcc" /> <Option compiler="gcc" />
<Compiler> <Compiler>
<Add option="-m32" />
<Add option="-g" /> <Add option="-g" />
<Add option="-static-libgcc" />
<Add option="-static-libstdc++" />
<Add option="-enable-static" />
<Add option="-D_DEBUG" /> <Add option="-D_DEBUG" />
<Add option="-DWIN32" />
<Add directory="../config/mingw32" /> <Add directory="../config/mingw32" />
</Compiler> </Compiler>
<Linker> <Linker>
<Add option="-m32" />
<Add option="-static" /> <Add option="-static" />
<Add library="common-d" />
<Add library="squirrel-d" />
<Add library="sqlite-d" />
<Add library="Ws2_32" /> <Add library="Ws2_32" />
<Add directory="../lib/mingw32" /> <Add directory="../lib/mingw32-d" />
</Linker> </Linker>
<ExtraCommands>
<Add after='cmd /c copy /Y &quot;$(PROJECT_DIR)$(TARGET_OUTPUT_FILE)&quot; &quot;$(PROJECT_DIR)..\bin\plugins\$(TARGET_OUTPUT_BASENAME).dll&quot;' />
</ExtraCommands>
</Target> </Target>
<Target title="Win32 Release Dynamic"> <Target title="Win32 Release Dynamic">
<Option output="../bin/win32/sqmod" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" /> <Option output="../bin/win32/sqmod32" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="0" extension_auto="1" />
<Option working_dir="../bin/win32/" /> <Option working_dir="../bin/win32/" />
<Option object_output="../obj/win32/" /> <Option object_output="../obj/mingw32/" />
<Option type="3" /> <Option type="3" />
<Option compiler="gcc" /> <Option compiler="gcc" />
<Compiler> <Compiler>
<Add option="-O3" /> <Add option="-O3" />
<Add option="-static-libgcc" /> <Add option="-m32" />
<Add option="-static-libstdc++" />
<Add option="-enable-static" />
<Add option="-DNDEBUG" /> <Add option="-DNDEBUG" />
<Add option="-DWIN32" />
<Add directory="../config/mingw32" /> <Add directory="../config/mingw32" />
</Compiler> </Compiler>
<Linker> <Linker>
<Add option="-s" /> <Add option="-s" />
<Add option="-m32" />
<Add option="-static" /> <Add option="-static" />
<Add library="common" />
<Add library="squirrel" />
<Add library="sqlite" />
<Add library="Ws2_32" /> <Add library="Ws2_32" />
<Add directory="../lib/mingw32" /> <Add directory="../lib/mingw32" />
</Linker> </Linker>
<ExtraCommands>
<Add after='cmd /c copy /Y &quot;$(PROJECT_DIR)$(TARGET_OUTPUT_FILE)&quot; &quot;$(PROJECT_DIR)..\bin\plugins\$(TARGET_OUTPUT_BASENAME).dll&quot;' />
</ExtraCommands>
</Target> </Target>
<Target title="Win64 Debug Dynamic"> <Target title="Win64 Debug Dynamic">
<Option output="../bin/win64-d/sqmod" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" /> <Option output="../bin/win64-d/sqmod64" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="0" extension_auto="1" />
<Option working_dir="../bin/win64-d/" /> <Option working_dir="../bin/win64-d/" />
<Option object_output="../obj/win64-d/" /> <Option object_output="../obj/mingw64-d/" />
<Option type="3" /> <Option type="3" />
<Option compiler="gcc" /> <Option compiler="gcc" />
<Compiler> <Compiler>
<Add option="-m64" />
<Add option="-g" /> <Add option="-g" />
<Add option="-static-libgcc" />
<Add option="-static-libstdc++" />
<Add option="-enable-static" />
<Add option="-D_DEBUG" /> <Add option="-D_DEBUG" />
<Add option="-DWIN32" />
<Add option="-DWIN64" />
<Add option="-D_SQ64" /> <Add option="-D_SQ64" />
<Add directory="../config/mingw64" /> <Add directory="../config/mingw64" />
</Compiler> </Compiler>
<Linker> <Linker>
<Add option="-m64" />
<Add option="-static" /> <Add option="-static" />
<Add library="common-d" />
<Add library="squirrel-d" />
<Add library="sqlite-d" />
<Add library="Ws2_32" /> <Add library="Ws2_32" />
<Add directory="../lib/mingw64" /> <Add directory="../lib/mingw64-d" />
</Linker> </Linker>
<ExtraCommands>
<Add after='cmd /c copy /Y &quot;$(PROJECT_DIR)$(TARGET_OUTPUT_FILE)&quot; &quot;$(PROJECT_DIR)..\bin\plugins\$(TARGET_OUTPUT_BASENAME).dll&quot;' />
</ExtraCommands>
</Target> </Target>
<Target title="Win64 Release Dynamic"> <Target title="Win64 Release Dynamic">
<Option output="../bin/win64/sqmod" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="1" extension_auto="1" /> <Option output="../bin/win64/sqmod64" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="0" extension_auto="1" />
<Option working_dir="../bin/win64/" /> <Option working_dir="../bin/win64/" />
<Option object_output="../obj/win64/" /> <Option object_output="../obj/mingw64/" />
<Option type="3" /> <Option type="3" />
<Option compiler="gcc" /> <Option compiler="gcc" />
<Compiler> <Compiler>
<Add option="-O3" /> <Add option="-O3" />
<Add option="-static-libgcc" /> <Add option="-m64" />
<Add option="-static-libstdc++" />
<Add option="-enable-static" />
<Add option="-DNDEBUG" /> <Add option="-DNDEBUG" />
<Add option="-DWIN32" />
<Add option="-DWIN64" />
<Add option="-D_SQ64" /> <Add option="-D_SQ64" />
<Add directory="../config/mingw64" /> <Add directory="../config/mingw64" />
</Compiler> </Compiler>
<Linker> <Linker>
<Add option="-s" /> <Add option="-s" />
<Add option="-m64" />
<Add option="-static" /> <Add option="-static" />
<Add library="common" />
<Add library="squirrel" />
<Add library="sqlite" />
<Add library="Ws2_32" /> <Add library="Ws2_32" />
<Add directory="../lib/mingw64" /> <Add directory="../lib/mingw64" />
</Linker> </Linker>
<ExtraCommands>
<Add after='cmd /c copy /Y &quot;$(PROJECT_DIR)$(TARGET_OUTPUT_FILE)&quot; &quot;$(PROJECT_DIR)..\bin\plugins\$(TARGET_OUTPUT_BASENAME).dll&quot;' />
</ExtraCommands>
</Target>
<Target title="Linux32 Debug Dynamic">
<Option output="../bin/linux32-d/sqmod32" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="0" extension_auto="1" />
<Option working_dir="../bin/linux32-d/" />
<Option object_output="../obj/gcc32-d/" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-m32" />
<Add option="-g" />
<Add option="-fPIC" />
<Add option="-D_DEBUG" />
<Add directory="../config/gcc32" />
</Compiler>
<Linker>
<Add option="-m32" />
<Add option="-Bstatic" />
<Add directory="../lib/gcc32-d" />
</Linker>
</Target>
<Target title="Linux32 Release Dynamic">
<Option output="../bin/linux32/sqmod32" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="0" extension_auto="1" />
<Option working_dir="../bin/linux32/" />
<Option object_output="../obj/gcc32/" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O3" />
<Add option="-m32" />
<Add option="-fPIC" />
<Add option="-DNDEBUG" />
<Add directory="../config/gcc32" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-m32" />
<Add option="-Bstatic" />
<Add directory="../lib/gcc32" />
</Linker>
</Target>
<Target title="Linux64 Debug Dynamic">
<Option output="../bin/linux64-d/sqmod64" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="0" extension_auto="1" />
<Option working_dir="../bin/linux64-d/" />
<Option object_output="../obj/gcc64-d/" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-m64" />
<Add option="-g" />
<Add option="-fPIC" />
<Add option="-D_DEBUG" />
<Add option="-D_SQ64" />
<Add directory="../config/gcc64" />
</Compiler>
<Linker>
<Add option="-m64" />
<Add option="-Bstatic" />
<Add directory="../lib/gcc64-d" />
</Linker>
</Target>
<Target title="Linux64 Release Dynamic">
<Option output="../bin/linux64/sqmod64" imp_lib="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).a" def_file="$(TARGET_OUTPUT_DIR)$(TARGET_OUTPUT_BASENAME).def" prefix_auto="0" extension_auto="1" />
<Option working_dir="../bin/linux64/" />
<Option object_output="../obj/gcc64/" />
<Option type="3" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O3" />
<Add option="-m64" />
<Add option="-fPIC" />
<Add option="-DNDEBUG" />
<Add option="-D_SQ64" />
<Add directory="../config/gcc64" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-m64" />
<Add option="-Bstatic" />
<Add directory="../lib/gcc64" />
</Linker>
</Target> </Target>
</Build> </Build>
<Compiler> <Compiler>
<Add option="-Wextra" />
<Add option="-Wall" /> <Add option="-Wall" />
<Add option="-std=c++11" /> <Add option="-static-libgcc" />
<Add option="-DFMT_USE_VARIADIC_TEMPLATES" /> <Add option="-static-libstdc++" />
<Add option="-DFMT_USE_RVALUE_REFERENCES" /> <Add option="-enable-static" />
<Add option="-DSCRAT_USE_CXX11_OPTIMIZATIONS" />
<Add directory="../include" />
<Add directory="../source" /> <Add directory="../source" />
<Add directory="../shared" /> <Add directory="../shared" />
<Add directory="../include" />
<Add directory="../config/common" /> <Add directory="../config/common" />
<Add directory="../external/Common" /> <Add directory="../external/Common" />
<Add directory="../external/Hash" />
</Compiler> </Compiler>
<ExtraCommands> <Linker>
<Add after='cmd /c copy /Y &quot;$(PROJECT_DIR)$(TARGET_OUTPUT_FILE)&quot; &quot;H:\VCMP\plugins&quot;' /> <Add library="squirrel" />
</ExtraCommands> <Add library="sqlite" />
<Add library="hash" />
</Linker>
<Unit filename="../source/Base/AABB.cpp" /> <Unit filename="../source/Base/AABB.cpp" />
<Unit filename="../source/Base/AABB.hpp" /> <Unit filename="../source/Base/AABB.hpp" />
<Unit filename="../source/Base/Buffer.cpp" /> <Unit filename="../source/Base/Buffer.cpp" />
@ -137,35 +208,30 @@
<Unit filename="../source/Base/Color4.hpp" /> <Unit filename="../source/Base/Color4.hpp" />
<Unit filename="../source/Base/Quaternion.cpp" /> <Unit filename="../source/Base/Quaternion.cpp" />
<Unit filename="../source/Base/Quaternion.hpp" /> <Unit filename="../source/Base/Quaternion.hpp" />
<Unit filename="../source/Base/Random.cpp" />
<Unit filename="../source/Base/Shared.cpp" /> <Unit filename="../source/Base/Shared.cpp" />
<Unit filename="../source/Base/Shared.hpp" /> <Unit filename="../source/Base/Shared.hpp" />
<Unit filename="../source/Base/Sphere.cpp" /> <Unit filename="../source/Base/Sphere.cpp" />
<Unit filename="../source/Base/Sphere.hpp" /> <Unit filename="../source/Base/Sphere.hpp" />
<Unit filename="../source/Base/Vector2f.cpp" /> <Unit filename="../source/Base/Vector2.cpp" />
<Unit filename="../source/Base/Vector2f.hpp" /> <Unit filename="../source/Base/Vector2.hpp" />
<Unit filename="../source/Base/Vector2i.cpp" /> <Unit filename="../source/Base/Vector2i.cpp" />
<Unit filename="../source/Base/Vector2i.hpp" /> <Unit filename="../source/Base/Vector2i.hpp" />
<Unit filename="../source/Base/Vector2u.cpp" />
<Unit filename="../source/Base/Vector2u.hpp" />
<Unit filename="../source/Base/Vector3.cpp" /> <Unit filename="../source/Base/Vector3.cpp" />
<Unit filename="../source/Base/Vector3.hpp" /> <Unit filename="../source/Base/Vector3.hpp" />
<Unit filename="../source/Base/Vector4.cpp" /> <Unit filename="../source/Base/Vector4.cpp" />
<Unit filename="../source/Base/Vector4.hpp" /> <Unit filename="../source/Base/Vector4.hpp" />
<Unit filename="../source/Command.cpp" /> <Unit filename="../source/Command.cpp" />
<Unit filename="../source/Command.hpp" /> <Unit filename="../source/Command.hpp" />
<Unit filename="../source/Common.cpp" /> <Unit filename="../source/Constants.cpp" />
<Unit filename="../source/Common.hpp" />
<Unit filename="../source/Config.hpp" />
<Unit filename="../source/Core.cpp" /> <Unit filename="../source/Core.cpp" />
<Unit filename="../source/Core.hpp" /> <Unit filename="../source/Core.hpp" />
<Unit filename="../source/Debug.cpp" />
<Unit filename="../source/Debug.hpp" />
<Unit filename="../source/Entity.cpp" />
<Unit filename="../source/Entity.hpp" />
<Unit filename="../source/Entity/Blip.cpp" /> <Unit filename="../source/Entity/Blip.cpp" />
<Unit filename="../source/Entity/Blip.hpp" /> <Unit filename="../source/Entity/Blip.hpp" />
<Unit filename="../source/Entity/Checkpoint.cpp" /> <Unit filename="../source/Entity/Checkpoint.cpp" />
<Unit filename="../source/Entity/Checkpoint.hpp" /> <Unit filename="../source/Entity/Checkpoint.hpp" />
<Unit filename="../source/Entity/Forcefield.cpp" />
<Unit filename="../source/Entity/Forcefield.hpp" />
<Unit filename="../source/Entity/Keybind.cpp" /> <Unit filename="../source/Entity/Keybind.cpp" />
<Unit filename="../source/Entity/Keybind.hpp" /> <Unit filename="../source/Entity/Keybind.hpp" />
<Unit filename="../source/Entity/Object.cpp" /> <Unit filename="../source/Entity/Object.cpp" />
@ -174,26 +240,12 @@
<Unit filename="../source/Entity/Pickup.hpp" /> <Unit filename="../source/Entity/Pickup.hpp" />
<Unit filename="../source/Entity/Player.cpp" /> <Unit filename="../source/Entity/Player.cpp" />
<Unit filename="../source/Entity/Player.hpp" /> <Unit filename="../source/Entity/Player.hpp" />
<Unit filename="../source/Entity/Sphere.cpp" />
<Unit filename="../source/Entity/Sphere.hpp" />
<Unit filename="../source/Entity/Sprite.cpp" /> <Unit filename="../source/Entity/Sprite.cpp" />
<Unit filename="../source/Entity/Sprite.hpp" /> <Unit filename="../source/Entity/Sprite.hpp" />
<Unit filename="../source/Entity/Textdraw.cpp" /> <Unit filename="../source/Entity/Textdraw.cpp" />
<Unit filename="../source/Entity/Textdraw.hpp" /> <Unit filename="../source/Entity/Textdraw.hpp" />
<Unit filename="../source/Entity/Vehicle.cpp" /> <Unit filename="../source/Entity/Vehicle.cpp" />
<Unit filename="../source/Entity/Vehicle.hpp" /> <Unit filename="../source/Entity/Vehicle.hpp" />
<Unit filename="../source/Event/Basic.cpp" />
<Unit filename="../source/Event/Basic.hpp" />
<Unit filename="../source/Event/Global.cpp" />
<Unit filename="../source/Event/Global.hpp" />
<Unit filename="../source/Event/Local.cpp" />
<Unit filename="../source/Event/Local.hpp" />
<Unit filename="../source/Event/Routine.cpp" />
<Unit filename="../source/Event/Routine.hpp" />
<Unit filename="../source/Event/Shared.cpp" />
<Unit filename="../source/Event/Shared.hpp" />
<Unit filename="../source/Iterators.cpp" />
<Unit filename="../source/Iterators.hpp" />
<Unit filename="../source/Library/Datetime.cpp" /> <Unit filename="../source/Library/Datetime.cpp" />
<Unit filename="../source/Library/Datetime.hpp" /> <Unit filename="../source/Library/Datetime.hpp" />
<Unit filename="../source/Library/FileIO.cpp" /> <Unit filename="../source/Library/FileIO.cpp" />
@ -202,24 +254,12 @@
<Unit filename="../source/Library/Format.hpp" /> <Unit filename="../source/Library/Format.hpp" />
<Unit filename="../source/Library/Hashing.cpp" /> <Unit filename="../source/Library/Hashing.cpp" />
<Unit filename="../source/Library/Hashing.hpp" /> <Unit filename="../source/Library/Hashing.hpp" />
<Unit filename="../source/Library/INI.cpp" />
<Unit filename="../source/Library/INI.hpp" />
<Unit filename="../source/Library/IRC.cpp" />
<Unit filename="../source/Library/IRC.hpp" />
<Unit filename="../source/Library/JSON.cpp" />
<Unit filename="../source/Library/JSON.hpp" />
<Unit filename="../source/Library/LongInt.cpp" />
<Unit filename="../source/Library/LongInt.hpp" />
<Unit filename="../source/Library/Math.cpp" /> <Unit filename="../source/Library/Math.cpp" />
<Unit filename="../source/Library/Math.hpp" /> <Unit filename="../source/Library/Math.hpp" />
<Unit filename="../source/Library/Numeric.cpp" /> <Unit filename="../source/Library/Numeric.cpp" />
<Unit filename="../source/Library/Numeric.hpp" /> <Unit filename="../source/Library/Numeric.hpp" />
<Unit filename="../source/Library/SQLite/Connection.cpp" /> <Unit filename="../source/Library/Random.cpp" />
<Unit filename="../source/Library/SQLite/Connection.hpp" /> <Unit filename="../source/Library/Random.hpp" />
<Unit filename="../source/Library/SQLite/Shared.cpp" />
<Unit filename="../source/Library/SQLite/Shared.hpp" />
<Unit filename="../source/Library/SQLite/Statement.cpp" />
<Unit filename="../source/Library/SQLite/Statement.hpp" />
<Unit filename="../source/Library/Shared.cpp" /> <Unit filename="../source/Library/Shared.cpp" />
<Unit filename="../source/Library/Shared.hpp" /> <Unit filename="../source/Library/Shared.hpp" />
<Unit filename="../source/Library/String.cpp" /> <Unit filename="../source/Library/String.cpp" />
@ -232,39 +272,25 @@
<Unit filename="../source/Library/Timer.hpp" /> <Unit filename="../source/Library/Timer.hpp" />
<Unit filename="../source/Library/Utils.cpp" /> <Unit filename="../source/Library/Utils.cpp" />
<Unit filename="../source/Library/Utils.hpp" /> <Unit filename="../source/Library/Utils.hpp" />
<Unit filename="../source/Library/XML.cpp" />
<Unit filename="../source/Library/XML.hpp" />
<Unit filename="../source/Logger.cpp" /> <Unit filename="../source/Logger.cpp" />
<Unit filename="../source/Logger.hpp" /> <Unit filename="../source/Logger.hpp" />
<Unit filename="../source/Misc/Automobile.cpp" /> <Unit filename="../source/Main.cpp" />
<Unit filename="../source/Misc/Automobile.hpp" /> <Unit filename="../source/Misc.cpp" />
<Unit filename="../source/Misc/Constants.cpp" />
<Unit filename="../source/Misc/Constants.hpp" />
<Unit filename="../source/Misc/Functions.cpp" /> <Unit filename="../source/Misc/Functions.cpp" />
<Unit filename="../source/Misc/Functions.hpp" /> <Unit filename="../source/Misc/Functions.hpp" />
<Unit filename="../source/Misc/Model.cpp" /> <Unit filename="../source/Misc/Model.cpp" />
<Unit filename="../source/Misc/Model.hpp" /> <Unit filename="../source/Misc/Model.hpp" />
<Unit filename="../source/Misc/PlayerImmunity.cpp" /> <Unit filename="../source/Misc/Player.cpp" />
<Unit filename="../source/Misc/PlayerImmunity.hpp" /> <Unit filename="../source/Misc/Player.hpp" />
<Unit filename="../source/Misc/Radio.cpp" /> <Unit filename="../source/Misc/Register.cpp" />
<Unit filename="../source/Misc/Radio.hpp" /> <Unit filename="../source/Misc/Vehicle.cpp" />
<Unit filename="../source/Misc/Shared.cpp" /> <Unit filename="../source/Misc/Vehicle.hpp" />
<Unit filename="../source/Misc/Shared.hpp" />
<Unit filename="../source/Misc/Skin.cpp" />
<Unit filename="../source/Misc/Skin.hpp" />
<Unit filename="../source/Misc/Sound.cpp" />
<Unit filename="../source/Misc/Sound.hpp" />
<Unit filename="../source/Misc/VehicleImmunity.cpp" />
<Unit filename="../source/Misc/VehicleImmunity.hpp" />
<Unit filename="../source/Misc/WastedSettings.cpp" />
<Unit filename="../source/Misc/WastedSettings.hpp" />
<Unit filename="../source/Misc/Weapon.cpp" /> <Unit filename="../source/Misc/Weapon.cpp" />
<Unit filename="../source/Misc/Weapon.hpp" /> <Unit filename="../source/Misc/Weapon.hpp" />
<Unit filename="../source/Misc/WorldBounds.cpp" /> <Unit filename="../source/Misc/World.cpp" />
<Unit filename="../source/Misc/WorldBounds.hpp" /> <Unit filename="../source/Misc/World.hpp" />
<Unit filename="../source/Register.cpp" /> <Unit filename="../source/Register.cpp" />
<Unit filename="../source/Register.hpp" /> <Unit filename="../source/SqBase.hpp" />
<Unit filename="../source/Signal.hpp" />
<Extensions> <Extensions>
<code_completion /> <code_completion />
<envvars /> <envvars />

View File

@ -7,71 +7,160 @@
<Option compiler="gcc" /> <Option compiler="gcc" />
<Build> <Build>
<Target title="Win32 Debug Static"> <Target title="Win32 Debug Static">
<Option output="../lib/mingw32/sqlite-d" prefix_auto="1" extension_auto="1" /> <Option output="../lib/mingw32-d/sqlite" prefix_auto="1" extension_auto="1" />
<Option working_dir="" /> <Option working_dir="" />
<Option object_output="../obj/win32-d/" /> <Option object_output="../obj/mingw32-d/" />
<Option type="2" /> <Option type="2" />
<Option compiler="gcc" /> <Option compiler="gcc" />
<Option createDefFile="1" /> <Option createDefFile="1" />
<Compiler> <Compiler>
<Add option="-m32" />
<Add option="-g" /> <Add option="-g" />
<Add option="-D_DEBUG" /> <Add option="-D_DEBUG" />
<Add option="-DWIN32" />
<Add directory="../config/mingw32" /> <Add directory="../config/mingw32" />
</Compiler> </Compiler>
<Linker>
<Add option="-m32" />
</Linker>
</Target> </Target>
<Target title="Win32 Release Static"> <Target title="Win32 Release Static">
<Option output="../lib/mingw32/sqlite" prefix_auto="1" extension_auto="1" /> <Option output="../lib/mingw32/sqlite" prefix_auto="1" extension_auto="1" />
<Option working_dir="" /> <Option working_dir="" />
<Option object_output="../obj/win32/" /> <Option object_output="../obj/mingw32/" />
<Option type="2" /> <Option type="2" />
<Option compiler="gcc" /> <Option compiler="gcc" />
<Option createDefFile="1" /> <Option createDefFile="1" />
<Compiler> <Compiler>
<Add option="-fexpensive-optimizations" />
<Add option="-O3" /> <Add option="-O3" />
<Add option="-m32" />
<Add option="-DNDEBUG" /> <Add option="-DNDEBUG" />
<Add option="-DWIN32" />
<Add directory="../config/mingw32" /> <Add directory="../config/mingw32" />
</Compiler> </Compiler>
<Linker> <Linker>
<Add option="-s" /> <Add option="-s" />
<Add option="-m32" />
</Linker> </Linker>
</Target> </Target>
<Target title="Win64 Debug Static"> <Target title="Win64 Debug Static">
<Option output="../lib/mingw64/sqlite-d" prefix_auto="1" extension_auto="1" /> <Option output="../lib/mingw64-d/sqlite" prefix_auto="1" extension_auto="1" />
<Option working_dir="" /> <Option working_dir="" />
<Option object_output="../obj/win32-d/" /> <Option object_output="../obj/mingw64-d/" />
<Option type="2" /> <Option type="2" />
<Option compiler="gcc" /> <Option compiler="gcc" />
<Option createDefFile="1" /> <Option createDefFile="1" />
<Compiler> <Compiler>
<Add option="-m64" />
<Add option="-g" /> <Add option="-g" />
<Add option="-D_DEBUG" /> <Add option="-D_DEBUG" />
<Add option="-DWIN64" />
<Add directory="../config/mingw64" /> <Add directory="../config/mingw64" />
</Compiler> </Compiler>
<Linker>
<Add option="-m64" />
</Linker>
</Target> </Target>
<Target title="Win64 Release Static"> <Target title="Win64 Release Static">
<Option output="../lib/mingw64/sqlite" prefix_auto="1" extension_auto="1" /> <Option output="../lib/mingw64/sqlite" prefix_auto="1" extension_auto="1" />
<Option working_dir="" /> <Option working_dir="" />
<Option object_output="../obj/win64/" /> <Option object_output="../obj/mingw64/" />
<Option type="2" /> <Option type="2" />
<Option compiler="gcc" /> <Option compiler="gcc" />
<Option createDefFile="1" /> <Option createDefFile="1" />
<Compiler> <Compiler>
<Add option="-fexpensive-optimizations" />
<Add option="-O3" /> <Add option="-O3" />
<Add option="-m64" />
<Add option="-DNDEBUG" /> <Add option="-DNDEBUG" />
<Add option="-DWIN64" />
<Add directory="../config/mingw64" /> <Add directory="../config/mingw64" />
</Compiler> </Compiler>
<Linker> <Linker>
<Add option="-s" /> <Add option="-s" />
<Add option="-m64" />
</Linker>
</Target>
<Target title="Linux32 Debug Static">
<Option output="../lib/gcc32-d/sqlite" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/gcc32-d/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-m32" />
<Add option="-g" />
<Add option="-fPIC" />
<Add option="-D_DEBUG" />
<Add directory="../config/gcc32" />
</Compiler>
<Linker>
<Add option="-m32" />
</Linker>
</Target>
<Target title="Linux32 Release Static">
<Option output="../lib/gcc32/sqlite" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/gcc32/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-fexpensive-optimizations" />
<Add option="-O3" />
<Add option="-m32" />
<Add option="-fPIC" />
<Add option="-DNDEBUG" />
<Add directory="../config/gcc32" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-m32" />
</Linker>
</Target>
<Target title="Linux64 Debug Static">
<Option output="../lib/gcc64-d/sqlite" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/gcc64-d/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-m64" />
<Add option="-g" />
<Add option="-fPIC" />
<Add option="-D_DEBUG" />
<Add directory="../config/gcc64" />
</Compiler>
<Linker>
<Add option="-m64" />
</Linker>
</Target>
<Target title="Linux64 Release Static">
<Option output="../lib/gcc64/sqlite" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/gcc64/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-fexpensive-optimizations" />
<Add option="-O3" />
<Add option="-m64" />
<Add option="-fPIC" />
<Add option="-DNDEBUG" />
<Add directory="../config/gcc64" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-m64" />
</Linker> </Linker>
</Target> </Target>
</Build> </Build>
<Compiler> <Compiler>
<Add option="-Wall" /> <Add option="-Wall" />
<Add option="-Wno-unused-but-set-variable" /> <Add option="-DSQLITE_ENABLE_FTS3" />
<Add option="-DSQLITE_ENABLE_FTS4" />
<Add option="-DSQLITE_ENABLE_FTS5" />
<Add option="-DSQLITE_THREADSAFE=0" />
<Add directory="../include" /> <Add directory="../include" />
<Add directory="../config/common" /> <Add directory="../config/common" />
</Compiler> </Compiler>
@ -82,7 +171,6 @@
<code_completion /> <code_completion />
<envvars /> <envvars />
<debugger /> <debugger />
<lib_finder disable_auto="1" />
</Extensions> </Extensions>
</Project> </Project>
</CodeBlocks_project_file> </CodeBlocks_project_file>

View File

@ -8,58 +8,160 @@
<Build> <Build>
<Target title="Win32 Debug Executable"> <Target title="Win32 Debug Executable">
<Option output="../bin/win32-d/sbox" prefix_auto="1" extension_auto="1" /> <Option output="../bin/win32-d/sbox" prefix_auto="1" extension_auto="1" />
<Option working_dir="../bin/win32-d" /> <Option working_dir="../bin/win32-d/" />
<Option object_output="../obj/win32-d/" /> <Option object_output="../obj/mingw32-d/" />
<Option type="1" /> <Option type="1" />
<Option compiler="gcc" /> <Option compiler="gcc" />
<Option use_console_runner="0" />
<Compiler> <Compiler>
<Add option="-m32" />
<Add option="-g" /> <Add option="-g" />
<Add option="-D_DEBUG" /> <Add option="-D_DEBUG" />
<Add directory="../config/mingw32" /> <Add directory="../config/mingw32" />
</Compiler> </Compiler>
<Linker> <Linker>
<Add library="common-d" /> <Add option="-m32" />
<Add library="squirrel-d" /> <Add directory="../lib/mingw32-d" />
<Add directory="../lib/mingw32" />
</Linker> </Linker>
</Target> </Target>
<Target title="Win32 Release Executable"> <Target title="Win32 Release Executable">
<Option output="../bin/win32/sbox" prefix_auto="1" extension_auto="1" /> <Option output="../bin/win32/sbox" prefix_auto="1" extension_auto="1" />
<Option working_dir="../bin/win32" /> <Option working_dir="../bin/win32/" />
<Option object_output="../obj/win32/" /> <Option object_output="../obj/mingw32/" />
<Option type="1" /> <Option type="1" />
<Option compiler="gcc" /> <Option compiler="gcc" />
<Option use_console_runner="0" />
<Compiler> <Compiler>
<Add option="-O3" /> <Add option="-O3" />
<Add option="-static-libgcc" /> <Add option="-m32" />
<Add option="-static-libstdc++" />
<Add option="-enable-static" />
<Add option="-DNDEBUG" /> <Add option="-DNDEBUG" />
<Add directory="../config/mingw32" /> <Add directory="../config/mingw32" />
</Compiler> </Compiler>
<Linker> <Linker>
<Add option="-s" /> <Add option="-s" />
<Add option="-static" /> <Add option="-m32" />
<Add library="common" /> <Add directory="../lib/mingw32" />
<Add library="squirrel" /> </Linker>
</Target>
<Target title="Win64 Debug Executable">
<Option output="../bin/win64-d/sbox" prefix_auto="1" extension_auto="1" />
<Option working_dir="../bin/win64-d/" />
<Option object_output="../obj/mingw64-d/" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-m64" />
<Add option="-g" />
<Add option="-D_DEBUG" />
<Add directory="../config/mingw32" />
</Compiler>
<Linker>
<Add option="-m64" />
<Add directory="../lib/mingw32-d" />
</Linker>
</Target>
<Target title="Win64 Release Executable">
<Option output="../bin/win64/sbox" prefix_auto="1" extension_auto="1" />
<Option working_dir="../bin/win64/" />
<Option object_output="../obj/mingw64/" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O3" />
<Add option="-m64" />
<Add option="-DNDEBUG" />
<Add directory="../config/mingw32" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-m64" />
<Add directory="../lib/mingw32" />
</Linker>
</Target>
<Target title="Linux32 Debug Executable">
<Option output="../bin/linux32-d/sbox" prefix_auto="0" extension_auto="1" />
<Option working_dir="../bin/linux32-d/" />
<Option object_output="../obj/gcc32-d/" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-m32" />
<Add option="-g" />
<Add option="-D_DEBUG" />
<Add directory="../config/mingw32" />
</Compiler>
<Linker>
<Add option="-m32" />
<Add directory="../lib/mingw32-d" />
</Linker>
</Target>
<Target title="Linux32 Release Executable">
<Option output="../bin/linux32/sbox" prefix_auto="0" extension_auto="1" />
<Option working_dir="../bin/linux32/" />
<Option object_output="../obj/gcc32/" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O3" />
<Add option="-m32" />
<Add option="-DNDEBUG" />
<Add directory="../config/mingw32" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-m32" />
<Add directory="../lib/mingw32" />
</Linker>
</Target>
<Target title="Linux64 Debug Executable">
<Option output="../bin/linux64-d/sbox" prefix_auto="0" extension_auto="1" />
<Option working_dir="../bin/linux64-d/" />
<Option object_output="../obj/gcc64-d/" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-m64" />
<Add option="-g" />
<Add option="-D_DEBUG" />
<Add directory="../config/mingw32" />
</Compiler>
<Linker>
<Add option="-m64" />
<Add directory="../lib/mingw32-d" />
</Linker>
</Target>
<Target title="Linux64 Release Executable">
<Option output="../bin/linux64/sbox" prefix_auto="0" extension_auto="1" />
<Option working_dir="../bin/linux64/" />
<Option object_output="../obj/gcc64/" />
<Option type="1" />
<Option compiler="gcc" />
<Compiler>
<Add option="-O3" />
<Add option="-m64" />
<Add option="-DNDEBUG" />
<Add directory="../config/mingw32" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-m64" />
<Add directory="../lib/mingw32" /> <Add directory="../lib/mingw32" />
</Linker> </Linker>
</Target> </Target>
</Build> </Build>
<Compiler> <Compiler>
<Add option="-Wall" /> <Add option="-Wall" />
<Add option="-std=c++11" />
<Add option="-DFMT_USE_VARIADIC_TEMPLATES" />
<Add option="-DFMT_USE_RVALUE_REFERENCES" />
<Add directory="../include" /> <Add directory="../include" />
<Add directory="../sandbox" /> <Add directory="../sandbox" />
<Add directory="../source" /> <Add directory="../source" />
<Add directory="../shared" /> <Add directory="../shared" />
<Add directory="../config/common" /> <Add directory="../config/common" />
<Add directory="../external/Common" /> <Add directory="../external/Common" />
<Add directory="../external/Hash" />
</Compiler> </Compiler>
<Linker>
<Add library="squirrel" />
<Add library="sqlite" />
<Add library="hash" />
</Linker>
<Unit filename="../sandbox/main.cpp" /> <Unit filename="../sandbox/main.cpp" />
<Extensions> <Extensions>
<code_completion /> <code_completion />

View File

@ -7,73 +7,155 @@
<Option compiler="gcc" /> <Option compiler="gcc" />
<Build> <Build>
<Target title="Win32 Debug Static"> <Target title="Win32 Debug Static">
<Option output="../lib/mingw32/squirrel-d" prefix_auto="1" extension_auto="1" /> <Option output="../lib/mingw32-d/squirrel" prefix_auto="1" extension_auto="1" />
<Option working_dir="" /> <Option working_dir="" />
<Option object_output="../obj/win32-d/" /> <Option object_output="../obj/mingw32-d/" />
<Option type="2" /> <Option type="2" />
<Option compiler="gcc" /> <Option compiler="gcc" />
<Option createDefFile="1" /> <Option createDefFile="1" />
<Compiler> <Compiler>
<Add option="-m32" />
<Add option="-g" /> <Add option="-g" />
<Add option="-D_DEBUG" /> <Add option="-D_DEBUG" />
<Add option="-DWIN32" />
<Add option="-DGARBAGE_COLLECTOR" />
<Add directory="../config/mingw32" /> <Add directory="../config/mingw32" />
</Compiler> </Compiler>
<Linker>
<Add option="-m32" />
</Linker>
</Target> </Target>
<Target title="Win32 Release Static"> <Target title="Win32 Release Static">
<Option output="../lib/mingw32/squirrel" prefix_auto="1" extension_auto="1" /> <Option output="../lib/mingw32/squirrel" prefix_auto="1" extension_auto="1" />
<Option working_dir="" /> <Option working_dir="" />
<Option object_output="../obj/win32/" /> <Option object_output="../obj/mingw32/" />
<Option type="2" /> <Option type="2" />
<Option compiler="gcc" /> <Option compiler="gcc" />
<Option createDefFile="1" /> <Option createDefFile="1" />
<Compiler> <Compiler>
<Add option="-fexpensive-optimizations" /> <Add option="-fexpensive-optimizations" />
<Add option="-O3" /> <Add option="-O3" />
<Add option="-m32" />
<Add option="-DNDEBUG" /> <Add option="-DNDEBUG" />
<Add option="-DWIN32" />
<Add option="-DGARBAGE_COLLECTOR" />
<Add directory="../config/mingw32" /> <Add directory="../config/mingw32" />
</Compiler> </Compiler>
<Linker> <Linker>
<Add option="-s" /> <Add option="-s" />
<Add option="-m32" />
</Linker> </Linker>
</Target> </Target>
<Target title="Win64 Debug Static"> <Target title="Win64 Debug Static">
<Option output="../lib/mingw64/squirrel-d" prefix_auto="1" extension_auto="1" /> <Option output="../lib/mingw64-d/squirrel" prefix_auto="1" extension_auto="1" />
<Option working_dir="" /> <Option working_dir="" />
<Option object_output="../obj/win32-d/" /> <Option object_output="../obj/mingw64-d/" />
<Option type="2" /> <Option type="2" />
<Option compiler="gcc" /> <Option compiler="gcc" />
<Option createDefFile="1" /> <Option createDefFile="1" />
<Compiler> <Compiler>
<Add option="-m64" />
<Add option="-g" /> <Add option="-g" />
<Add option="-D_DEBUG" /> <Add option="-D_DEBUG" />
<Add option="-DWIN64" />
<Add option="-D_SQ64" /> <Add option="-D_SQ64" />
<Add option="-DGARBAGE_COLLECTOR" />
<Add directory="../config/mingw64" /> <Add directory="../config/mingw64" />
</Compiler> </Compiler>
<Linker>
<Add option="-m64" />
</Linker>
</Target> </Target>
<Target title="Win64 Release Static"> <Target title="Win64 Release Static">
<Option output="../lib/mingw64/squirrel" prefix_auto="1" extension_auto="1" /> <Option output="../lib/mingw64/squirrel" prefix_auto="1" extension_auto="1" />
<Option working_dir="" /> <Option working_dir="" />
<Option object_output="../obj/win32/" /> <Option object_output="../obj/mingw64/" />
<Option type="2" /> <Option type="2" />
<Option compiler="gcc" /> <Option compiler="gcc" />
<Option createDefFile="1" /> <Option createDefFile="1" />
<Compiler> <Compiler>
<Add option="-fexpensive-optimizations" /> <Add option="-fexpensive-optimizations" />
<Add option="-O3" /> <Add option="-O3" />
<Add option="-m64" />
<Add option="-DNDEBUG" /> <Add option="-DNDEBUG" />
<Add option="-DWIN64" />
<Add option="-D_SQ64" /> <Add option="-D_SQ64" />
<Add option="-DGARBAGE_COLLECTOR" />
<Add directory="../config/mingw64" /> <Add directory="../config/mingw64" />
</Compiler> </Compiler>
<Linker> <Linker>
<Add option="-s" /> <Add option="-s" />
<Add option="-m64" />
</Linker>
</Target>
<Target title="Linux32 Debug Static">
<Option output="../lib/gcc32-d/squirrel" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/gcc32-d/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-m32" />
<Add option="-g" />
<Add option="-fPIC" />
<Add option="-D_DEBUG" />
<Add directory="../config/gcc32" />
</Compiler>
<Linker>
<Add option="-m32" />
</Linker>
</Target>
<Target title="Linux32 Release Static">
<Option output="../lib/gcc32/squirrel" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/gcc32/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-fexpensive-optimizations" />
<Add option="-O3" />
<Add option="-m32" />
<Add option="-fPIC" />
<Add option="-DNDEBUG" />
<Add directory="../config/gcc32" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-m32" />
</Linker>
</Target>
<Target title="Linux64 Debug Static">
<Option output="../lib/gcc64-d/squirrel" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/gcc64-d/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-m64" />
<Add option="-g" />
<Add option="-fPIC" />
<Add option="-D_DEBUG" />
<Add option="-D_SQ64" />
<Add directory="../config/gcc64" />
</Compiler>
<Linker>
<Add option="-m64" />
</Linker>
</Target>
<Target title="Linux64 Release Static">
<Option output="../lib/gcc64/squirrel" prefix_auto="1" extension_auto="1" />
<Option working_dir="" />
<Option object_output="../obj/gcc64/" />
<Option type="2" />
<Option compiler="gcc" />
<Option createDefFile="1" />
<Compiler>
<Add option="-fexpensive-optimizations" />
<Add option="-O3" />
<Add option="-m64" />
<Add option="-fPIC" />
<Add option="-DNDEBUG" />
<Add option="-D_SQ64" />
<Add directory="../config/gcc64" />
</Compiler>
<Linker>
<Add option="-s" />
<Add option="-m64" />
</Linker> </Linker>
</Target> </Target>
</Build> </Build>
@ -83,6 +165,7 @@
<Add option="-fno-rtti" /> <Add option="-fno-rtti" />
<Add option="-fno-strict-aliasing" /> <Add option="-fno-strict-aliasing" />
<Add option="-Wno-unused-variable" /> <Add option="-Wno-unused-variable" />
<Add option="-DGARBAGE_COLLECTOR" />
<Add directory="../include" /> <Add directory="../include" />
<Add directory="../config/common" /> <Add directory="../config/common" />
</Compiler> </Compiler>

View File

@ -3,8 +3,8 @@
<Workspace title="SqMod"> <Workspace title="SqMod">
<Project filename="Module.cbp" /> <Project filename="Module.cbp" />
<Project filename="Sandbox.cbp" /> <Project filename="Sandbox.cbp" />
<Project filename="Common.cbp" />
<Project filename="Squirrel.cbp" /> <Project filename="Squirrel.cbp" />
<Project filename="SQLite.cbp" /> <Project filename="SQLite.cbp" />
<Project filename="Hash.cbp" />
</Workspace> </Workspace>
</CodeBlocks_workspace_file> </CodeBlocks_workspace_file>

View File

@ -1,74 +0,0 @@
/**
* pugixml parser - version 1.7
* --------------------------------------------------------
* Copyright (C) 2006-2015, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com)
* Report bugs and download new versions at http://pugixml.org/
*
* This library is distributed under the MIT License. See notice at the end
* of this file.
*
* This work is based on the pugxml parser, which is:
* Copyright (C) 2003, by Kristen Wegner (kristen@tima.net)
*/
#ifndef HEADER_PUGICONFIG_HPP
#define HEADER_PUGICONFIG_HPP
// Uncomment this to enable wchar_t mode
// #define PUGIXML_WCHAR_MODE
// Uncomment this to enable compact mode
// #define PUGIXML_COMPACT
// Uncomment this to disable XPath
// #define PUGIXML_NO_XPATH
// Uncomment this to disable STL
// #define PUGIXML_NO_STL
// Uncomment this to disable exceptions
// #define PUGIXML_NO_EXCEPTIONS
// Set this to control attributes for public classes/functions, i.e.:
// #define PUGIXML_API __declspec(dllexport) // to export all public symbols from DLL
// #define PUGIXML_CLASS __declspec(dllimport) // to import all classes from DLL
// #define PUGIXML_FUNCTION __fastcall // to set calling conventions to all public functions to fastcall
// In absence of PUGIXML_CLASS/PUGIXML_FUNCTION definitions PUGIXML_API is used instead
// Tune these constants to adjust memory-related behavior
// #define PUGIXML_MEMORY_PAGE_SIZE 32768
// #define PUGIXML_MEMORY_OUTPUT_STACK 10240
// #define PUGIXML_MEMORY_XPATH_PAGE_SIZE 4096
// Uncomment this to switch to header-only version
// #define PUGIXML_HEADER_ONLY
// Uncomment this to enable long long support
// #define PUGIXML_HAS_LONG_LONG
#endif
/**
* Copyright (c) 2006-2015 Arseny Kapoulkine
*
* 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.
*/

View File

@ -60,7 +60,11 @@ typedef wchar_t SQChar;
#define scstrcmp wcscmp #define scstrcmp wcscmp
#define scsprintf swprintf #ifdef _MSC_VER
#define scsprintf _snwprintf
#else
#define scsprintf snwprintf
#endif
#define scstrlen wcslen #define scstrlen wcslen
#define scstrtod wcstod #define scstrtod wcstod
#ifdef _SQ64 #ifdef _SQ64
@ -95,7 +99,7 @@ typedef wchar_t SQChar;
#define scisalnum iswalnum #define scisalnum iswalnum
#define sq_rsl(l) ((l)<<WCHAR_SHIFT_MUL)
#else #else
typedef char SQChar; typedef char SQChar;
@ -129,6 +133,9 @@ typedef char SQChar;
#define scisalnum isalnum #define scisalnum isalnum
#define scprintf printf #define scprintf printf
#define MAX_CHAR 0xFF #define MAX_CHAR 0xFF
#define sq_rsl(l) (l)
#endif #endif
#ifdef _SQ64 #ifdef _SQ64

View File

@ -1,110 +0,0 @@
/* src/config.h. Generated from config.h.in by configure. */
/* include/config.h.in. Generated from configure.in by autoheader. */
/* Define to 1 if you have the `getaddrinfo' function. */
/* #undef HAVE_GETADDRINFO */
/* Define to 1 if you have the `gethostbyname_r' function. */
/* #undef HAVE_GETHOSTBYNAME_R */
/* Define to 1 if you have the `inet_ntoa' function. */
/* #undef HAVE_INET_NTOA */
/* Define to 1 if you have the `inet_pton' function. */
/* #undef HAVE_INET_PTON */
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `localtime_r' function. */
/* #undef HAVE_LOCALTIME_R */
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
to 0 otherwise. */
#define HAVE_MALLOC 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `socket' function. */
/* #undef HAVE_SOCKET */
/* Define to 1 if `stat' has the bug that it succeeds when given the
zero-length file name argument. */
/* #undef HAVE_STAT_EMPTY_STRING_BUG */
/* Define to 1 if stdbool.h conforms to C99. */
#define HAVE_STDBOOL_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/select.h> header file. */
/* #undef HAVE_SYS_SELECT_H */
/* Define to 1 if you have the <sys/socket.h> header file. */
/* #undef HAVE_SYS_SOCKET_H */
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if the system has the type `_Bool'. */
#define HAVE__BOOL 1
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
slash. */
/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "gyunaev@ulduzsoft.com"
/* Define to the full name of this package. */
#define PACKAGE_NAME "libircclient"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "libircclient 1.3"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "libircclient"
/* Define to the version of this package. */
#define PACKAGE_VERSION "1.3"
/* Define to the type of arg 1 for `select'. */
#define SELECT_TYPE_ARG1 int
/* Define to the type of args 2, 3 and 4 for `select'. */
#define SELECT_TYPE_ARG234 (int *)
/* Define to the type of arg 5 for `select'. */
#define SELECT_TYPE_ARG5 (struct timeval *)
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#define TIME_WITH_SYS_TIME 1
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define to rpl_malloc if the replacement function should be used. */
/* #undef malloc */
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */

View File

@ -1,110 +0,0 @@
/* src/config.h. Generated from config.h.in by configure. */
/* include/config.h.in. Generated from configure.in by autoheader. */
/* Define to 1 if you have the `getaddrinfo' function. */
/* #undef HAVE_GETADDRINFO */
/* Define to 1 if you have the `gethostbyname_r' function. */
/* #undef HAVE_GETHOSTBYNAME_R */
/* Define to 1 if you have the `inet_ntoa' function. */
/* #undef HAVE_INET_NTOA */
/* Define to 1 if you have the `inet_pton' function. */
/* #undef HAVE_INET_PTON */
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the `localtime_r' function. */
/* #undef HAVE_LOCALTIME_R */
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
to 0 otherwise. */
#define HAVE_MALLOC 1
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H 1
/* Define to 1 if you have the `socket' function. */
/* #undef HAVE_SOCKET */
/* Define to 1 if `stat' has the bug that it succeeds when given the
zero-length file name argument. */
/* #undef HAVE_STAT_EMPTY_STRING_BUG */
/* Define to 1 if stdbool.h conforms to C99. */
#define HAVE_STDBOOL_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the <sys/select.h> header file. */
/* #undef HAVE_SYS_SELECT_H */
/* Define to 1 if you have the <sys/socket.h> header file. */
/* #undef HAVE_SYS_SOCKET_H */
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define to 1 if the system has the type `_Bool'. */
#define HAVE__BOOL 1
/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
slash. */
/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT "gyunaev@ulduzsoft.com"
/* Define to the full name of this package. */
#define PACKAGE_NAME "libircclient"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "libircclient 1.3"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "libircclient"
/* Define to the version of this package. */
#define PACKAGE_VERSION "1.3"
/* Define to the type of arg 1 for `select'. */
#define SELECT_TYPE_ARG1 int
/* Define to the type of args 2, 3 and 4 for `select'. */
#define SELECT_TYPE_ARG234 (int *)
/* Define to the type of arg 5 for `select'. */
#define SELECT_TYPE_ARG5 (struct timeval *)
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#define TIME_WITH_SYS_TIME 1
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define to rpl_malloc if the replacement function should be used. */
/* #undef malloc */
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */

View File

@ -1,253 +0,0 @@
/*
A C++ interface to POSIX functions.
Copyright (c) 2014 - 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// Disable bogus MSVC warnings.
#ifndef _CRT_SECURE_NO_WARNINGS
# define _CRT_SECURE_NO_WARNINGS
#endif
#include "posix.h"
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32
# include <unistd.h>
#else
# include <windows.h>
# include <io.h>
# define O_CREAT _O_CREAT
# define O_TRUNC _O_TRUNC
# ifndef S_IRUSR
# define S_IRUSR _S_IREAD
# endif
# ifndef S_IWUSR
# define S_IWUSR _S_IWRITE
# endif
# ifdef __MINGW32__
# define _SH_DENYNO 0x40
# undef fileno
# endif
#endif // _WIN32
namespace {
#ifdef _WIN32
// Return type of read and write functions.
typedef int RWResult;
// On Windows the count argument to read and write is unsigned, so convert
// it from size_t preventing integer overflow.
inline unsigned convert_rwcount(std::size_t count) {
return count <= UINT_MAX ? static_cast<unsigned>(count) : UINT_MAX;
}
#else
// Return type of read and write functions.
typedef ssize_t RWResult;
inline std::size_t convert_rwcount(std::size_t count) { return count; }
#endif
}
fmt::BufferedFile::~BufferedFile() FMT_NOEXCEPT {
if (file_ && FMT_SYSTEM(fclose(file_)) != 0)
fmt::report_system_error(errno, "cannot close file");
}
fmt::BufferedFile::BufferedFile(
fmt::CStringRef filename, fmt::CStringRef mode) {
FMT_RETRY_VAL(file_, FMT_SYSTEM(fopen(filename.c_str(), mode.c_str())), 0);
if (!file_)
throw SystemError(errno, "cannot open file {}", filename);
}
void fmt::BufferedFile::close() {
if (!file_)
return;
int result = FMT_SYSTEM(fclose(file_));
file_ = 0;
if (result != 0)
throw SystemError(errno, "cannot close file");
}
// A macro used to prevent expansion of fileno on broken versions of MinGW.
#define FMT_ARGS
int fmt::BufferedFile::fileno() const {
int fd = FMT_POSIX_CALL(fileno FMT_ARGS(file_));
if (fd == -1)
throw SystemError(errno, "cannot get file descriptor");
return fd;
}
fmt::File::File(fmt::CStringRef path, int oflag) {
int mode = S_IRUSR | S_IWUSR;
#if defined(_WIN32) && !defined(__MINGW32__)
fd_ = -1;
FMT_POSIX_CALL(sopen_s(&fd_, path.c_str(), oflag, _SH_DENYNO, mode));
#else
FMT_RETRY(fd_, FMT_POSIX_CALL(open(path.c_str(), oflag, mode)));
#endif
if (fd_ == -1)
throw SystemError(errno, "cannot open file {}", path);
}
fmt::File::~File() FMT_NOEXCEPT {
// Don't retry close in case of EINTR!
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
if (fd_ != -1 && FMT_POSIX_CALL(close(fd_)) != 0)
fmt::report_system_error(errno, "cannot close file");
}
void fmt::File::close() {
if (fd_ == -1)
return;
// Don't retry close in case of EINTR!
// See http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
int result = FMT_POSIX_CALL(close(fd_));
fd_ = -1;
if (result != 0)
throw SystemError(errno, "cannot close file");
}
fmt::LongLong fmt::File::size() const {
#ifdef _WIN32
// Use GetFileSize instead of GetFileSizeEx for the case when _WIN32_WINNT
// is less than 0x0500 as is the case with some default MinGW builds.
// Both functions support large file sizes.
DWORD size_upper = 0;
HANDLE handle = reinterpret_cast<HANDLE>(_get_osfhandle(fd_));
DWORD size_lower = FMT_SYSTEM(GetFileSize(handle, &size_upper));
if (size_lower == INVALID_FILE_SIZE) {
DWORD error = GetLastError();
if (error != NO_ERROR)
throw WindowsError(GetLastError(), "cannot get file size");
}
fmt::ULongLong long_size = size_upper;
return (long_size << sizeof(DWORD) * CHAR_BIT) | size_lower;
#else
typedef struct stat Stat;
Stat file_stat = Stat();
if (FMT_POSIX_CALL(fstat(fd_, &file_stat)) == -1)
throw SystemError(errno, "cannot get file attributes");
FMT_STATIC_ASSERT(sizeof(fmt::LongLong) >= sizeof(file_stat.st_size),
"return type of File::size is not large enough");
return file_stat.st_size;
#endif
}
std::size_t fmt::File::read(void *buffer, std::size_t count) {
RWResult result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(read(fd_, buffer, convert_rwcount(count))));
if (result < 0)
throw SystemError(errno, "cannot read from file");
return result;
}
std::size_t fmt::File::write(const void *buffer, std::size_t count) {
RWResult result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(write(fd_, buffer, convert_rwcount(count))));
if (result < 0)
throw SystemError(errno, "cannot write to file");
return result;
}
fmt::File fmt::File::dup(int fd) {
// Don't retry as dup doesn't return EINTR.
// http://pubs.opengroup.org/onlinepubs/009695399/functions/dup.html
int new_fd = FMT_POSIX_CALL(dup(fd));
if (new_fd == -1)
throw SystemError(errno, "cannot duplicate file descriptor {}", fd);
return File(new_fd);
}
void fmt::File::dup2(int fd) {
int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1) {
throw SystemError(errno,
"cannot duplicate file descriptor {} to {}", fd_, fd);
}
}
void fmt::File::dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT {
int result = 0;
FMT_RETRY(result, FMT_POSIX_CALL(dup2(fd_, fd)));
if (result == -1)
ec = ErrorCode(errno);
}
void fmt::File::pipe(File &read_end, File &write_end) {
// Close the descriptors first to make sure that assignments don't throw
// and there are no leaks.
read_end.close();
write_end.close();
int fds[2] = {};
#ifdef _WIN32
// Make the default pipe capacity same as on Linux 2.6.11+.
enum { DEFAULT_CAPACITY = 65536 };
int result = FMT_POSIX_CALL(pipe(fds, DEFAULT_CAPACITY, _O_BINARY));
#else
// Don't retry as the pipe function doesn't return EINTR.
// http://pubs.opengroup.org/onlinepubs/009696799/functions/pipe.html
int result = FMT_POSIX_CALL(pipe(fds));
#endif
if (result != 0)
throw SystemError(errno, "cannot create pipe");
// The following assignments don't throw because read_fd and write_fd
// are closed.
read_end = File(fds[0]);
write_end = File(fds[1]);
}
fmt::BufferedFile fmt::File::fdopen(const char *mode) {
// Don't retry as fdopen doesn't return EINTR.
FILE *f = FMT_POSIX_CALL(fdopen(fd_, mode));
if (!f)
throw SystemError(errno, "cannot associate stream with file descriptor");
BufferedFile file(f);
fd_ = -1;
return file;
}
long fmt::getpagesize() {
#ifdef _WIN32
SYSTEM_INFO si;
GetSystemInfo(&si);
return si.dwPageSize;
#else
long size = FMT_POSIX_CALL(sysconf(_SC_PAGESIZE));
if (size < 0)
throw SystemError(errno, "cannot get memory page size");
return size;
#endif
}

View File

@ -1,340 +0,0 @@
/*
A C++ interface to POSIX functions.
Copyright (c) 2014 - 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef FMT_POSIX_H_
#define FMT_POSIX_H_
#ifdef __MINGW32__
// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
# undef __STRICT_ANSI__
#endif
#include <errno.h>
#include <fcntl.h> // for O_RDONLY
#include <stdio.h>
#include <cstddef>
#include "format.h"
#ifndef FMT_POSIX
# if defined(_WIN32) && !defined(__MINGW32__)
// Fix warnings about deprecated symbols.
# define FMT_POSIX(call) _##call
# else
# define FMT_POSIX(call) call
# endif
#endif
// Calls to system functions are wrapped in FMT_SYSTEM for testability.
#ifdef FMT_SYSTEM
# define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
#else
# define FMT_SYSTEM(call) call
# ifdef _WIN32
// Fix warnings about deprecated symbols.
# define FMT_POSIX_CALL(call) ::_##call
# else
# define FMT_POSIX_CALL(call) ::call
# endif
#endif
#if FMT_GCC_VERSION >= 407
# define FMT_UNUSED __attribute__((unused))
#else
# define FMT_UNUSED
#endif
#if FMT_USE_STATIC_ASSERT || FMT_HAS_CPP_ATTRIBUTE(cxx_static_assert) || \
(FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600
# define FMT_STATIC_ASSERT(cond, message) static_assert(cond, message)
#else
# define FMT_CONCAT_(a, b) FMT_CONCAT(a, b)
# define FMT_STATIC_ASSERT(cond, message) \
typedef int FMT_CONCAT_(Assert, __LINE__)[(cond) ? 1 : -1] FMT_UNUSED
#endif
// Retries the expression while it evaluates to error_result and errno
// equals to EINTR.
#ifndef _WIN32
# define FMT_RETRY_VAL(result, expression, error_result) \
do { \
result = (expression); \
} while (result == error_result && errno == EINTR)
#else
# define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
#endif
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
namespace fmt {
// An error code.
class ErrorCode {
private:
int value_;
public:
explicit ErrorCode(int value = 0) FMT_NOEXCEPT : value_(value) {}
int get() const FMT_NOEXCEPT { return value_; }
};
// A buffered file.
class BufferedFile {
private:
FILE *file_;
friend class File;
explicit BufferedFile(FILE *f) : file_(f) {}
public:
// Constructs a BufferedFile object which doesn't represent any file.
BufferedFile() FMT_NOEXCEPT : file_(0) {}
// Destroys the object closing the file it represents if any.
~BufferedFile() FMT_NOEXCEPT;
#if !FMT_USE_RVALUE_REFERENCES
// Emulate a move constructor and a move assignment operator if rvalue
// references are not supported.
private:
// A proxy object to emulate a move constructor.
// It is private to make it impossible call operator Proxy directly.
struct Proxy {
FILE *file;
};
public:
// A "move constructor" for moving from a temporary.
BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {}
// A "move constructor" for for moving from an lvalue.
BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) {
f.file_ = 0;
}
// A "move assignment operator" for moving from a temporary.
BufferedFile &operator=(Proxy p) {
close();
file_ = p.file;
return *this;
}
// A "move assignment operator" for moving from an lvalue.
BufferedFile &operator=(BufferedFile &other) {
close();
file_ = other.file_;
other.file_ = 0;
return *this;
}
// Returns a proxy object for moving from a temporary:
// BufferedFile file = BufferedFile(...);
operator Proxy() FMT_NOEXCEPT {
Proxy p = {file_};
file_ = 0;
return p;
}
#else
private:
FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile);
public:
BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_) {
other.file_ = 0;
}
BufferedFile& operator=(BufferedFile &&other) {
close();
file_ = other.file_;
other.file_ = 0;
return *this;
}
#endif
// Opens a file.
BufferedFile(CStringRef filename, CStringRef mode);
// Closes the file.
void close();
// Returns the pointer to a FILE object representing this file.
FILE *get() const FMT_NOEXCEPT { return file_; }
// We place parentheses around fileno to workaround a bug in some versions
// of MinGW that define fileno as a macro.
int (fileno)() const;
void print(CStringRef format_str, const ArgList &args) {
fmt::print(file_, format_str, args);
}
FMT_VARIADIC(void, print, CStringRef)
};
// A file. Closed file is represented by a File object with descriptor -1.
// Methods that are not declared with FMT_NOEXCEPT may throw
// fmt::SystemError in case of failure. Note that some errors such as
// closing the file multiple times will cause a crash on Windows rather
// than an exception. You can get standard behavior by overriding the
// invalid parameter handler with _set_invalid_parameter_handler.
class File {
private:
int fd_; // File descriptor.
// Constructs a File object with a given descriptor.
explicit File(int fd) : fd_(fd) {}
public:
// Possible values for the oflag argument to the constructor.
enum {
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
};
// Constructs a File object which doesn't represent any file.
File() FMT_NOEXCEPT : fd_(-1) {}
// Opens a file and constructs a File object representing this file.
File(CStringRef path, int oflag);
#if !FMT_USE_RVALUE_REFERENCES
// Emulate a move constructor and a move assignment operator if rvalue
// references are not supported.
private:
// A proxy object to emulate a move constructor.
// It is private to make it impossible call operator Proxy directly.
struct Proxy {
int fd;
};
public:
// A "move constructor" for moving from a temporary.
File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {}
// A "move constructor" for for moving from an lvalue.
File(File &other) FMT_NOEXCEPT : fd_(other.fd_) {
other.fd_ = -1;
}
// A "move assignment operator" for moving from a temporary.
File &operator=(Proxy p) {
close();
fd_ = p.fd;
return *this;
}
// A "move assignment operator" for moving from an lvalue.
File &operator=(File &other) {
close();
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
// Returns a proxy object for moving from a temporary:
// File file = File(...);
operator Proxy() FMT_NOEXCEPT {
Proxy p = {fd_};
fd_ = -1;
return p;
}
#else
private:
FMT_DISALLOW_COPY_AND_ASSIGN(File);
public:
File(File &&other) FMT_NOEXCEPT : fd_(other.fd_) {
other.fd_ = -1;
}
File& operator=(File &&other) {
close();
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
#endif
// Destroys the object closing the file it represents if any.
~File() FMT_NOEXCEPT;
// Returns the file descriptor.
int descriptor() const FMT_NOEXCEPT { return fd_; }
// Closes the file.
void close();
// Returns the file size.
LongLong size() const;
// Attempts to read count bytes from the file into the specified buffer.
std::size_t read(void *buffer, std::size_t count);
// Attempts to write count bytes from the specified buffer to the file.
std::size_t write(const void *buffer, std::size_t count);
// Duplicates a file descriptor with the dup function and returns
// the duplicate as a file object.
static File dup(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
void dup2(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if
// necessary.
void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT;
// Creates a pipe setting up read_end and write_end file objects for reading
// and writing respectively.
static void pipe(File &read_end, File &write_end);
// Creates a BufferedFile object associated with this file and detaches
// this File object from the file.
BufferedFile fdopen(const char *mode);
};
// Returns the memory page size.
long getpagesize();
} // namespace fmt
#if !FMT_USE_RVALUE_REFERENCES
namespace std {
// For compatibility with C++98.
inline fmt::BufferedFile &move(fmt::BufferedFile &f) { return f; }
inline fmt::File &move(fmt::File &f) { return f; }
}
#endif
#endif // FMT_POSIX_H_

View File

@ -1,23 +0,0 @@
Copyright (c) 2012 - 2015, Victor Zverovich
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

File diff suppressed because it is too large Load Diff

482
external/IRC/LICENSE vendored
View File

@ -1,482 +0,0 @@
GNU LIBRARY GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1991 Free Software Foundation, Inc.
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the library GPL. It is
numbered 2 because it goes with version 2 of the ordinary GPL.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Library General Public License, applies to some
specially designated Free Software Foundation software, and to any
other libraries whose authors decide to use it. You can use it for
your libraries, 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
this service 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 make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if
you distribute copies of the library, or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link a program with the library, you must provide
complete object files to the recipients so that they can relink them
with the library, after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
Our method of protecting your rights has two steps: (1) copyright
the library, and (2) offer you this license which gives you legal
permission to copy, distribute and/or modify the library.
Also, for each distributor's protection, we want to make certain
that everyone understands that there is no warranty for this free
library. If the library is modified by someone else and passed on, we
want its recipients to know that what they have is not the original
version, so that any problems introduced by others will not reflect on
the original authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that companies distributing free
software will individually obtain patent licenses, thus in effect
transforming the program into proprietary software. To prevent this,
we have made it clear that any patent must be licensed for everyone's
free use or not licensed at all.
Most GNU software, including some libraries, is covered by the ordinary
GNU General Public License, which was designed for utility programs. This
license, the GNU Library General Public License, applies to certain
designated libraries. This license is quite different from the ordinary
one; be sure to read it in full, and don't assume that anything in it is
the same as in the ordinary license.
The reason we have a separate public license for some libraries is that
they blur the distinction we usually make between modifying or adding to a
program and simply using it. Linking a program with a library, without
changing the library, is in some sense simply using the library, and is
analogous to running a utility program or application program. However, in
a textual and legal sense, the linked executable is a combined work, a
derivative of the original library, and the ordinary General Public License
treats it as such.
Because of this blurred distinction, using the ordinary General
Public License for libraries did not effectively promote software
sharing, because most developers did not use the libraries. We
concluded that weaker conditions might promote sharing better.
However, unrestricted linking of non-free programs would deprive the
users of those programs of all benefit from the free status of the
libraries themselves. This Library General Public License is intended to
permit developers of non-free programs to use free libraries, while
preserving your freedom as a user of such programs to change the free
libraries that are incorporated in them. (We have not seen how to achieve
this as regards changes in header files, but we have achieved it as regards
changes in the actual functions of the Library.) The hope is that this
will lead to faster development of free libraries.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, while the latter only
works together with the library.
Note that it is possible for a library to be covered by the ordinary
General Public License rather than by this special one.
GNU LIBRARY GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library which
contains a notice placed by the copyright holder or other authorized
party saying it may be distributed under the terms of this Library
General Public License (also called "this License"). Each licensee is
addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also compile or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
c) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
d) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the source code distributed need not include anything that is normally
distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
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
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Library 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 Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "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
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY 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
LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

388
external/IRC/colors.c vendored
View File

@ -1,388 +0,0 @@
/*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*/
#include <ctype.h>
#define LIBIRC_COLORPARSER_BOLD (1<<1)
#define LIBIRC_COLORPARSER_UNDERLINE (1<<2)
#define LIBIRC_COLORPARSER_REVERSE (1<<3)
#define LIBIRC_COLORPARSER_COLOR (1<<4)
#define LIBIRC_COLORPARSER_MAXCOLORS 15
static const char * color_replacement_table[] =
{
"WHITE",
"BLACK",
"DARKBLUE",
"DARKGREEN",
"RED",
"BROWN",
"PURPLE",
"OLIVE",
"YELLOW",
"GREEN",
"TEAL",
"CYAN",
"BLUE",
"MAGENTA",
"DARKGRAY",
"LIGHTGRAY",
0
};
static inline void libirc_colorparser_addorcat (char ** destline, unsigned int * destlen, const char * str)
{
unsigned int len = strlen(str);
if ( *destline )
{
strcpy (*destline, str);
*destline += len;
}
else
*destlen += len;
}
static void libirc_colorparser_applymask (unsigned int * mask,
char ** destline, unsigned int * destlen,
unsigned int bitmask, const char * start, const char * end)
{
if ( (*mask & bitmask) != 0 )
{
*mask &= ~bitmask;
libirc_colorparser_addorcat (destline, destlen, end);
}
else
{
*mask |= bitmask;
libirc_colorparser_addorcat (destline, destlen, start);
}
}
static void libirc_colorparser_applycolor (unsigned int * mask,
char ** destline, unsigned int * destlen,
unsigned int colorid, unsigned int bgcolorid)
{
const char * end = "[/COLOR]";
char startbuf[64];
if ( bgcolorid != 0 )
sprintf (startbuf, "[COLOR=%s/%s]", color_replacement_table[colorid], color_replacement_table[bgcolorid]);
else
sprintf (startbuf, "[COLOR=%s]", color_replacement_table[colorid]);
if ( (*mask & LIBIRC_COLORPARSER_COLOR) != 0 )
libirc_colorparser_addorcat (destline, destlen, end);
*mask |= LIBIRC_COLORPARSER_COLOR;
libirc_colorparser_addorcat (destline, destlen, startbuf);
}
static void libirc_colorparser_closetags (unsigned int * mask,
char ** destline, unsigned int * destlen)
{
if ( *mask & LIBIRC_COLORPARSER_BOLD )
libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_BOLD, 0, "[/B]");
if ( *mask & LIBIRC_COLORPARSER_UNDERLINE )
libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_UNDERLINE, 0, "[/U]");
if ( *mask & LIBIRC_COLORPARSER_REVERSE )
libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_REVERSE, 0, "[/I]");
if ( *mask & LIBIRC_COLORPARSER_COLOR )
libirc_colorparser_applymask (mask, destline, destlen, LIBIRC_COLORPARSER_COLOR, 0, "[/COLOR]");
}
/*
* IRC to [code] color conversion. Or strip.
*/
static char * libirc_colorparser_irc2code (const char * source, int strip)
{
unsigned int mask = 0, destlen = 0;
char * destline = 0, *d = 0;
const char *p;
int current_bg = 0;
/*
* There will be two passes. First pass calculates the total length of
* the destination string. The second pass allocates memory for the string,
* and fills it.
*/
while ( destline == 0 ) // destline will be set after the 2nd pass
{
if ( destlen > 0 )
{
// This is the 2nd pass; allocate memory.
if ( (destline = malloc (destlen)) == 0 )
return 0;
d = destline;
}
for ( p = source; *p; p++ )
{
switch (*p)
{
case 0x02: // bold
if ( strip )
continue;
libirc_colorparser_applymask (&mask, &d, &destlen, LIBIRC_COLORPARSER_BOLD, "[B]", "[/B]");
break;
case 0x1F: // underline
if ( strip )
continue;
libirc_colorparser_applymask (&mask, &d, &destlen, LIBIRC_COLORPARSER_UNDERLINE, "[U]", "[/U]");
break;
case 0x16: // reverse
if ( strip )
continue;
libirc_colorparser_applymask (&mask, &d, &destlen, LIBIRC_COLORPARSER_REVERSE, "[I]", "[/I]");
break;
case 0x0F: // reset colors
if ( strip )
continue;
libirc_colorparser_closetags (&mask, &d, &destlen);
break;
case 0x03: // set color
if ( isdigit (p[1]) )
{
// Parse
int bgcolor = -1, color = p[1] - 0x30;
p++;
if ( isdigit (p[1]) )
{
color = color * 10 + (p[1] - 0x30);
p++;
}
// If there is a comma, search for the following
// background color
if ( p[1] == ',' && isdigit (p[2]) )
{
bgcolor = p[2] - 0x30;
p += 2;
if ( isdigit (p[1]) )
{
bgcolor = bgcolor * 10 + (p[1] - 0x30);
p++;
}
}
// Check for range
if ( color <= LIBIRC_COLORPARSER_MAXCOLORS
&& bgcolor <= LIBIRC_COLORPARSER_MAXCOLORS )
{
if ( strip )
continue;
if ( bgcolor != -1 )
current_bg = bgcolor;
libirc_colorparser_applycolor (&mask, &d, &destlen, color, current_bg);
}
}
break;
default:
if ( destline )
*d++ = *p;
else
destlen++;
break;
}
}
// Close all the opened tags
libirc_colorparser_closetags (&mask, &d, &destlen);
destlen++; // for 0-terminator
}
*d = '\0';
return destline;
}
static int libirc_colorparser_colorlookup (const char * color)
{
int i;
for ( i = 0; color_replacement_table[i]; i++ )
if ( !strcmp (color, color_replacement_table[i]) )
return i;
return -1;
}
/*
* [code] to IRC color conversion.
*/
char * irc_color_convert_to_mirc (const char * source)
{
unsigned int destlen = 0;
char * destline = 0, *d = 0;
const char *p1, *p2, *cur;
/*
* There will be two passes. First pass calculates the total length of
* the destination string. The second pass allocates memory for the string,
* and fills it.
*/
while ( destline == 0 ) // destline will be set after the 2nd pass
{
if ( destlen > 0 )
{
// This is the 2nd pass; allocate memory.
if ( (destline = malloc (destlen)) == 0 )
return 0;
d = destline;
}
cur = source;
while ( (p1 = strchr (cur, '[')) != 0 )
{
const char * replacedval = 0;
p2 = 0;
// Check if the closing bracket is available after p1
// and the tag length is suitable
if ( p1[1] != '\0'
&& (p2 = strchr (p1, ']')) != 0
&& (p2 - p1) > 1
&& (p2 - p1) < 31 )
{
// Get the tag
char tagbuf[32];
int taglen = p2 - p1 - 1;
memcpy (tagbuf, p1 + 1, taglen);
tagbuf[taglen] = '\0';
if ( !strcmp (tagbuf, "/COLOR") )
replacedval = "\x0F";
else if ( strstr (tagbuf, "COLOR=") == tagbuf )
{
int color, bgcolor = -2;
char * bcol;
bcol = strchr (tagbuf + 6, '/');
if ( bcol )
{
*bcol++ = '\0';
bgcolor = libirc_colorparser_colorlookup (bcol);
}
color = libirc_colorparser_colorlookup (tagbuf + 6);
if ( color != -1 && bgcolor == -2 )
{
sprintf (tagbuf, "\x03%02d", color);
replacedval = tagbuf;
}
else if ( color != -1 && bgcolor >= 0 )
{
sprintf (tagbuf, "\x03%02d,%02d", color, bgcolor);
replacedval = tagbuf;
}
}
else if ( !strcmp (tagbuf, "B") || !strcmp (tagbuf, "/B") )
replacedval = "\x02";
else if ( !strcmp (tagbuf, "U") || !strcmp (tagbuf, "/U") )
replacedval = "\x1F";
else if ( !strcmp (tagbuf, "I") || !strcmp (tagbuf, "/I") )
replacedval = "\x16";
}
if ( replacedval )
{
// add a part before the tag
int partlen = p1 - cur;
if ( destline )
{
memcpy (d, cur, partlen);
d += partlen;
}
else
destlen += partlen;
// Add the replacement
libirc_colorparser_addorcat (&d, &destlen, replacedval);
// And move the pointer
cur = p2 + 1;
}
else
{
// add a whole part before the end tag
int partlen;
if ( !p2 )
p2 = cur + strlen(cur);
partlen = p2 - cur + 1;
if ( destline )
{
memcpy (d, cur, partlen);
d += partlen;
}
else
destlen += partlen;
// And move the pointer
cur = p2 + 1;
}
}
// Add the rest of string
libirc_colorparser_addorcat (&d, &destlen, cur);
destlen++; // for 0-terminator
}
*d = '\0';
return destline;
}
char * irc_color_strip_from_mirc (const char * message)
{
return libirc_colorparser_irc2code (message, 1);
}
char * irc_color_convert_from_mirc (const char * message)
{
return libirc_colorparser_irc2code (message, 0);
}

892
external/IRC/dcc.c vendored
View File

@ -1,892 +0,0 @@
/*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*/
#define LIBIRC_DCC_CHAT 1
#define LIBIRC_DCC_SENDFILE 2
#define LIBIRC_DCC_RECVFILE 3
static irc_dcc_session_t * libirc_find_dcc_session (irc_session_t * session, irc_dcc_t dccid, int lock_list)
{
irc_dcc_session_t * s, *found = 0;
if ( lock_list )
libirc_mutex_lock (&session->mutex_dcc);
for ( s = session->dcc_sessions; s; s = s->next )
{
if ( s->id == dccid )
{
found = s;
break;
}
}
if ( found == 0 && lock_list )
libirc_mutex_unlock (&session->mutex_dcc);
return found;
}
static void libirc_dcc_destroy_nolock (irc_session_t * session, irc_dcc_t dccid)
{
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 0);
if ( dcc )
{
if ( dcc->sock >= 0 )
socket_close (&dcc->sock);
dcc->state = LIBIRC_STATE_REMOVED;
}
}
static void libirc_remove_dcc_session (irc_session_t * session, irc_dcc_session_t * dcc, int lock_list)
{
if ( dcc->sock >= 0 )
socket_close (&dcc->sock);
if ( dcc->dccsend_file_fp )
fclose (dcc->dccsend_file_fp);
dcc->dccsend_file_fp = 0;
libirc_mutex_destroy (&dcc->mutex_outbuf);
if ( lock_list )
libirc_mutex_lock (&session->mutex_dcc);
if ( session->dcc_sessions != dcc )
{
irc_dcc_session_t * s;
for ( s = session->dcc_sessions; s; s = s->next )
{
if ( s->next == dcc )
{
s->next = dcc->next;
break;
}
}
}
else
session->dcc_sessions = dcc->next;
if ( lock_list )
libirc_mutex_unlock (&session->mutex_dcc);
free (dcc);
}
static void libirc_dcc_add_descriptors (irc_session_t * ircsession, fd_set *in_set, fd_set *out_set, int * maxfd)
{
irc_dcc_session_t * dcc, *dcc_next;
time_t now = time (0);
libirc_mutex_lock (&ircsession->mutex_dcc);
// Preprocessing DCC list:
// - ask DCC send callbacks for data;
// - remove unused DCC structures
for ( dcc = ircsession->dcc_sessions; dcc; dcc = dcc_next )
{
dcc_next = dcc->next;
// Remove timed-out sessions
if ( (dcc->state == LIBIRC_STATE_CONNECTING
|| dcc->state == LIBIRC_STATE_INIT
|| dcc->state == LIBIRC_STATE_LISTENING)
&& now - dcc->timeout > ircsession->dcc_timeout )
{
// Inform the caller about DCC timeout.
// Do not inform when state is LIBIRC_STATE_INIT - session
// was initiated from someone else, and callbacks aren't set yet.
if ( dcc->state != LIBIRC_STATE_INIT )
{
libirc_mutex_unlock (&ircsession->mutex_dcc);
if ( dcc->cb )
(*dcc->cb)(ircsession, dcc->id, LIBIRC_ERR_TIMEOUT, dcc->ctx, 0, 0);
libirc_mutex_lock (&ircsession->mutex_dcc);
}
libirc_remove_dcc_session (ircsession, dcc, 0);
}
/*
* If we're sending file, and the output buffer is empty, we need
* to provide some data.
*/
if ( dcc->state == LIBIRC_STATE_CONNECTED
&& dcc->dccmode == LIBIRC_DCC_SENDFILE
&& dcc->dccsend_file_fp
&& dcc->outgoing_offset == 0 )
{
int len = fread (dcc->outgoing_buf, 1, sizeof (dcc->outgoing_buf), dcc->dccsend_file_fp);
if ( len <= 0 )
{
int err = (len < 0 ? LIBIRC_ERR_READ : 0);
libirc_mutex_unlock (&ircsession->mutex_dcc);
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
libirc_mutex_lock (&ircsession->mutex_dcc);
libirc_dcc_destroy_nolock (ircsession, dcc->id);
}
else
dcc->outgoing_offset = len;
}
// Clean up unused sessions
if ( dcc->state == LIBIRC_STATE_REMOVED )
libirc_remove_dcc_session (ircsession, dcc, 0);
}
for ( dcc = ircsession->dcc_sessions; dcc; dcc = dcc->next )
{
switch (dcc->state)
{
case LIBIRC_STATE_LISTENING:
// While listening, only in_set descriptor should be set
libirc_add_to_set (dcc->sock, in_set, maxfd);
break;
case LIBIRC_STATE_CONNECTING:
// While connection, only out_set descriptor should be set
libirc_add_to_set (dcc->sock, out_set, maxfd);
break;
case LIBIRC_STATE_CONNECTED:
// Add input descriptor if there is space in input buffer
// and it is DCC chat (during DCC send, there is nothing to recv)
if ( dcc->incoming_offset < sizeof(dcc->incoming_buf) - 1 )
libirc_add_to_set (dcc->sock, in_set, maxfd);
// Add output descriptor if there is something in output buffer
libirc_mutex_lock (&dcc->mutex_outbuf);
if ( dcc->outgoing_offset > 0 )
libirc_add_to_set (dcc->sock, out_set, maxfd);
libirc_mutex_unlock (&dcc->mutex_outbuf);
break;
case LIBIRC_STATE_CONFIRM_SIZE:
/*
* If we're receiving file, then WE should confirm the transferred
* part (so we have to sent data). But if we're sending the file,
* then RECEIVER should confirm the packet, so we have to receive
* data.
*
* We don't need to LOCK_DCC_OUTBUF - during file transfer, buffers
* can't change asynchronously.
*/
if ( dcc->dccmode == LIBIRC_DCC_RECVFILE && dcc->outgoing_offset > 0 )
libirc_add_to_set (dcc->sock, out_set, maxfd);
if ( dcc->dccmode == LIBIRC_DCC_SENDFILE && dcc->incoming_offset < 4 )
libirc_add_to_set (dcc->sock, in_set, maxfd);
}
}
libirc_mutex_unlock (&ircsession->mutex_dcc);
}
static void libirc_dcc_process_descriptors (irc_session_t * ircsession, fd_set *in_set, fd_set *out_set)
{
irc_dcc_session_t * dcc;
/*
* We need to use such a complex scheme here, because on every callback
* a number of DCC sessions could be destroyed.
*/
libirc_mutex_lock (&ircsession->mutex_dcc);
for ( dcc = ircsession->dcc_sessions; dcc; dcc = dcc->next )
{
if ( dcc->state == LIBIRC_STATE_LISTENING
&& FD_ISSET (dcc->sock, in_set) )
{
socklen_t len = sizeof(dcc->remote_addr);
int nsock, err = 0;
// New connection is available; accept it.
if ( socket_accept (&dcc->sock, (socket_t*)&nsock, (struct sockaddr *) &dcc->remote_addr, &len) )
err = LIBIRC_ERR_ACCEPT;
// On success, change the active socket and change the state
if ( err == 0 )
{
// close the listen socket, and replace it by a newly
// accepted
socket_close (&dcc->sock);
dcc->sock = nsock;
dcc->state = LIBIRC_STATE_CONNECTED;
}
// If this is DCC chat, inform the caller about accept()
// success or failure.
// Otherwise (DCC send) there is no reason.
if ( dcc->dccmode == LIBIRC_DCC_CHAT )
{
libirc_mutex_unlock (&ircsession->mutex_dcc);
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
libirc_mutex_lock (&ircsession->mutex_dcc);
}
if ( err )
libirc_dcc_destroy_nolock (ircsession, dcc->id);
}
if ( dcc->state == LIBIRC_STATE_CONNECTING
&& FD_ISSET (dcc->sock, out_set) )
{
// Now we have to determine whether the socket is connected
// or the connect is failed
struct sockaddr_in saddr;
socklen_t slen = sizeof(saddr);
int err = 0;
if ( getpeername (dcc->sock, (struct sockaddr*)&saddr, &slen) < 0 )
err = LIBIRC_ERR_CONNECT;
// On success, change the state
if ( err == 0 )
dcc->state = LIBIRC_STATE_CONNECTED;
// If this is DCC chat, inform the caller about connect()
// success or failure.
// Otherwise (DCC send) there is no reason.
if ( dcc->dccmode == LIBIRC_DCC_CHAT )
{
libirc_mutex_unlock (&ircsession->mutex_dcc);
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
libirc_mutex_lock (&ircsession->mutex_dcc);
}
if ( err )
libirc_dcc_destroy_nolock (ircsession, dcc->id);
}
if ( dcc->state == LIBIRC_STATE_CONNECTED
|| dcc->state == LIBIRC_STATE_CONFIRM_SIZE )
{
if ( FD_ISSET (dcc->sock, in_set) )
{
int length, offset = 0, err = 0;
unsigned int amount = sizeof (dcc->incoming_buf) - dcc->incoming_offset;
length = socket_recv (&dcc->sock, dcc->incoming_buf + dcc->incoming_offset, amount);
if ( length < 0 )
{
err = LIBIRC_ERR_READ;
}
else if ( length == 0 )
{
err = LIBIRC_ERR_CLOSED;
if ( dcc->dccsend_file_fp )
{
fclose (dcc->dccsend_file_fp);
dcc->dccsend_file_fp = 0;
}
}
else
{
dcc->incoming_offset += length;
if ( dcc->dccmode != LIBIRC_DCC_CHAT )
offset = dcc->incoming_offset;
else
offset = libirc_findcrorlf (dcc->incoming_buf, dcc->incoming_offset);
/*
* In LIBIRC_STATE_CONFIRM_SIZE state we don't call any
* callbacks (except there is an error). We just receive
* the data, and compare it with the amount sent.
*/
if ( dcc->state == LIBIRC_STATE_CONFIRM_SIZE )
{
if ( dcc->dccmode != LIBIRC_DCC_SENDFILE )
abort();
if ( dcc->incoming_offset == 4 )
{
// The order is big-endian
const unsigned char * bptr = (const unsigned char *) dcc->incoming_buf;
unsigned int received_size = (bptr[0] << 24) | (bptr[1] << 16) | (bptr[2] << 8) | bptr[3];
// Sent size confirmed
if ( dcc->file_confirm_offset == received_size )
{
dcc->state = LIBIRC_STATE_CONNECTED;
dcc->incoming_offset = 0;
}
else
err = LIBIRC_ERR_WRITE;
}
}
else
{
/*
* If it is DCC_CHAT, we send a 0-terminated string
* (which is smaller than offset). Otherwise we send
* a full buffer.
*/
libirc_mutex_unlock (&ircsession->mutex_dcc);
if ( dcc->dccmode != LIBIRC_DCC_CHAT )
{
if ( dcc->dccmode != LIBIRC_DCC_RECVFILE )
abort();
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, dcc->incoming_buf, offset);
/*
* If the session is not terminated in callback,
* put the sent amount into the sent_packet_size_net_byteorder
*/
if ( dcc->state != LIBIRC_STATE_REMOVED )
{
dcc->state = LIBIRC_STATE_CONFIRM_SIZE;
dcc->file_confirm_offset += offset;
// Store as big endian
dcc->outgoing_buf[0] = (char) dcc->file_confirm_offset >> 24;
dcc->outgoing_buf[1] = (char) dcc->file_confirm_offset >> 16;
dcc->outgoing_buf[2] = (char) dcc->file_confirm_offset >> 8;
dcc->outgoing_buf[3] = (char) dcc->file_confirm_offset;
dcc->outgoing_offset = 4;
}
}
else
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, dcc->incoming_buf, strlen(dcc->incoming_buf));
libirc_mutex_lock (&ircsession->mutex_dcc);
if ( dcc->incoming_offset - offset > 0 )
memmove (dcc->incoming_buf, dcc->incoming_buf + offset, dcc->incoming_offset - offset);
dcc->incoming_offset -= offset;
}
}
/*
* If error arises somewhere above, we inform the caller
* of failure, and destroy this session.
*/
if ( err )
{
libirc_mutex_unlock (&ircsession->mutex_dcc);
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
libirc_mutex_lock (&ircsession->mutex_dcc);
libirc_dcc_destroy_nolock (ircsession, dcc->id);
}
}
/*
* Session might be closed (with sock = -1) after the in_set
* processing, so before out_set processing we should check
* for this case
*/
if ( dcc->state == LIBIRC_STATE_REMOVED )
continue;
/*
* Write bit set - we can send() something, and it won't block.
*/
if ( FD_ISSET (dcc->sock, out_set) )
{
int length, offset, err = 0;
/*
* Because in some cases outgoing_buf could be changed
* asynchronously (by another thread), we should lock
* it.
*/
libirc_mutex_lock (&dcc->mutex_outbuf);
offset = dcc->outgoing_offset;
if ( offset > 0 )
{
length = socket_send (&dcc->sock, dcc->outgoing_buf, offset);
if ( length < 0 )
err = LIBIRC_ERR_WRITE;
else if ( length == 0 )
err = LIBIRC_ERR_CLOSED;
else
{
/*
* If this was DCC_SENDFILE, and we just sent a packet,
* change the state to wait for confirmation (and store
* sent packet size)
*/
if ( dcc->state == LIBIRC_STATE_CONNECTED
&& dcc->dccmode == LIBIRC_DCC_SENDFILE )
{
dcc->file_confirm_offset += offset;
dcc->state = LIBIRC_STATE_CONFIRM_SIZE;
libirc_mutex_unlock (&ircsession->mutex_dcc);
libirc_mutex_unlock (&dcc->mutex_outbuf);
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, offset);
libirc_mutex_lock (&ircsession->mutex_dcc);
libirc_mutex_lock (&dcc->mutex_outbuf);
}
if ( dcc->outgoing_offset - length > 0 )
memmove (dcc->outgoing_buf, dcc->outgoing_buf + length, dcc->outgoing_offset - length);
dcc->outgoing_offset -= length;
/*
* If we just sent the confirmation data, change state
* back.
*/
if ( dcc->state == LIBIRC_STATE_CONFIRM_SIZE
&& dcc->dccmode == LIBIRC_DCC_RECVFILE
&& dcc->outgoing_offset == 0 )
{
/*
* If the file is already received, we should inform
* the caller, and close the session.
*/
if ( dcc->received_file_size == dcc->file_confirm_offset )
{
libirc_mutex_unlock (&ircsession->mutex_dcc);
libirc_mutex_unlock (&dcc->mutex_outbuf);
(*dcc->cb)(ircsession, dcc->id, 0, dcc->ctx, 0, 0);
libirc_dcc_destroy_nolock (ircsession, dcc->id);
}
else
{
/* Continue to receive the file */
dcc->state = LIBIRC_STATE_CONNECTED;
}
}
}
}
libirc_mutex_unlock (&dcc->mutex_outbuf);
/*
* If error arises somewhere above, we inform the caller
* of failure, and destroy this session.
*/
if ( err )
{
libirc_mutex_unlock (&ircsession->mutex_dcc);
(*dcc->cb)(ircsession, dcc->id, err, dcc->ctx, 0, 0);
libirc_mutex_lock (&ircsession->mutex_dcc);
libirc_dcc_destroy_nolock (ircsession, dcc->id);
}
}
}
}
libirc_mutex_unlock (&ircsession->mutex_dcc);
}
static int libirc_new_dcc_session (irc_session_t * session, unsigned long ip, unsigned short port, int dccmode, void * ctx, irc_dcc_session_t ** pdcc)
{
irc_dcc_session_t * dcc = malloc (sizeof(irc_dcc_session_t));
if ( !dcc )
return LIBIRC_ERR_NOMEM;
// setup
memset (dcc, 0, sizeof(irc_dcc_session_t));
dcc->dccsend_file_fp = 0;
if ( libirc_mutex_init (&dcc->mutex_outbuf) )
goto cleanup_exit_error;
if ( socket_create (PF_INET, SOCK_STREAM, &dcc->sock) )
goto cleanup_exit_error;
if ( !ip )
{
unsigned long arg = 1;
setsockopt (dcc->sock, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, sizeof(arg));
#if defined (ENABLE_IPV6)
if ( session->flags & SESSIONFL_USES_IPV6 )
{
struct sockaddr_in6 saddr6;
memset (&saddr6, 0, sizeof(saddr6));
saddr6.sin6_family = AF_INET6;
memcpy (&saddr6.sin6_addr, &session->local_addr6, sizeof(session->local_addr6));
saddr6.sin6_port = htons (0);
if ( bind (dcc->sock, (struct sockaddr *) &saddr6, sizeof(saddr6)) < 0 )
goto cleanup_exit_error;
}
else
#endif
{
struct sockaddr_in saddr;
memset (&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
memcpy (&saddr.sin_addr, &session->local_addr, sizeof(session->local_addr));
saddr.sin_port = htons (0);
if ( bind (dcc->sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0 )
goto cleanup_exit_error;
}
if ( listen (dcc->sock, 5) < 0 )
goto cleanup_exit_error;
dcc->state = LIBIRC_STATE_LISTENING;
}
else
{
// make socket non-blocking, so connect() call won't block
if ( socket_make_nonblocking (&dcc->sock) )
goto cleanup_exit_error;
memset (&dcc->remote_addr, 0, sizeof(dcc->remote_addr));
dcc->remote_addr.sin_family = AF_INET;
dcc->remote_addr.sin_addr.s_addr = htonl (ip); // what idiot came up with idea to send IP address in host-byteorder?
dcc->remote_addr.sin_port = htons(port);
dcc->state = LIBIRC_STATE_INIT;
}
dcc->dccmode = dccmode;
dcc->ctx = ctx;
time (&dcc->timeout);
// and store it
libirc_mutex_lock (&session->mutex_dcc);
dcc->id = session->dcc_last_id++;
dcc->next = session->dcc_sessions;
session->dcc_sessions = dcc;
libirc_mutex_unlock (&session->mutex_dcc);
*pdcc = dcc;
return 0;
cleanup_exit_error:
if ( dcc->sock >= 0 )
socket_close (&dcc->sock);
free (dcc);
return LIBIRC_ERR_SOCKET;
}
int irc_dcc_destroy (irc_session_t * session, irc_dcc_t dccid)
{
// This function doesn't actually destroy the session; it just changes
// its state to "removed" and closes the socket. The memory is actually
// freed after the processing loop.
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 1);
if ( !dcc )
return 1;
if ( dcc->sock >= 0 )
socket_close (&dcc->sock);
dcc->state = LIBIRC_STATE_REMOVED;
libirc_mutex_unlock (&session->mutex_dcc);
return 0;
}
int irc_dcc_chat (irc_session_t * session, void * ctx, const char * nick, irc_dcc_callback_t callback, irc_dcc_t * dccid)
{
struct sockaddr_in saddr;
socklen_t len = sizeof(saddr);
char cmdbuf[128], notbuf[128];
irc_dcc_session_t * dcc;
int err;
if ( session->state != LIBIRC_STATE_CONNECTED )
{
session->lasterror = LIBIRC_ERR_STATE;
return 1;
}
err = libirc_new_dcc_session (session, 0, 0, LIBIRC_DCC_CHAT, ctx, &dcc);
if ( err )
{
session->lasterror = err;
return 1;
}
if ( getsockname (dcc->sock, (struct sockaddr*) &saddr, &len) < 0 )
{
session->lasterror = LIBIRC_ERR_SOCKET;
libirc_remove_dcc_session (session, dcc, 1);
return 1;
}
sprintf (notbuf, "DCC Chat (%s)", inet_ntoa (saddr.sin_addr));
sprintf (cmdbuf, "DCC CHAT chat %lu %u", (unsigned long) ntohl (saddr.sin_addr.s_addr), ntohs (saddr.sin_port));
if ( irc_cmd_notice (session, nick, notbuf)
|| irc_cmd_ctcp_request (session, nick, cmdbuf) )
{
libirc_remove_dcc_session (session, dcc, 1);
return 1;
}
*dccid = dcc->id;
dcc->cb = callback;
dcc->dccmode = LIBIRC_DCC_CHAT;
return 0;
}
int irc_dcc_msg (irc_session_t * session, irc_dcc_t dccid, const char * text)
{
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 1);
if ( !dcc )
return 1;
if ( dcc->dccmode != LIBIRC_DCC_CHAT )
{
session->lasterror = LIBIRC_ERR_INVAL;
libirc_mutex_unlock (&session->mutex_dcc);
return 1;
}
if ( (strlen(text) + 2) >= (sizeof(dcc->outgoing_buf) - dcc->outgoing_offset) )
{
session->lasterror = LIBIRC_ERR_NOMEM;
libirc_mutex_unlock (&session->mutex_dcc);
return 1;
}
libirc_mutex_lock (&dcc->mutex_outbuf);
strcpy (dcc->outgoing_buf + dcc->outgoing_offset, text);
dcc->outgoing_offset += strlen (text);
dcc->outgoing_buf[dcc->outgoing_offset++] = 0x0D;
dcc->outgoing_buf[dcc->outgoing_offset++] = 0x0A;
libirc_mutex_unlock (&dcc->mutex_outbuf);
libirc_mutex_unlock (&session->mutex_dcc);
return 0;
}
static void libirc_dcc_request (irc_session_t * session, const char * nick, const char * req)
{
char filenamebuf[256];
unsigned long ip, size;
unsigned short port;
if ( sscanf (req, "DCC CHAT chat %lu %hu", &ip, &port) == 2 )
{
if ( session->callbacks.event_dcc_chat_req )
{
irc_dcc_session_t * dcc;
int err = libirc_new_dcc_session (session, ip, port, LIBIRC_DCC_CHAT, 0, &dcc);
if ( err )
{
session->lasterror = err;
return;
}
(*session->callbacks.event_dcc_chat_req) (session,
nick,
inet_ntoa (dcc->remote_addr.sin_addr),
dcc->id);
}
return;
}
else if ( sscanf (req, "DCC SEND %s %lu %hu %lu", filenamebuf, &ip, &port, &size) == 4 )
{
if ( session->callbacks.event_dcc_send_req )
{
irc_dcc_session_t * dcc;
int err = libirc_new_dcc_session (session, ip, port, LIBIRC_DCC_RECVFILE, 0, &dcc);
if ( err )
{
session->lasterror = err;
return;
}
(*session->callbacks.event_dcc_send_req) (session,
nick,
inet_ntoa (dcc->remote_addr.sin_addr),
filenamebuf,
size,
dcc->id);
dcc->received_file_size = size;
}
return;
}
#if defined (ENABLE_DEBUG)
fprintf (stderr, "BUG: Unhandled DCC message: %s\n", req);
abort();
#endif
}
int irc_dcc_accept (irc_session_t * session, irc_dcc_t dccid, void * ctx, irc_dcc_callback_t callback)
{
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 1);
if ( !dcc )
return 1;
if ( dcc->state != LIBIRC_STATE_INIT )
{
session->lasterror = LIBIRC_ERR_STATE;
libirc_mutex_unlock (&session->mutex_dcc);
return 1;
}
dcc->cb = callback;
dcc->ctx = ctx;
// Initiate the connect
if ( socket_connect (&dcc->sock, (struct sockaddr *) &dcc->remote_addr, sizeof(dcc->remote_addr)) )
{
libirc_dcc_destroy_nolock (session, dccid);
libirc_mutex_unlock (&session->mutex_dcc);
session->lasterror = LIBIRC_ERR_CONNECT;
return 1;
}
dcc->state = LIBIRC_STATE_CONNECTING;
libirc_mutex_unlock (&session->mutex_dcc);
return 0;
}
int irc_dcc_decline (irc_session_t * session, irc_dcc_t dccid)
{
irc_dcc_session_t * dcc = libirc_find_dcc_session (session, dccid, 1);
if ( !dcc )
return 1;
if ( dcc->state != LIBIRC_STATE_INIT )
{
session->lasterror = LIBIRC_ERR_STATE;
libirc_mutex_unlock (&session->mutex_dcc);
return 1;
}
libirc_dcc_destroy_nolock (session, dccid);
libirc_mutex_unlock (&session->mutex_dcc);
return 0;
}
int irc_dcc_sendfile (irc_session_t * session, void * ctx, const char * nick, const char * filename, irc_dcc_callback_t callback, irc_dcc_t * dccid)
{
struct sockaddr_in saddr;
socklen_t len = sizeof(saddr);
char cmdbuf[128], notbuf[128];
irc_dcc_session_t * dcc;
const char * p;
int err;
long filesize;
if ( !session || !dccid || !filename || !callback )
{
session->lasterror = LIBIRC_ERR_INVAL;
return 1;
}
if ( session->state != LIBIRC_STATE_CONNECTED )
{
session->lasterror = LIBIRC_ERR_STATE;
return 1;
}
if ( (err = libirc_new_dcc_session (session, 0, 0, LIBIRC_DCC_SENDFILE, ctx, &dcc)) != 0 )
{
session->lasterror = err;
return 1;
}
if ( (dcc->dccsend_file_fp = fopen (filename, "rb")) == 0 )
{
libirc_remove_dcc_session (session, dcc, 1);
session->lasterror = LIBIRC_ERR_OPENFILE;
return 1;
}
/* Get file length */
if ( fseek (dcc->dccsend_file_fp, 0, SEEK_END)
|| (filesize = ftell (dcc->dccsend_file_fp)) == -1
|| fseek (dcc->dccsend_file_fp, 0, SEEK_SET) )
{
libirc_remove_dcc_session (session, dcc, 1);
session->lasterror = LIBIRC_ERR_NODCCSEND;
return 1;
}
if ( getsockname (dcc->sock, (struct sockaddr*) &saddr, &len) < 0 )
{
libirc_remove_dcc_session (session, dcc, 1);
session->lasterror = LIBIRC_ERR_SOCKET;
return 1;
}
// Remove path from the filename
if ( (p = strrchr (filename, '\\')) == 0
&& (p = strrchr (filename, '/')) == 0 )
p = filename;
else
p++; // skip directory slash
sprintf (notbuf, "DCC Send %s (%s)", p, inet_ntoa (saddr.sin_addr));
sprintf (cmdbuf, "DCC SEND %s %lu %u %ld", p, (unsigned long) ntohl (saddr.sin_addr.s_addr), ntohs (saddr.sin_port), filesize);
if ( irc_cmd_notice (session, nick, notbuf)
|| irc_cmd_ctcp_request (session, nick, cmdbuf) )
{
libirc_remove_dcc_session (session, dcc, 1);
return 1;
}
*dccid = dcc->id;
dcc->cb = callback;
return 0;
}

54
external/IRC/dcc.h vendored
View File

@ -1,54 +0,0 @@
/*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*/
#ifndef INCLUDE_IRC_DCC_H
#define INCLUDE_IRC_DCC_H
/*
* This structure keeps the state of a single DCC connection.
*/
struct irc_dcc_session_s
{
irc_dcc_session_t * next;
irc_dcc_t id;
void * ctx;
socket_t sock; /*!< DCC socket */
int dccmode; /*!< Boolean value to differ chat vs send
requests. Changes the cb behavior - when
it is chat, data is sent by lines with
stripped CRLFs. In file mode, the data
is sent as-is */
int state;
time_t timeout;
FILE * dccsend_file_fp;
unsigned int received_file_size;
unsigned int file_confirm_offset;
struct sockaddr_in remote_addr;
char incoming_buf[LIBIRC_DCC_BUFFER_SIZE];
unsigned int incoming_offset;
char outgoing_buf[LIBIRC_DCC_BUFFER_SIZE];
unsigned int outgoing_offset;
port_mutex_t mutex_outbuf;
irc_dcc_callback_t cb;
};
#endif /* INCLUDE_IRC_DCC_H */

54
external/IRC/errors.c vendored
View File

@ -1,54 +0,0 @@
/*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*/
static const char * libirc_strerror[LIBIRC_ERR_MAX] =
{
"No error",
"Invalid argument",
"Host not resolved",
"Socket error",
"Could not connect",
"Remote connection closed",
"Out of memory",
"Could not accept new connection",
"Object not found",
"Could not DCC send this object",
"Read error",
"Write error",
"Illegal operation for this state",
"Timeout error",
"Could not open file",
"IRC session terminated",
"IPv6 not supported",
"SSL not supported",
"SSL initialization failed",
"SSL connection failed",
"SSL certificate verify failed",
};
int irc_errno (irc_session_t * session)
{
return session->lasterror;
}
const char * irc_strerror (int ircerrno)
{
if ( ircerrno >= 0 && ircerrno < LIBIRC_ERR_MAX )
return libirc_strerror[ircerrno];
else
return "Invalid irc_errno value";
}

File diff suppressed because it is too large Load Diff

36
external/IRC/params.h vendored
View File

@ -1,36 +0,0 @@
/*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*/
#ifndef INCLUDE_IRC_PARAMS_H
#define INCLUDE_IRC_PARAMS_H
#define LIBIRC_VERSION_HIGH 1
#define LIBIRC_VERSION_LOW 8
#define LIBIRC_BUFFER_SIZE 1024
#define LIBIRC_DCC_BUFFER_SIZE 1024
#define LIBIRC_STATE_INIT 0
#define LIBIRC_STATE_LISTENING 1
#define LIBIRC_STATE_CONNECTING 2
#define LIBIRC_STATE_CONNECTED 3
#define LIBIRC_STATE_DISCONNECTED 4
#define LIBIRC_STATE_CONFIRM_SIZE 5 // Used only by DCC send to confirm the amount of sent data
#define LIBIRC_STATE_REMOVED 10 // this state is used only in DCC
#define SSL_PREFIX '#'
#endif /* INCLUDE_IRC_PARAMS_H */

View File

@ -1,156 +0,0 @@
/*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*/
#if !defined (_WIN32)
#include "config.h"
#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>
#include <ctype.h>
#include <time.h>
#if defined (ENABLE_THREADS)
#include <pthread.h>
typedef pthread_mutex_t port_mutex_t;
#if !defined (PTHREAD_MUTEX_RECURSIVE) && defined (PTHREAD_MUTEX_RECURSIVE_NP)
#define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
#endif
#endif
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#if defined (ENABLE_THREADS)
typedef CRITICAL_SECTION port_mutex_t;
#endif
#define inline
#define snprintf _snprintf
#define vsnprintf _vsnprintf
#define strncasecmp _strnicmp
#endif
#if defined (ENABLE_SSL)
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#endif
#if defined (ENABLE_THREADS)
static inline int libirc_mutex_init (port_mutex_t * mutex)
{
#if defined (_WIN32)
InitializeCriticalSection (mutex);
return 0;
#elif defined (PTHREAD_MUTEX_RECURSIVE)
pthread_mutexattr_t attr;
return (pthread_mutexattr_init (&attr)
|| pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE)
|| pthread_mutex_init (mutex, &attr));
#else /* !defined (PTHREAD_MUTEX_RECURSIVE) */
return pthread_mutex_init (mutex, 0);
#endif /* defined (_WIN32) */
}
static inline void libirc_mutex_destroy (port_mutex_t * mutex)
{
#if defined (_WIN32)
DeleteCriticalSection (mutex);
#else
pthread_mutex_destroy (mutex);
#endif
}
static inline void libirc_mutex_lock (port_mutex_t * mutex)
{
#if defined (_WIN32)
EnterCriticalSection (mutex);
#else
pthread_mutex_lock (mutex);
#endif
}
static inline void libirc_mutex_unlock (port_mutex_t * mutex)
{
#if defined (_WIN32)
LeaveCriticalSection (mutex);
#else
pthread_mutex_unlock (mutex);
#endif
}
#else
typedef void * port_mutex_t;
static inline int libirc_mutex_init (port_mutex_t * mutex) { return 0; }
static inline void libirc_mutex_destroy (port_mutex_t * mutex) {}
static inline void libirc_mutex_lock (port_mutex_t * mutex) {}
static inline void libirc_mutex_unlock (port_mutex_t * mutex) {}
#endif
/*
* Stub for WIN32 dll to initialize winsock API
*/
#if defined (WIN32_DLL)
BOOL WINAPI DllMain (HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved)
{
WORD wVersionRequested = MAKEWORD (1, 1);
WSADATA wsaData;
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
if ( WSAStartup (wVersionRequested, &wsaData) != 0 )
return FALSE;
DisableThreadLibraryCalls (hinstDll);
break;
case DLL_PROCESS_DETACH:
WSACleanup();
break;
}
return TRUE;
}
#endif

View File

@ -1,79 +0,0 @@
/*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*/
#ifndef INCLUDE_IRC_SESSION_H
#define INCLUDE_IRC_SESSION_H
#include "params.h"
#include "dcc.h"
#include "libirc_events.h"
// Session flags
#define SESSIONFL_MOTD_RECEIVED (0x00000001)
#define SESSIONFL_SSL_CONNECTION (0x00000002)
#define SESSIONFL_SSL_WRITE_WANTS_READ (0x00000004)
#define SESSIONFL_SSL_READ_WANTS_WRITE (0x00000008)
#define SESSIONFL_USES_IPV6 (0x00000010)
struct irc_session_s
{
void * ctx;
int dcc_timeout;
int options;
int lasterror;
char incoming_buf[LIBIRC_BUFFER_SIZE];
unsigned int incoming_offset;
char outgoing_buf[LIBIRC_BUFFER_SIZE];
unsigned int outgoing_offset;
port_mutex_t mutex_session;
socket_t sock;
int state;
int flags;
char * server;
char * server_password;
char * realname;
char * username;
char * nick;
char * ctcp_version;
#if defined( ENABLE_IPV6 )
struct in6_addr local_addr6;
#endif
struct in_addr local_addr;
irc_dcc_t dcc_last_id;
irc_dcc_session_t * dcc_sessions;
port_mutex_t mutex_dcc;
irc_callbacks_t callbacks;
#if defined (ENABLE_SSL)
SSL * ssl;
#endif
};
#endif /* INCLUDE_IRC_SESSION_H */

159
external/IRC/sockets.c vendored
View File

@ -1,159 +0,0 @@
/*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*/
/*
* The sockets interface was moved out to simplify going OpenSSL integration.
*/
#if !defined (_WIN32)
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#define IS_SOCKET_ERROR(a) ((a)<0)
typedef int socket_t;
#else
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#define IS_SOCKET_ERROR(a) ((a)==SOCKET_ERROR)
#if !defined(EWOULDBLOCK)
#define EWOULDBLOCK WSAEWOULDBLOCK
#endif
#if !defined(EINPROGRESS)
#define EINPROGRESS WSAEINPROGRESS
#endif
#if !defined(EINTR)
#define EINTR WSAEINTR
#endif
#if !defined(EAGAIN)
#define EAGAIN EWOULDBLOCK
#endif
typedef SOCKET socket_t;
#endif
#ifndef INADDR_NONE
#define INADDR_NONE 0xFFFFFFFF
#endif
static int socket_error()
{
#if !defined (_WIN32)
return errno;
#else
return WSAGetLastError();
#endif
}
static int socket_create (int domain, int type, socket_t * sock)
{
*sock = socket (domain, type, 0);
return IS_SOCKET_ERROR(*sock) ? 1 : 0;
}
static int socket_make_nonblocking (socket_t * sock)
{
#if !defined (_WIN32)
return fcntl (*sock, F_SETFL, fcntl (*sock, F_GETFL,0 ) | O_NONBLOCK) != 0;
#else
unsigned long mode = 0;
return ioctlsocket (*sock, FIONBIO, &mode) == SOCKET_ERROR;
#endif
}
static int socket_close (socket_t * sock)
{
#if !defined (_WIN32)
close (*sock);
#else
closesocket (*sock);
#endif
*sock = -1;
return 0;
}
static int socket_connect (socket_t * sock, const struct sockaddr *saddr, socklen_t len)
{
while ( 1 )
{
if ( connect (*sock, saddr, len) < 0 )
{
if ( socket_error() == EINTR )
continue;
if ( socket_error() != EINPROGRESS && socket_error() != EWOULDBLOCK )
return 1;
}
return 0;
}
}
static int socket_accept (socket_t * sock, socket_t * newsock, struct sockaddr *saddr, socklen_t * len)
{
while ( IS_SOCKET_ERROR(*newsock = accept (*sock, saddr, len)) )
{
if ( socket_error() == EINTR )
continue;
return 1;
}
return 0;
}
static int socket_recv (socket_t * sock, void * buf, size_t len)
{
int length;
while ( (length = recv (*sock, buf, len, 0)) < 0 )
{
int err = socket_error();
if ( err != EINTR && err != EAGAIN )
break;
}
return length;
}
static int socket_send (socket_t * sock, const void *buf, size_t len)
{
int length;
while ( (length = send (*sock, buf, len, 0)) < 0 )
{
int err = socket_error();
if ( err != EINTR && err != EAGAIN )
break;
}
return length;
}

390
external/IRC/ssl.c vendored
View File

@ -1,390 +0,0 @@
/*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*/
#if defined (ENABLE_SSL)
// Nonzero if OpenSSL has been initialized
static SSL_CTX * ssl_context = 0;
#if defined (_WIN32)
#include <windows.h>
// This array will store all of the mutexes available to OpenSSL
static CRITICAL_SECTION * mutex_buf = 0;
// OpenSSL callback to utilize static locks
static void cb_openssl_locking_function( int mode, int n, const char * file, int line )
{
if ( mode & CRYPTO_LOCK)
EnterCriticalSection( &mutex_buf[n] );
else
LeaveCriticalSection( &mutex_buf[n] );
}
// OpenSSL callback to get the thread ID
static unsigned long cb_openssl_id_function(void)
{
return ((unsigned long) GetCurrentThreadId() );
}
static int alloc_mutexes( unsigned int total )
{
unsigned int i;
// Enable thread safety in OpenSSL
mutex_buf = (CRITICAL_SECTION*) malloc( total * sizeof(CRITICAL_SECTION) );
if ( !mutex_buf )
return -1;
for ( i = 0; i < total; i++)
InitializeCriticalSection( &(mutex_buf[i]) );
return 0;
}
#else
// This array will store all of the mutexes available to OpenSSL
static pthread_mutex_t * mutex_buf = 0;
// OpenSSL callback to utilize static locks
static void cb_openssl_locking_function( int mode, int n, const char * file, int line )
{
(void)file;
(void)line;
if ( mode & CRYPTO_LOCK)
pthread_mutex_lock( &mutex_buf[n] );
else
pthread_mutex_unlock( &mutex_buf[n] );
}
// OpenSSL callback to get the thread ID
static unsigned long cb_openssl_id_function()
{
return ((unsigned long) pthread_self() );
}
static int alloc_mutexes( unsigned int total )
{
unsigned i;
// Enable thread safety in OpenSSL
mutex_buf = (pthread_mutex_t*) malloc( total * sizeof(pthread_mutex_t) );
if ( !mutex_buf )
return -1;
for ( i = 0; i < total; i++)
pthread_mutex_init( &(mutex_buf[i]), 0 );
return 0;
}
#endif
static int ssl_init_context( irc_session_t * session )
{
// Load the strings and init the library
SSL_load_error_strings();
// Enable thread safety in OpenSSL
if ( alloc_mutexes( CRYPTO_num_locks() ) )
return LIBIRC_ERR_NOMEM;
// Register our callbacks
CRYPTO_set_id_callback( cb_openssl_id_function );
CRYPTO_set_locking_callback( cb_openssl_locking_function );
// Init it
if ( !SSL_library_init() )
return LIBIRC_ERR_SSL_INIT_FAILED;
if ( RAND_status() == 0 )
return LIBIRC_ERR_SSL_INIT_FAILED;
// Create an SSL context; currently a single context is used for all connections
ssl_context = SSL_CTX_new( SSLv23_method() );
if ( !ssl_context )
return LIBIRC_ERR_SSL_INIT_FAILED;
// Disable SSLv2 as it is unsecure
if ( (SSL_CTX_set_options( ssl_context, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2) == 0 )
return LIBIRC_ERR_SSL_INIT_FAILED;
// Enable only strong ciphers
if ( SSL_CTX_set_cipher_list( ssl_context, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH" ) != 1 )
return LIBIRC_ERR_SSL_INIT_FAILED;
// Set the verification
if ( session->options & LIBIRC_OPTION_SSL_NO_VERIFY )
SSL_CTX_set_verify( ssl_context, SSL_VERIFY_NONE, 0 );
else
SSL_CTX_set_verify( ssl_context, SSL_VERIFY_PEER, 0 );
// Disable session caching
SSL_CTX_set_session_cache_mode( ssl_context, SSL_SESS_CACHE_OFF );
// Enable SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER so we can move the buffer during sending
SSL_CTX_set_mode( ssl_context, SSL_CTX_get_mode(ssl_context) | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER | SSL_MODE_ENABLE_PARTIAL_WRITE );
return 0;
}
#if defined (_WIN32)
#define SSLINIT_LOCK_MUTEX(a) WaitForSingleObject( a, INFINITE )
#define SSLINIT_UNLOCK_MUTEX(a) ReleaseMutex( a )
#else
#define SSLINIT_LOCK_MUTEX(a) pthread_mutex_lock( &a )
#define SSLINIT_UNLOCK_MUTEX(a) pthread_mutex_unlock( &a )
#endif
// Initializes the SSL context. Must be called after the socket is created.
static int ssl_init( irc_session_t * session )
{
static int ssl_context_initialized = 0;
#if defined (_WIN32)
static HANDLE initmutex = 0;
// First time run? Create the mutex
if ( initmutex == 0 )
{
HANDLE m = CreateMutex( 0, FALSE, 0 );
// Now we check if the mutex has already been created by another thread performing the init concurrently.
// If it was, we close our mutex and use the original one. This could be done synchronously by using the
// InterlockedCompareExchangePointer function.
if ( InterlockedCompareExchangePointer( &m, m, 0 ) != 0 )
CloseHandle( m );
}
#else
static pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER;
#endif
// This initialization needs to be performed only once. The problem is that it is called from
// irc_connect() and this function may be called simultaneously from different threads. So we have
// to use mutex on Linux because it allows static mutex initialization. Windows doesn't, so here
// we do the sabre dance around it.
SSLINIT_LOCK_MUTEX( initmutex );
if ( ssl_context_initialized == 0 )
{
int res = ssl_init_context( session );
if ( res )
{
SSLINIT_UNLOCK_MUTEX( initmutex );
return res;
}
ssl_context_initialized = 1;
}
SSLINIT_UNLOCK_MUTEX( initmutex );
// Get the SSL context
session->ssl = SSL_new( ssl_context );
if ( !session->ssl )
return LIBIRC_ERR_SSL_INIT_FAILED;
// Let OpenSSL use our socket
if ( SSL_set_fd( session->ssl, session->sock) != 1 )
return LIBIRC_ERR_SSL_INIT_FAILED;
// Since we're connecting on our own, tell openssl about it
SSL_set_connect_state( session->ssl );
return 0;
}
static void ssl_handle_error( irc_session_t * session, int ssl_error )
{
if ( ERR_GET_LIB(ssl_error) == ERR_LIB_SSL )
{
if ( ERR_GET_REASON(ssl_error) == SSL_R_CERTIFICATE_VERIFY_FAILED )
{
session->lasterror = LIBIRC_ERR_SSL_CERT_VERIFY_FAILED;
return;
}
if ( ERR_GET_REASON(ssl_error) == SSL_R_UNKNOWN_PROTOCOL )
{
session->lasterror = LIBIRC_ERR_CONNECT_SSL_FAILED;
return;
}
}
#if defined (ENABLE_DEBUG)
if ( IS_DEBUG_ENABLED(session) )
fprintf (stderr, "[DEBUG] SSL error: %s\n\t(%d, %d)\n",
ERR_error_string( ssl_error, NULL), ERR_GET_LIB( ssl_error), ERR_GET_REASON(ssl_error) );
#endif
}
static int ssl_recv( irc_session_t * session )
{
int count;
unsigned int amount = (sizeof (session->incoming_buf) - 1) - session->incoming_offset;
ERR_clear_error();
// Read up to m_bufferLength bytes
count = SSL_read( session->ssl, session->incoming_buf + session->incoming_offset, amount );
if ( count > 0 )
return count;
else if ( count == 0 )
return -1; // remote connection closed
else
{
int ssl_error = SSL_get_error( session->ssl, count );
// Handle SSL error since not all of them are actually errors
switch ( ssl_error )
{
case SSL_ERROR_WANT_READ:
// This is not really an error. We received something, but
// OpenSSL gave nothing to us because all it read was
// internal data. Repeat the same read.
return 0;
case SSL_ERROR_WANT_WRITE:
// This is not really an error. We received something, but
// now OpenSSL needs to send the data before returning any
// data to us (like negotiations). This means we'd need
// to wait for WRITE event, but call SSL_read() again.
session->flags |= SESSIONFL_SSL_READ_WANTS_WRITE;
return 0;
}
// This is an SSL error, handle it
ssl_handle_error( session, ERR_get_error() );
}
return -1;
}
static int ssl_send( irc_session_t * session )
{
int count;
ERR_clear_error();
count = SSL_write( session->ssl, session->outgoing_buf, session->outgoing_offset );
if ( count > 0 )
return count;
else if ( count == 0 )
return -1;
else
{
int ssl_error = SSL_get_error( session->ssl, count );
switch ( ssl_error )
{
case SSL_ERROR_WANT_READ:
// This is not really an error. We sent some internal OpenSSL data,
// but now it needs to read more data before it can send anything.
// Thus we wait for READ event, but will call SSL_write() again.
session->flags |= SESSIONFL_SSL_WRITE_WANTS_READ;
return 0;
case SSL_ERROR_WANT_WRITE:
// This is not really an error. We sent some data, but now OpenSSL
// wants to send some internal data before sending ours.
// Repeat the same write.
return 0;
}
// This is an SSL error, handle it
ssl_handle_error( session, ERR_get_error() );
}
return -1;
}
#endif
// Handles both SSL and non-SSL reads.
// Returns -1 in case there is an error and socket should be closed/connection terminated
// Returns 0 in case there is a temporary error and the call should be retried (SSL_WANTS_WRITE case)
// Returns a positive number if we actually read something
static int session_socket_read( irc_session_t * session )
{
int length;
#if defined (ENABLE_SSL)
if ( session->ssl )
{
// Yes, I know this is tricky
if ( session->flags & SESSIONFL_SSL_READ_WANTS_WRITE )
{
session->flags &= ~SESSIONFL_SSL_READ_WANTS_WRITE;
ssl_send( session );
return 0;
}
return ssl_recv( session );
}
#endif
length = socket_recv( &session->sock,
session->incoming_buf + session->incoming_offset,
(sizeof (session->incoming_buf) - 1) - session->incoming_offset );
// There is no "retry" errors for regular sockets
if ( length <= 0 )
return -1;
return length;
}
// Handles both SSL and non-SSL writes.
// Returns -1 in case there is an error and socket should be closed/connection terminated
// Returns 0 in case there is a temporary error and the call should be retried (SSL_WANTS_WRITE case)
// Returns a positive number if we actually sent something
static int session_socket_write( irc_session_t * session )
{
int length;
#if defined (ENABLE_SSL)
if ( session->ssl )
{
// Yep
if ( session->flags & SESSIONFL_SSL_WRITE_WANTS_READ )
{
session->flags &= ~SESSIONFL_SSL_WRITE_WANTS_READ;
ssl_recv( session );
return 0;
}
return ssl_send( session );
}
#endif
length = socket_send (&session->sock, session->outgoing_buf, session->outgoing_offset);
// There is no "retry" errors for regular sockets
if ( length <= 0 )
return -1;
return length;
}

130
external/IRC/utils.c vendored
View File

@ -1,130 +0,0 @@
/*
* Copyright (C) 2004-2012 George Yunaev gyunaev@ulduzsoft.com
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*/
static void libirc_add_to_set (int fd, fd_set *set, int * maxfd)
{
FD_SET (fd, set);
if ( *maxfd < fd )
*maxfd = fd;
}
#if defined (ENABLE_DEBUG)
static void libirc_dump_data (const char * prefix, const char * buf, unsigned int length)
{
printf ("%s: ", prefix);
for ( ; length > 0; length -- )
printf ("%c", *buf++);
}
#endif
/*
* Finds a separator (\x0D\x0A), which separates two lines.
*/
static int libirc_findcrlf (const char * buf, int length)
{
int offset = 0;
for ( ; offset < length; offset++ )
{
if ( buf[offset] == 0x0D && offset < length - 1 && buf[offset+1] == 0x0A )
return offset;
if ( buf[offset] == 0x0A)
return offset;
}
return 0;
}
static int libirc_findcrlf_offset(const char *buf, int offset, const int length)
{
for(; offset < length; offset++)
{
if(buf[offset] != 0x0D && buf[offset] != 0x0A)
{
break;
}
}
return offset;
}
static int libirc_findcrorlf (char * buf, int length)
{
int offset = 0;
for ( ; offset < length; offset++ )
{
if ( buf[offset] == 0x0D || buf[offset] == 0x0A )
{
buf[offset++] = '\0';
if ( offset < (length - 1)
&& (buf[offset] == 0x0D || buf[offset] == 0x0A) )
offset++;
return offset;
}
}
return 0;
}
static void libirc_event_ctcp_internal (irc_session_t * session, const char * event, const char * origin, const char ** params, unsigned int count)
{
(void)event;
(void)count;
if ( origin )
{
char nickbuf[128], textbuf[256];
irc_target_get_nick (origin, nickbuf, sizeof(nickbuf));
if ( strstr (params[0], "PING") == params[0] )
irc_cmd_ctcp_reply (session, nickbuf, params[0]);
else if ( !strcmp (params[0], "VERSION") )
{
if ( !session->ctcp_version )
{
unsigned int high, low;
irc_get_version (&high, &low);
snprintf (textbuf, sizeof (textbuf), "VERSION libircclient by Georgy Yunaev ver.%d.%d", high, low);
}
else
snprintf (textbuf, sizeof (textbuf), "VERSION %s", session->ctcp_version);
irc_cmd_ctcp_reply (session, nickbuf, textbuf);
}
else if ( !strcmp (params[0], "FINGER") )
{
sprintf (textbuf, "FINGER %s (%s) Idle 0 seconds",
session->username ? session->username : "nobody",
session->realname ? session->realname : "noname");
irc_cmd_ctcp_reply (session, nickbuf, textbuf);
}
else if ( !strcmp (params[0], "TIME") )
{
time_t now = time(0);
#if defined (ENABLE_THREADS) && defined (HAVE_LOCALTIME_R)
struct tm tmtmp, *ltime = localtime_r (&now, &tmtmp);
#else
struct tm * ltime = localtime (&now);
#endif
strftime (textbuf, sizeof(textbuf), "%a %b %d %H:%M:%S %Z %Y", ltime);
irc_cmd_ctcp_reply (session, nickbuf, textbuf);
}
}
}

View File

@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2006-2014 Arseny Kapoulkine
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.

File diff suppressed because it is too large Load Diff

View File

@ -1,57 +0,0 @@
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.
If you have downloaded a copy of the RapidJSON binary from Tencent, please note that the RapidJSON binary is licensed under the MIT License.
If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON. To avoid the problematic JSON license in your own projects, it's sufficient to exclude the bin/jsonchecker/ directory, as it's the only code under the JSON license.
A copy of the MIT License is included in this file.
Other dependencies and licenses:
Open Source Software Licensed Under the BSD License:
--------------------------------------------------------------------
The msinttypes r29
Copyright (c) 2006-2013 Alexander Chemeris
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
* Neither the name of copyright holder 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Open Source Software Licensed Under the JSON License:
--------------------------------------------------------------------
json.org
Copyright (c) 2002 JSON.org
All Rights Reserved.
JSON_checker
Copyright (c) 2002 JSON.org
All Rights Reserved.
Terms of the JSON License:
---------------------------------------------------
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 shall be used for Good, not Evil.
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.
Terms of the MIT License:
--------------------------------------------------------------------
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.

13938
external/SQLite/sqlite3.c vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,539 +0,0 @@
/*
* Copyright 2001-2004 Unicode, Inc.
*
* Disclaimer
*
* This source code is provided as is by Unicode, Inc. No claims are
* made as to fitness for any particular purpose. No warranties of any
* kind are expressed or implied. The recipient agrees to determine
* applicability of information provided. If this file has been
* purchased on magnetic or optical media from Unicode, Inc., the
* sole remedy for any claim will be exchange of defective media
* within 90 days of receipt.
*
* Limitations on Rights to Redistribute This Code
*
* Unicode, Inc. hereby grants the right to freely use the information
* supplied in this file in the creation of products supporting the
* Unicode Standard, and to make copies of this file in any form
* for internal or external distribution as long as this notice
* remains attached.
*/
/* ---------------------------------------------------------------------
Conversions between UTF32, UTF-16, and UTF-8. Source code file.
Author: Mark E. Davis, 1994.
Rev History: Rick McGowan, fixes & updates May 2001.
Sept 2001: fixed const & error conditions per
mods suggested by S. Parent & A. Lillich.
June 2002: Tim Dodd added detection and handling of incomplete
source sequences, enhanced error detection, added casts
to eliminate compiler warnings.
July 2003: slight mods to back out aggressive FFFE detection.
Jan 2004: updated switches in from-UTF8 conversions.
Oct 2004: updated to use UNI_MAX_LEGAL_UTF32 in UTF-32 conversions.
See the header file "ConvertUTF.h" for complete documentation.
------------------------------------------------------------------------ */
#include "ConvertUTF.h"
#ifdef CVTUTF_DEBUG
#include <stdio.h>
#endif
static const int halfShift = 10; /* used for shifting by 10 bits */
static const UTF32 halfBase = 0x0010000UL;
static const UTF32 halfMask = 0x3FFUL;
#define UNI_SUR_HIGH_START (UTF32)0xD800
#define UNI_SUR_HIGH_END (UTF32)0xDBFF
#define UNI_SUR_LOW_START (UTF32)0xDC00
#define UNI_SUR_LOW_END (UTF32)0xDFFF
#define false 0
#define true 1
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF32toUTF16 (
const UTF32** sourceStart, const UTF32* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF32* source = *sourceStart;
UTF16* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch;
if (target >= targetEnd) {
result = targetExhausted; break;
}
ch = *source++;
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
/* UTF-16 surrogate values are illegal in UTF-32; 0xffff or 0xfffe are both reserved values */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
if (flags == strictConversion) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
*target++ = (UTF16)ch; /* normal case */
}
} else if (ch > UNI_MAX_LEGAL_UTF32) {
if (flags == strictConversion) {
result = sourceIllegal;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
/* target is a character in range 0xFFFF - 0x10FFFF. */
if (target + 1 >= targetEnd) {
--source; /* Back up source pointer! */
result = targetExhausted; break;
}
ch -= halfBase;
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF16toUTF32 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF16* source = *sourceStart;
UTF32* target = *targetStart;
UTF32 ch, ch2;
while (source < sourceEnd) {
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
ch = *source++;
/* If we have a surrogate pair, convert to UTF32 first. */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
/* If the 16 bits following the high surrogate are in the source buffer... */
if (source < sourceEnd) {
ch2 = *source;
/* If it's a low surrogate, convert to UTF32. */
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
++source;
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
} else { /* We don't have the 16 bits following the high surrogate. */
--source; /* return to the high surrogate */
result = sourceExhausted;
break;
}
} else if (flags == strictConversion) {
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
if (target >= targetEnd) {
source = oldSource; /* Back up source pointer! */
result = targetExhausted; break;
}
*target++ = ch;
}
*sourceStart = source;
*targetStart = target;
#ifdef CVTUTF_DEBUG
if (result == sourceIllegal) {
fprintf(stderr, "ConvertUTF16toUTF32 illegal seq 0x%04x,%04x\n", ch, ch2);
fflush(stderr);
}
#endif
return result;
}
/* --------------------------------------------------------------------- */
/*
* Index into the table below with the first byte of a UTF-8 sequence to
* get the number of trailing bytes that are supposed to follow it.
* Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is
* left as-is for anyone who may want to do such conversion, which was
* allowed in earlier algorithms.
*/
static const char trailingBytesForUTF8[256] = {
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,
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,
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
};
/*
* Magic values subtracted from a buffer value during UTF8 conversion.
* This table contains as many values as there might be trailing bytes
* in a UTF-8 sequence.
*/
static const UTF32 offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL,
0x03C82080UL, 0xFA082080UL, 0x82082080UL };
/*
* Once the bits are split out into bytes of UTF-8, this is a mask OR-ed
* into the first byte, depending on how many bytes follow. There are
* as many entries in this table as there are UTF-8 sequence types.
* (I.e., one byte sequence, two byte... etc.). Remember that sequencs
* for *legal* UTF-8 will be 4 or fewer bytes total.
*/
static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
/* --------------------------------------------------------------------- */
/* The interface converts a whole buffer to avoid function-call overhead.
* Constants have been gathered. Loops & conditionals have been removed as
* much as possible for efficiency, in favor of drop-through switches.
* (See "Note A" at the bottom of the file for equivalent code.)
* If your compiler supports it, the "isLegalUTF8" call can be turned
* into an inline function.
*/
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF16toUTF8 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF16* source = *sourceStart;
UTF8* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch;
unsigned short bytesToWrite = 0;
const UTF32 byteMask = 0xBF;
const UTF32 byteMark = 0x80;
const UTF16* oldSource = source; /* In case we have to back up because of target overflow. */
ch = *source++;
/* If we have a surrogate pair, convert to UTF32 first. */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_HIGH_END) {
/* If the 16 bits following the high surrogate are in the source buffer... */
if (source < sourceEnd) {
UTF32 ch2 = *source;
/* If it's a low surrogate, convert to UTF32. */
if (ch2 >= UNI_SUR_LOW_START && ch2 <= UNI_SUR_LOW_END) {
ch = ((ch - UNI_SUR_HIGH_START) << halfShift)
+ (ch2 - UNI_SUR_LOW_START) + halfBase;
++source;
} else if (flags == strictConversion) { /* it's an unpaired high surrogate */
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
} else { /* We don't have the 16 bits following the high surrogate. */
--source; /* return to the high surrogate */
result = sourceExhausted;
break;
}
} else if (flags == strictConversion) {
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_LOW_START && ch <= UNI_SUR_LOW_END) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
/* Figure out how many bytes the result will require */
if (ch < (UTF32)0x80) { bytesToWrite = 1;
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
} else if (ch < (UTF32)0x110000) { bytesToWrite = 4;
} else { bytesToWrite = 3;
ch = UNI_REPLACEMENT_CHAR;
}
target += bytesToWrite;
if (target > targetEnd) {
source = oldSource; /* Back up source pointer! */
target -= bytesToWrite; result = targetExhausted; break;
}
switch (bytesToWrite) { /* note: everything falls through. */
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
}
target += bytesToWrite;
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
/*
* Utility routine to tell whether a sequence of bytes is legal UTF-8.
* This must be called with the length pre-determined by the first byte.
* If not calling this from ConvertUTF8to*, then the length can be set by:
* length = trailingBytesForUTF8[*source]+1;
* and the sequence is illegal right away if there aren't that many bytes
* available.
* If presented with a length > 4, this returns false. The Unicode
* definition of UTF-8 goes up to 4-byte sequences.
*/
static Boolean isLegalUTF8(const UTF8 *source, int length) {
UTF8 a;
const UTF8 *srcptr = source+length;
switch (length) {
default: return false;
/* Everything else falls through when "true"... */
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return false;
case 2: if ((a = (*--srcptr)) > 0xBF) return false;
switch (*source) {
/* no fall-through in this inner switch */
case 0xE0: if (a < 0xA0) return false; break;
case 0xED: if (a > 0x9F) return false; break;
case 0xF0: if (a < 0x90) return false; break;
case 0xF4: if (a > 0x8F) return false; break;
default: if (a < 0x80) return false;
}
case 1: if (*source >= 0x80 && *source < 0xC2) return false;
}
if (*source > 0xF4) return false;
return true;
}
/* --------------------------------------------------------------------- */
/*
* Exported function to return whether a UTF-8 sequence is legal or not.
* This is not used here; it's just exported.
*/
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd) {
int length = trailingBytesForUTF8[*source]+1;
if (source+length > sourceEnd) {
return false;
}
return isLegalUTF8(source, length);
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF8toUTF16 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF8* source = *sourceStart;
UTF16* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch = 0;
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
if (source + extraBytesToRead >= sourceEnd) {
result = sourceExhausted; break;
}
/* Do this check whether lenient or strict */
if (! isLegalUTF8(source, extraBytesToRead+1)) {
result = sourceIllegal;
break;
}
/*
* The cases all fall through. See "Note A" below.
*/
switch (extraBytesToRead) {
case 5: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
case 4: ch += *source++; ch <<= 6; /* remember, illegal UTF-8 */
case 3: ch += *source++; ch <<= 6;
case 2: ch += *source++; ch <<= 6;
case 1: ch += *source++; ch <<= 6;
case 0: ch += *source++;
}
ch -= offsetsFromUTF8[extraBytesToRead];
if (target >= targetEnd) {
source -= (extraBytesToRead+1); /* Back up source pointer! */
result = targetExhausted; break;
}
if (ch <= UNI_MAX_BMP) { /* Target is a character <= 0xFFFF */
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
if (flags == strictConversion) {
source -= (extraBytesToRead+1); /* return to the illegal value itself */
result = sourceIllegal;
break;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
*target++ = (UTF16)ch; /* normal case */
}
} else if (ch > UNI_MAX_UTF16) {
if (flags == strictConversion) {
result = sourceIllegal;
source -= (extraBytesToRead+1); /* return to the start */
break; /* Bail out; shouldn't continue */
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
/* target is a character in range 0xFFFF - 0x10FFFF. */
if (target + 1 >= targetEnd) {
source -= (extraBytesToRead+1); /* Back up source pointer! */
result = targetExhausted; break;
}
ch -= halfBase;
*target++ = (UTF16)((ch >> halfShift) + UNI_SUR_HIGH_START);
*target++ = (UTF16)((ch & halfMask) + UNI_SUR_LOW_START);
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF32toUTF8 (
const UTF32** sourceStart, const UTF32* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF32* source = *sourceStart;
UTF8* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch;
unsigned short bytesToWrite = 0;
const UTF32 byteMask = 0xBF;
const UTF32 byteMark = 0x80;
ch = *source++;
if (flags == strictConversion ) {
/* UTF-16 surrogate values are illegal in UTF-32 */
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
--source; /* return to the illegal value itself */
result = sourceIllegal;
break;
}
}
/*
* Figure out how many bytes the result will require. Turn any
* illegally large UTF32 things (> Plane 17) into replacement chars.
*/
if (ch < (UTF32)0x80) { bytesToWrite = 1;
} else if (ch < (UTF32)0x800) { bytesToWrite = 2;
} else if (ch < (UTF32)0x10000) { bytesToWrite = 3;
} else if (ch <= UNI_MAX_LEGAL_UTF32) { bytesToWrite = 4;
} else { bytesToWrite = 3;
ch = UNI_REPLACEMENT_CHAR;
result = sourceIllegal;
}
target += bytesToWrite;
if (target > targetEnd) {
--source; /* Back up source pointer! */
target -= bytesToWrite; result = targetExhausted; break;
}
switch (bytesToWrite) { /* note: everything falls through. */
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
case 1: *--target = (UTF8) (ch | firstByteMark[bytesToWrite]);
}
target += bytesToWrite;
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* --------------------------------------------------------------------- */
ConversionResult ConvertUTF8toUTF32 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags) {
ConversionResult result = conversionOK;
const UTF8* source = *sourceStart;
UTF32* target = *targetStart;
while (source < sourceEnd) {
UTF32 ch = 0;
unsigned short extraBytesToRead = trailingBytesForUTF8[*source];
if (source + extraBytesToRead >= sourceEnd) {
result = sourceExhausted; break;
}
/* Do this check whether lenient or strict */
if (! isLegalUTF8(source, extraBytesToRead+1)) {
result = sourceIllegal;
break;
}
/*
* The cases all fall through. See "Note A" below.
*/
switch (extraBytesToRead) {
case 5: ch += *source++; ch <<= 6;
case 4: ch += *source++; ch <<= 6;
case 3: ch += *source++; ch <<= 6;
case 2: ch += *source++; ch <<= 6;
case 1: ch += *source++; ch <<= 6;
case 0: ch += *source++;
}
ch -= offsetsFromUTF8[extraBytesToRead];
if (target >= targetEnd) {
source -= (extraBytesToRead+1); /* Back up the source pointer! */
result = targetExhausted; break;
}
if (ch <= UNI_MAX_LEGAL_UTF32) {
/*
* UTF-16 surrogate values are illegal in UTF-32, and anything
* over Plane 17 (> 0x10FFFF) is illegal.
*/
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END) {
if (flags == strictConversion) {
source -= (extraBytesToRead+1); /* return to the illegal value itself */
result = sourceIllegal;
break;
} else {
*target++ = UNI_REPLACEMENT_CHAR;
}
} else {
*target++ = ch;
}
} else { /* i.e., ch > UNI_MAX_LEGAL_UTF32 */
result = sourceIllegal;
*target++ = UNI_REPLACEMENT_CHAR;
}
}
*sourceStart = source;
*targetStart = target;
return result;
}
/* ---------------------------------------------------------------------
Note A.
The fall-through switches in UTF-8 reading code save a
temp variable, some decrements & conditionals. The switches
are equivalent to the following loop:
{
int tmpBytesToRead = extraBytesToRead+1;
do {
ch += *source++;
--tmpBytesToRead;
if (tmpBytesToRead) ch <<= 6;
} while (tmpBytesToRead > 0);
}
In UTF-8 writing code, the switches on "bytesToWrite" are
similarly unrolled loops.
--------------------------------------------------------------------- */

View File

@ -1,150 +0,0 @@
simpleini
=========
A cross-platform library that provides a simple API to read and write INI-style configuration files. It supports data files in ASCII, MBCS and Unicode. It is designed explicitly to be portable to any platform and has been tested on Windows, WinCE and Linux. Released as open-source and free using the MIT licence.
# Feature Summary
- MIT Licence allows free use in all software (including GPL and commercial)
- multi-platform (Windows 95/98/ME/NT/2K/XP/2003, Windows CE, Linux, Unix)
- loading and saving of INI-style configuration files
- configuration files can have any newline format on all platforms
- liberal acceptance of file format
* key/values with no section
* removal of whitespace around sections, keys and values
- support for multi-line values (values with embedded newline characters)
- optional support for multiple keys with the same name
- optional case-insensitive sections and keys (for ASCII characters only)
- saves files with sections and keys in the same order as they were loaded
- preserves comments on the file, section and keys where possible.
- supports both char or wchar_t programming interfaces
- supports both MBCS (system locale) and UTF-8 file encodings
- system locale does not need to be UTF-8 on Linux/Unix to load UTF-8 file
- support for non-ASCII characters in section, keys, values and comments
- support for non-standard character types or file encodings via user-written converter classes
- support for adding/modifying values programmatically
- compiles cleanly in the following compilers:
* Windows/VC6 (warning level 3)
* Windows/VC.NET 2003 (warning level 4)
* Windows/VC 2005 (warning level 4)
* Linux/gcc (-Wall)
* Windows/MinGW GCC
# Documentation
Full documentation of the interface is available in doxygen format.
# Examples
These snippets are included with the distribution in the file snippets.cpp.
### SIMPLE USAGE
```c++
CSimpleIniA ini;
ini.SetUnicode();
ini.LoadFile("myfile.ini");
const char * pVal = ini.GetValue("section", "key", "default");
ini.SetValue("section", "key", "newvalue");
```
### LOADING DATA
```c++
// load from a data file
CSimpleIniA ini(a_bIsUtf8, a_bUseMultiKey, a_bUseMultiLine);
SI_Error rc = ini.LoadFile(a_pszFile);
if (rc < 0) return false;
// load from a string
std::string strData;
rc = ini.LoadData(strData.c_str(), strData.size());
if (rc < 0) return false;
```
### GETTING SECTIONS AND KEYS
```c++
// get all sections
CSimpleIniA::TNamesDepend sections;
ini.GetAllSections(sections);
// get all keys in a section
CSimpleIniA::TNamesDepend keys;
ini.GetAllKeys("section-name", keys);
```
### GETTING VALUES
```c++
// get the value of a key
const char * pszValue = ini.GetValue("section-name",
"key-name", NULL /*default*/);
// get the value of a key which may have multiple
// values. If bHasMultipleValues is true, then just
// one value has been returned
bool bHasMultipleValues;
pszValue = ini.GetValue("section-name", "key-name",
NULL /*default*/, &amp;bHasMultipleValues);
// get all values of a key with multiple values
CSimpleIniA::TNamesDepend values;
ini.GetAllValues("section-name", "key-name", values);
// sort the values into the original load order
values.sort(CSimpleIniA::Entry::LoadOrder());
// output all of the items
CSimpleIniA::TNamesDepend::const_iterator i;
for (i = values.begin(); i != values.end(); ++i) {
printf("key-name = '%s'\n", i->pItem);
}
```
### MODIFYING DATA
```c++
// adding a new section
rc = ini.SetValue("new-section", NULL, NULL);
if (rc < 0) return false;
printf("section: %s\n", rc == SI_INSERTED ?
"inserted" : "updated");
// adding a new key ("new-section" will be added
// automatically if it doesn't already exist)
rc = ini.SetValue("new-section", "new-key", "value");
if (rc < 0) return false;
printf("key: %s\n", rc == SI_INSERTED ?
"inserted" : "updated");
// changing the value of a key
rc = ini.SetValue("section", "key", "updated-value");
if (rc < 0) return false;
printf("key: %s\n", rc == SI_INSERTED ?
"inserted" : "updated");
```
### DELETING DATA
```c++
// deleting a key from a section. Optionally the entire
// section may be deleted if it is now empty.
ini.Delete("section-name", "key-name",
true /*delete the section if empty*/);
// deleting an entire section and all keys in it
ini.Delete("section-name", NULL);
```
### SAVING DATA
```c++
// save the data to a string
rc = ini.Save(strData);
if (rc < 0) return false;
// save the data back to the file
rc = ini.SaveFile(a_pszFile);
if (rc < 0) return false;
```

View File

@ -13,7 +13,7 @@
#include "sqfuncstate.h" #include "sqfuncstate.h"
#include "sqclass.h" #include "sqclass.h"
bool sq_aux_gettypedarg(HSQUIRRELVM v,SQInteger idx,SQObjectType type,SQObjectPtr **o) static bool sq_aux_gettypedarg(HSQUIRRELVM v,SQInteger idx,SQObjectType type,SQObjectPtr **o)
{ {
*o = &stack_get(v,idx); *o = &stack_get(v,idx);
if(type(**o) != type){ if(type(**o) != type){
@ -34,7 +34,8 @@ bool sq_aux_gettypedarg(HSQUIRRELVM v,SQInteger idx,SQObjectType type,SQObjectPt
SQInteger sq_aux_invalidtype(HSQUIRRELVM v,SQObjectType type) SQInteger sq_aux_invalidtype(HSQUIRRELVM v,SQObjectType type)
{ {
scsprintf(_ss(v)->GetScratchPad(100), 100 *sizeof(SQChar), _SC("unexpected type %s"), IdType2Name(type)); SQUnsignedInteger buf_size = 100 *sizeof(SQChar);
scsprintf(_ss(v)->GetScratchPad(buf_size), buf_size, _SC("unexpected type %s"), IdType2Name(type));
return sq_throwerror(v, _ss(v)->GetScratchPad(-1)); return sq_throwerror(v, _ss(v)->GetScratchPad(-1));
} }
@ -179,6 +180,12 @@ SQBool sq_release(HSQUIRRELVM v,HSQOBJECT *po)
#endif #endif
} }
SQUnsignedInteger sq_getvmrefcount(HSQUIRRELVM v, const HSQOBJECT *po)
{
if (!ISREFCOUNTED(type(*po))) return 0;
return po->_unVal.pRefCounted->_uiRef;
}
const SQChar *sq_objtostring(const HSQOBJECT *o) const SQChar *sq_objtostring(const HSQOBJECT *o)
{ {
if(sq_type(*o) == OT_STRING) { if(sq_type(*o) == OT_STRING) {
@ -251,6 +258,11 @@ void sq_pushuserpointer(HSQUIRRELVM v,SQUserPointer p)
v->Push(p); v->Push(p);
} }
void sq_pushthread(HSQUIRRELVM v, HSQUIRRELVM thread)
{
v->Push(thread);
}
SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size) SQUserPointer sq_newuserdata(HSQUIRRELVM v,SQUnsignedInteger size)
{ {
SQUserData *ud = SQUserData::Create(_ss(v), size + SQ_ALIGNMENT); SQUserData *ud = SQUserData::Create(_ss(v), size + SQ_ALIGNMENT);
@ -443,6 +455,7 @@ SQRESULT sq_bindenv(HSQUIRRELVM v,SQInteger idx)
return sq_throwerror(v,_SC("the target is not a closure")); return sq_throwerror(v,_SC("the target is not a closure"));
SQObjectPtr &env = stack_get(v,-1); SQObjectPtr &env = stack_get(v,-1);
if(!sq_istable(env) && if(!sq_istable(env) &&
!sq_isarray(env) &&
!sq_isclass(env) && !sq_isclass(env) &&
!sq_isinstance(env)) !sq_isinstance(env))
return sq_throwerror(v,_SC("invalid environment")); return sq_throwerror(v,_SC("invalid environment"));
@ -880,29 +893,30 @@ SQRESULT sq_set(HSQUIRRELVM v,SQInteger idx)
SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx) SQRESULT sq_rawset(HSQUIRRELVM v,SQInteger idx)
{ {
SQObjectPtr &self = stack_get(v, idx); SQObjectPtr &self = stack_get(v, idx);
if(type(v->GetUp(-2)) == OT_NULL) { SQObjectPtr &key = v->GetUp(-2);
if(type(key) == OT_NULL) {
v->Pop(2); v->Pop(2);
return sq_throwerror(v, _SC("null key")); return sq_throwerror(v, _SC("null key"));
} }
switch(type(self)) { switch(type(self)) {
case OT_TABLE: case OT_TABLE:
_table(self)->NewSlot(v->GetUp(-2), v->GetUp(-1)); _table(self)->NewSlot(key, v->GetUp(-1));
v->Pop(2); v->Pop(2);
return SQ_OK; return SQ_OK;
break; break;
case OT_CLASS: case OT_CLASS:
_class(self)->NewSlot(_ss(v), v->GetUp(-2), v->GetUp(-1),false); _class(self)->NewSlot(_ss(v), key, v->GetUp(-1),false);
v->Pop(2); v->Pop(2);
return SQ_OK; return SQ_OK;
break; break;
case OT_INSTANCE: case OT_INSTANCE:
if(_instance(self)->Set(v->GetUp(-2), v->GetUp(-1))) { if(_instance(self)->Set(key, v->GetUp(-1))) {
v->Pop(2); v->Pop(2);
return SQ_OK; return SQ_OK;
} }
break; break;
case OT_ARRAY: case OT_ARRAY:
if(v->Set(self, v->GetUp(-2), v->GetUp(-1),false)) { if(v->Set(self, key, v->GetUp(-1),false)) {
v->Pop(2); v->Pop(2);
return SQ_OK; return SQ_OK;
} }
@ -918,8 +932,9 @@ SQRESULT sq_newmember(HSQUIRRELVM v,SQInteger idx,SQBool bstatic)
{ {
SQObjectPtr &self = stack_get(v, idx); SQObjectPtr &self = stack_get(v, idx);
if(type(self) != OT_CLASS) return sq_throwerror(v, _SC("new member only works with classes")); if(type(self) != OT_CLASS) return sq_throwerror(v, _SC("new member only works with classes"));
if(type(v->GetUp(-3)) == OT_NULL) return sq_throwerror(v, _SC("null key")); SQObjectPtr &key = v->GetUp(-3);
if(!v->NewSlotA(self,v->GetUp(-3),v->GetUp(-2),v->GetUp(-1),bstatic?true:false,false)) if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null key"));
if(!v->NewSlotA(self,key,v->GetUp(-2),v->GetUp(-1),bstatic?true:false,false))
return SQ_ERROR; return SQ_ERROR;
return SQ_OK; return SQ_OK;
} }
@ -928,8 +943,9 @@ SQRESULT sq_rawnewmember(HSQUIRRELVM v,SQInteger idx,SQBool bstatic)
{ {
SQObjectPtr &self = stack_get(v, idx); SQObjectPtr &self = stack_get(v, idx);
if(type(self) != OT_CLASS) return sq_throwerror(v, _SC("new member only works with classes")); if(type(self) != OT_CLASS) return sq_throwerror(v, _SC("new member only works with classes"));
if(type(v->GetUp(-3)) == OT_NULL) return sq_throwerror(v, _SC("null key")); SQObjectPtr &key = v->GetUp(-3);
if(!v->NewSlotA(self,v->GetUp(-3),v->GetUp(-2),v->GetUp(-1),bstatic?true:false,true)) if(type(key) == OT_NULL) return sq_throwerror(v, _SC("null key"));
if(!v->NewSlotA(self,key,v->GetUp(-2),v->GetUp(-1),bstatic?true:false,true))
return SQ_ERROR; return SQ_ERROR;
return SQ_OK; return SQ_OK;
} }
@ -999,7 +1015,8 @@ SQRESULT sq_getdelegate(HSQUIRRELVM v,SQInteger idx)
SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx) SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx)
{ {
SQObjectPtr &self=stack_get(v,idx); SQObjectPtr &self=stack_get(v,idx);
if(v->Get(self,v->GetUp(-1),v->GetUp(-1),false,DONT_FALL_BACK)) SQObjectPtr &obj = v->GetUp(-1);
if(v->Get(self,obj,obj,false,DONT_FALL_BACK))
return SQ_OK; return SQ_OK;
v->Pop(); v->Pop();
return SQ_ERROR; return SQ_ERROR;
@ -1008,23 +1025,23 @@ SQRESULT sq_get(HSQUIRRELVM v,SQInteger idx)
SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx) SQRESULT sq_rawget(HSQUIRRELVM v,SQInteger idx)
{ {
SQObjectPtr &self=stack_get(v,idx); SQObjectPtr &self=stack_get(v,idx);
SQObjectPtr &obj = v->GetUp(-1);
switch(type(self)) { switch(type(self)) {
case OT_TABLE: case OT_TABLE:
if(_table(self)->Get(v->GetUp(-1),v->GetUp(-1))) if(_table(self)->Get(obj,obj))
return SQ_OK; return SQ_OK;
break; break;
case OT_CLASS: case OT_CLASS:
if(_class(self)->Get(v->GetUp(-1),v->GetUp(-1))) if(_class(self)->Get(obj,obj))
return SQ_OK; return SQ_OK;
break; break;
case OT_INSTANCE: case OT_INSTANCE:
if(_instance(self)->Get(v->GetUp(-1),v->GetUp(-1))) if(_instance(self)->Get(obj,obj))
return SQ_OK; return SQ_OK;
break; break;
case OT_ARRAY:{ case OT_ARRAY:{
SQObjectPtr& key = v->GetUp(-1); if(sq_isnumeric(obj)){
if(sq_isnumeric(key)){ if(_array(self)->Get(tointeger(obj),obj)) {
if(_array(self)->Get(tointeger(key),v->GetUp(-1))) {
return SQ_OK; return SQ_OK;
} }
} }
@ -1120,7 +1137,8 @@ SQRESULT sq_reservestack(HSQUIRRELVM v,SQInteger nsize)
SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror) SQRESULT sq_resume(HSQUIRRELVM v,SQBool retval,SQBool raiseerror)
{ {
if(type(v->GetUp(-1))==OT_GENERATOR){ if (type(v->GetUp(-1)) == OT_GENERATOR)
{
v->PushNull(); //retval v->PushNull(); //retval
if (!v->Execute(v->GetUp(-2), 0, v->_top, v->GetUp(-1), raiseerror, SQVM::ET_RESUME_GENERATOR)) if (!v->Execute(v->GetUp(-2), 0, v->_top, v->GetUp(-1), raiseerror, SQVM::ET_RESUME_GENERATOR))
{v->Raise_Error(v->_lasterror); return SQ_ERROR;} {v->Raise_Error(v->_lasterror); return SQ_ERROR;}
@ -1192,6 +1210,20 @@ void sq_setreleasehook(HSQUIRRELVM v,SQInteger idx,SQRELEASEHOOK hook)
} }
} }
SQRELEASEHOOK sq_getreleasehook(HSQUIRRELVM v,SQInteger idx)
{
if(sq_gettop(v) >= 1){
SQObjectPtr &ud=stack_get(v,idx);
switch( type(ud) ) {
case OT_USERDATA: return _userdata(ud)->_hook; break;
case OT_INSTANCE: return _instance(ud)->_hook; break;
case OT_CLASS: return _class(ud)->_hook; break;
default: break; //shutup compiler
}
}
return NULL;
}
void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f) void sq_setcompilererrorhandler(HSQUIRRELVM v,SQCOMPILERERROR f)
{ {
_ss(v)->_compilererrorhandler = f; _ss(v)->_compilererrorhandler = f;

View File

@ -13,7 +13,7 @@
#include <stdarg.h> #include <stdarg.h>
#include <ctype.h> #include <ctype.h>
bool str2num(const SQChar *s,SQObjectPtr &res,SQInteger base) static bool str2num(const SQChar *s,SQObjectPtr &res,SQInteger base)
{ {
SQChar *end; SQChar *end;
const SQChar *e = s; const SQChar *e = s;
@ -166,10 +166,12 @@ static SQInteger get_slice_params(HSQUIRRELVM v,SQInteger &sidx,SQInteger &eidx,
sidx=0; sidx=0;
eidx=0; eidx=0;
o=stack_get(v,1); o=stack_get(v,1);
if(top>1){
SQObjectPtr &start=stack_get(v,2); SQObjectPtr &start=stack_get(v,2);
if(type(start)!=OT_NULL && sq_isnumeric(start)){ if(type(start)!=OT_NULL && sq_isnumeric(start)){
sidx=tointeger(start); sidx=tointeger(start);
} }
}
if(top>2){ if(top>2){
SQObjectPtr &end=stack_get(v,3); SQObjectPtr &end=stack_get(v,3);
if(sq_isnumeric(end)){ if(sq_isnumeric(end)){
@ -653,7 +655,7 @@ static SQInteger array_find(HSQUIRRELVM v)
} }
bool _sort_compare(HSQUIRRELVM v,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret) static bool _sort_compare(HSQUIRRELVM v,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQInteger &ret)
{ {
if(func < 0) { if(func < 0) {
if(!v->ObjCmp(a,b,ret)) return false; if(!v->ObjCmp(a,b,ret)) return false;
@ -679,7 +681,7 @@ bool _sort_compare(HSQUIRRELVM v,SQObjectPtr &a,SQObjectPtr &b,SQInteger func,SQ
return true; return true;
} }
bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteger bottom, SQInteger func) static bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteger bottom, SQInteger func)
{ {
SQInteger maxChild; SQInteger maxChild;
SQInteger done = 0; SQInteger done = 0;
@ -719,7 +721,7 @@ bool _hsort_sift_down(HSQUIRRELVM v,SQArray *arr, SQInteger root, SQInteger bott
return true; return true;
} }
bool _hsort(HSQUIRRELVM v,SQObjectPtr &arr, SQInteger l, SQInteger r,SQInteger func) static bool _hsort(HSQUIRRELVM v,SQObjectPtr &arr, SQInteger l, SQInteger r,SQInteger func)
{ {
SQArray *a = _array(arr); SQArray *a = _array(arr);
SQInteger i; SQInteger i;
@ -758,7 +760,7 @@ static SQInteger array_slice(HSQUIRRELVM v)
if(sidx < 0)sidx = alen + sidx; if(sidx < 0)sidx = alen + sidx;
if(eidx < 0)eidx = alen + eidx; if(eidx < 0)eidx = alen + eidx;
if(eidx < sidx)return sq_throwerror(v,_SC("wrong indexes")); if(eidx < sidx)return sq_throwerror(v,_SC("wrong indexes"));
if(eidx > alen)return sq_throwerror(v,_SC("slice out of range")); if(eidx > alen || sidx < 0)return sq_throwerror(v, _SC("slice out of range"));
SQArray *arr=SQArray::Create(_ss(v),eidx-sidx); SQArray *arr=SQArray::Create(_ss(v),eidx-sidx);
SQObjectPtr t; SQObjectPtr t;
SQInteger count=0; SQInteger count=0;
@ -805,7 +807,7 @@ static SQInteger string_slice(HSQUIRRELVM v)
if(sidx < 0)sidx = slen + sidx; if(sidx < 0)sidx = slen + sidx;
if(eidx < 0)eidx = slen + eidx; if(eidx < 0)eidx = slen + eidx;
if(eidx < sidx) return sq_throwerror(v,_SC("wrong indexes")); if(eidx < sidx) return sq_throwerror(v,_SC("wrong indexes"));
if(eidx > slen) return sq_throwerror(v,_SC("slice out of range")); if(eidx > slen || sidx < 0) return sq_throwerror(v, _SC("slice out of range"));
v->Push(SQString::Create(_ss(v),&_stringval(o)[sidx],eidx-sidx)); v->Push(SQString::Create(_ss(v),&_stringval(o)[sidx],eidx-sidx));
return 1; return 1;
} }
@ -830,12 +832,20 @@ static SQInteger string_find(HSQUIRRELVM v)
#define STRING_TOFUNCZ(func) static SQInteger string_##func(HSQUIRRELVM v) \ #define STRING_TOFUNCZ(func) static SQInteger string_##func(HSQUIRRELVM v) \
{\ {\
SQObject str=stack_get(v,1); \ SQInteger sidx,eidx; \
SQObjectPtr str; \
if(SQ_FAILED(get_slice_params(v,sidx,eidx,str)))return -1; \
SQInteger slen = _string(str)->_len; \
if(sidx < 0)sidx = slen + sidx; \
if(eidx < 0)eidx = slen + eidx; \
if(eidx < sidx) return sq_throwerror(v,_SC("wrong indexes")); \
if(eidx > slen || sidx < 0) return sq_throwerror(v,_SC("slice out of range")); \
SQInteger len=_string(str)->_len; \ SQInteger len=_string(str)->_len; \
const SQChar *sThis=_stringval(str); \ const SQChar *sthis=_stringval(str); \
SQChar *sNew=(_ss(v)->GetScratchPad(rsl(len))); \ SQChar *snew=(_ss(v)->GetScratchPad(sq_rsl(len))); \
for(SQInteger i=0;i<len;i++) sNew[i]=func(sThis[i]); \ memcpy(snew,sthis,sq_rsl(len));\
v->Push(SQString::Create(_ss(v),sNew,len)); \ for(SQInteger i=sidx;i<eidx;i++) snew[i] = func(sthis[i]); \
v->Push(SQString::Create(_ss(v),snew,len)); \
return 1; \ return 1; \
} }
@ -850,8 +860,8 @@ SQRegFunction SQSharedState::_string_default_delegate_funcz[]={
{_SC("tostring"),default_delegate_tostring,1, _SC(".")}, {_SC("tostring"),default_delegate_tostring,1, _SC(".")},
{_SC("slice"),string_slice,-1, _SC("s n n")}, {_SC("slice"),string_slice,-1, _SC("s n n")},
{_SC("find"),string_find,-2, _SC("s s n")}, {_SC("find"),string_find,-2, _SC("s s n")},
{_SC("tolower"),string_tolower,1, _SC("s")}, {_SC("tolower"),string_tolower,-1, _SC("s n n")},
{_SC("toupper"),string_toupper,1, _SC("s")}, {_SC("toupper"),string_toupper,-1, _SC("s n n")},
{_SC("weakref"),obj_delegate_weakref,1, NULL }, {_SC("weakref"),obj_delegate_weakref,1, NULL },
{0,0} {0,0}
}; };
@ -1032,7 +1042,7 @@ static SQInteger thread_wakeup(HSQUIRRELVM v)
} }
} }
SQInteger wakeupret = sq_gettop(v)>1?1:0; SQInteger wakeupret = sq_gettop(v)>1?SQTrue:SQFalse;
if(wakeupret) { if(wakeupret) {
sq_move(thread,v,2); sq_move(thread,v,2);
} }
@ -1051,6 +1061,47 @@ static SQInteger thread_wakeup(HSQUIRRELVM v)
return sq_throwerror(v,_SC("wrong parameter")); return sq_throwerror(v,_SC("wrong parameter"));
} }
static SQInteger thread_wakeupthrow(HSQUIRRELVM v)
{
SQObjectPtr o = stack_get(v,1);
if(type(o) == OT_THREAD) {
SQVM *thread = _thread(o);
SQInteger state = sq_getvmstate(thread);
if(state != SQ_VMSTATE_SUSPENDED) {
switch(state) {
case SQ_VMSTATE_IDLE:
return sq_throwerror(v,_SC("cannot wakeup a idle thread"));
break;
case SQ_VMSTATE_RUNNING:
return sq_throwerror(v,_SC("cannot wakeup a running thread"));
break;
}
}
sq_move(thread,v,2);
sq_throwobject(thread);
SQBool rethrow_error = SQTrue;
if(sq_gettop(v) > 2) {
sq_getbool(v,3,&rethrow_error);
}
if(SQ_SUCCEEDED(sq_wakeupvm(thread,SQFalse,SQTrue,SQTrue,SQTrue))) {
sq_move(v,thread,-1);
sq_pop(thread,1); //pop retval
if(sq_getvmstate(thread) == SQ_VMSTATE_IDLE) {
sq_settop(thread,1); //pop roottable
}
return 1;
}
sq_settop(thread,1);
if(rethrow_error) {
v->_lasterror = thread->_lasterror;
return SQ_ERROR;
}
return SQ_OK;
}
return sq_throwerror(v,_SC("wrong parameter"));
}
static SQInteger thread_getstatus(HSQUIRRELVM v) static SQInteger thread_getstatus(HSQUIRRELVM v)
{ {
SQObjectPtr &o = stack_get(v,1); SQObjectPtr &o = stack_get(v,1);
@ -1106,6 +1157,7 @@ static SQInteger thread_getstackinfos(HSQUIRRELVM v)
SQRegFunction SQSharedState::_thread_default_delegate_funcz[] = { SQRegFunction SQSharedState::_thread_default_delegate_funcz[] = {
{_SC("call"), thread_call, -1, _SC("v")}, {_SC("call"), thread_call, -1, _SC("v")},
{_SC("wakeup"), thread_wakeup, -1, _SC("v")}, {_SC("wakeup"), thread_wakeup, -1, _SC("v")},
{_SC("wakeupthrow"), thread_wakeupthrow, -2, _SC("v.b")},
{_SC("getstatus"), thread_getstatus, 1, _SC("v")}, {_SC("getstatus"), thread_getstatus, 1, _SC("v")},
{_SC("weakref"),obj_delegate_weakref,1, NULL }, {_SC("weakref"),obj_delegate_weakref,1, NULL },
{_SC("getstackinfos"),thread_getstackinfos,2, _SC("vn")}, {_SC("getstackinfos"),thread_getstackinfos,2, _SC("vn")},

View File

@ -157,7 +157,7 @@ public:
void MoveIfCurrentTargetIsLocal() { void MoveIfCurrentTargetIsLocal() {
SQInteger trg = _fs->TopTarget(); SQInteger trg = _fs->TopTarget();
if(_fs->IsLocal(trg)) { if(_fs->IsLocal(trg)) {
trg = _fs->PopTarget(); //no pops the target and move it trg = _fs->PopTarget(); //pops the target and moves it
_fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg); _fs->AddInstruction(_OP_MOVE, _fs->PushTarget(), trg);
} }
} }
@ -338,6 +338,7 @@ public:
_fs->PushTarget(p1); _fs->PushTarget(p1);
//EmitCompArithLocal(tok, p1, p1, p2); //EmitCompArithLocal(tok, p1, p1, p2);
_fs->AddInstruction(ChooseArithOpByToken(tok),p1, p2, p1, 0); _fs->AddInstruction(ChooseArithOpByToken(tok),p1, p2, p1, 0);
_fs->SnoozeOpt();
} }
break; break;
case OBJECT: case OBJECT:
@ -356,7 +357,9 @@ public:
SQInteger tmp = _fs->PushTarget(); SQInteger tmp = _fs->PushTarget();
_fs->AddInstruction(_OP_GETOUTER, tmp, pos); _fs->AddInstruction(_OP_GETOUTER, tmp, pos);
_fs->AddInstruction(ChooseArithOpByToken(tok), tmp, val, tmp, 0); _fs->AddInstruction(ChooseArithOpByToken(tok), tmp, val, tmp, 0);
_fs->AddInstruction(_OP_SETOUTER, tmp, pos, tmp); _fs->PopTarget();
_fs->PopTarget();
_fs->AddInstruction(_OP_SETOUTER, _fs->PushTarget(), pos, tmp);
} }
break; break;
} }
@ -656,6 +659,7 @@ public:
case EXPR: Error(_SC("can't '++' or '--' an expression")); break; case EXPR: Error(_SC("can't '++' or '--' an expression")); break;
case OBJECT: case OBJECT:
case BASE: case BASE:
if(_es.donot_get == true) { Error(_SC("can't '++' or '--' an expression")); break; } //mmh dor this make sense?
Emit2ArgsOP(_OP_PINC, diff); Emit2ArgsOP(_OP_PINC, diff);
break; break;
case LOCAL: { case LOCAL: {
@ -706,7 +710,7 @@ public:
} }
SQInteger Factor() SQInteger Factor()
{ {
_es.etype = EXPR; //_es.etype = EXPR;
switch(_token) switch(_token)
{ {
case TK_STRING_LITERAL: case TK_STRING_LITERAL:
@ -864,6 +868,7 @@ public:
case TK___FILE__: _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_sourcename)); Lex(); break; case TK___FILE__: _fs->AddInstruction(_OP_LOAD, _fs->PushTarget(), _fs->GetConstant(_sourcename)); Lex(); break;
default: Error(_SC("expression expected")); default: Error(_SC("expression expected"));
} }
_es.etype = EXPR;
return -1; return -1;
} }
void EmitLoadConstInt(SQInteger value,SQInteger target) void EmitLoadConstInt(SQInteger value,SQInteger target)
@ -871,7 +876,7 @@ public:
if(target < 0) { if(target < 0) {
target = _fs->PushTarget(); target = _fs->PushTarget();
} }
if((value & (~((SQInteger)0xFFFFFFFF))) == 0) { //does it fit in 32 bits? if(value <= INT_MAX && value > INT_MIN) { //does it fit in 32 bits?
_fs->AddInstruction(_OP_LOADINT, target,value); _fs->AddInstruction(_OP_LOADINT, target,value);
} }
else { else {
@ -900,8 +905,13 @@ public:
{ {
switch(_token) { switch(_token) {
case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_MODEQ: case TK_MULEQ: case _SC('='): case _SC('('): case TK_NEWSLOT: case TK_MODEQ: case TK_MULEQ:
case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ: case TK_PLUSPLUS: case TK_MINUSMINUS: case TK_DIVEQ: case TK_MINUSEQ: case TK_PLUSEQ:
return false; return false;
case TK_PLUSPLUS: case TK_MINUSMINUS:
if (!IsEndOfStatement()) {
return false;
}
break;
} }
return (!_es.donot_get || ( _es.donot_get && (_token == _SC('.') || _token == _SC('[')))); return (!_es.donot_get || ( _es.donot_get && (_token == _SC('.') || _token == _SC('['))));
} }
@ -1017,6 +1027,28 @@ public:
if(_token == _SC(',')) Lex(); else break; if(_token == _SC(',')) Lex(); else break;
} while(1); } while(1);
} }
void IfBlock()
{
if (_token == _SC('{'))
{
BEGIN_SCOPE();
Lex();
Statements();
Expect(_SC('}'));
if (true) {
END_SCOPE();
}
else {
END_SCOPE_NO_CLOSE();
}
}
else {
//BEGIN_SCOPE();
Statement();
if (_lex._prevtoken != _SC('}') && _lex._prevtoken != _SC(';')) OptionalSemicolon();
//END_SCOPE();
}
}
void IfStatement() void IfStatement()
{ {
SQInteger jmppos; SQInteger jmppos;
@ -1024,22 +1056,33 @@ public:
Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')')); Lex(); Expect(_SC('(')); CommaExpr(); Expect(_SC(')'));
_fs->AddInstruction(_OP_JZ, _fs->PopTarget()); _fs->AddInstruction(_OP_JZ, _fs->PopTarget());
SQInteger jnepos = _fs->GetCurrentPos(); SQInteger jnepos = _fs->GetCurrentPos();
BEGIN_SCOPE();
Statement();
IfBlock();
// //
if(_token != _SC('}') && _token != TK_ELSE) OptionalSemicolon(); /*static int n = 0;
if (_token != _SC('}') && _token != TK_ELSE) {
printf("IF %d-----------------------!!!!!!!!!\n", n);
if (n == 5)
{
printf("asd");
}
n++;
//OptionalSemicolon();
}*/
END_SCOPE();
SQInteger endifblock = _fs->GetCurrentPos(); SQInteger endifblock = _fs->GetCurrentPos();
if(_token == TK_ELSE){ if(_token == TK_ELSE){
haselse = true; haselse = true;
BEGIN_SCOPE(); //BEGIN_SCOPE();
_fs->AddInstruction(_OP_JMP); _fs->AddInstruction(_OP_JMP);
jmppos = _fs->GetCurrentPos(); jmppos = _fs->GetCurrentPos();
Lex(); Lex();
Statement(); if(_lex._prevtoken != _SC('}')) OptionalSemicolon(); //Statement(); if(_lex._prevtoken != _SC('}')) OptionalSemicolon();
END_SCOPE(); IfBlock();
//END_SCOPE();
_fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos); _fs->SetIntructionParam(jmppos, 1, _fs->GetCurrentPos() - jmppos);
} }
_fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0)); _fs->SetIntructionParam(jnepos, 1, endifblock - jnepos + (haselse?1:0));

View File

@ -61,7 +61,7 @@ void SQVM::Raise_Error(const SQChar *s, ...)
va_list vl; va_list vl;
va_start(vl, s); va_start(vl, s);
SQInteger buffersize = (SQInteger)scstrlen(s)+(NUMBER_MAX_CHAR*2); SQInteger buffersize = (SQInteger)scstrlen(s)+(NUMBER_MAX_CHAR*2);
scvsprintf(_sp(rsl(buffersize)),buffersize, s, vl); scvsprintf(_sp(sq_rsl(buffersize)),buffersize, s, vl);
va_end(vl); va_end(vl);
_lasterror = SQString::Create(_ss(this),_spval,-1); _lasterror = SQString::Create(_ss(this),_spval,-1);
} }
@ -76,11 +76,11 @@ SQString *SQVM::PrintObjVal(const SQObjectPtr &o)
switch(type(o)) { switch(type(o)) {
case OT_STRING: return _string(o); case OT_STRING: return _string(o);
case OT_INTEGER: case OT_INTEGER:
scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)),rsl(NUMBER_MAX_CHAR), _PRINT_INT_FMT, _integer(o)); scsprintf(_sp(sq_rsl(NUMBER_MAX_CHAR+1)),sq_rsl(NUMBER_MAX_CHAR), _PRINT_INT_FMT, _integer(o));
return SQString::Create(_ss(this), _spval); return SQString::Create(_ss(this), _spval);
break; break;
case OT_FLOAT: case OT_FLOAT:
scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)), rsl(NUMBER_MAX_CHAR), _SC("%.14g"), _float(o)); scsprintf(_sp(sq_rsl(NUMBER_MAX_CHAR+1)), sq_rsl(NUMBER_MAX_CHAR), _SC("%.14g"), _float(o));
return SQString::Create(_ss(this), _spval); return SQString::Create(_ss(this), _spval);
break; break;
default: default:

View File

@ -73,7 +73,6 @@ SQInstructionDesc g_InstrDesc[]={
{_SC("_OP_NEWSLOTA")}, {_SC("_OP_NEWSLOTA")},
{_SC("_OP_GETBASE")}, {_SC("_OP_GETBASE")},
{_SC("_OP_CLOSE")}, {_SC("_OP_CLOSE")},
{_SC("_OP_JCMP")}
}; };
#endif #endif
void DumpLiteral(SQObjectPtr &o) void DumpLiteral(SQObjectPtr &o)

View File

@ -29,7 +29,7 @@ void SQLexer::Init(SQSharedState *ss, SQLEXREADFUNC rg, SQUserPointer up,Compile
_errfunc = efunc; _errfunc = efunc;
_errtarget = ed; _errtarget = ed;
_sharedstate = ss; _sharedstate = ss;
_keywords = SQTable::Create(ss, 26); _keywords = SQTable::Create(ss, 37);
ADD_KEYWORD(while, TK_WHILE); ADD_KEYWORD(while, TK_WHILE);
ADD_KEYWORD(do, TK_DO); ADD_KEYWORD(do, TK_DO);
ADD_KEYWORD(if, TK_IF); ADD_KEYWORD(if, TK_IF);

View File

@ -2,8 +2,10 @@
see copyright notice in squirrel.h see copyright notice in squirrel.h
*/ */
#include "sqpcheader.h" #include "sqpcheader.h"
#ifndef SQ_EXCLUDE_DEFAULT_MEMFUNCTIONS
void *sq_vm_malloc(SQUnsignedInteger size){ return malloc(size); } void *sq_vm_malloc(SQUnsignedInteger size){ return malloc(size); }
void *sq_vm_realloc(void *p, SQUnsignedInteger oldsize, SQUnsignedInteger size){ return realloc(p, size); } void *sq_vm_realloc(void *p, SQUnsignedInteger oldsize, SQUnsignedInteger size){ return realloc(p, size); }
void sq_vm_free(void *p, SQUnsignedInteger size){ free(p); } void sq_vm_free(void *p, SQUnsignedInteger size){ free(p); }
#endif

View File

@ -86,6 +86,9 @@ SQWeakRef *SQRefCounted::GetWeakRef(SQObjectType type)
{ {
if(!_weakref) { if(!_weakref) {
sq_new(_weakref,SQWeakRef); sq_new(_weakref,SQWeakRef);
#if defined(SQUSEDOUBLE) && !defined(_SQ64)
_weakref->_obj._unVal.raw = 0; //clean the whole union on 32 bits with double
#endif
_weakref->_obj._type = type; _weakref->_obj._type = type;
_weakref->_obj._unVal.pRefCounted = this; _weakref->_obj._unVal.pRefCounted = this;
} }
@ -150,6 +153,10 @@ bool SQGenerator::Yield(SQVM *v,SQInteger target)
for(SQInteger i=0;i<_ci._etraps;i++) { for(SQInteger i=0;i<_ci._etraps;i++) {
_etraps.push_back(v->_etraps.top()); _etraps.push_back(v->_etraps.top());
v->_etraps.pop_back(); v->_etraps.pop_back();
// store relative stack base and size in case of resume to other _top
SQExceptionTrap &et = _etraps.back();
et._stackbase -= v->_stackbase;
et._stacksize -= v->_stackbase;
} }
_state=eSuspended; _state=eSuspended;
return true; return true;
@ -162,6 +169,7 @@ bool SQGenerator::Resume(SQVM *v,SQObjectPtr &dest)
SQInteger size = _stack.size(); SQInteger size = _stack.size();
SQInteger target = &dest - &(v->_stack._vals[v->_stackbase]); SQInteger target = &dest - &(v->_stack._vals[v->_stackbase]);
assert(target>=0 && target<=255); assert(target>=0 && target<=255);
SQInteger newbase = v->_top;
if(!v->EnterFrame(v->_top, v->_top + size, false)) if(!v->EnterFrame(v->_top, v->_top + size, false))
return false; return false;
v->ci->_generator = this; v->ci->_generator = this;
@ -177,6 +185,10 @@ bool SQGenerator::Resume(SQVM *v,SQObjectPtr &dest)
for(SQInteger i=0;i<_ci._etraps;i++) { for(SQInteger i=0;i<_ci._etraps;i++) {
v->_etraps.push_back(_etraps.top()); v->_etraps.push_back(_etraps.top());
_etraps.pop_back(); _etraps.pop_back();
SQExceptionTrap &et = v->_etraps.back();
// restore absolute stack base and size
et._stackbase += newbase;
et._stacksize += newbase;
} }
SQObject _this = _stack._vals[0]; SQObject _this = _stack._vals[0];
v->_stack[v->_stackbase] = type(_this) == OT_WEAKREF ? _weakref(_this)->_obj : _this; v->_stack[v->_stackbase] = type(_this) == OT_WEAKREF ? _weakref(_this)->_obj : _this;
@ -305,7 +317,7 @@ bool WriteObject(HSQUIRRELVM v,SQUserPointer up,SQWRITEFUNC write,SQObjectPtr &o
switch(type(o)){ switch(type(o)){
case OT_STRING: case OT_STRING:
_CHECK_IO(SafeWrite(v,write,up,&_string(o)->_len,sizeof(SQInteger))); _CHECK_IO(SafeWrite(v,write,up,&_string(o)->_len,sizeof(SQInteger)));
_CHECK_IO(SafeWrite(v,write,up,_stringval(o),rsl(_string(o)->_len))); _CHECK_IO(SafeWrite(v,write,up,_stringval(o),sq_rsl(_string(o)->_len)));
break; break;
case OT_BOOL: case OT_BOOL:
case OT_INTEGER: case OT_INTEGER:
@ -330,7 +342,7 @@ bool ReadObject(HSQUIRRELVM v,SQUserPointer up,SQREADFUNC read,SQObjectPtr &o)
case OT_STRING:{ case OT_STRING:{
SQInteger len; SQInteger len;
_CHECK_IO(SafeRead(v,read,up,&len,sizeof(SQInteger))); _CHECK_IO(SafeRead(v,read,up,&len,sizeof(SQInteger)));
_CHECK_IO(SafeRead(v,read,up,_ss(v)->GetScratchPad(rsl(len)),rsl(len))); _CHECK_IO(SafeRead(v,read,up,_ss(v)->GetScratchPad(sq_rsl(len)),sq_rsl(len)));
o=SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1),len); o=SQString::Create(_ss(v),_ss(v)->GetScratchPad(-1),len);
} }
break; break;

View File

@ -99,7 +99,7 @@ enum SQOpcode
_OP_THROW= 0x39, _OP_THROW= 0x39,
_OP_NEWSLOTA= 0x3A, _OP_NEWSLOTA= 0x3A,
_OP_GETBASE= 0x3B, _OP_GETBASE= 0x3B,
_OP_CLOSE= 0x3C, _OP_CLOSE= 0x3C
}; };
struct SQInstructionDesc { struct SQInstructionDesc {

View File

@ -6,6 +6,7 @@
#include <crtdbg.h> #include <crtdbg.h>
#endif #endif
#include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>

View File

@ -596,14 +596,14 @@ SQString *SQStringTable::Add(const SQChar *news,SQInteger len)
SQHash h = newhash&(_numofslots-1); SQHash h = newhash&(_numofslots-1);
SQString *s; SQString *s;
for (s = _strings[h]; s; s = s->_next){ for (s = _strings[h]; s; s = s->_next){
if(s->_len == len && (!memcmp(news,s->_val,rsl(len)))) if(s->_len == len && (!memcmp(news,s->_val,sq_rsl(len))))
return s; //found return s; //found
} }
SQString *t = (SQString *)SQ_MALLOC(rsl(len)+sizeof(SQString)); SQString *t = (SQString *)SQ_MALLOC(sq_rsl(len)+sizeof(SQString));
new (t) SQString; new (t) SQString;
t->_sharedstate = _sharedstate; t->_sharedstate = _sharedstate;
memcpy(t->_val,news,rsl(len)); memcpy(t->_val,news,sq_rsl(len));
t->_val[len] = _SC('\0'); t->_val[len] = _SC('\0');
t->_len = len; t->_len = len;
t->_hash = newhash; t->_hash = newhash;
@ -648,7 +648,7 @@ void SQStringTable::Remove(SQString *bs)
_slotused--; _slotused--;
SQInteger slen = s->_len; SQInteger slen = s->_len;
s->~SQString(); s->~SQString();
SQ_FREE(s,sizeof(SQString) + rsl(slen)); SQ_FREE(s,sizeof(SQString) + sq_rsl(slen));
return; return;
} }
prev = s; prev = s;

View File

@ -130,14 +130,6 @@ private:
#define _instance_ddel _table(_sharedstate->_instance_default_delegate) #define _instance_ddel _table(_sharedstate->_instance_default_delegate)
#define _weakref_ddel _table(_sharedstate->_weakref_default_delegate) #define _weakref_ddel _table(_sharedstate->_weakref_default_delegate)
#ifdef SQUNICODE //rsl REAL STRING LEN
#define rsl(l) ((l)<<WCHAR_SHIFT_MUL)
#else
#define rsl(l) (l)
#endif
//extern SQObjectPtr _null_;
bool CompileTypemask(SQIntVec &res,const SQChar *typemask); bool CompileTypemask(SQIntVec &res,const SQChar *typemask);

View File

@ -69,10 +69,12 @@ bool SQVM::ARITH_OP(SQUnsignedInteger op,SQObjectPtr &trg,const SQObjectPtr &o1,
case '+': res = i1 + i2; break; case '+': res = i1 + i2; break;
case '-': res = i1 - i2; break; case '-': res = i1 - i2; break;
case '/': if (i2 == 0) { Raise_Error(_SC("division by zero")); return false; } case '/': if (i2 == 0) { Raise_Error(_SC("division by zero")); return false; }
else if (i2 == -1 && i1 == INT_MIN) { Raise_Error(_SC("integer overflow")); return false; }
res = i1 / i2; res = i1 / i2;
break; break;
case '*': res = i1 * i2; break; case '*': res = i1 * i2; break;
case '%': if (i2 == 0) { Raise_Error(_SC("modulo by zero")); return false; } case '%': if (i2 == 0) { Raise_Error(_SC("modulo by zero")); return false; }
else if (i2 == -1 && i1 == INT_MIN) { res = 0; break; }
res = i1 % i2; res = i1 % i2;
break; break;
default: res = 0xDEADBEEF; default: res = 0xDEADBEEF;
@ -284,13 +286,13 @@ bool SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res)
res = o; res = o;
return true; return true;
case OT_FLOAT: case OT_FLOAT:
scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)),rsl(NUMBER_MAX_CHAR),_SC("%g"),_float(o)); scsprintf(_sp(sq_rsl(NUMBER_MAX_CHAR+1)),sq_rsl(NUMBER_MAX_CHAR),_SC("%g"),_float(o));
break; break;
case OT_INTEGER: case OT_INTEGER:
scsprintf(_sp(rsl(NUMBER_MAX_CHAR+1)),rsl(NUMBER_MAX_CHAR),_PRINT_INT_FMT,_integer(o)); scsprintf(_sp(sq_rsl(NUMBER_MAX_CHAR+1)),sq_rsl(NUMBER_MAX_CHAR),_PRINT_INT_FMT,_integer(o));
break; break;
case OT_BOOL: case OT_BOOL:
scsprintf(_sp(rsl(6)),rsl(6),_integer(o)?_SC("true"):_SC("false")); scsprintf(_sp(sq_rsl(6)),sq_rsl(6),_integer(o)?_SC("true"):_SC("false"));
break; break;
case OT_TABLE: case OT_TABLE:
case OT_USERDATA: case OT_USERDATA:
@ -309,7 +311,7 @@ bool SQVM::ToString(const SQObjectPtr &o,SQObjectPtr &res)
} }
} }
default: default:
scsprintf(_sp(rsl(sizeof(void*)+20)),rsl(sizeof(void*)+20),_SC("(%s : 0x%p)"),GetTypeName(o),(void*)_rawval(o)); scsprintf(_sp(sq_rsl((sizeof(void*)*2)+NUMBER_MAX_CHAR)),sq_rsl((sizeof(void*)*2)+NUMBER_MAX_CHAR),_SC("(%s : 0x%p)"),GetTypeName(o),(void*)_rawval(o));
} }
res = SQString::Create(_ss(this),_spval); res = SQString::Create(_ss(this),_spval);
return true; return true;
@ -322,9 +324,9 @@ bool SQVM::StringCat(const SQObjectPtr &str,const SQObjectPtr &obj,SQObjectPtr &
if(!ToString(str, a)) return false; if(!ToString(str, a)) return false;
if(!ToString(obj, b)) return false; if(!ToString(obj, b)) return false;
SQInteger l = _string(a)->_len , ol = _string(b)->_len; SQInteger l = _string(a)->_len , ol = _string(b)->_len;
SQChar *s = _sp(rsl(l + ol + 1)); SQChar *s = _sp(sq_rsl(l + ol + 1));
memcpy(s, _stringval(a), rsl(l)); memcpy(s, _stringval(a), sq_rsl(l));
memcpy(s + l, _stringval(b), rsl(ol)); memcpy(s + l, _stringval(b), sq_rsl(ol));
dest = SQString::Create(_ss(this), _spval, l + ol); dest = SQString::Create(_ss(this), _spval, l + ol);
return true; return true;
} }
@ -485,7 +487,7 @@ bool SQVM::PLOCAL_INC(SQInteger op,SQObjectPtr &target, SQObjectPtr &a, SQObject
bool SQVM::DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix,SQInteger selfidx) bool SQVM::DerefInc(SQInteger op,SQObjectPtr &target, SQObjectPtr &self, SQObjectPtr &key, SQObjectPtr &incr, bool postfix,SQInteger selfidx)
{ {
SQObjectPtr tmp, tself = self, tkey = key; SQObjectPtr tmp, tself = self, tkey = key;
if (!Get(tself, tkey, tmp, false, selfidx)) { return false; } if (!Get(tself, tkey, tmp, 0, selfidx)) { return false; }
_RET_ON_FAIL(ARITH_OP( op , target, tmp, incr)) _RET_ON_FAIL(ARITH_OP( op , target, tmp, incr))
if (!Set(tself, tkey, target,selfidx)) { return false; } if (!Set(tself, tkey, target,selfidx)) { return false; }
if (postfix) target = tmp; if (postfix) target = tmp;
@ -539,7 +541,7 @@ bool SQVM::FOREACH_OP(SQObjectPtr &o1,SQObjectPtr &o2,SQObjectPtr
if(CallMetaMethod(closure, MT_NEXTI, 2, itr)) { if(CallMetaMethod(closure, MT_NEXTI, 2, itr)) {
o4 = o2 = itr; o4 = o2 = itr;
if(type(itr) == OT_NULL) _FINISH(exitpos); if(type(itr) == OT_NULL) _FINISH(exitpos);
if(!Get(o1, itr, o3, false, DONT_FALL_BACK)) { if(!Get(o1, itr, o3, 0, DONT_FALL_BACK)) {
Raise_Error(_SC("_nexti returned an invalid idx")); // cloud be changed Raise_Error(_SC("_nexti returned an invalid idx")); // cloud be changed
return false; return false;
} }
@ -713,7 +715,7 @@ exception_restore:
#ifndef _SQ64 #ifndef _SQ64
TARGET = (SQInteger)arg1; continue; TARGET = (SQInteger)arg1; continue;
#else #else
TARGET = (SQInteger)((SQUnsignedInteger32)arg1); continue; TARGET = (SQInteger)((SQInt32)arg1); continue;
#endif #endif
case _OP_LOADFLOAT: TARGET = *((SQFloat *)&arg1); continue; case _OP_LOADFLOAT: TARGET = *((SQFloat *)&arg1); continue;
case _OP_DLOAD: TARGET = ci->_literals[arg1]; STK(arg2) = ci->_literals[arg3];continue; case _OP_DLOAD: TARGET = ci->_literals[arg1]; STK(arg2) = ci->_literals[arg3];continue;
@ -800,7 +802,7 @@ exception_restore:
case _OP_PREPCALLK: { case _OP_PREPCALLK: {
SQObjectPtr &key = _i_.op == _OP_PREPCALLK?(ci->_literals)[arg1]:STK(arg1); SQObjectPtr &key = _i_.op == _OP_PREPCALLK?(ci->_literals)[arg1]:STK(arg1);
SQObjectPtr &o = STK(arg2); SQObjectPtr &o = STK(arg2);
if (!Get(o, key, temp_reg,false,arg2)) { if (!Get(o, key, temp_reg,0,arg2)) {
SQ_THROW(); SQ_THROW();
} }
STK(arg3) = o; STK(arg3) = o;
@ -808,7 +810,7 @@ exception_restore:
} }
continue; continue;
case _OP_GETK: case _OP_GETK:
if (!Get(STK(arg2), ci->_literals[arg1], temp_reg, false,arg2)) { SQ_THROW();} if (!Get(STK(arg2), ci->_literals[arg1], temp_reg, 0,arg2)) { SQ_THROW();}
_Swap(TARGET,temp_reg);//TARGET = temp_reg; _Swap(TARGET,temp_reg);//TARGET = temp_reg;
continue; continue;
case _OP_MOVE: TARGET = STK(arg1); continue; case _OP_MOVE: TARGET = STK(arg1); continue;
@ -822,7 +824,7 @@ exception_restore:
if (arg0 != 0xFF) TARGET = STK(arg3); if (arg0 != 0xFF) TARGET = STK(arg3);
continue; continue;
case _OP_GET: case _OP_GET:
if (!Get(STK(arg1), STK(arg2), temp_reg, false,arg1)) { SQ_THROW(); } if (!Get(STK(arg1), STK(arg2), temp_reg, 0,arg1)) { SQ_THROW(); }
_Swap(TARGET,temp_reg);//TARGET = temp_reg; _Swap(TARGET,temp_reg);//TARGET = temp_reg;
continue; continue;
case _OP_EQ:{ case _OP_EQ:{
@ -907,7 +909,7 @@ exception_restore:
#ifndef _SQ64 #ifndef _SQ64
val._unVal.nInteger = (SQInteger)arg1; val._unVal.nInteger = (SQInteger)arg1;
#else #else
val._unVal.nInteger = (SQInteger)((SQUnsignedInteger32)arg1); val._unVal.nInteger = (SQInteger)((SQInt32)arg1);
#endif #endif
break; break;
case AAT_FLOAT: case AAT_FLOAT:
@ -918,7 +920,7 @@ exception_restore:
val._type = OT_BOOL; val._type = OT_BOOL;
val._unVal.nInteger = arg1; val._unVal.nInteger = arg1;
break; break;
default: assert(0); break; default: val._type = OT_INTEGER; assert(0); break;
} }
_array(STK(arg0))->Append(val); continue; _array(STK(arg0))->Append(val); continue;
@ -952,7 +954,7 @@ exception_restore:
} continue; } continue;
case _OP_CMP: _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg1),TARGET)) continue; case _OP_CMP: _GUARD(CMP_OP((CmpOP)arg3,STK(arg2),STK(arg1),TARGET)) continue;
case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, true, EXISTS_FALL_BACK)?true:false;continue; case _OP_EXISTS: TARGET = Get(STK(arg1), STK(arg2), temp_reg, GET_FLAG_DO_NOT_RAISE_ERROR | GET_FLAG_RAW, DONT_FALL_BACK) ? true : false; continue;
case _OP_INSTANCEOF: case _OP_INSTANCEOF:
if(type(STK(arg1)) != OT_CLASS) if(type(STK(arg1)) != OT_CLASS)
{Raise_Error(_SC("cannot apply instanceof between a %s and a %s"),GetTypeName(STK(arg1)),GetTypeName(STK(arg2))); SQ_THROW();} {Raise_Error(_SC("cannot apply instanceof between a %s and a %s"),GetTypeName(STK(arg1)),GetTypeName(STK(arg2))); SQ_THROW();}
@ -1198,14 +1200,14 @@ bool SQVM::CallNative(SQNativeClosure *nclosure, SQInteger nargs, SQInteger newb
#define FALLBACK_NO_MATCH 1 #define FALLBACK_NO_MATCH 1
#define FALLBACK_ERROR 2 #define FALLBACK_ERROR 2
bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,bool raw, SQInteger selfidx) bool SQVM::Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, SQUnsignedInteger getflags, SQInteger selfidx)
{ {
switch(type(self)){ switch(type(self)){
case OT_TABLE: case OT_TABLE:
if(_table(self)->Get(key,dest))return true; if(_table(self)->Get(key,dest))return true;
break; break;
case OT_ARRAY: case OT_ARRAY:
if(sq_isnumeric(key)) { if(_array(self)->Get(tointeger(key),dest)) { return true; } if(selfidx != EXISTS_FALL_BACK) Raise_IdxError(key); return false; } if (sq_isnumeric(key)) { if (_array(self)->Get(tointeger(key), dest)) { return true; } if ((getflags & GET_FLAG_DO_NOT_RAISE_ERROR) == 0) Raise_IdxError(key); return false; }
break; break;
case OT_INSTANCE: case OT_INSTANCE:
if(_instance(self)->Get(key,dest)) return true; if(_instance(self)->Get(key,dest)) return true;
@ -1216,18 +1218,19 @@ bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,
case OT_STRING: case OT_STRING:
if(sq_isnumeric(key)){ if(sq_isnumeric(key)){
SQInteger n = tointeger(key); SQInteger n = tointeger(key);
if(abs((int)n) < _string(self)->_len) { SQInteger len = _string(self)->_len;
if(n < 0) n = _string(self)->_len - n; if (n < 0) { n += len; }
if (n >= 0 && n < len) {
dest = SQInteger(_stringval(self)[n]); dest = SQInteger(_stringval(self)[n]);
return true; return true;
} }
if(selfidx != EXISTS_FALL_BACK) Raise_IdxError(key); if ((getflags & GET_FLAG_DO_NOT_RAISE_ERROR) == 0) Raise_IdxError(key);
return false; return false;
} }
break; break;
default:break; //shut up compiler default:break; //shut up compiler
} }
if(!raw) { if ((getflags & GET_FLAG_RAW) == 0) {
switch(FallBackGet(self,key,dest)) { switch(FallBackGet(self,key,dest)) {
case FALLBACK_OK: return true; //okie case FALLBACK_OK: return true; //okie
case FALLBACK_NO_MATCH: break; //keep falling back case FALLBACK_NO_MATCH: break; //keep falling back
@ -1242,12 +1245,12 @@ bool SQVM::Get(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest,
SQWeakRef *w = _closure(ci->_closure)->_root; SQWeakRef *w = _closure(ci->_closure)->_root;
if(type(w->_obj) != OT_NULL) if(type(w->_obj) != OT_NULL)
{ {
if(Get(*((const SQObjectPtr *)&w->_obj),key,dest,false,DONT_FALL_BACK)) return true; if(Get(*((const SQObjectPtr *)&w->_obj),key,dest,0,DONT_FALL_BACK)) return true;
} }
} }
//#endif //#endif
if(selfidx != EXISTS_FALL_BACK) Raise_IdxError(key); if ((getflags & GET_FLAG_DO_NOT_RAISE_ERROR) == 0) Raise_IdxError(key);
return false; return false;
} }
@ -1278,7 +1281,7 @@ SQInteger SQVM::FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObj
case OT_USERDATA: case OT_USERDATA:
//delegation //delegation
if(_delegable(self)->_delegate) { if(_delegable(self)->_delegate) {
if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,false,DONT_FALL_BACK)) return FALLBACK_OK; if(Get(SQObjectPtr(_delegable(self)->_delegate),key,dest,0,DONT_FALL_BACK)) return FALLBACK_OK;
} }
else { else {
return FALLBACK_NO_MATCH; return FALLBACK_NO_MATCH;
@ -1551,7 +1554,8 @@ SQInteger prevstackbase = _stackbase;
SQObjectPtr constr; SQObjectPtr constr;
SQObjectPtr temp; SQObjectPtr temp;
CreateClassInstance(_class(closure),outres,constr); CreateClassInstance(_class(closure),outres,constr);
if(type(constr) != OT_NULL) { SQObjectType ctype = type(constr);
if (ctype == OT_NATIVECLOSURE || ctype == OT_CLOSURE) {
_stack[stackbase] = outres; _stack[stackbase] = outres;
return Call(constr,nparams,stackbase,temp,raiseerror); return Call(constr,nparams,stackbase,temp,raiseerror);
} }
@ -1631,7 +1635,7 @@ bool SQVM::EnterFrame(SQInteger newbase, SQInteger newtop, bool tailcall)
Raise_Error(_SC("stack overflow, cannot resize stack while in a metamethod")); Raise_Error(_SC("stack overflow, cannot resize stack while in a metamethod"));
return false; return false;
} }
_stack.resize(_stack.size() + (MIN_STACK_OVERHEAD << 2)); _stack.resize(newtop + (MIN_STACK_OVERHEAD << 2));
RelocateOuters(); RelocateOuters();
} }
return true; return true;

View File

@ -9,7 +9,10 @@
#define SQ_SUSPEND_FLAG -666 #define SQ_SUSPEND_FLAG -666
#define DONT_FALL_BACK 666 #define DONT_FALL_BACK 666
#define EXISTS_FALL_BACK -1 //#define EXISTS_FALL_BACK -1
#define GET_FLAG_RAW 0x00000001
#define GET_FLAG_DO_NOT_RAISE_ERROR 0x00000002
//base lib //base lib
void sq_base_register(HSQUIRRELVM v); void sq_base_register(HSQUIRRELVM v);
@ -66,7 +69,7 @@ public:
void CallDebugHook(SQInteger type,SQInteger forcedline=0); void CallDebugHook(SQInteger type,SQInteger forcedline=0);
void CallErrorHandler(SQObjectPtr &e); void CallErrorHandler(SQObjectPtr &e);
bool Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, bool raw, SQInteger selfidx); bool Get(const SQObjectPtr &self, const SQObjectPtr &key, SQObjectPtr &dest, SQUnsignedInteger getflags, SQInteger selfidx);
SQInteger FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest); SQInteger FallBackGet(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest);
bool InvokeDefaultDelegate(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest); bool InvokeDefaultDelegate(const SQObjectPtr &self,const SQObjectPtr &key,SQObjectPtr &dest);
bool Set(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val, SQInteger selfidx); bool Set(const SQObjectPtr &self, const SQObjectPtr &key, const SQObjectPtr &val, SQInteger selfidx);

View File

@ -1,149 +0,0 @@
/*
* Copyright 2001-2004 Unicode, Inc.
*
* Disclaimer
*
* This source code is provided as is by Unicode, Inc. No claims are
* made as to fitness for any particular purpose. No warranties of any
* kind are expressed or implied. The recipient agrees to determine
* applicability of information provided. If this file has been
* purchased on magnetic or optical media from Unicode, Inc., the
* sole remedy for any claim will be exchange of defective media
* within 90 days of receipt.
*
* Limitations on Rights to Redistribute This Code
*
* Unicode, Inc. hereby grants the right to freely use the information
* supplied in this file in the creation of products supporting the
* Unicode Standard, and to make copies of this file in any form
* for internal or external distribution as long as this notice
* remains attached.
*/
/* ---------------------------------------------------------------------
Conversions between UTF32, UTF-16, and UTF-8. Header file.
Several funtions are included here, forming a complete set of
conversions between the three formats. UTF-7 is not included
here, but is handled in a separate source file.
Each of these routines takes pointers to input buffers and output
buffers. The input buffers are const.
Each routine converts the text between *sourceStart and sourceEnd,
putting the result into the buffer between *targetStart and
targetEnd. Note: the end pointers are *after* the last item: e.g.
*(sourceEnd - 1) is the last item.
The return result indicates whether the conversion was successful,
and if not, whether the problem was in the source or target buffers.
(Only the first encountered problem is indicated.)
After the conversion, *sourceStart and *targetStart are both
updated to point to the end of last text successfully converted in
the respective buffers.
Input parameters:
sourceStart - pointer to a pointer to the source buffer.
The contents of this are modified on return so that
it points at the next thing to be converted.
targetStart - similarly, pointer to pointer to the target buffer.
sourceEnd, targetEnd - respectively pointers to the ends of the
two buffers, for overflow checking only.
These conversion functions take a ConversionFlags argument. When this
flag is set to strict, both irregular sequences and isolated surrogates
will cause an error. When the flag is set to lenient, both irregular
sequences and isolated surrogates are converted.
Whether the flag is strict or lenient, all illegal sequences will cause
an error return. This includes sequences such as: <F4 90 80 80>, <C0 80>,
or <A0> in UTF-8, and values above 0x10FFFF in UTF-32. Conformant code
must check for illegal sequences.
When the flag is set to lenient, characters over 0x10FFFF are converted
to the replacement character; otherwise (when the flag is set to strict)
they constitute an error.
Output parameters:
The value "sourceIllegal" is returned from some routines if the input
sequence is malformed. When "sourceIllegal" is returned, the source
value will point to the illegal value that caused the problem. E.g.,
in UTF-8 when a sequence is malformed, it points to the start of the
malformed sequence.
Author: Mark E. Davis, 1994.
Rev History: Rick McGowan, fixes & updates May 2001.
Fixes & updates, Sept 2001.
------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------
The following 4 definitions are compiler-specific.
The C standard does not guarantee that wchar_t has at least
16 bits, so wchar_t is no less portable than unsigned short!
All should be unsigned values to avoid sign extension during
bit mask & shift operations.
------------------------------------------------------------------------ */
typedef unsigned int UTF32; /* at least 32 bits */
typedef unsigned short UTF16; /* at least 16 bits */
typedef unsigned char UTF8; /* typically 8 bits */
typedef unsigned char Boolean; /* 0 or 1 */
/* Some fundamental constants */
#define UNI_REPLACEMENT_CHAR (UTF32)0x0000FFFD
#define UNI_MAX_BMP (UTF32)0x0000FFFF
#define UNI_MAX_UTF16 (UTF32)0x0010FFFF
#define UNI_MAX_UTF32 (UTF32)0x7FFFFFFF
#define UNI_MAX_LEGAL_UTF32 (UTF32)0x0010FFFF
typedef enum {
conversionOK, /* conversion successful */
sourceExhausted, /* partial character in source, but hit end */
targetExhausted, /* insuff. room in target for conversion */
sourceIllegal /* source sequence is illegal/malformed */
} ConversionResult;
typedef enum {
strictConversion = 0,
lenientConversion
} ConversionFlags;
/* This is for C++ and does no harm in C */
#ifdef __cplusplus
extern "C" {
#endif
ConversionResult ConvertUTF8toUTF16 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF16toUTF8 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF8toUTF32 (
const UTF8** sourceStart, const UTF8* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF32toUTF8 (
const UTF32** sourceStart, const UTF32* sourceEnd,
UTF8** targetStart, UTF8* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF16toUTF32 (
const UTF16** sourceStart, const UTF16* sourceEnd,
UTF32** targetStart, UTF32* targetEnd, ConversionFlags flags);
ConversionResult ConvertUTF32toUTF16 (
const UTF32** sourceStart, const UTF32* sourceEnd,
UTF16** targetStart, UTF16* targetEnd, ConversionFlags flags);
Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
#ifdef __cplusplus
}
#endif
/* --------------------------------------------------------------------- */

View File

@ -0,0 +1,13 @@
#define RANDOMLIB_VERSION_STRING "Unconfigured"
#define RANDOMLIB_VERSION_MAJOR -1
#define RANDOMLIB_VERSION_MINOR -1
#define RANDOMLIB_VERSION_PATCH -1
// Define HAVE_SSE2 to be 1 if Intel/AMD CPU with SSE2 support
/* #undef HAVE_SSE2 */
// Define HAVE_ALTIVEC to be 1 if Power PC CPU with AltiVec support
/* #undef HAVE_ALTIVEC */
// Undefine HAVE_LONG_DOUBLE if this type is unknown to the compiler
#define HAVE_LONG_DOUBLE 1

View File

@ -0,0 +1,432 @@
/**
* \file DiscreteNormal.hpp
* \brief Header for DiscreteNormal
*
* Sample exactly from the discrete normal distribution.
*
* Copyright (c) Charles Karney (2013) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_DISCRETENORMAL_HPP)
#define RANDOMLIB_DISCRETENORMAL_HPP 1
#include <vector>
#include <limits>
namespace RandomLib {
/**
* \brief The discrete normal distribution.
*
* Sample integers \e i with probability proportional to
* \f[
* \exp\biggl[-\frac12\biggl(\frac{i-\mu}{\sigma}\biggr)^2\biggr],
* \f]
* where &sigma; and &mu; are given as rationals (the ratio of two integers).
* The sampling is exact (provided that the random generator is ideal). For
* example
* \code
#include <iostream>
#include <RandomLib/Random.hpp>
#include <RandomLib/DiscreteNormal.hpp>
int main() {
RandomLib::Random r; // Create r
r.Reseed(); // and give it a unique seed
int sigma_num = 7, sigma_den = 1, mu_num = 1, mu_den = 3;
RandomLib::DiscreteNormal<int> d(sigma_num, sigma_den,
mu_num, mu_den);
for (int i = 0; i < 100; ++i)
std::cout << d(r) << "\n";
}
\endcode
* prints out 100 samples with &sigma; = 7 and &mu; = 1/3.
*
* The algorithm is much the same as for ExactNormal; for details see
* - C. F. F. Karney, <i>Sampling exactly from the normal distribution</i>,
* http://arxiv.org/abs/1303.6257 (Mar. 2013).
* .
* That algorithm samples the integer part of the result \e k, samples \e x
* in [0,1], and (unless rejected) returns <i>s</i>(\e k + \e x), where \e s
* = &plusmn;1. For the discrete case, we sample \e x in [0,1) such that
* \f[
* s(k + x) = (i - \mu)/\sigma,
* \f]
* or
* \f[
* x = s(i - \mu)/\sigma - k
* \f]
* The value of \e i which results in the smallest \e x &ge; 0 is
* \f[
* i_0 = s\lceil k \sigma + s \mu\rceil
* \f]
* so sample
* \f[
* i = i_0 + sj
* \f]
* where \e j is uniformly distributed in [0, &lceil;&sigma;&rceil;). The
* corresponding value of \e x is
* \f[
* \begin{aligned}
* x &= \bigl(si_0 - (k\sigma + s\mu)\bigr)/\sigma + j/\sigma\\
* &= x_0 + j/\sigma,\\
* x_0 &= \bigl(\lceil k \sigma + s \mu\rceil -
* (k \sigma + s \mu)\bigr)/\sigma.
* \end{aligned}
* \f]
* After \e x is sampled in this way, it should be rejected if \e x &ge; 1
* (this is counted with the next larger value of \e k) or if \e x = 0, \e k
* = 0, and \e s = &minus;1 (to avoid double counting the origin). If \e x
* is accepted (in Step 4 of the ExactNormal algorithm), then return \e i.
*
* When &sigma; and &mu; are given as rationals, all the arithmetic outlined
* above can be carried out exactly. The basic rejection techniques used by
* ExactNormal are exact. Thus the result of this discrete form of the
* algorithm is also exact.
*
* RandomLib provides two classes to sample from this distribution:
* - DiscreteNormal which is tuned for speed on a typical general purpose
* computer. This assumes that random samples can be generated relatively
* quickly.
* - DiscreteNormalAlt, which is a prototype for what might be needed on a
* small device used for cryptography which is using a hardware generator
* for obtaining truly random bits. This assumption here is that the
* random bits are relatively expensive to obtain.
* .
* The basic algorithm is the same in the two cases. The main advantages of
* this method are:
* - exact sampling (provided that the source of random numbers is ideal),
* - no need to cut off the tails of the distribution,
* - a short program involving simple integer operations only,
* - no dependence on external libraries (except to generate random bits),
* - no large tables of constants needed,
* - minimal time to set up for a new &sigma; and &mu; (roughly comparable to
* the time it takes to generate one sample),
* - only about 5&ndash;20 times slower than standard routines to sample from
* a normal distribution using plain double-precision arithmetic.
* - DiscreteNormalAlt exhibits ideal scaling for the consumption of random
* bits, namely a constant + log<sub>2</sub>&sigma;, for large &sigma;,
* where the constant is about 31.
* .
* The possible drawbacks of this method are:
* - &sigma; and &mu; are restricted to rational numbers with sufficiently
* small numerators and denominators to avoid overflow (this is unlikely to
* be a severe restriction especially if the template parameter IntType is
* set to <code>long long</code>),
* - the running time is unbounded (but not in any practical sense),
* - the memory consumption is unbounded (but not in any practical sense),
* - the toll, about 30 bits, is considerably worse than that obtained using
* the Knuth-Yao algorithm, for which the toll is no more than 2 (but this
* requires a large table which is expensive to compute and requires a lot
* of memory to store).
*
* This class uses a mutable private vector. So a single DiscreteNormal
* object cannot safely be used by multiple threads. In a multi-processing
* environment, each thread should use a thread-specific DiscreteNormal
* object.
*
* Some timing results for IntType = int, &mu; = 0, and 10<sup>8</sup>
* samples (time = time per sample, including setup time, rv = mean number of
* random variables per sample)
* - &sigma; = 10, time = 219 ns, rv = 17.52
* - &sigma; = 32, time = 223 ns, rv = 17.82
* - &sigma; = 1000, time = 225 ns, rv = 17.95
* - &sigma; = 160000, time = 226 ns, rv = 17.95
*
* @tparam IntType the integer type to use (default int).
**********************************************************************/
template<typename IntType = int> class DiscreteNormal {
public:
/**
* Constructor.
*
* @param[in] sigma_num the numerator of &sigma;.
* @param[in] sigma_den the denominator of &sigma; (default 1).
* @param[in] mu_num the numerator of &mu; (default 0).
* @param[in] mu_den the denominator of &mu; (default 1).
*
* The constructor creates a DiscreteNormal objects for sampling with
* specific values of &sigma; and &mu;. This may throw an exception if the
* parameters are such that overflow is possible. Internally &sigma; and
* &mu; are expressed with a common denominator, so it may be possible to
* avoid overflow by picking the fractions of these quantities so that \e
* sigma_den and \e mu_den have many common factors.
**********************************************************************/
DiscreteNormal(IntType sigma_num, IntType sigma_den = 1,
IntType mu_num = 0, IntType mu_den = 1);
/**
* Return a sample.
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @return discrete normal integer.
**********************************************************************/
template<class Random>
IntType operator()(Random& r) const;
private:
/**
* sigma = _sig / _d, mu = _imu + _mu / _d, _isig = floor(sigma)
**********************************************************************/
IntType _sig, _mu, _d, _isig, _imu;
typedef unsigned short word;
/**
* Holds as much of intermediate uniform deviates as needed.
**********************************************************************/
mutable std::vector<word> _v;
mutable unsigned _m, _l;
/**
* Increment on size of _v.
**********************************************************************/
static const unsigned alloc_incr = 16;
// ceil(n/d) for d > 0
static IntType iceil(IntType n, IntType d);
// abs(n) needed because Visual Studio's std::abs has problems
static IntType iabs(IntType n);
static IntType gcd(IntType u, IntType v);
// After x = LeadingDigit(p), p/_sig = (x + p'/_sig)/b where p and p' are
// in [0, _sig) and b = 1 + max(word).
word LeadingDigit(IntType& p) const;
/**
* Implement outcomes for choosing with prob (\e x + 2\e k) / (2\e k + 2);
* return:
* - 1 (succeed unconditionally) with prob (\e m &minus; 2) / \e m,
* - 0 (succeed with probability x) with prob 1 / \e m,
* - &minus;1 (fail unconditionally) with prob 1 / \e m.
**********************************************************************/
template<class Random> static int Choose(Random& r, int m);
// Compute v' < v. If true set v = v'.
template<class Random> bool less_than(Random& r) const;
// Compute v < (x + p/_sig)/base (updating v)
template<class Random> bool less_than(Random& r, word x, IntType p) const;
// true with prob (x + p/_sig)/base
template<class Random> bool bernoulli(Random& r, word x, IntType p) const;
/**
* Return true with probability exp(&minus;1/2).
**********************************************************************/
template<class Random> bool ExpProbH(Random& r) const;
/**
* Return true with probability exp(&minus;<i>n</i>/2).
**********************************************************************/
template<class Random> bool ExpProb(Random& r, int n) const;
/**
* Return \e n with probability exp(&minus;<i>n</i>/2)
* (1&minus;exp(&minus;1/2)).
**********************************************************************/
template<class Random> int ExpProbN(Random& r) const;
/**
* Algorithm B: true with prob exp(-x * (2*k + x) / (2*k + 2)) where
* x = (x0 + xn / _sig)/b.
**********************************************************************/
template<class Random>
bool B(Random& r, int k, word x0, IntType xn) const;
};
template<typename IntType> DiscreteNormal<IntType>::DiscreteNormal
(IntType sigma_num, IntType sigma_den,
IntType mu_num, IntType mu_den)
: _v(std::vector<word>(alloc_incr)), _m(0), _l(alloc_incr) {
STATIC_ASSERT(std::numeric_limits<IntType>::is_integer,
"DiscreteNormal: invalid integer type IntType");
STATIC_ASSERT(std::numeric_limits<IntType>::is_signed,
"DiscreteNormal: IntType must be a signed type");
STATIC_ASSERT(!std::numeric_limits<word>::is_signed,
"DiscreteNormal: word must be an unsigned type");
STATIC_ASSERT(std::numeric_limits<IntType>::digits + 1 >=
std::numeric_limits<word>::digits,
"DiscreteNormal: IntType must be at least as wide as word");
if (!( sigma_num > 0 && sigma_den > 0 && mu_den > 0 ))
throw RandomErr("DiscreteNormal: need sigma > 0");
_imu = mu_num / mu_den;
if (_imu == (std::numeric_limits<IntType>::min)())
throw RandomErr("DiscreteNormal: abs(mu) too large");
mu_num -= _imu * mu_den;
IntType l;
l = gcd(sigma_num, sigma_den); sigma_num /= l; sigma_den /= l;
l = gcd(mu_num, mu_den); mu_num /= l; mu_den /= l;
_isig = iceil(sigma_num, sigma_den);
l = gcd(sigma_den, mu_den);
_sig = sigma_num * (mu_den / l);
_mu = mu_num * (sigma_den / l);
_d = sigma_den * (mu_den / l);
// The rest of the constructor tests for possible overflow
// Check for overflow in computing member variables
IntType maxint = (std::numeric_limits<IntType>::max)();
if (!( mu_den / l <= maxint / sigma_num &&
mu_num <= maxint / (sigma_den / l) &&
mu_den / l <= maxint / sigma_den ))
throw RandomErr("DiscreteNormal: sigma or mu overflow");
// The probability that k = kmax is about 10^-543.
int kmax = 50;
// Check that max plausible result fits in an IntType, i.e.,
// _isig * (kmax + 1) + abs(_imu) does not lead to overflow.
if (!( kmax + 1 <= maxint / _isig &&
_isig * (kmax + 1) <= maxint - iabs(_imu) ))
throw RandomErr("DiscreteNormal: possible overflow a");
// Check xn0 = _sig * k + s * _mu;
if (!( kmax <= maxint / _sig &&
_sig * kmax <= maxint - iabs(_mu) ))
throw RandomErr("DiscreteNormal: possible overflow b");
// Check for overflow in LeadingDigit
// p << bits, p = _sig - 1, bits = 8
if (!( _sig <= (maxint >> 8) ))
throw RandomErr("DiscreteNormal: overflow in LeadingDigit");
}
template<typename IntType> template<class Random>
IntType DiscreteNormal<IntType>::operator()(Random& r) const {
for (;;) {
int k = ExpProbN(r);
if (!ExpProb(r, k * (k - 1))) continue;
IntType
s = r.Boolean() ? -1 : 1,
xn = _sig * IntType(k) + s * _mu,
i = iceil(xn, _d) + r.template Integer<IntType>(_isig);
xn = i * _d - xn;
if (xn >= _sig || (k == 0 && s < 0 && xn <= 0)) continue;
if (xn > 0) {
word x0 = LeadingDigit(xn); // Find first digit in expansion in words
int h = k + 1; while (h-- && B(r, k, x0, xn));
if (!(h < 0)) continue;
}
return s * i + _imu;
}
}
template<typename IntType>
IntType DiscreteNormal<IntType>::iceil(IntType n, IntType d)
{ IntType k = n / d; return k + (k * d < n ? 1 : 0); }
template<typename IntType> IntType DiscreteNormal<IntType>::iabs(IntType n)
{ return n < 0 ? -n : n; }
template<typename IntType>
IntType DiscreteNormal<IntType>::gcd(IntType u, IntType v) {
// Knuth, TAOCP, vol 2, 4.5.2, Algorithm A
u = iabs(u); v = iabs(v);
while (v > 0) { IntType r = u % v; u = v; v = r; }
return u;
}
template<typename IntType> typename DiscreteNormal<IntType>::word
DiscreteNormal<IntType>::LeadingDigit(IntType& p) const {
static const unsigned bits = 8;
static const unsigned num = std::numeric_limits<word>::digits / bits;
STATIC_ASSERT(bits * num == std::numeric_limits<word>::digits,
"Number of digits in word must be multiple of 8");
word s = 0;
for (unsigned c = num; c--;) {
p <<= bits; s <<= bits;
word d = word(p / _sig);
s += d;
p -= IntType(d) * _sig;
}
return s;
}
template<typename IntType> template<class Random>
int DiscreteNormal<IntType>::Choose(Random& r, int m) {
int k = r.template Integer<int>(m);
return k == 0 ? 0 : (k == 1 ? -1 : 1);
}
template<typename IntType> template<class Random>
bool DiscreteNormal<IntType>::less_than(Random& r) const {
for (unsigned j = 0; ; ++j) {
if (j == _m) {
// Need more bits in the old V
if (_l == _m) _v.resize(_l += alloc_incr);
_v[_m++] = r.template Integer<word>();
}
word w = r.template Integer<word>();
if (w > _v[j])
return false; // New V is bigger, so exit
else if (w < _v[j]) {
_v[j] = w; // New V is smaller, update _v
_m = j + 1; // adjusting its size
return true; // and generate the next V
}
// Else w == _v[j] and we need to check the next word
}
}
template<typename IntType> template<class Random>
bool DiscreteNormal<IntType>::less_than(Random& r, word x, IntType p) const {
if (_m == 0) _v[_m++] = r.template Integer<word>();
if (_v[0] != x) return _v[0] < x;
for (unsigned j = 1; ; ++j) {
if (p == 0) return false;
if (j == _m) {
if (_l == _m) _v.resize(_l += alloc_incr);
_v[_m++] = r.template Integer<word>();
}
x = LeadingDigit(p);
if (_v[j] != x) return _v[j] < x;
}
}
template<typename IntType> template<class Random>
bool DiscreteNormal<IntType>::bernoulli(Random& r, word x, IntType p) const {
word w = r.template Integer<word>();
if (w != x) return w < x;
for (;;) {
if (p == 0) return false;
x = LeadingDigit(p);
w = r.template Integer<word>();
if (w != x) return w < x;
}
}
template<typename IntType> template<class Random>
bool DiscreteNormal<IntType>::ExpProbH(Random& r) const {
static const word half = word(1) << (std::numeric_limits<word>::digits - 1);
_m = 0;
if ((_v[_m++] = r.template Integer<word>()) & half) return true;
// Here _v < 1/2. Now loop finding decreasing V. Exit when first
// increasing one is found.
for (unsigned s = 0; ; s ^= 1) { // Parity of loop count
if (!less_than(r)) return s != 0u;
}
}
template<typename IntType> template<class Random>
bool DiscreteNormal<IntType>::ExpProb(Random& r, int n) const {
while (n-- > 0) { if (!ExpProbH(r)) return false; }
return true;
}
template<typename IntType> template<class Random>
int DiscreteNormal<IntType>::ExpProbN(Random& r) const {
int n = 0;
while (ExpProbH(r)) ++n;
return n;
}
template<typename IntType> template<class Random>
bool DiscreteNormal<IntType>::B(Random& r, int k, word x0, IntType xn)
const {
int n = 0, h = 2 * k + 2, f;
_m = 0;
for (;; ++n) {
if ( ((f = k ? 0 : Choose(r, h)) < 0) ||
!(n ? less_than(r) : less_than(r, x0, xn)) ||
((f = k ? Choose(r, h) : f) < 0) ||
(f == 0 && !bernoulli(r, x0, xn)) ) break;
}
return (n % 2) == 0;
}
} // namespace RandomLib
#endif // RANDOMLIB_DISCRETENORMAL_HPP

View File

@ -0,0 +1,328 @@
/**
* \file DiscreteNormalAlt.hpp
* \brief Header for DiscreteNormalAlt
*
* Sample exactly from the discrete normal distribution (alternate version).
*
* Copyright (c) Charles Karney (2013) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_DISCRETENORMALALT_HPP)
#define RANDOMLIB_DISCRETENORMALALT_HPP 1
#include <RandomLib/RandomNumber.hpp>
#include <RandomLib/UniformInteger.hpp>
#include <limits>
namespace RandomLib {
/**
* \brief The discrete normal distribution (alternate version).
*
* Sample integers \e i with probability proportional to
* \f[
* \exp\biggl[-\frac12\biggl(\frac{i-\mu}{\sigma}\biggr)^2\biggr],
* \f]
* where &sigma; and &mu; are given as rationals (the ratio of two integers).
* The sampling is exact (provided that the random generator is ideal). The
* results of this class are UniformInteger objects which represent a
* contiguous range which is a power of 2<sup>\e bits</sup>. This can be
* narrowed down to a specific integer as follows
* \code
#include <iostream>
#include <RandomLib/Random.hpp>
#include <RandomLib/UniformInteger.hpp>
#include <RandomLib/DiscreteNormalAlt.hpp>
int main() {
RandomLib::Random r; // Create r
r.Reseed(); // and give it a unique seed
int sigma_num = 7, sigma_den = 1, mu_num = 1, mu_den = 3;
RandomLib::DiscreteNormalAlt<int,1> d(sigma_num, sigma_den,
mu_num, mu_den);
for (int i = 0; i < 100; ++i) {
RandomLib::UniformInteger<int,1> u = d(r);
std::cout << u << " = ";
std::cout << u(r) << "\n";
}
}
\endcode
* prints out 100 samples with &sigma; = 7 and &mu; = 1/3; the samples are
* first given as a range and then <code>u(r)</code> is used to obtain a
* specific integer. In some applications, it might be possible to avoid
* sampling all the additional digits to get to a specific integer. (An
* example would be drawing a sample which satisfies an inequality.) This
* version is slower (by a factor of about 4 for \e bits = 1) than
* DiscreteNormal on a conventional computer, but may be faster when random
* bits are generated by a slow hardware device.
*
* The basic algorithm is the same as for DiscreteNormal. However randomness
* in metered out \e bits random bits at a time. The algorithm uses the
* least random bits (and is slowest!) when \e bits = 1. This rationing of
* random bits also applies to sampling \e j in the expression
* \f[
* x = x_0 + j/\sigma.
* \f]
* Rather than sampling a definite value for \e j, which then might be
* rejected, \e j is sampled using UniformInteger. UniformInteger uses
* Lumbroso's method from sampling an integer uniformly in [0, \e m) using at
* most 2 + log<sub>2</sub>\e m bits on average (for \e bits = 1). However
* when a UniformInteger object is first constructed it samples at most 3
* bits (on average) to obtain a range for \e j which is power of 2. This
* allows the algorithm to achieve ideal scaling in the limit of large
* &sigma; consuming constant + log<sub>2</sub>&sigma; bits on average. In
* addition it can deliver the resuls in the form of a UniformInteger
* consuming a constant number of bits on average (and then about
* log<sub>2</sub>&sigma; additional bits are required to convert the
* UniformInteger into an integer sample). The consumption of random bits
* (for \e bits = 1) is summarized here \verbatim
min mean max
bits for UniformInteger result 30.4 34.3 35.7
bits for integer result - log2(sigma) 28.8 31.2 32.5
toll 26.8 29.1 30.4 \endverbatim
* These results are averaged over many samples. The "min" results apply
* when &sigma; is a power of 2; the "max" results apply when &sigma; is
* slightly more than a power of two; the "mean" results are averaged over
* &sigma;. The toll is the excess number of bits over the entropy of the
* distribution, which is log<sub>2</sub>(2&pi;\e e)/2 +
* log<sub>2</sub>&sigma; (for &sigma; large).
*
* The data for the first two lines in the table above are taken for the blue
* and red lines in the figure below where the abscissa is the fractional
* part of log<sub>2</sub>&sigma;
* \image html
* discrete-bits.png "Random bits to sample from discrete normal distribution"
*
* This class uses a mutable RandomNumber objects. So a single
* DiscreteNormalAlt object cannot safely be used by multiple threads. In a
* multi-processing environment, each thread should use a thread-specific
* DiscreteNormalAlt object.
*
* @tparam IntType the integer type to use (default int).
**********************************************************************/
template<typename IntType = int, int bits = 1> class DiscreteNormalAlt {
public:
/**
* Constructor.
*
* @param[in] sigma_num the numerator of &sigma;.
* @param[in] sigma_den the denominator of &sigma; (default 1).
* @param[in] mu_num the numerator of &mu; (default 0).
* @param[in] mu_den the denominator of &mu; (default 1).
*
* This may throw an exception is the parameters are such that overflow is
* possible.
**********************************************************************/
DiscreteNormalAlt(IntType sigma_num, IntType sigma_den = 1,
IntType mu_num = 0, IntType mu_den = 1);
/**
* Return a sample.
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @return discrete normal sample in the form of a UniformInteger object.
**********************************************************************/
template<class Random>
UniformInteger<IntType, bits> operator()(Random& r) const;
private:
/**
* sigma = _sig / _d, mu = _imu + _mu / _d, _isig = ceil(sigma)
**********************************************************************/
IntType _sig, _mu, _d, _isig, _imu;
mutable RandomNumber<bits> _p;
mutable RandomNumber<bits> _q;
// ceil(n/d) for d > 0
static IntType iceil(IntType n, IntType d);
// abs(n) needed because Visual Studio's std::abs has problems
static IntType iabs(IntType n);
static IntType gcd(IntType u, IntType v);
/**
* Implement outcomes for choosing with prob (\e x + 2\e k) / (2\e k + 2);
* return:
* - 1 (succeed unconditionally) with prob (\e m &minus; 2) / \e m,
* - 0 (succeed with probability x) with prob 1 / \e m,
* - &minus;1 (fail unconditionally) with prob 1 / \e m.
**********************************************************************/
template<class Random> static int Choose(Random& r, int m);
/**
* Return true with probability exp(&minus;1/2).
**********************************************************************/
template<class Random> bool ExpProbH(Random& r) const;
/**
* Return true with probability exp(&minus;<i>n</i>/2).
**********************************************************************/
template<class Random> bool ExpProb(Random& r, int n) const;
/**
* Return \e n with probability exp(&minus;<i>n</i>/2)
* (1&minus;exp(&minus;1/2)).
**********************************************************************/
template<class Random> int ExpProbN(Random& r) const;
/**
* Algorithm B: true with prob exp(-x * (2*k + x) / (2*k + 2)) where
* x = (xn0 + _d * j) / _sig
**********************************************************************/
template<class Random>
bool B(Random& r, int k, IntType xn0, UniformInteger<IntType, bits>& j)
const;
};
template<typename IntType, int bits>
DiscreteNormalAlt<IntType, bits>::DiscreteNormalAlt
(IntType sigma_num, IntType sigma_den, IntType mu_num, IntType mu_den) {
STATIC_ASSERT(std::numeric_limits<IntType>::is_integer,
"DiscreteNormalAlt: invalid integer type IntType");
STATIC_ASSERT(std::numeric_limits<IntType>::is_signed,
"DiscreteNormalAlt: IntType must be a signed type");
if (!( sigma_num > 0 && sigma_den > 0 && mu_den > 0 ))
throw RandomErr("DiscreteNormalAlt: need sigma > 0");
_imu = mu_num / mu_den;
if (_imu == (std::numeric_limits<IntType>::min)())
throw RandomErr("DiscreteNormalAlt: abs(mu) too large");
mu_num -= _imu * mu_den;
IntType l;
l = gcd(sigma_num, sigma_den); sigma_num /= l; sigma_den /= l;
l = gcd(mu_num, mu_den); mu_num /= l; mu_den /= l;
_isig = iceil(sigma_num, sigma_den);
l = gcd(sigma_den, mu_den);
_sig = sigma_num * (mu_den / l);
_mu = mu_num * (sigma_den / l);
_d = sigma_den * (mu_den / l);
// The rest of the constructor tests for possible overflow
// Check for overflow in computing member variables
IntType maxint = (std::numeric_limits<IntType>::max)();
if (!( mu_den / l <= maxint / sigma_num &&
iabs(mu_num) <= maxint / (sigma_den / l) &&
mu_den / l <= maxint / sigma_den ))
throw RandomErr("DiscreteNormalAlt: sigma or mu overflow");
if (!UniformInteger<IntType, bits>::Check(_isig, _d))
throw RandomErr("DiscreteNormalAlt: overflow in UniformInteger");
// The probability that k = kmax is about 10^-543.
int kmax = 50;
// Check that max plausible result fits in an IntType, i.e.,
// _isig * (kmax + 1) + abs(_imu) does not lead to overflow.
if (!( kmax + 1 <= maxint / _isig &&
_isig * (kmax + 1) <= maxint - iabs(_imu) ))
throw RandomErr("DiscreteNormalAlt: possible overflow a");
// Check xn0 = _sig * k + s * _mu;
if (!( kmax <= maxint / _sig &&
_sig * kmax <= maxint - iabs(_mu) ))
throw RandomErr("DiscreteNormalAlt: possible overflow b");
// Check for overflow in RandomNumber::LessThan(..., UniformInteger& j)
// p0 * b, p0 = arg2 = xn0 = _d - 1
// c *= b, c = arg3 = _d
// digit(D, k) * q, digit(D, k) = b - 1, q = arg4 = _sig
if (!( _d <= maxint >> bits ))
throw std::runtime_error("DiscreteNormalAlt: overflow in RandomNumber a");
if (!( (IntType(1) << bits) - 1 <= maxint / _sig ))
throw std::runtime_error("DiscreteNormalAlt: overflow in RandomNumber b");
}
template<typename IntType, int bits> template<class Random>
UniformInteger<IntType, bits>
DiscreteNormalAlt<IntType, bits>::operator()(Random& r) const {
for (;;) {
int k = ExpProbN(r);
if (!ExpProb(r, k * (k - 1))) continue;
UniformInteger<IntType, bits> j(r, _isig);
IntType
s = r.Boolean() ? -1 : 1,
xn0 = _sig * IntType(k) + s * _mu,
i0 = iceil(xn0, _d); // i = i0 + j
xn0 = i0 * _d - xn0; // xn = xn0 + _d * j
if (!j.LessThan(r, _sig - xn0, _d) ||
(k == 0 && s < 0 && !j.GreaterThan(r, -xn0, _d))) continue;
int h = k + 1; while (h-- && B(r, k, xn0, j));
if (!(h < 0)) continue;
j.Add(i0 + s * _imu);
if (s < 0) j.Negate();
return j;
}
}
template<typename IntType, int bits>
IntType DiscreteNormalAlt<IntType, bits>::iceil(IntType n, IntType d)
{ IntType k = n / d; return k + (k * d < n ? 1 : 0); }
template<typename IntType, int bits>
IntType DiscreteNormalAlt<IntType, bits>::iabs(IntType n)
{ return n < 0 ? -n : n; }
template<typename IntType, int bits>
IntType DiscreteNormalAlt<IntType, bits>::gcd(IntType u, IntType v) {
// Knuth, TAOCP, vol 2, 4.5.2, Algorithm A
u = iabs(u); v = iabs(v);
while (v > 0) { IntType r = u % v; u = v; v = r; }
return u;
}
template<typename IntType, int bits> template<class Random>
int DiscreteNormalAlt<IntType, bits>::Choose(Random& r, int m) {
// Limit base to 2^15 to avoid integer overflow
const int b = bits > 15 ? 15 : bits;
const unsigned mask = (1u << b) - 1;
int n1 = m - 2, n2 = m - 1;
// Evaluate u < n/m where u is a random real number in [0,1). Write u =
// (d + u') / 2^b where d is a random integer in [0,2^b) and u' is in
// [0,1). Then u < n/m becomes u' < n'/m where n' = 2^b * n - d * m and
// exit if n' <= 0 (false) or n' >= m (true).
for (;;) {
int d = (mask & RandomNumber<bits>::RandomDigit(r)) * m;
n1 = (std::max)((n1 << b) - d, 0);
if (n1 >= m) return 1;
n2 = (std::min)((n2 << b) - d, m);
if (n2 <= 0) return -1;
if (n1 == 0 && n2 == m) return 0;
}
}
template<typename IntType, int bits> template<class Random>
bool DiscreteNormalAlt<IntType, bits>::ExpProbH(Random& r) const {
_p.Init();
if (_p.Digit(r, 0) >> (bits - 1)) return true;
for (;;) {
_q.Init(); if (!_q.LessThan(r, _p)) return false;
_p.Init(); if (!_p.LessThan(r, _q)) return true;
}
}
template<typename IntType, int bits> template<class Random>
bool DiscreteNormalAlt<IntType, bits>::ExpProb(Random& r, int n) const {
while (n-- > 0) { if (!ExpProbH(r)) return false; }
return true;
}
template<typename IntType, int bits> template<class Random>
int DiscreteNormalAlt<IntType, bits>::ExpProbN(Random& r) const {
int n = 0;
while (ExpProbH(r)) ++n;
return n;
}
template<typename IntType, int bits> template<class Random> bool
DiscreteNormalAlt<IntType, bits>::B(Random& r, int k, IntType xn0,
UniformInteger<IntType, bits>& j)
const {
int n = 0, m = 2 * k + 2, f;
for (;; ++n) {
if ( ((f = k ? 0 : Choose(r, m)) < 0) ||
(_q.Init(),
!(n ? _q.LessThan(r, _p) : _q.LessThan(r, xn0, _d, _sig, j))) ||
((f = k ? Choose(r, m) : f) < 0) ||
(f == 0 && (_p.Init(), !_p.LessThan(r, xn0, _d, _sig, j))) )
break;
_p.swap(_q); // an efficient way of doing p = q
}
return (n % 2) == 0;
}
} // namespace RandomLib
#endif // RANDOMLIB_DISCRETENORMALALT_HPP

View File

@ -0,0 +1,241 @@
/**
* \file ExactExponential.hpp
* \brief Header for ExactExponential
*
* Sample exactly from an exponential distribution.
*
* Copyright (c) Charles Karney (2006-2012) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_EXACTEXPONENTIAL_HPP)
#define RANDOMLIB_EXACTEXPONENTIAL_HPP 1
#include <RandomLib/RandomNumber.hpp>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional expressions
# pragma warning (push)
# pragma warning (disable: 4127)
#endif
namespace RandomLib {
/**
* \brief Sample exactly from an exponential distribution.
*
* Sample \e x &ge; 0 from exp(&minus;\e x). See:
* - J. von Neumann, Various Techniques used in Connection with Random
* Digits, J. Res. Nat. Bur. Stand., Appl. Math. Ser. 12, 36--38
* (1951), reprinted in Collected Works, Vol. 5, 768--770 (Pergammon,
* 1963).
* - M. Abramowitz and I. A. Stegun, Handbook of Mathematical Functions
* (National Bureau of Standards, 1964), Sec. 26.8.6.c(2).
* - G. E. Forsythe, Von Neumann's Comparison Method for Random Sampling from
* Normal and Other Distributions, Math. Comp. 26, 817--826 (1972).
* - D. E. Knuth, TAOCP, Vol 2, Sec 3.4.1.C.3.
* - D. E. Knuth and A. C. Yao, The Complexity of Nonuniform Random Number
* Generation, in "Algorithms and Complexity" (Academic Press, 1976),
* pp. 357--428.
* - P. Flajolet and N. Saheb, The Complexity of Generating an
* Exponentially Distributed Variate, J. Algorithms 7, 463--488 (1986).
*
* The following code illustrates the basic method given by von Neumann:
* \code
// Return a random number x >= 0 distributed with probability exp(-x).
double ExpDist(RandomLib::Random& r) {
for (unsigned k = 0; ; ++k) {
double x = r.Fixed(), // executed 1/(1-exp(-1)) times on average
p = x, q;
do {
q = r.Fixed(); // executed exp(x)*cosh(x) times on average
if (!(q < p)) return k + x;
p = r.Fixed(); // executed exp(x)*sinh(x) times on average
} while (p < q);
}
}
\endcode
* This returns a result consuming exp(1)/(1 &minus; exp(-1)) = 4.30 random
* numbers on average. (Von Neumann incorrectly states that the method takes
* (1 + exp(1))/(1 &minus; exp(-1)) = 5.88 random numbers on average.)
* Because of the finite precision of Random::Fixed(), the code snippet above
* only approximates exp(&minus;\e x). Instead, it returns \e x with
* probability \e h(1 &minus; \e h)<sup><i>x</i>/<i>h</i></sup> for \e x = \e
* ih, \e h = 2<sup>&minus;53</sup>, and integer \e i &ge; 0.
*
* The above is precisely von Neumann's method. Abramowitz and Stegun
* consider a variant: sample uniform variants until the first is less than
* the sum of the rest. Forsythe converts the < ranking for the runs to &le;
* which makes the analysis of the discrete case more difficult. He also
* drops the "trick" by which the integer part of the deviate is given by the
* number of rejections when finding the fractional part.
*
* Von Neumann says of his method: "The machine has in effect computed a
* logarithm by performing only discriminations on the relative magnitude of
* numbers in (0,1). It is a sad fact of life, however, that under the
* particular conditions of the Eniac it was slightly quicker to use a
* truncated power series for log(1&minus;\e T) than to carry out all the
* discriminations."
*
* Here the code is modified to make it more efficient:
* \code
// Return a random number x >= 0 distributed with probability exp(-x).
double ExpDist(RandomLib::Random& r) {
for (unsigned k = 0; ; ++k) {
double x = r.Fixed(); // executed 1/(1-exp(-1/2)) times on average
if (x >= 0.5) continue;
double p = x, q;
do {
q = r.Fixed(); // executed exp(x)*cosh(x) times on average
if (!(q < p)) return 0.5 * k + x;
p = r.Fixed(); // executed exp(x)*sinh(x) times on average
} while (p < q);
}
}
\endcode
* In addition, the method is extended to use infinite precision uniform
* deviates implemented by RandomNumber and returning \e exact results for
* the exponential distribution. This is possible because only comparisons
* are done in the method. The template parameter \e bits specifies the
* number of bits in the base used for RandomNumber (i.e., base =
* 2<sup><i>bits</i></sup>).
*
* For example the following samples from an exponential distribution and
* prints various representations of the result.
* \code
#include <RandomLib/RandomNumber.hpp>
#include <RandomLib/ExactExponential.hpp>
RandomLib::Random r;
const int bits = 1;
RandomLib::ExactExponential<bits> edist;
for (size_t i = 0; i < 10; ++i) {
RandomLib::RandomNumber<bits> x = edist(r); // Sample
std::pair<double, double> z = x.Range();
std::cout << x << " = " // Print in binary with ellipsis
<< "(" << z.first << "," << z.second << ")"; // Print range
double v = x.Value<double>(r); // Round exactly to nearest double
std::cout << " = " << v << "\n";
}
\endcode
* Here's a possible result: \verbatim
0.0111... = (0.4375,0.5) = 0.474126
10.000... = (2,2.125) = 2.05196
1.00... = (1,1.25) = 1.05766
0.010... = (0.25,0.375) = 0.318289
10.1... = (2.5,3) = 2.8732
0.0... = (0,0.5) = 0.30753
0.101... = (0.625,0.75) = 0.697654
0.00... = (0,0.25) = 0.0969214
0.0... = (0,0.5) = 0.194053
0.11... = (0.75,1) = 0.867946 \endverbatim
* First number is in binary with ... indicating an infinite sequence of
* random bits. Second number gives the corresponding interval. Third
* number is the result of filling in the missing bits and rounding exactly
* to the nearest representable double.
*
* This class uses some mutable RandomNumber objects. So a single
* ExactExponential object cannot safely be used by multiple threads. In a
* multi-processing environment, each thread should use a thread-specific
* ExactExponential object. In addition, these should be invoked with
* thread-specific random generator objects.
*
* @tparam bits the number of bits in each digit.
**********************************************************************/
template<int bits = 1> class ExactExponential {
public:
/**
* Return a random deviate with an exponential distribution, exp(&minus;\e
* x) for \e x &ge; 0. Requires 7.232 bits per invocation for \e bits = 1.
* The average number of bits in the fraction = 1.743. The relative
* frequency of the results for the fractional part with \e bits = 1 is
* shown by the histogram
* \image html exphist.png
* The base of each rectangle gives the range represented by the
* corresponding binary number and the area is proportional to its
* frequency. A PDF version of this figure is given
* <a href="exphist.pdf">here</a>. This allows the figure to be magnified
* to show the rectangles for all binary numbers up to 9 bits. Note that
* this histogram was generated using an earlier version of
* ExactExponential (thru version 1.3) that implements von Neumann's
* original method. The histogram generated with the current version of
* ExactExponential is the same as this figure for \e u in [0, 1/2]. The
* histogram for \e u in [1/2, 1] is obtained by shifting and scaling the
* part for \e u in [0, 1/2] to fit under the exponential curve.
*
* Another way of assessing the efficiency of the algorithm is thru the
* mean value of the balance = (number of random bits consumed) &minus;
* (number of bits in the result). If we code the result in mixed Knuth
* and Yao's unary-binary notation (integer is given in unary, followed by
* "0" as a separator, followed by the fraction in binary), then the mean
* balance is 3.906. (Flajolet and Saheb analyzed the algorithm based on
* the original von Neumann method and showed that the balance is 5.680 in
* that case.)
*
* For \e bits large, the mean number of random digits is exp(1/2)/(1
* &minus; exp(&minus;1/2)) = 4.19 (versus 4.30 digits for the original
* method).
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @return the random sample.
**********************************************************************/
template<class Random> RandomNumber<bits> operator()(Random& r) const;
private:
/**
* Return true with probability exp(&minus;\e p) for \e p in (0,1/2).
**********************************************************************/
template<class Random> bool
ExpFraction(Random& r, RandomNumber<bits>& p) const;
mutable RandomNumber<bits> _x;
mutable RandomNumber<bits> _v;
mutable RandomNumber<bits> _w;
};
template<int bits> template<class Random> RandomNumber<bits>
ExactExponential<bits>::operator()(Random& r) const {
// A simple rejection method gives the 1/2 fractional part. The number of
// rejections gives the multiples of 1/2.
//
// bits: used fract un-bin balance double
// original stats: 9.31615 2.05429 3.63628 5.67987 61.59456
// new stats: 7.23226 1.74305 3.32500 3.90725 59.82198
//
// The difference between un-bin and fract is exp(1)/(exp(1)-1) = 1.58198
_x.Init();
int k = 0;
while (!ExpFraction(r, _x)) { // Executed 1/(1 - exp(-1/2)) on average
++k;
_x.Init();
}
if (k & 1) _x.RawDigit(0) += 1U << (bits - 1);
_x.AddInteger(k >> 1);
return _x;
}
template<int bits> template<class Random> bool
ExactExponential<bits>::ExpFraction(Random& r, RandomNumber<bits>& p)
const {
// The early bale out
if (p.Digit(r, 0) >> (bits - 1)) return false;
// Implement the von Neumann algorithm
_w.Init();
if (!_w.LessThan(r, p)) // if (w < p)
return true;
while (true) { // Unroll loop to avoid copying RandomNumber
_v.Init(); // v = r.Fixed();
if (!_v.LessThan(r, _w)) // if (v < w)
return false;
_w.Init(); // w = r.Fixed();
if (!_w.LessThan(r, _v)) // if (w < v)
return true;
}
}
} // namespace RandomLib
#if defined(_MSC_VER)
# pragma warning (pop)
#endif
#endif // RANDOMLIB_EXACTEXPONENTIAL_HPP

View File

@ -0,0 +1,417 @@
/**
* \file ExactNormal.hpp
* \brief Header for ExactNormal
*
* Sample exactly from a normal distribution.
*
* Copyright (c) Charles Karney (2011-2012) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_EXACTNORMAL_HPP)
#define RANDOMLIB_EXACTNORMAL_HPP 1
#include <RandomLib/RandomNumber.hpp>
#include <algorithm> // for max/min
#if defined(_MSC_VER)
// Squelch warnings about constant conditional expressions
# pragma warning (push)
# pragma warning (disable: 4127)
#endif
namespace RandomLib {
/**
* \brief Sample exactly from a normal distribution.
*
* Sample \e x from exp(&minus;<i>x</i><sup>2</sup>/2) / sqrt(2&pi;). For
* background, see:
* - J. von Neumann, Various Techniques used in Connection with Random
* Digits, J. Res. Nat. Bur. Stand., Appl. Math. Ser. 12, 36--38
* (1951), reprinted in Collected Works, Vol. 5, 768--770 (Pergammon,
* 1963).
* - D. E. Knuth and A. C. Yao, The Complexity of Nonuniform Random Number
* Generation, in "Algorithms and Complexity" (Academic Press, 1976),
* pp. 357--428.
* - P. Flajolet and N. Saheb, The Complexity of Generating an Exponentially
* Distributed Variate, J. Algorithms 7, 463--488 (1986).
*
* The algorithm is given in
* - C. F. F. Karney, <i>Sampling exactly from the normal distribution</i>,
* http://arxiv.org/abs/1303.6257 (Mar. 2013).
* .
* In brief, the algorithm is:
* -# Select an integer \e k &ge; 0 with probability
* exp(&minus;<i>k</i>/2) (1&minus;exp(&minus;1/2)).
* -# Accept with probability
* exp(&minus; \e k (\e k &minus; 1) / 2); otherwise, reject and start
* over at step 1.
* -# Sample a random number \e x uniformly from [0,1).
* -# Accept with probability exp(&minus; \e x (\e x + 2\e k) / 2);
* otherwise, reject and start over at step 1.
* -# Set \e x = \e k + \e x.
* -# With probability 1/2, negate \e x.
* -# Return \e x.
* .
* It is easy to show that this algorithm returns samples from the normal
* distribution with zero mean and unit variance. Futhermore, all these
* steps can be carried out exactly as follows:
* - Step 1:
* - \e k = 0;
* - while (ExpProb(&minus;1/2)) increment \e k by 1.
* - Step 2:
* - \e n = \e k (\e k &minus; 1) / 2;
* - while (\e n > 0)
* { if (!ExpProb(&minus;1/2)) go to step 1; decrement \e n by 1; }
* - Step 4:
* - repeat \e k + 1 times:
* if (!ExpProb(&minus; \e x (\e x + 2\e k) / (2\e k + 2))) go to step 1.
* .
* Here, ExpProb(&minus;\e p) returns true with probability exp(&minus;\e p).
* With \e p = 1/2 (steps 1 and 2), this is implemented with von Neumann's
* rejection technique:
* - Generate a sequence of random numbers <i>U</i><sub><i>i</i></sub> and
* find the greatest \e n such that 1/2 > <i>U</i><sub>1</sub> >
* <i>U</i><sub>2</sub> > . . . > <i>U</i><sub><i>n</i></sub>. (The
* resulting value of \e n may be 0.)
* - If \e n is even, accept and return true; otherwise (\e n odd), reject
* and return false.
* .
* For \e p = \e x (\e x + 2\e k) / (2\e k + 2) (step 4), we generalize von
* Neumann's procedure as follows:
* - Generate two sequences of random numbers <i>U</i><sub><i>i</i></sub>
* and <i>V</i><sub><i>i</i></sub> and find the greatest \e n such that
* both the following conditions hold
* - \e x > <i>U</i><sub>1</sub> > <i>U</i><sub>2</sub> > . . . >
* <i>U</i><sub><i>n</i></sub>;
* - <i>V</i><sub><i>i</i></sub> &lt; (\e x + 2 \e k) / (2 \e k + 2) for
* all \e i in [1, \e n].
* .
* (The resulting value of \e n may be 0.)
* - If \e n is even, accept (return true); otherwise (\e n odd), reject
* (return false).
* .
* Here, instead of testing <i>V</i><sub><i>i</i></sub> &lt; (\e x + 2 \e k)
* / (2 \e k + 2), we carry out the following tests:
* - return true, with probability 2 \e k / (2 \e k + 2);
* - return false, with probability 1 / (2 \e k + 2);
* - otherwise (also with probability 1 / (2 \e k + 2)),
* return \e x > <i>V</i><sub><i>i</i></sub>.
* .
* The resulting method now entails evaluation of simple fractional
* probabilities (e.g., 1 / (2 \e k + 2)), or comparing random numbers (e.g.,
* <i>U</i><sub>1</sub> > <i>U</i><sub>2</sub>). These may be carried out
* exactly with a finite mean running time.
*
* With \e bits = 1, this consumes 30.1 digits on average and the result has
* 1.19 digits in the fraction. It takes about 676 ns to generate a result
* (1460 ns, including the time to round it to a double). With bits = 32, it
* takes 437 ns to generate a result (621 ns, including the time to round it
* to a double). In contrast, NormalDistribution takes about 44 ns to
* generate a double result.
*
* Another way of assessing the efficiency of the algorithm is thru the mean
* value of the balance = (number of random bits consumed) &minus; (number of
* bits in the result). If we code the result in Knuth & Yao's unary-binary
* notation, then the mean balance is 26.6.
*
* For example the following samples from a normal exponential distribution
* and prints various representations of the result.
* \code
#include <RandomLib/RandomNumber.hpp>
#include <RandomLib/ExactNormal.hpp>
RandomLib::Random r;
const int bits = 1;
RandomLib::ExactNormal<bits> ndist;
for (size_t i = 0; i < 10; ++i) {
RandomLib::RandomNumber<bits> x = ndist(r); // Sample
std::pair<double, double> z = x.Range();
std::cout << x << " = " // Print in binary with ellipsis
<< "(" << z.first << "," << z.second << ")"; // Print range
double v = x.Value<double>(r); // Round exactly to nearest double
std::cout << " = " << v << "\n";
}
\endcode
* Here's a possible result: \verbatim
-1.00... = (-1.25,-1) = -1.02142
-0.... = (-1,0) = -0.319708
0.... = (0,1) = 0.618735
-0.0... = (-0.5,0) = -0.396591
0.0... = (0,0.5) = 0.20362
0.0... = (0,0.5) = 0.375662
-1.111... = (-2,-1.875) = -1.88295
-1.10... = (-1.75,-1.5) = -1.68088
-0.... = (-1,0) = -0.577547
-0.... = (-1,0) = -0.890553
\endverbatim
* First number is in binary with ... indicating an infinite sequence of
* random bits. Second number gives the corresponding interval. Third
* number is the result of filling in the missing bits and rounding exactly
* to the nearest representable double.
*
* This class uses some mutable RandomNumber objects. So a single
* ExactNormal object cannot safely be used by multiple threads. In a
* multi-processing environment, each thread should use a thread-specific
* ExactNormal object. In addition, these should be invoked with
* thread-specific random generator objects.
*
* @tparam bits the number of bits in each digit.
**********************************************************************/
template<int bits = 1> class ExactNormal {
public:
/**
* Return a random deviate with a normal distribution of mean 0 and
* variance 1.
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @return the random sample.
**********************************************************************/
template<class Random> RandomNumber<bits> operator()(Random& r) const;
private:
/**
* Return true with probability exp(&minus;1/2). For \e bits = 1, this
* consumes, on average, \e t = 2.846 random digits. We have \e t = \e a
* (1&minus;exp(&minus;1/2)) + \e b exp(&minus;1/2), where \e a is the mean
* bit count for false result = 3.786 and \e b is the mean bit count for
* true result = 2.236.
**********************************************************************/
template<class Random> bool ExpProbH(Random& r) const;
/**
* Return true with probability exp(&minus;<i>n</i>/2). For \e bits = 1,
* this consumes, on average, \e t
* (1&minus;exp(&minus;<i>n</i>/2))/(1&minus;exp(&minus;1/2)) random
* digits. A true result uses \e n \e b random digits. A false result
* uses \e a + \e b [exp(&minus;1/2)/(1&minus;exp(&minus;1/2)) &minus;
* <i>n</i> exp(&minus;<i>n</i>/2)/(1&minus;exp(&minus;<i>n</i>/2))] random
* digits.
**********************************************************************/
template<class Random> bool ExpProb(Random& r, unsigned n) const;
/**
* Return \e n with probability exp(&minus;<i>n</i>/2)
* (1&minus;exp(&minus;1/2)). For \e bits = 1, this consumes \e n \e a +
* \e b random digits if the result is \e n. Averaging over \e n this
* becomes (\e b &minus; (\e b &minus; \e a) exp(&minus;1/2))/(1 &minus;
* exp(&minus;1/2)) digits.
**********************************************************************/
template<class Random> unsigned ExpProbN(Random& r) const;
/**
* Return true with probability 1/2. This is similar to r.Boolean() but
* forces all the random results to come thru RandomNumber::RandomDigit.
**********************************************************************/
template<class Random> static bool Boolean(Random& r) {
// A more general implementation which deals with the case where the base
// might be negative is:
//
// const unsigned base = 1u << bits;
// unsigned b;
// do
// b = RandomNumber<bits>::RandomDigit(r);
// while (b == (base / 2) * 2);
// return b & 1u;
return RandomNumber<bits>::RandomDigit(r) & 1u;
}
/**
* Implement outcomes for choosing with prob (\e x + 2\e k) / (2\e k + 2);
* return:
* - 1 (succeed unconditionally) with prob (2\e k) / (2\e k + 2),
* - 0 (succeed with probability x) with prob 1 / (2\e k + 2),
* - &minus;1 (fail unconditionally) with prob 1 / (2\e k + 2).
* .
* This simulates \code
double x = r.Fixed(); // Uniform in [0,1)
x *= (2 * k + 2);
return x < 2 * k ? 1 : (x < 2 * k + 1 ? 0 : -1);
\endcode
**********************************************************************/
template<class Random> static int Choose(Random& r, int k) {
// Limit base to 2^15 to avoid integer overflow
const int b = bits > 15 ? 15 : bits;
const unsigned mask = (1u << b) - 1;
const int m = 2 * k + 2;
int n1 = m - 2, n2 = m - 1;
// Evaluate u < n/m where u is a random real number in [0,1). Write u =
// (d + u') / 2^b where d is a random integer in [0,2^b) and u' is in
// [0,1). Then u < n/m becomes u' < n'/m where n' = 2^b * n - d * m and
// exit if n' <= 0 (false) or n' >= m (true).
while (true) {
int d = (mask & RandomNumber<bits>::RandomDigit(r)) * m;
n1 = (std::max)((n1 << b) - d, 0);
if (n1 >= m) return 1;
n2 = (std::min)((n2 << b) - d, m);
if (n2 <= 0) return -1;
if (n1 == 0 && n2 == m) return 0;
}
}
mutable RandomNumber<bits> _x;
mutable RandomNumber<bits> _p;
mutable RandomNumber<bits> _q;
};
template<int bits> template<class Random>
bool ExactNormal<bits>::ExpProbH(Random& r) const {
// Bit counts
// ExpProbH: 2.846 = 3.786 * (1-exp(-1/2)) + 2.236 * exp(-1/2)
// t = a * (1-exp(-1/2)) + b * exp(-1/2)
// t = mean bit count for result = 2.846
// a = mean bit count for false result = 3.786
// b = mean bit count for true result = 2.236
//
// for bits large
// t = exp(1/2) = 1.6487
// a = exp(1/2)/(2*(1-exp(-1/2))) = 2.0951
// b = exp(1/2)/(2*exp(-1/2)) = 1.3591
//
// Results for Prob(exp(-1)), omitting first test
// total = 5.889, false = 5.347, true = 6.826
//
// Results for Prob(exp(-1)) using ExpProbH(r) && ExpProbH(r),
// total = 4.572 = (1 - exp(-1)) * a + (1 + exp(-1/2)) * exp(-1/2) * b
// false = 4.630 = a + b * exp(-1/2)/(1 + exp(-1/2)),
// true = 4.472 = 2 * b
_p.Init();
if (_p.Digit(r, 0) >> (bits - 1)) return true;
while (true) {
_q.Init(); if (!_q.LessThan(r, _p)) return false;
_p.Init(); if (!_p.LessThan(r, _q)) return true;
}
}
template<int bits> template<class Random>
bool ExactNormal<bits>::ExpProb(Random& r, unsigned n) const {
// Bit counts
// ExpProb(n): t * (1-exp(-n/2))/(1-exp(-1/2))
// ExpProb(n) = true: n * b
// ExpProb(n) = false: a +
// b * (exp(-1/2)/(1-exp(-1/2)) - n*exp(-n/2)/(1-exp(-n/2)))
while (n--) { if (!ExpProbH(r)) return false; }
return true;
}
template<int bits> template<class Random>
unsigned ExactNormal<bits>::ExpProbN(Random& r) const {
// Bit counts
// ExpProbN() = n: n * a + b
unsigned n = 0;
while (ExpProbH(r)) ++n;
return n;
}
template<int bits> template<class Random> RandomNumber<bits>
ExactNormal<bits>::operator()(Random& r) const {
// With bits = 1,
// - mean number of bits used = 30.10434
// - mean number of bits in fraction = 1.18700
// - mean number of bits in result = 3.55257 (unary-binary)
// - mean balance = 30.10434 - 3.55257 = 26.55177
// - mean number of bits to generate a double = 83.33398
// .
// Note
// - unary-binary notation (Knuth + Yao, 1976): write x = n + y, with n =
// integer and y in [0,1). If n >=0, then write (n+1) 1's followed by a
// 0; otherwise (n < 0), write (-n) 0's followed by a 1. Write y as a
// binary fraction.
// - (bits in result) - (bits in fraction) = 2 (for encoding overhead for
// the integer part) + 0.36557, where 0.36557 = (bits used for integer
// part) = sum(k*int(sqrt(2/pi)*exp(-x^2/2), x=k..k+1), k=0..inf)
// - (bits for double) approx (bits used) - (bits in fraction) + 1 (for
// guard bit) + 53.41664 where 53.41664 = (bits in fraction of double) =
// sum((52-l)*int(sqrt(2/pi)*exp(-x^2/2), x=2^l,2^(l+1)), l=-inf..inf)
// This is approximate because it doesn't account for the minimum
// exponent, denormalized numbers, and rounding changing the exponent.
//
while (true) {
// Executed sqrt(2/pi)/(1-exp(-1/2)) = 2.027818889827955 times on
// average.
unsigned k = ExpProbN(r); // the integer part of the result.
if (ExpProb(r, (k - 1) * k)) {
// Probability that this test succeeds is
// (1 - exp(-1/2)) * sum(exp(-k/2) * exp(-(k-1)*k/2), k=0..inf))
// = (1 - exp(-1/2)) * G = 0.689875359564630
// where G = sum(exp(-k^2/2, k=0..inf) = 1.75331414402145
// For k == 0, sample from exp(-x^2/2) for x in [0,1]. This succeeds
// with probability int(exp(-x^2/2),x=0..1).
//
// For general k, substitute x' = x + k in exp(-x'^2/2), and obtain
// exp(-k^2/2) * exp(-x*(x+2*k)/2). So sample from exp(-x*(x+2*k)/2).
// This succeeds with probability int(exp(-x*(x+2*k)/2),x=0..1) =
// int(exp(-x^2/2),x=k..k+1)*exp(k^2/2) =
//
// 0.8556243918921 for k = 0
// 0.5616593588061 for k = 1
// 0.3963669350376 for k = 2
// 0.2974440159655 for k = 3
// 0.2345104783458 for k = 4
// 0.1921445042826 for k = 5
//
// Returns a result with prob sqrt(pi/2) / G = 0.714825772431666;
// otherwise another trip through the outer loop is taken.
_x.Init();
unsigned s = 1;
for (unsigned j = 0; j <= k; ++j) { // execute k + 1 times
bool first;
for (s = 1, first = true; ; s ^= 1, first = false) {
// A simpler algorithm is indicated by ALT, results in
// - mean number of bits used = 29.99968
// - mean number of bits in fraction = 1.55580
// - mean number of bits in result = 3.92137 (unary-binary)
// - mean balance = 29.99968 - 3.92137 = 26.07831
// - mean number of bits to generate a double = 82.86049
// .
// This has a smaller balance (by 0.47 bits). However the number
// of bits in the fraction is larger by 0.37
if (first) { // ALT: if (false) {
// This implements the success prob (x + 2*k) / (2*k + 2).
int y = Choose(r, k);
if (y < 0) break; // the y test fails
_q.Init();
if (y > 0) { // the y test succeeds just test q < x
if (!_q.LessThan(r, _x)) break;
} else { // the y test is ambiguous
// Test max(q, p) < x. List _q before _p since it ends up with
// slightly more digits generated (and these will be used
// subsequently). (_p's digits are immediately thrown away.)
_p.Init(); if (!_x.GreaterPair(r, _q, _p)) break;
}
} else {
// Split off the failure test for k == 0, i.e., factor the prob
// x/2 test into the product: 1/2 (here) times x (in assignment
// of y).
if (k == 0 && Boolean(r)) break;
// ALT: _q.Init(); if (!_q.LessThan(r, first ? _x : _p)) break;
_q.Init(); if (!_q.LessThan(r, _p)) break;
// succeed with prob k == 0 ? x : (x + 2*k) / (2*k + 2)
int y = k == 0 ? 0 : Choose(r, k);
if (y < 0)
break;
else if (y == 0) {
_p.Init(); if (!_p.LessThan(r, _x)) break;
}
}
_p.swap(_q); // a fast way of doing p = q
}
if (s == 0) break;
}
if (s != 0) {
_x.AddInteger(k);
if (Boolean(r)) _x.Negate(); // half of the numbers are negative
return _x;
}
}
}
}
} // namespace RandomLib
#if defined(_MSC_VER)
# pragma warning (pop)
#endif
#endif // RANDOMLIB_EXACTNORMAL_HPP

View File

@ -0,0 +1,100 @@
/**
* \file ExactPower.hpp
* \brief Header for ExactPower
*
* Sample exactly from a power distribution.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_EXACTPOWER_HPP)
#define RANDOMLIB_EXACTPOWER_HPP 1
#include <RandomLib/RandomNumber.hpp>
namespace RandomLib {
/**
* \brief Sample exactly from a power distribution.
*
* Sample exactly from power distribution (<i>n</i> + 1)
* <i>x</i><sup><i>n</i></sup> for \e x in (0,1) and integer \e n &ge; 0 using
* infinite precision. The template parameter \e bits specifies the number
* of bits in the base used for RandomNumber (i.e., base =
* 2<sup><i>bits</i></sup>).
*
* This class uses some mutable RandomNumber objects. So a single ExactPower
* object cannot safely be used by multiple threads. In a multi-processing
* environment, each thread should use a thread-specific ExactPower object.
* In addition, these should be invoked with thread-specific random generator
* objects.
*
* @tparam bits the number of bits in each digit.
**********************************************************************/
template<int bits = 1> class ExactPower {
public:
/**
* Return the random deviate with a power distribution, (<i>n</i> + 1)
* <i>x</i><sup><i>n</i></sup> for \e x in (0,1) and integer \e n &ge; 0.
* Returned result is a RandomNumber with base 2<sup><i>bits</i></sup>.
* For \e bits = 1, the number of random bits in the result and consumed
* are as follows: \verbatim
n random bits
result consumed
0 0 0
1 2 4
2 2.33 6.67
3 2.67 9.24
4 2.96 11.71
5 3.20 14.11
6 3.41 16.45
7 3.59 18.75
8 3.75 21.01
9 3.89 23.25
10 4.02 25.47
\endverbatim
* The relative frequency of the results with \e bits = 1 and \e n = 2 can
* be is shown by the histogram
* \image html powerhist.png
* The base of each rectangle gives the range represented by the
* corresponding binary number and the area is proportional to its
* frequency. A PDF version of this figure
* <a href="powerhist.pdf">here</a>. This allows the figure to be
* magnified to show the rectangles for all binary numbers up to 9 bits.
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in] n the power.
* @return the random sample.
**********************************************************************/
template<class Random>
RandomNumber<bits> operator()(Random& r, unsigned n) const;
private:
mutable RandomNumber<bits> _x;
mutable RandomNumber<bits> _y;
};
template<int bits> template<class Random> RandomNumber<bits>
ExactPower<bits>::operator()(Random& r, unsigned n) const {
// Return max(u_0, u_1, u_2, ..., u_n). Equivalent to taking the
// (n+1)th root of u_0.
_x.Init();
for (; n--;) {
_y.Init();
// For bits = 1, we can save 1 bit on the first iteration by using a
// technique suggested by Knuth and Yao (1976). When comparing the
// digits of x and y, use 1 bit to determine if the digits are the same.
// If they are, then use another bit for the value of the digit. If they
// are not, then the next bit of the maximum must be 1 (avoiding using a
// second bit). Applying this optimization to subsequent iterations
// (when x already is filled with some bits) gets trickier.
if (_x.LessThan(r, _y))
_x.swap(_y); // x = y;
}
return _x;
}
} // namespace RandomLib
#endif // RANDOMLIB_EXACTPOWER_HPP

View File

@ -0,0 +1,69 @@
/**
* \file ExponentialDistribution.hpp
* \brief Header for ExponentialDistribution
*
* Sample from an exponential distribution.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_EXPONENTIALDISTRIBUTION_HPP)
#define RANDOMLIB_EXPONENTIALDISTRIBUTION_HPP 1
#include <cmath>
namespace RandomLib {
/**
* \brief The exponential distribution.
*
* Sample from the distribution exp(&minus;<i>x</i>/&mu;) for \e x &ge; 0.
* This uses the logarithm method, see Knuth, TAOCP, Vol 2, Sec 3.4.1.D.
* Example \code
#include <RandomLib/ExponentialDistribution.hpp>
RandomLib::Random r;
std::cout << "Seed set to " << r.SeedString() << "\n";
RandomLib::ExponentialDistribution<double> expdist;
std::cout << "Select from exponential distribution:";
for (size_t i = 0; i < 10; ++i)
std::cout << " " << expdist(r);
std::cout << "\n";
\endcode
*
* @tparam RealType the real type of the results (default double).
**********************************************************************/
template<typename RealType = double> class ExponentialDistribution {
public:
/**
* The type returned by ExponentialDistribution::operator()(Random&)
**********************************************************************/
typedef RealType result_type;
/**
* Return a sample of type RealType from the exponential distribution and
* mean &mu;. This uses Random::FloatU() which avoids taking log(0) and
* allows rare large values to be returned. If &mu; = 1, minimum returned
* value = 0 with prob 1/2<sup><i>p</i></sup>; maximum returned value =
* log(2)(\e p + \e e) with prob 1/2<sup><i>p</i> + <i>e</i></sup>. Here
* \e p is the precision of real type RealType and \e e is the exponent
* range.
*
* @tparam Random the type of RandomCanonical generator.
* @param[in,out] r the RandomCanonical generator.
* @param[in] mu the mean value of the exponential distribution (default 1).
* @return the random sample.
**********************************************************************/
template<class Random>
RealType operator()(Random& r, RealType mu = RealType(1)) const throw();
};
template<typename RealType> template<class Random> inline RealType
ExponentialDistribution<RealType>::operator()(Random& r, RealType mu) const
throw() {
return -mu * std::log(r.template FloatU<RealType>());
}
} // namespace RandomLib
#endif // RANDOMLIB_EXPONENTIALDISTRIBUTION_HPP

View File

@ -0,0 +1,166 @@
/**
* \file ExponentialProb.hpp
* \brief Header for ExponentialProb
*
* Return true with probabililty exp(-\e p).
*
* Copyright (c) Charles Karney (2006-2012) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_EXPONENTIALPROB_HPP)
#define RANDOMLIB_EXPONENTIALPROB_HPP 1
#include <vector>
#include <limits>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional expressions
# pragma warning (push)
# pragma warning (disable: 4127)
#endif
namespace RandomLib {
/**
* \brief The exponential probability.
*
* Return true with probability exp(&minus;\e p). Basic method taken from:\n
* J. von Neumann,\n Various Techniques used in Connection with Random
* Digits,\n J. Res. Nat. Bur. Stand., Appl. Math. Ser. 12, 36--38
* (1951),\n reprinted in Collected Works, Vol. 5, 768--770 (Pergammon,
* 1963).\n See also the references given for the ExactExponential class.
*
* Here the method is extended to be exact by generating sufficient bits in
* the random numbers in the algorithm to allow the unambiguous comparisons
* to be made.
*
* Here's one way of sampling from a normal distribution with zero mean and
* unit variance in the interval [&minus;1,1] with reasonable accuracy:
* \code
#include <RandomLib/Random.hpp>
#include <RandomLib/ExponentialProb.hpp>
double Normal(RandomLib::Random& r) {
double x;
RandomLib::ExponentialProb e;
do
x = r.FloatW();
while ( !e(r, - 0.5 * x * x) );
return x;
}
\endcode
* (Note that the ExactNormal class samples from the normal distribution
* exactly.)
*
* This class uses a mutable private vector. So a single ExponentialProb
* object cannot safely be used by multiple threads. In a multi-processing
* environment, each thread should use a thread-specific ExponentialProb
* object.
**********************************************************************/
class ExponentialProb {
private:
typedef unsigned word;
public:
ExponentialProb() : _v(std::vector<word>(alloc_incr)) {}
/**
* Return true with probability exp(&minus;\e p). Returns false if \e p
* &le; 0. For in \e p (0,1], it requires about exp(\e p) random deviates.
* For \e p large, it requires about exp(1)/(1 &minus; exp(&minus;1))
* random deviates.
*
* @tparam RealType the real type of the argument.
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in] p the probability.
* @return true with probability \e p.
**********************************************************************/
template<typename RealType, class Random>
bool operator()(Random& r, RealType p) const;
private:
/**
* Return true with probability exp(&minus;\e p) for \e p in [0,1].
**********************************************************************/
template<typename RealType, class Random>
bool ExpFraction(Random& r, RealType p) const;
/**
* Holds as much of intermediate uniform deviates as needed.
**********************************************************************/
mutable std::vector<word> _v;
/**
* Increment on size of _v.
**********************************************************************/
static const unsigned alloc_incr = 16;
};
template<typename RealType, class Random>
bool ExponentialProb::operator()(Random& r, RealType p) const {
STATIC_ASSERT(!std::numeric_limits<RealType>::is_integer,
"ExponentialProb(): invalid real type RealType");
return p <= 0 || // True if p <=0
// Ensure p - 1 < p. Also deal with IsNaN(p)
( p < RealType(1)/std::numeric_limits<RealType>::epsilon() &&
// exp(a+b) = exp(a) * exp(b)
ExpFraction(r, p < RealType(1) ? p : RealType(1)) &&
( p <= RealType(1) || operator()(r, p - RealType(1)) ) );
}
template<typename RealType, class Random>
bool ExponentialProb::ExpFraction(Random& r, RealType p) const {
// Base of _v is 2^c. Adjust so that word(p) doesn't lose precision.
static const int c = // The Intel compiler needs this to be static??
std::numeric_limits<word>::digits <
std::numeric_limits<RealType>::digits ?
std::numeric_limits<word>::digits :
std::numeric_limits<RealType>::digits;
// m gives number of valid words in _v
unsigned m = 0, l = unsigned(_v.size());
if (p < RealType(1))
while (true) {
if (p <= RealType(0))
return true;
// p in (0, 1)
if (l == m)
_v.resize(l += alloc_incr);
_v[m++] = r.template Integer<word, c>();
p *= std::pow(RealType(2), c); // p in (0, 2^c)
word w = word(p); // w in [0, 2^c)
if (_v[m - 1] > w)
return true;
else if (_v[m - 1] < w)
break;
else // _v[m - 1] == w
p -= RealType(w); // p in [0, 1)
}
// Here _v < p. Now loop finding decreasing V. Exit when first increasing
// one is found.
for (unsigned s = 0; ; s ^= 1) { // Parity of loop count
for (unsigned j = 0; ; ++j) {
if (j == m) {
// Need more bits in the old V
if (l == m)
_v.resize(l += alloc_incr);
_v[m++] = r.template Integer<word, c>();
}
word w = r.template Integer<word, c>();
if (w > _v[j])
return s != 0u; // New V is bigger, so exit
else if (w < _v[j]) {
_v[j] = w; // New V is smaller, update _v
m = j + 1; // adjusting its size
break; // and generate the next V
}
// Else w == _v[j] and we need to check the next c bits
}
}
}
} // namespace RandomLib
#if defined(_MSC_VER)
# pragma warning (pop)
#endif
#endif // RANDOMLIB_EXPONENTIALPROB_HPP

View File

@ -0,0 +1,67 @@
/**
* \file InverseEProb.hpp
* \brief Header for InverseEProb
*
* Return true with probabililty 1/\e e.
*
* Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed under
* the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_INVERSEEPROB_HPP)
#define RANDOMLIB_INVERSEEPROB_HPP 1
#include <vector>
#include <RandomLib/Random.hpp>
namespace RandomLib {
/**
* \brief Return true with probability 1/\e e = exp(&minus;1).
*
* InverseEProb p; p(Random& r) returns true with prob 1/\e e using von
* Neumann's rejection method. It consumes 4.572 bits per call on average.
*
* This class illustrates how to return an exact result using coin tosses
* only. A more efficient way of returning an exact result would be to use
* ExponentialProb p; p(r, 1.0f);
**********************************************************************/
class InverseEProb {
private:
mutable std::vector<bool> _p;
template<class Random> bool exph(Random& r) {
// Return true with prob 1/sqrt(e).
if (r.Boolean()) return true;
_p.clear(); // vector of bits in p
_p.push_back(false);
for (bool s = false; ; s = !s) { // s is a parity
for (size_t i = 0; ; ++i) { // Compare bits of p and q
if (i == _p.size())
_p.push_back(r.Boolean()); // Generate next bit of p if necessary
if (r.Boolean()) { // Half the time the bits differ
if (_p[i]) { // p's bit is 1, so q is smaller, update p
_p[i] = false; // Last bit of q 0
if (++i < _p.size()) _p.resize(i); // p = q
break;
} else
return s; // p's bit is 0, so q is bigger, return parity
} // The other half of the time the bits match, so go to next bit
}
}
}
public:
/**
* Return true with probability 1/\e e.
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @return true with probability 1/\e e.
**********************************************************************/
template<class Random> bool operator()(Random& r)
{ return exph(r) && exph(r); }
};
} // namespace RandomLib
#endif // RANDOMLIB_INVERSEEPROB_HPP

View File

@ -0,0 +1,150 @@
/**
* \file InversePiProb.hpp
* \brief Header for InversePiProb
*
* Return true with probabililty 1/&pi;.
*
* Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_INVERSEPIPROB_HPP)
#define RANDOMLIB_INVERSEPIPROB_HPP 1
#include <cstdlib> // for abs(int)
#include <RandomLib/Random.hpp>
namespace RandomLib {
/**
* \brief Return true with probability 1/&pi;.
*
* InversePiProb p; p(Random& r) returns true with prob 1/&pi; using the
* method of Flajolet et al. It consumes 9.6365 bits per call on average.
*
* The method is given in Section 3.3 of
* - P. Flajolet, M. Pelletier, and M. Soria,<br>
* On Buffon Machines and Numbers,<br> Proc. 22nd ACM-SIAM Symposium on
* Discrete Algorithms (SODA), Jan. 2011.<br>
* http://www.siam.org/proceedings/soda/2011/SODA11_015_flajoletp.pdf <br>
* .
* using the identity
* \f[ \frac 1\pi = \sum_{n=0}^\infty
* {{2n}\choose n}^3 \frac{6n+1}{2^{8n+2}} \f]
*
* It is based on the expression for 1/&pi; given by Eq. (28) of<br>
* - S. Ramanujan,<br>
* Modular Equations and Approximations to &pi;,<br>
* Quart. J. Pure App. Math. 45, 350--372 (1914);<br>
* In Collected Papers, edited by G. H. Hardy, P. V. Seshu Aiyar,
* B. M. Wilson (Cambridge Univ. Press, 1927; reprinted AMS, 2000).<br>
* http://books.google.com/books?id=oSioAM4wORMC&pg=PA36 <br>
* .
* \f[\frac4\pi = 1 + \frac74 \biggl(\frac 12 \biggr)^3
* + \frac{13}{4^2} \biggl(\frac {1\cdot3}{2\cdot4} \biggr)^3
* + \frac{19}{4^3} \biggl(\frac {1\cdot3\cdot5}{2\cdot4\cdot6} \biggr)^3
* + \ldots \f]
*
* The following is a description of how to carry out the algorithm "by hand"
* with a real coin, together with a worked example:
* -# Perform three coin tossing experiments in which you toss a coin until
* you get tails, e.g., <tt>HHHHT</tt>; <tt>HHHT</tt>; <tt>HHT</tt>. Let
* <i>h</i><sub>1</sub> = 4, <i>h</i><sub>2</sub> = 3,
* <i>h</i><sub>3</sub> = 2 be the numbers of heads tossed in each
* experiment.
* -# Compute <i>n</i> = &lfloor;<i>h</i><sub>1</sub>/2&rfloor; +
* &lfloor;<i>h</i><sub>2</sub>/2&rfloor; +
* mod(&lfloor;(<i>h</i><sub>3</sub> &minus; 1)/3&rfloor;, 2) = 2 + 1 + 0
* = 3. Here is a table of the 3 contributions to <i>n</i>:\verbatim
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 h
0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 floor(h1/2)
0 0 1 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 floor(h2/2)
1 0 0 0 1 1 1 0 0 0 1 1 1 0 0 0 1 1 mod(floor((h3-1)/3), 2)
\endverbatim
* -# Perform three additional coin tossing experiments in each of which you
* toss a coin 2<i>n</i> = 6 times, e.g., <tt>TTHHTH</tt>;
* <tt>HHTHH|H</tt>; <tt>THHHHH</tt>. Are the number of heads and tails
* equal in each experiment? <b>yes</b> and <b>no</b> and <b>no</b> &rarr;
* <b>false</b>. (Here, you can give up at the |.)
* .
* The final result in this example is <b>false</b>. The most common way a
* <b>true</b> result is obtained is with <i>n</i> = 0, in which case the
* last step vacuously returns <b>true</b>.
*
* Proof of the algorithm: Flajolet et al. rearrange Ramanujan's identity as
* \f[ \frac 1\pi = \sum_{n=0}^\infty
* \biggl[{2n\choose n} \frac1{2^{2n}} \biggr]^3
* \frac{6n+1}{2^{2n+2}}. \f]
* Noticing that
* \f[ \sum_{n=0}^\infty
* \frac{6n+1}{2^{2n+2}} = 1, \f]
* the algorithm becomes:
* -# pick <i>n</i> &ge; 0 with prob (6<i>n</i>+1) / 2<sup>2<i>n</i>+2</sup>
* (mean <i>n</i> = 11/9);
* -# return <b>true</b> with prob (binomial(2<i>n</i>, <i>n</i>) /
* 2<sup>2<i>n</i></sup>)<sup>3</sup>.
*
* Implement (1) as
* - geom4(r) + geom4(r) returns <i>n</i> with probability 9(<i>n</i> +
* 1) / 2<sup>2<i>n</i>+4</sup>;
* - geom4(r) + geom4(r) + 1 returns <i>n</i> with probability
* 36<i>n</i> / 2<sup>2<i>n</i>+4</sup>;
* - combine these with probabilities [4/9, 5/9] to yield (6<i>n</i> +
* 1) / 2<sup>2<i>n</i>+2</sup>, as required.
* .
* Implement (2) as the outcome of 3 coin tossing experiments of 2<i>n</i>
* tosses with success defined as equal numbers of heads and tails in each
* trial.
*
* This class illustrates how to return an exact result using coin tosses
* only. A more efficient implementation (which is still exact) would
* replace prob59 by r.Prob(5,9) and geom4 by LeadingZeros z; z(r)/2.
**********************************************************************/
class InversePiProb {
private:
template<class Random> bool prob59(Random& r) {
// true with prob 5/9 = 0.1 000 111 000 111 000 111 ... (binary expansion)
if (r.Boolean()) return true;
for (bool res = false; ; res = !res)
for (int i = 3; i--; ) if (r.Boolean()) return res;
}
template<class Random> int geom4(Random& r) { // Geom(1/4)
int sum = 0;
while (r.Boolean() && r.Boolean()) ++sum;
return sum;
}
template<class Random> bool binom(Random& r, int n) {
// Probability of equal heads and tails on 2*n tosses
// = binomial(2*n, n) / 2^(2*n)
int d = 0;
for (int k = n; k--; ) d += r.Boolean() ? 1 : -1;
for (int k = n; k--; ) {
d += r.Boolean() ? 1 : -1;
// This optimization saves 0.1686 bit per call to operator() on average.
if (std::abs(d) > k) return false;
}
return true;
}
public:
/**
* Return true with probability 1/&pi;.
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @return true with probability 1/&pi;.
**********************************************************************/
template<class Random> bool operator()(Random& r) {
// Return true with prob 1/pi.
int n = geom4(r) + geom4(r) + (prob59(r) ? 1 : 0);
for (int j = 3; j--; ) if (!binom(r, n)) return false;
return true;
}
};
} // namespace RandomLib
#endif // RANDOMLIB_INVERSEPIPROB_HPP

View File

@ -0,0 +1,84 @@
/**
* \file LeadingZeros.hpp
* \brief Header for LeadingZeros
*
* Count the leading zeros in a real number.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_LEADINGZEROS_HPP)
#define RANDOMLIB_LEADINGZEROS_HPP 1
namespace RandomLib {
/**
* \brief Count of leading zeros.
*
* Count of leading zero bits after the binary point in a real number
* uniformly distributed in (0,1). (This is equivalent to the geometric
* distribution with probability 1/2.) For example
* \code
#include <RandomLib/LeadingZeros.hpp>
RandomLib::Random r; // A RandomGenerator works here too
std::cout << "Seed set to " << r.SeedString() << "\n";
LeadingZeros zeros;
std::cout << "Count of leading zeros:";
for (size_t i = 0; i < 20; ++i)
std::cout << " " << zeros(r);
std::cout << "\n";
\endcode
**********************************************************************/
class LeadingZeros {
public:
/**
* Return the number of zero bits after the binary point in a real number
* uniformly distributed in (0,1). Thus \e k is returned with probability
* 1/2<sup><i>k</i>+1</sup>. Because MT19937 is \e not a perfect random
* number generator, this always returns a result in [0, 19937).
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @return the random sample.
**********************************************************************/
template<class Random> unsigned operator()(Random& r) const throw();
};
template<class Random>
unsigned LeadingZeros::operator()(Random& r) const throw() {
// It's simpler to count the number of trailing ones in each w-bit block
// stopping when we get to a zero bit.
//
// Process a word in chunks of size m. The algorithm here can deal with
// any m assuming that z is modified accordingly. m = 4 is an approximate
// optimum.
//
// Can also adapt this routine to use RandomNumber::highest_bit_idx
// instead. However the result is considerably slower.
const int m = 4;
STATIC_ASSERT(m <= Random::width, "LeadingZeros: m too large");
// mask with m low bits set
const typename Random::result_type mask = ~(Random::max << m);
// Number of trailing 1 bits in [0, 1<<m). However, correct results are
// also obtained with any permutation of this array. This particular
// permutation is useful since the initial 1/2, 1/4, etc. can be used for
// m-1, m-2, etc. To generate the array for the next higher m, append a
// duplicate of the array and increment the last entry by one.
const unsigned z[1 << m] =
{ 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, 4, };
typename Random::result_type x = r();
for (unsigned b = m, n = 0; b < Random::width; b += m) {
n += z[x & mask]; // count trailing 1s in chunk
if (n < b) // chunk contains a 0
return n;
x >>= m; // shift out the chunk we've processed
}
// x is all ones (prob 1/2^w); process the next word.
return Random::width + operator()(r);
}
} // namespace RandomLib
#endif // RANDOMLIB_LEADINGZEROS_HPP

View File

@ -0,0 +1,92 @@
/**
* \file MPFRExponential.hpp
* \brief Header for MPFRExponential
*
* Sampling exactly from the normal distribution for MPFR.
*
* Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed under
* the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_MPFREXPONENTIAL_HPP)
#define RANDOMLIB_MPFREXPONENTIAL_HPP 1
#include <RandomLib/MPFRRandom.hpp>
#if HAVE_MPFR || defined(DOXYGEN)
namespace RandomLib {
/**
* \brief The exponential distribution for MPFR.
*
* This is a transcription of ExactExponential (version 1.4) for use with
* MPFR.
*
* This class uses mutable private objects. So a single MPFRExponential
* object cannot safely be used by multiple threads. In a multi-processing
* environment, each thread should use a thread-specific MPFRExponential
* object.
*
* @tparam bits the number of bits in each digit.
**********************************************************************/
template<int bits = 32> class MPFRExponential {
public:
/**
* Initialize the MPFRExponential object.
**********************************************************************/
MPFRExponential() {};
/**
* Sample from the exponential distribution with mean 1 returning a
* MPFRRandom.
*
* @param[out] t the MPFRRandom result.
* @param[in,out] r a GMP random generator.
**********************************************************************/
void operator()(MPFRRandom<bits>& t, gmp_randstate_t r) const
{ Compute(r); _x.swap(t); }
/**
* Sample from the exponential distribution with mean 1.
*
* @param[out] val the sample from the exponential distribution
* @param[in,out] r a GMP random generator.
* @param[in] round the rounding direction.
* @return the MPFR ternary result (&plusmn; if val is larger/smaller than
* the exact sample).
**********************************************************************/
int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const
{ Compute(r); return _x(val, r, round); }
private:
// Disable copy constructor and assignment operator
MPFRExponential(const MPFRExponential&);
MPFRExponential& operator=(const MPFRExponential&);
int ExpFraction(gmp_randstate_t r, MPFRRandom<bits>& p) const {
// The early bale out
if (p.TestHighBit(r)) return 0;
// Implement the von Neumann algorithm
_w.Init();
if (!_w.LessThan(r, p)) return 1;
while (true) {
_v.Init(); if (!_v.LessThan(r, _w)) return 0;
_w.Init(); if (!_w.LessThan(r, _v)) return 1;
}
}
void Compute(gmp_randstate_t r) const {
_x.Init();
unsigned k = 0;
while (!ExpFraction(r, _x)) { ++k; _x.Init(); }
if (k & 1) _x.SetHighBit(r);
_x.AddInteger(k >> 1);
return;
}
mutable MPFRRandom<bits> _x;
mutable MPFRRandom<bits> _v;
mutable MPFRRandom<bits> _w;
};
} // namespace RandomLib
#endif // HAVE_MPFR
#endif // RANDOMLIB_MPFREXPONENTIAL_HPP

View File

@ -0,0 +1,123 @@
/**
* \file MPFRExponentialL.hpp
* \brief Header for MPFRExponentialL
*
* Sampling exactly from the exponential distribution for MPFR using the
* traditional method.
*
* Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed under
* the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_MPFREXPONENTIALL_HPP)
#define RANDOMLIB_MPFREXPONENTIALL_HPP 1
#include <cmath> // for log
#include <mpfr.h>
#define HAVE_MPFR (MPFR_VERSION_MAJOR >= 3)
#if HAVE_MPFR || defined(DOXYGEN)
namespace RandomLib {
/**
* \brief The exponential distribution for MPFR (the log method).
*
* This class is <b>DEPRECATED</b>. It is included for illustrative purposes
* only. The MPFRExponential class provides a much more efficient method for
* sampling from the exponential distribution.
*
* This is an adaption of ExponentialDistribution to MPFR. The changes are
* - Use MPFR's random number generator
* - Use sufficient precision internally to ensure that a correctly rounded
* result is returned.
*
* This class uses mutable private objects. So a single MPFRExponentialL
* object cannot safely be used by multiple threads. In a multi-processing
* environment, each thread should use a thread-specific MPFRExponentialL
* object.
**********************************************************************/
class MPFRExponentialL {
private:
// The number of bits of randomness to add at a time.
static const long chunk_ = 32;
public:
/**
* Initialize the MPFRExponentialL object.
**********************************************************************/
MPFRExponentialL() {
mpz_init(_vi);
mpfr_init2(_eps, chunk_);
mpfr_init2(_v1, chunk_);
mpfr_init2(_v2, chunk_);
}
/**
* Destroy the MPFRExponentialL object.
**********************************************************************/
~MPFRExponentialL() {
mpfr_clear(_v2);
mpfr_clear(_v1);
mpfr_clear(_eps);
mpz_clear(_vi);
}
/**
* Sample from the exponential distribution with mean 1.
*
* @param[out] val the sample from the exponential distribution
* @param[in,out] r a GMP random generator.
* @param[in] round the rounding direction.
* @return the MPFR ternary result (&plusmn; if val is larger/smaller than
* the exact sample).
**********************************************************************/
int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const {
mpfr_prec_t prec0 = mpfr_get_prec (val);
mpfr_prec_t prec = prec0 + 10; // A rough optimum
mpz_urandomb(_vi, r, prec);
mpfr_set_ui_2exp(_eps, 1u, -prec, MPFR_RNDN);
mpfr_set_prec(_v1, prec);
mpfr_set_z_2exp(_v1, _vi, -prec, MPFR_RNDN);
mpfr_set_prec(_v2, prec);
mpfr_add(_v2, _v1, _eps, MPFR_RNDN);
while (true) {
int f2 = mpfr_log(val, _v2, round); // val = log(upper bound)
mpfr_set_prec(_v2, prec0);
int f1 = mpfr_log(_v2, _v1, round); // v2 = log(lower bound)
if (f1 == f2 && mpfr_equal_p(val, _v2)) {
mpfr_neg(val, val, MPFR_RNDN);
return -f1;
}
prec = Refine(r, prec);
}
}
private:
// disable copy constructor and assignment operator
MPFRExponentialL(const MPFRExponentialL&);
MPFRExponentialL& operator=(const MPFRExponentialL&);
// Refine the random interval
mpfr_prec_t Refine(gmp_randstate_t r, mpfr_prec_t prec)
const {
prec += chunk_;
mpfr_div_2ui(_eps, _eps, chunk_, MPFR_RNDN);
mpz_urandomb(_vi, r, chunk_);
mpfr_set_prec(_v2, prec);
mpfr_set_z_2exp(_v2, _vi, -prec, MPFR_RNDN);
mpfr_add(_v2, _v1, _v2, MPFR_RNDN);
mpfr_swap(_v1, _v2); // v1 = v2;
mpfr_set_prec(_v2, prec);
mpfr_add(_v2, _v1, _eps, MPFR_RNDN);
return prec;
}
mutable mpz_t _vi;
mutable mpfr_t _eps;
mutable mpfr_t _v1;
mutable mpfr_t _v2;
};
} // namespace RandomLib
#endif // HAVE_MPFR
#endif // RANDOMLIB_MPFREXPONENTIALL_HPP

View File

@ -0,0 +1,144 @@
/**
* \file MPFRNormal.hpp
* \brief Header for MPFRNormal
*
* Sampling exactly from the normal distribution for MPFR.
*
* Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed under
* the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_MPFRNORMAL_HPP)
#define RANDOMLIB_MPFRNORMAL_HPP 1
#include <algorithm> // for max/min
#include <RandomLib/MPFRRandom.hpp>
#if HAVE_MPFR || defined(DOXYGEN)
namespace RandomLib {
/**
* \brief The normal distribution for MPFR.
*
* This is a transcription of ExactNormal (version 1.3) for use with MPFR.
*
* This class uses mutable private objects. So a single MPFRNormal object
* cannot safely be used by multiple threads. In a multi-processing
* environment, each thread should use a thread-specific MPFRNormal object.
*
* @tparam bits the number of bits in each digit.
**********************************************************************/
template<int bits = 32> class MPFRNormal {
public:
/**
* Initialize the MPFRNormal object.
**********************************************************************/
MPFRNormal() { mpz_init(_tt); }
/**
* Destroy the MPFRNormal object.
**********************************************************************/
~MPFRNormal() { mpz_clear(_tt); }
/**
* Sample from the normal distribution with mean 0 and variance 1 returning
* a MPFRRandom.
*
* @param[out] t the MPFRRandom result.
* @param[in,out] r a GMP random generator.
**********************************************************************/
void operator()(MPFRRandom<bits>& t,gmp_randstate_t r) const
{ Compute(r); return _x.swap(t); }
/**
* Sample from the normal distribution with mean 0 and variance 1.
*
* @param[out] val the sample from the normal distribution
* @param[in,out] r a GMP random generator.
* @param[in] round the rounding direction.
* @return the MPFR ternary result (&plusmn;1 if val is larger/smaller than
* the exact sample).
**********************************************************************/
int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const
{ Compute(r); return _x(val, r, round); }
private:
// Disable copy constructor and assignment operator
MPFRNormal(const MPFRNormal&);
MPFRNormal& operator=(const MPFRNormal&);
// True with prob exp(-1/2)
int ExpProbH(gmp_randstate_t r) const {
_p.Init(); if (_p.TestHighBit(r)) return 1;
// von Neumann rejection
while (true) {
_q.Init(); if (!_q.LessThan(r, _p)) return 0;
_p.Init(); if (!_p.LessThan(r, _q)) return 1;
}
}
// True with prob exp(-n/2)
int ExpProb(gmp_randstate_t r, unsigned n) const {
while (n--) { if (!ExpProbH(r)) return 0; }
return 1;
}
// n with prob (1-exp(-1/2)) * exp(-n/2)
unsigned ExpProbN(gmp_randstate_t r) const {
unsigned n = 0;
while (ExpProbH(r)) ++n;
return n;
}
// Return:
// 1 with prob 2k/(2k + 2)
// 0 with prob 1/(2k + 2)
// -1 with prob 1/(2k + 2)
int Choose(gmp_randstate_t r, int k) const {
const int b = 15; // To avoid integer overflow on multiplication
const int m = 2 * k + 2;
int n1 = m - 2, n2 = m - 1;
while (true) {
mpz_urandomb(_tt, r, b);
int d = int( mpz_get_ui(_tt) ) * m;
n1 = (std::max)((n1 << b) - d, 0);
if (n1 >= m) return 1;
n2 = (std::min)((n2 << b) - d, m);
if (n2 <= 0) return -1;
if (n1 == 0 && n2 == m) return 0;
}
}
void Compute(gmp_randstate_t r) const {
while (true) {
unsigned k = ExpProbN(r); // the integer part of the result.
if (ExpProb(r, (k - 1) * k)) {
_x.Init();
unsigned s = 1;
for (unsigned j = 0; j <= k; ++j) { // execute k + 1 times
bool first;
for (s = 1, first = true; ; s ^= 1, first = false) {
if (k == 0 && _x.Boolean(r)) break;
_q.Init(); if (!_q.LessThan(r, first ? _x : _p)) break;
int y = k == 0 ? 0 : Choose(r, k);
if (y < 0)
break;
else if (y == 0) {
_p.Init(); if (!_p.LessThan(r, _x)) break;
}
_p.swap(_q); // a fast way of doing p = q
}
if (s == 0) break;
}
if (s != 0) {
_x.AddInteger(k);
if (_x.Boolean(r)) _x.Negate();
return;
}
}
}
}
mutable mpz_t _tt; // A temporary
mutable MPFRRandom<bits> _x;
mutable MPFRRandom<bits> _p;
mutable MPFRRandom<bits> _q;
};
} // namespace RandomLib
#endif // HAVE_MPFR
#endif // RANDOMLIB_MPFRNORMAL_HPP

View File

@ -0,0 +1,138 @@
/**
* \file MPFRNormalK.hpp
* \brief Header for MPFRNormalK
*
* Sampling exactly from the normal distribution for MPFR.
*
* Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed under
* the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_MPFRNORMALK_HPP)
#define RANDOMLIB_MPFRNORMALK_HPP 1
#include <algorithm> // for max
#include <RandomLib/MPFRRandom.hpp>
#include <RandomLib/MPFRExponential.hpp>
#if HAVE_MPFR || defined(DOXYGEN)
namespace RandomLib {
/**
* \brief The normal distribution for MPFR (Kahn algorithm).
*
* This class is <b>DEPRECATED</b>. It is included for illustrative purposes
* only. The MPFRNormal class provides a somewhat more efficient method for
* sampling from the normal distribution.
*
* Refs:
* - H. Kahn, Rand Report RM-1237-AEC, p. 41 (1954).
* - M. Abramowitz and I. A. Stegun, p. 953, Sec. 26.8.6.a(4) (1964).
* .
* N.B. Damien Stehle' drew my attention to this algorithm as a useful way to
* compute normal deviates exactly.
*
* This class uses mutable private objects. So a single MPFRNormalK object
* cannot safely be used by multiple threads. In a multi-processing
* environment, each thread should use a thread-specific MPFRNormalK object.
*
* @tparam bits the number of bits in each digit.
**********************************************************************/
template<int bits = 32> class MPFRNormalK {
public:
/**
* Initialize the MPFRNormalK object.
**********************************************************************/
MPFRNormalK()
{ mpfr_init2(_xf, MPFR_PREC_MIN); mpfr_init2(_zf, MPFR_PREC_MIN); }
/**
* Destroy the MPFRNormalK object.
**********************************************************************/
~MPFRNormalK()
{ mpfr_clear(_zf); mpfr_clear(_xf); }
/**
* Sample from the normal distribution with mean 0 and variance 1 returning
* a MPFRRandom.
*
* @param[out] t the MPFRRandom result.
* @param[in,out] r a GMP random generator.
**********************************************************************/
void operator()(MPFRRandom<bits>& t, gmp_randstate_t r) const
{ Compute(r); _x.swap(t); }
/**
* Sample from the normal distribution with mean 0 and variance 1.
*
* @param[out] val the sample from the normal distribution
* @param[in,out] r a GMP random generator.
* @param[in] round the rounding direction.
* @return the MPFR ternary result (&plusmn;1 if val is larger/smaller than
* the exact sample).
**********************************************************************/
int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const
{ Compute(r); return _x(val, r, round); }
private:
// disable copy constructor and assignment operator
MPFRNormalK(const MPFRNormalK&);
MPFRNormalK& operator=(const MPFRNormalK&);
void Compute(gmp_randstate_t r) const {
// The algorithm is sample x and z from the exponential distribution; if
// (x-1)^2 < 2*z, return (random sign)*x; otherwise repeat. Probability
// of acceptance is sqrt(pi/2) * exp(-1/2) = 0.7602.
while (true) {
_edist(_x, r);
_edist(_z, r);
for (mp_size_t k = 1; ; ++k) {
_x.ExpandTo(r, k - 1);
_z.ExpandTo(r, k - 1);
mpfr_prec_t prec = (std::max)(mpfr_prec_t(MPFR_PREC_MIN), k * bits);
mpfr_set_prec(_xf, prec);
mpfr_set_prec(_zf, prec);
// Try for acceptance first; so compute upper limit on (y-1)^2 and
// lower limit on 2*z.
if (_x.UInteger() == 0) {
_x(_xf, MPFR_RNDD);
mpfr_ui_sub(_xf, 1u, _xf, MPFR_RNDU);
} else {
_x(_xf, MPFR_RNDU);
mpfr_sub_ui(_xf, _xf, 1u, MPFR_RNDU);
}
mpfr_sqr(_xf, _xf, MPFR_RNDU);
_z(_zf, MPFR_RNDD);
mpfr_mul_2ui(_zf, _zf, 1u, MPFR_RNDD);
if (mpfr_cmp(_xf, _zf) < 0) { // (y-1)^2 < 2*z, so accept
if (_x.Boolean(r)) _x.Negate(); // include a random sign
return;
}
// Try for rejection; so compute lower limit on (y-1)^2 and upper
// limit on 2*z.
if (_x.UInteger() == 0) {
_x(_xf, MPFR_RNDU);
mpfr_ui_sub(_xf, 1u, _xf, MPFR_RNDD);
} else {
_x(_xf, MPFR_RNDD);
mpfr_sub_ui(_xf, _xf, 1u, MPFR_RNDD);
}
mpfr_sqr(_xf, _xf, MPFR_RNDD);
_z(_zf, MPFR_RNDU);
mpfr_mul_2ui(_zf, _zf, 1u, MPFR_RNDU);
if (mpfr_cmp(_xf, _zf) > 0) // (y-1)^2 > 2*z, so reject
break;
// Otherwise repeat with more precision
}
// Reject and start over with a new y and z
}
}
mutable MPFRRandom<bits> _x;
mutable MPFRRandom<bits> _z;
mutable mpfr_t _xf;
mutable mpfr_t _zf;
const MPFRExponential<bits> _edist;
};
} // namespace RandomLib
#endif // HAVE_MPFR
#endif // RANDOMLIB_MPFRNORMALK_HPP

View File

@ -0,0 +1,255 @@
/**
* \file MPFRNormalR.hpp
* \brief Header for MPFRNormalR
*
* Sampling exactly from the normal distribution for MPFR using the ratio
* method.
*
* Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed under
* the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_MPFRNORMALR_HPP)
#define RANDOMLIB_MPFRNORMALR_HPP 1
#include <algorithm> // for max/min
#include <cmath> // for pow
#include <mpfr.h>
#define HAVE_MPFR (MPFR_VERSION_MAJOR >= 3)
#if HAVE_MPFR || defined(DOXYGEN)
namespace RandomLib {
/**
* \brief The normal distribution for MPFR (ratio method).
*
* This class is <b>DEPRECATED</b>. It is included for illustrative purposes
* only. The MPFRNormal class provides a much more efficient method for
* sampling from the normal distribution.
*
* This is an adaption of NormalDistribution to MPFR. The changes are
* - Use MPFR's random number generator
* - Use sufficient precision internally to ensure that a correctly rounded
* result is returned.
*
* This class uses a mutable private object. So a single MPFRNormalR
* object cannot safely be used by multiple threads. In a multi-processing
* environment, each thread should use a thread-specific MPFRNormalR
* object.
**********************************************************************/
class MPFRNormalR {
private:
// The number of bits of randomness to add at a time. Require that Leva's
// bounds "work" at a precision of 2^-chunk and that an unsigned long can
// hold this many bits.
static const long chunk_ = 32;
static const unsigned long m = 3684067834; // ceil(2^chunk*sqrt(2/e))
public:
/**
* Initialize the MPFRNormalR object.
**********************************************************************/
MPFRNormalR() {
mpz_init(_ui);
mpz_init(_vi);
mpfr_init2(_eps, chunk_);
mpfr_init2(_u, chunk_);
mpfr_init2(_v, chunk_);
mpfr_init2(_up, chunk_);
mpfr_init2(_vp, chunk_);
mpfr_init2(_vx, chunk_);
mpfr_init2(_x1, chunk_);
mpfr_init2(_x2, chunk_);
}
/**
* Destroy the MPFRNormalR object.
**********************************************************************/
~MPFRNormalR() {
mpfr_clear(_x2);
mpfr_clear(_x1);
mpfr_clear(_vx);
mpfr_clear(_vp);
mpfr_clear(_up);
mpfr_clear(_v);
mpfr_clear(_u);
mpfr_clear(_eps);
mpz_clear(_vi);
mpz_clear(_ui);
}
/**
* Sample from the normal distribution with mean 0 and variance 1.
*
* @param[out] val the sample from the normal distribution
* @param[in,out] r a GMP random generator.
* @param[in] round the rounding direction.
* @return the MPFR ternary result (&plusmn;1 if val is larger/smaller than
* the exact sample).
**********************************************************************/
int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const {
const double
s = 0.449871, // Constants from Leva
t = -0.386595,
a = 0.19600 ,
b = 0.25472 ,
r1 = 0.27597 ,
r2 = 0.27846 ,
u1 = 0.606530, // sqrt(1/e) rounded down and up
u2 = 0.606531,
scale = std::pow(2.0, -chunk_); // for turning randoms into doubles
while (true) {
mpz_urandomb(_vi, r, chunk_);
if (mpz_cmp_ui(_vi, m) >= 0) continue; // Very early reject
double vf = (mpz_get_ui(_vi) + 0.5) * scale;
mpz_urandomb(_ui, r, chunk_);
double uf = (mpz_get_ui(_ui) + 0.5) * scale;
double
x = uf - s,
y = vf - t,
Q = x*x + y * (a*y - b*x);
if (Q >= r2) continue; // Early reject
mpfr_set_ui_2exp(_eps, 1u, -chunk_, MPFR_RNDN);
mpfr_prec_t prec = chunk_;
mpfr_set_prec(_u, prec);
mpfr_set_prec(_v, prec);
// (u,v) = sw corner of range
mpfr_set_z_2exp(_u, _ui, -prec, MPFR_RNDN);
mpfr_set_z_2exp(_v, _vi, -prec, MPFR_RNDN);
mpfr_set_prec(_up, prec);
mpfr_set_prec(_vp, prec);
// (up,vp) = ne corner of range
mpfr_add(_up, _u, _eps, MPFR_RNDN);
mpfr_add(_vp, _v, _eps, MPFR_RNDN);
// Estimate how many extra bits will be needed to achieve the desired
// precision.
mpfr_prec_t prec_guard = 3 + chunk_ -
(std::max)(mpz_sizeinbase(_ui, 2), mpz_sizeinbase(_vi, 2));
if (Q > r1) {
int reject;
while (true) {
// Rejection curve v^2 + 4 * u^2 * log(u) < 0 has a peak at u =
// exp(-1/2) = 0.60653066. So treat uf in (0.606530, 0.606531) =
// (u1, u2) specially
// Try for rejection first
if (uf <= u1)
reject = Reject(_u, _vp, prec, MPFR_RNDU);
else if (uf >= u2)
reject = Reject(_up, _vp, prec, MPFR_RNDU);
else { // u in (u1, u2)
mpfr_set_prec(_vx, prec);
mpfr_add(_vx, _vp, _eps, MPFR_RNDN);
reject = Reject(_u, _vx, prec, MPFR_RNDU); // Could use _up too
}
if (reject < 0) break; // tried to reject but failed, so accept
// Try for acceptance
if (uf <= u1)
reject = Reject(_up, _v, prec, MPFR_RNDD);
else if (uf >= u2)
reject = Reject(_u, _v, prec, MPFR_RNDD);
else { // u in (u2, u2)
mpfr_sub(_vx, _v, _eps, MPFR_RNDN);
reject = Reject(_u, _vx, prec, MPFR_RNDD); // Could use _up too
}
if (reject > 0) break; // tried to accept but failed, so reject
prec = Refine(r, prec); // still can't decide, to refine
}
if (reject > 0) continue; // reject, back to outer loop
}
// Now evaluate v/u to the necessary precision
mpfr_prec_t prec0 = mpfr_get_prec (val);
// while (prec < prec0 + prec_guard) prec = Refine(r, prec);
if (prec < prec0 + prec_guard)
prec = Refine(r, prec,
(prec0 + prec_guard - prec + chunk_ - 1) / chunk_);
mpfr_set_prec(_x1, prec0);
mpfr_set_prec(_x2, prec0);
int flag;
while (true) {
int
f1 = mpfr_div(_x1, _v, _up, round), // min slope
f2 = mpfr_div(_x2, _vp, _u, round); // max slope
if (f1 == f2 && mpfr_equal_p(_x1, _x2)) {
flag = f1;
break;
}
prec = Refine(r, prec);
}
mpz_urandomb(_ui, r, 1);
if (mpz_tstbit(_ui, 0)) {
flag = -flag;
mpfr_neg(val, _x1, MPFR_RNDN);
} else
mpfr_set(val, _x1, MPFR_RNDN);
// std::cerr << uf << " " << vf << " " << Q << "\n";
return flag;
}
}
private:
// disable copy constructor and assignment operator
MPFRNormalR(const MPFRNormalR&);
MPFRNormalR& operator=(const MPFRNormalR&);
// Refine the random square
mpfr_prec_t Refine(gmp_randstate_t r, mpfr_prec_t prec, long num = 1)
const {
if (num <= 0) return prec;
// Use _vx as scratch
prec += num * chunk_;
mpfr_div_2ui(_eps, _eps, num * chunk_, MPFR_RNDN);
mpz_urandomb(_ui, r, num * chunk_);
mpfr_set_prec(_up, prec);
mpfr_set_z_2exp(_up, _ui, -prec, MPFR_RNDN);
mpfr_set_prec(_vx, prec);
mpfr_add(_vx, _u, _up, MPFR_RNDN);
mpfr_swap(_u, _vx); // u = vx
mpfr_add(_up, _u, _eps, MPFR_RNDN);
mpz_urandomb(_vi, r, num * chunk_);
mpfr_set_prec(_vp, prec);
mpfr_set_z_2exp(_vp, _vi, -prec, MPFR_RNDN);
mpfr_set_prec(_vx, prec);
mpfr_add(_vx, _v, _vp, MPFR_RNDN);
mpfr_swap(_v, _vx); // v = vx
mpfr_add(_vp, _v, _eps, MPFR_RNDN);
return prec;
}
// Evaluate the sign of the rejection condition v^2 + 4*u^2*log(u)
int Reject(mpfr_t u, mpfr_t v, mpfr_prec_t prec, mpfr_rnd_t round) const {
// Use x1, x2 as scratch
mpfr_set_prec(_x1, prec);
mpfr_log(_x1, u, round);
mpfr_mul(_x1, _x1, u, round); // Important to do the multiplications in
mpfr_mul(_x1, _x1, u, round); // this order so that rounding works right.
mpfr_mul_2ui(_x1, _x1, 2u, round); // 4*u^2*log(u)
mpfr_set_prec(_x2, prec);
mpfr_mul(_x2, v, v, round); // v^2
mpfr_add(_x1, _x1, _x2, round); // v^2 + 4*u^2*log(u)
return mpfr_sgn(_x1);
}
mutable mpz_t _ui;
mutable mpz_t _vi;
mutable mpfr_t _eps;
mutable mpfr_t _u;
mutable mpfr_t _v;
mutable mpfr_t _up;
mutable mpfr_t _vp;
mutable mpfr_t _vx;
mutable mpfr_t _x1;
mutable mpfr_t _x2;
};
} // namespace RandomLib
#endif // HAVE_MPFR
#endif // RANDOMLIB_MPFRNORMALR_HPP

View File

@ -0,0 +1,383 @@
/**
* \file MPFRRandom.hpp
* \brief Header for MPFRRandom
*
* Utility class for MPFRUniform, MPFRExponential, and MPFRNormal.
*
* Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed under
* the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_MPFRRANDOM_HPP)
#define RANDOMLIB_MPFRRANDOM_HPP 1
#include <algorithm> // for swap
#include <mpfr.h>
#define HAVE_MPFR (MPFR_VERSION_MAJOR >= 3)
#if HAVE_MPFR || defined(DOXYGEN)
/**
* A compile-time assert. Use C++11 static_assert, if available.
**********************************************************************/
#if !defined(STATIC_ASSERT)
# if defined(__GXX_EXPERIMENTAL_CXX0X__)
# define STATIC_ASSERT static_assert
# elif defined(_MSC_VER) && _MSC_VER >= 1600
# define STATIC_ASSERT static_assert
# else
# define STATIC_ASSERT(cond,reason) \
{ enum{ STATIC_ASSERT_ENUM = 1/int(cond) }; }
# endif
#endif
namespace RandomLib {
/**
* \brief Handling random numbers in MPFR.
*
* This class provides roughly the same capabilities as RandomNumber. The
* fraction is represented by a mpz integer \e f and an exponent \e e. We
* have \e e &ge; 0 and 0 &le; \e f < <i>b</i><sup><i>e</i></sup>, and \e b =
* 2<sup><i>bits</i></sup>. This represents the number \e x = \e f
* <i>b</i><sup>&minus;<i>e</i></sup>, with x in [0, 1).
*
* @tparam bits the number of bits in each digit.
*
* \e bits must divide GMP_LIMB_BITS. The default value \e bits = 32 yields
* portable results on all MPFR platforms.
**********************************************************************/
template<int bits = 32> class MPFRRandom {
private:
static const int limb_ = GMP_LIMB_BITS; // How many bits in a limb
static const int loglimb_ = (limb_ == 32 ? 5 :
(limb_ == 64 ? 6 :
(limb_ == 128 ? 7 : -1)));
static const int logbits_ = (bits == 1 ? 0 :
(bits == 2 ? 1 :
(bits == 4 ? 2 :
(bits == 8 ? 3 :
(bits == 16 ? 4 :
(bits == 32 ? 5 :
(bits == 64 ? 6 :
(bits == 128 ? 7 : -1))))))));
static const mp_limb_t mask_ = (bits == limb_ ? ~0UL : // Digit mask
~(~0UL << (bits < limb_ ? bits : 0)));
static const int logw_ = loglimb_ - logbits_; // 2^logw digits per limb
static const unsigned wmask_ = ~(~0U << logw_);
mutable mpz_t _tt; // A temporary
mpz_t _f; // The fraction
mp_size_t _e; // Count of digits
unsigned long _n; // Integer part
int _s; // Sign
void AddDigits(gmp_randstate_t r, long num = 1) { // Add num more digits
if (num <= 0) return;
mpz_mul_2exp(_f, _f, num << logbits_);
mpz_urandomb(_tt, r, num << logbits_);
mpz_add(_f, _f, _tt);
_e += num;
}
// return k'th digit counting k = 0 as most significant
mp_limb_t Digit(gmp_randstate_t r, mp_size_t k) {
ExpandTo(r, k); // Now e > k
k = _e - 1 - k; // Reverse k so k = 0 is least significant
// (k >> logw) is the limb index
// (k & wmask) is the digit position within the limb
return mask_ &
(mpz_getlimbn(_f, k >> logw_) >> ((k & wmask_) << logbits_));
}
// Return index [0..32] of highest bit set. Return 0 if x = 0, 32 is if x
// = ~0. (From Algorithms for programmers by Joerg Arndt.)
static int highest_bit_idx(unsigned long x) throw() {
if (x == 0) return 0;
int r = 1;
// STILL TO DO: handle 64-bit unsigned longs.
if (x & 0xffff0000UL) { x >>= 16; r += 16; }
if (x & 0x0000ff00UL) { x >>= 8; r += 8; }
if (x & 0x000000f0UL) { x >>= 4; r += 4; }
if (x & 0x0000000cUL) { x >>= 2; r += 2; }
if (x & 0x00000002UL) { r += 1; }
return r;
}
public:
/**
* Initialize the MPFRRandom object.
**********************************************************************/
MPFRRandom() : _e(0u), _n(0u), _s(1) {
STATIC_ASSERT(logbits_ >= 0 && loglimb_ >= 0 && logbits_ <= loglimb_,
"MPRFRandom: unsupported value for bits");
mpz_init(_f); mpz_init(_tt);
}
/**
* Initialize the MPFRRandom object from another one.
*
* @param[in] t the MPFRRandom to copy.
**********************************************************************/
MPFRRandom(const MPFRRandom& t) : _e(t._e), _n(t._n), _s(t._s)
{ mpz_init(_f); mpz_set(_f, t._f); mpz_init(_tt); }
/**
* Destroy the MPFRRandom object.
**********************************************************************/
~MPFRRandom() { mpz_clear(_f); mpz_clear(_tt); }
/**
* Assignment operator. (But swapping is typically faster.)
*
* @param[in] t the MPFRRandom to copy.
**********************************************************************/
MPFRRandom& operator=(const MPFRRandom& t) {
_e = t._e;
_n = t._n;
_s = t._s;
mpz_set(_f, t._f); // Don't copy _tt
return *this;
}
/**
* Swap with another MPFRRandom. This is a fast way of doing an
* assignment.
*
* @param[in,out] t the MPFRRandom to swap with.
**********************************************************************/
void swap(MPFRRandom& t) throw() {
if (this != &t) {
std::swap(_e, t._e);
std::swap(_n, t._n);
std::swap(_s, t._s);
mpz_swap(_f, t._f); // Don't swap _tt
}
}
/**
* Reinitialize the MPFRRandom object, setting its value to [0,1].
**********************************************************************/
void Init() { mpz_set_ui(_f, 0u); _e = 0; _n = 0; _s = 1; }
/**
* @return the sign of the MPFRRandom (&plusmn; 1).
**********************************************************************/
int Sign() const throw() { return _s; }
/**
* Change the sign of the MPFRRandom.
**********************************************************************/
void Negate() throw() { _s *= -1; }
/**
* @return the floor of the MPFRRandom
**********************************************************************/
long Floor() const throw() { return _s > 0 ? long(_n) : -1 - long(_n); }
/**
* @return the ceiling of the MPFRRandom
**********************************************************************/
long Ceiling() const throw() { return _s > 0 ? 1 + long(_n) : -long(_n); }
/**
* @return the unsigned integer component of the MPFRRandom.
**********************************************************************/
unsigned long UInteger() const throw() { return _n; }
/**
* @return the number of digits in fraction
**********************************************************************/
unsigned long Size() const throw() { return unsigned(_e); }
/**
* Add integer \e k to the MPRFRandom.
*
* @param[in] k the integer to add.
**********************************************************************/
void AddInteger(long k) {
k += Floor(); // The new floor
int ns = k < 0 ? -1 : 1; // The new sign
if (ns != _s) { // If sign changes, set f = 1 - f
mpz_set_ui(_tt, 1u);
mpz_mul_2exp(_tt, _tt, _e << logbits_);
mpz_sub_ui(_tt, _tt, 1u);
mpz_sub(_f, _tt, _f);
_s = ns;
}
_n = ns > 0 ? k : -(k + 1);
}
/**
* Compare with another MPFRRandom, *this < \e t.
*
* @param[in,out] r a random generator.
* @param[in,out] t a MPFRRandom to compare.
* @return true if *this < \e t.
**********************************************************************/
int LessThan(gmp_randstate_t r, MPFRRandom& t) {
if (this == &t) return false; // same object
if (_s != t._s) return _s < t._s;
if (_n != t._n) return (_s < 0) ^ (_n < t._n);
for (mp_size_t k = 0; ; ++k) {
mp_limb_t x = Digit(r, k);
mp_limb_t y = t.Digit(r, k);
if (x != y) return (_s < 0) ^ (x < y);
}
}
/**
* Set high bit of fraction to 1.
*
* @param[in,out] r a random generator.
**********************************************************************/
void SetHighBit(gmp_randstate_t r) { // Set the msb to 1
ExpandTo(r, 0); // Generate msb if necessary
mpz_setbit(_f, (_e << logbits_) - 1);
}
/**
* Test high bit of fraction.
*
* @param[in,out] r a random generator.
**********************************************************************/
int TestHighBit(gmp_randstate_t r) { // test the msb of f
ExpandTo(r, 0); // Generate msb if necessary
return mpz_tstbit(_f, (_e << logbits_) - 1);
}
/**
* Return the position of the most significant bit in the MPFRRandom.
*
* @param[in,out] r a random generator.
*
* The bit position is numbered such the 1/2 bit is 0, the 1/4 bit is -1,
* etc.
**********************************************************************/
mp_size_t LeadingBit(gmp_randstate_t r) {
if (_n) return highest_bit_idx(_n);
while (true) {
int sgn = mpz_sgn(_f);
if (sgn != 0)
return mp_size_t(mpz_sizeinbase(_f, 2)) - mp_size_t(_e << logbits_);
AddDigits(r);
}
}
/**
* Ensure that the k'th digit of the fraction is computed.
*
* @param[in,out] r a random generator.
* @param[in] k the digit number (0 is the most significant, 1 is the next
* most significant, etc.
**********************************************************************/
void ExpandTo(gmp_randstate_t r, mp_size_t k)
{ if (_e <= k) AddDigits(r, k - _e + 1); }
/**
* Convert to a MPFR number \e without adding more bits.
*
* @param[out] val the value of s * (n + *this).
* @param[in] round the rounding direction.
* @return the MPFR ternary result (&plusmn; if val is larger/smaller than
* the exact sample).
*
* If round is MPFR_RNDN, then the rounded midpoint of the interval
* represented by the MPFRRandom is returned. Otherwise it is the rounded
* lower or upper bound of the interval (whichever is appropriate).
**********************************************************************/
int operator()(mpfr_t val, mpfr_rnd_t round)
{ return operator()(val, NULL, round); }
/**
* Convert to a MPFR number.
*
* @param[out] val the value of s * (n + *this).
* @param[in,out] r a GMP random generator.
* @param[in] round the rounding direction.
* @return the MPFR ternary result (&plusmn; if val is larger/smaller than
* the exact sample).
*
* If \e r is NULL, then no additional random bits are generated and the
* lower bound, midpoint, or upper bound of the MPFRRandom interval is
* returned, depending on the value of \e round.
**********************************************************************/
int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) {
// The value is constructed as a positive quantity, so adjust rounding
// mode to account for this.
switch (round) {
case MPFR_RNDD:
case MPFR_RNDU:
case MPFR_RNDN:
break;
case MPFR_RNDZ:
round = _s < 0 ? MPFR_RNDU : MPFR_RNDD;
break;
case MPFR_RNDA:
round = _s < 0 ? MPFR_RNDD : MPFR_RNDU;
break;
default:
round = MPFR_RNDN; // New rounding modes are variants of N
break;
} // Now round is one of MPFR_RND{D,N,U}
mp_size_t excess;
mpfr_exp_t expt;
if (r == NULL) {
// If r is NULL then all the bits currently generated are considered
// significant. Thus no excess bits need to be squeezed out.
excess = 0;
// And the exponent shift in mpfr_set_z_2exp is just...
expt = -(_e << logbits_);
// However, if rounding to nearest, we need to make room for the
// midpoint bit.
if (round == MPFR_RNDN) {
excess = -1;
--expt;
}
} else { // r is non-NULL
// Generate enough digits, i.e., enough to generate prec significant
// figures for RNDD and RNDU; for RNDN we need to generate an
// additional guard bit.
mp_size_t lead = LeadingBit(r);
mpfr_prec_t prec = mpfr_get_prec (val);
mp_size_t trail = lead - prec; // position one past trailing bit
mp_size_t guard = trail + (round == MPFR_RNDN ? 0 : 1); // guard bit pos
// Generate the bits needed.
if (guard <= 0) ExpandTo(r, (-guard) >> logbits_);
// Unless bits = 1, the generation process will typically have
// generated too many bits. We figure out how many, but leaving room
// for one additional "inexact" bit. The inexact bit is set to 1 in
// order to force MPFR to treat the result as inexact, to break RNDN
// ties, and to get the ternary value set correctly.
//
// expt is the exponent used when forming the number using
// mpfr_set_z_2exp. Without the inexact bit, it's (guard - 1).
// Subtract 1 to account for the inexact bit.
expt = guard - 2;
// The number of excess bits is now the difference between the number
// of bits in the fraction (e << logbits) and -expt. Note that this
// may be -1 (meaning we'll need to shift the number left to
// accommodate the inexact bit).
excess = (_e << logbits_) + expt;
}
mpz_set_ui(_tt, _n); // The integer part
mpz_mul_2exp(_tt, _tt, _e << logbits_); // Shift to allow for fraction
mpz_add(_tt, _tt, _f); // Add fraction
if (excess > 0)
mpz_tdiv_q_2exp(_tt, _tt, excess);
else if (excess < 0)
mpz_mul_2exp(_tt, _tt, -excess);
if (r || round == MPFR_RNDN)
// Set the inexact bit (or compute the midpoint if r is NULL).
mpz_setbit(_tt, 0);
else if (round == MPFR_RNDU)
// If r is NULL, compute the upper bound.
mpz_add_ui(_tt, _tt, 1u);
// Convert to a mpfr number. If r is specified, then there are
// sufficient bits in tt that the result is inexact and that (in the case
// of RNDN) there are no ties.
int flag = mpfr_set_z_2exp(val, _tt, expt, round);
if (_s < 0) {
mpfr_neg (val, val, MPFR_RNDN);
flag = -flag;
}
return flag;
}
/**
* A coin toss. (This should really be a static function. But it uses the
* MPFRRandom temporary variable.)
*
* @param[in,out] r a GMP random generator.
* @return true or false.
**********************************************************************/
int Boolean(gmp_randstate_t r) const {
mpz_urandomb(_tt, r, 1);
return mpz_tstbit(_tt, 0);
}
};
} // namespace RandomLib
#endif // HAVE_MPFR
#endif // RANDOMLIB_MPFRRANDOM_HPP

View File

@ -0,0 +1,72 @@
/**
* \file MPFRUniform.hpp
* \brief Header for MPFRUniform
*
* Sampling exactly from a uniform distribution for MPFR.
*
* Copyright (c) Charles Karney (2012) <charles@karney.com> and licensed under
* the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_MPFRUNIFORM_HPP)
#define RANDOMLIB_MPFRUNIFORM_HPP 1
#include <RandomLib/MPFRRandom.hpp>
#if HAVE_MPFR || defined(DOXYGEN)
namespace RandomLib {
/**
* \brief The uniform distribution for MPFR.
*
* This is just a thin layer on top of MPFRRandom to provide random numbers
* uniformly distributed in [0,1].
*
* This class uses a mutable private object. So a single MPFRUniform object
* cannot safely be used by multiple threads. In a multi-processing
* environment, each thread should use a thread-specific MPFRUniform object.
*
* @tparam bits the number of bits in each digit.
**********************************************************************/
template<int bits = 32> class MPFRUniform {
public:
/**
* Initialize the MPFRUniform object.
**********************************************************************/
MPFRUniform() {};
/**
* Sample from the uniform distribution in [0,1] returning a MPFRRandom.
* This function takes an unused GMP random generator as a parameter, in
* order to parallel the usage of MPFRExponential and MPFRNormal.
*
* @param[out] t the MPFRRandom result.
* @param[in,out] r a GMP random generator (unused).
**********************************************************************/
void operator()(MPFRRandom<bits>& t, gmp_randstate_t r) const
{ Compute(r); _x.swap(t); }
/**
* Sample from the uniform distribution in [0,1].
*
* @param[out] val the sample from the uniform distribution
* @param[in,out] r a GMP random generator.
* @param[in] round the rounding direction.
* @return the MPFR ternary result (&plusmn; if val is larger/smaller than
* the exact sample).
**********************************************************************/
int operator()(mpfr_t val, gmp_randstate_t r, mpfr_rnd_t round) const
{ Compute(r); return _x(val, r, round); }
private:
// disable copy constructor and assignment operator
MPFRUniform(const MPFRUniform&);
MPFRUniform& operator=(const MPFRUniform&);
void Compute(gmp_randstate_t /* r */) const { _x. Init(); }
mutable MPFRRandom<bits> _x;
};
} // namespace RandomLib
#endif // HAVE_MPFR
#endif // RANDOMLIB_MPFRUNIFORM_HPP

View File

@ -0,0 +1,114 @@
/**
* \file NormalDistribution.hpp
* \brief Header for NormalDistribution
*
* Compute normal deviates.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_NORMALDISTRIBUTION_HPP)
#define RANDOMLIB_NORMALDISTRIBUTION_HPP 1
#include <cmath> // for std::log
namespace RandomLib {
/**
* \brief Normal deviates
*
* Sample from the normal distribution.
*
* This uses the ratio method; see Knuth, TAOCP, Vol 2, Sec. 3.4.1.C,
* Algorithm R. Unlike the Box-Muller method which generates two normal
* deviates at a time, this method generates just one. This means that this
* class has no state that needs to be saved when checkpointing a
* calculation. Original citation is\n A. J. Kinderman, J. F. Monahan,\n
* Computer Generation of Random Variables Using the Ratio of Uniform
* Deviates,\n ACM TOMS 3, 257--260 (1977).
*
* Improved "quadratic" bounds are given by\n J. L. Leva,\n A Fast Normal
* Random Number Generator,\n ACM TOMS 18, 449--453 and 454--455
* (1992).
*
* The log is evaluated 1.369 times per normal deviate with no bounds, 0.232
* times with Knuth's bounds, and 0.012 times with the quadratic bounds.
* Time is approx 0.3 us per deviate (1GHz machine, optimized, RealType =
* float).
*
* Example
* \code
* #include <RandomLib/NormalDistribution.hpp>
*
* RandomLib::Random r;
* std::cout << "Seed set to " << r.SeedString() << "\n";
* RandomLib::NormalDistribution<double> normdist;
* std::cout << "Select from normal distribution:";
* for (size_t i = 0; i < 10; ++i)
* std::cout << " " << normdist(r);
* std::cout << "\n";
* \endcode
*
* @tparam RealType the real type of the results (default double).
**********************************************************************/
template<typename RealType = double> class NormalDistribution {
public:
/**
* The type returned by NormalDistribution::operator()(Random&)
**********************************************************************/
typedef RealType result_type;
/**
* Return a sample of type RealType from the normal distribution with mean
* &mu; and standard deviation &sigma;.
*
* For &mu; = 0 and &sigma; = 1 (the defaults), the distribution is
* symmetric about zero and is nonzero. The maximum result is less than 2
* sqrt(log(2) \e p) where \e p is the precision of real type RealType.
* The minimum positive value is approximately 1/2<sup><i>p</i>+1</sup>.
* Here \e p is the precision of real type RealType.
*
* @tparam Random the type of RandomCanonical generator.
* @param[in,out] r the RandomCanonical generator.
* @param[in] mu the mean value of the normal distribution (default 0).
* @param[in] sigma the standard deviation of the normal distribution
* (default 1).
* @return the random sample.
**********************************************************************/
template<class Random>
RealType operator()(Random& r, RealType mu = RealType(0),
RealType sigma = RealType(1)) const throw();
};
template<typename RealType> template<class Random> inline RealType
NormalDistribution<RealType>::operator()(Random& r, RealType mu,
RealType sigma) const throw() {
// N.B. These constants can be regarded as "exact", so that the same number
// of significant figures are used in all versions. (They serve to
// "bracket" the real boundary specified by the log expression.)
const RealType
m = RealType( 1.7156 ), // sqrt(8/e) (rounded up)
s = RealType( 0.449871), // Constants from Leva
t = RealType(-0.386595),
a = RealType( 0.19600 ),
b = RealType( 0.25472 ),
r1 = RealType( 0.27597 ),
r2 = RealType( 0.27846 );
RealType u, v, Q;
do { // This loop is executed 1.369 times on average
// Pick point P = (u, v)
u = r.template FixedU<RealType>(); // Sample u in (0,1]
v = m * r.template FixedS<RealType>(); // Sample v in (-m/2, m/2); avoid 0
// Compute quadratic form Q
const RealType x = u - s;
const RealType y = (v < 0 ? -v : v) - t; // Sun has no long double abs!
Q = x*x + y * (a*y - b*x);
} while ( Q >= r1 && // accept P if Q < r1
( Q > r2 || // reject P if Q > r2
v*v > - 4 * u*u * std::log(u) ) ); // accept P if v^2 <= ...
return mu + sigma * (v / u); // return the slope of P (note u != 0)
}
} // namespace RandomLib
#endif // RANDOMLIB_NORMALDISTRIBUTION_HPP

View File

@ -0,0 +1,141 @@
/**
* \file Random.hpp
* \brief Header for Random, RandomGenerator.
*
* This loads up the header for RandomCanonical, RandomEngine, etc., to
* provide access to random integers of various sizes, random reals with
* various precisions, a random probability, etc.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_RANDOM_HPP)
#define RANDOMLIB_RANDOM_HPP 1
#include <RandomLib/Config.h>
#if defined(_MSC_VER)
typedef unsigned uint32_t;
typedef unsigned long long uint64_t;
#else
#include <stdint.h>
#endif
/**
* Use table, Power2::power2, for pow2? This isn't necessary with g++ 4.0
* because calls to std::pow are optimized. g++ 4.1 seems to have lost this
* capability though! And it's back in g++ 4.4. So, for simplicity, assume
* that all "current" versions of g++ perform the optimization.
**********************************************************************/
#if !defined(RANDOMLIB_POWERTABLE)
#if defined(__GNUC__)
#define RANDOMLIB_POWERTABLE 0
#else
// otherwise use a lookup table
#define RANDOMLIB_POWERTABLE 1
#endif
#endif
#if !HAVE_LONG_DOUBLE || defined(_MSC_VER)
#define RANDOMLIB_LONGDOUBLEPREC 53
#elif defined(__sparc)
#define RANDOMLIB_LONGDOUBLEPREC 113
#else
/**
* The precision of long doubles, used for sizing Power2::power2. 64 on
* Linux/Intel, 106 on MaxOS/PowerPC
**********************************************************************/
#define RANDOMLIB_LONGDOUBLEPREC __LDBL_MANT_DIG__
#endif
/**
* A compile-time assert. Use C++11 static_assert, if available.
**********************************************************************/
#if !defined(STATIC_ASSERT)
# if __cplusplus >= 201103
# define STATIC_ASSERT static_assert
# elif defined(__GXX_EXPERIMENTAL_CXX0X__)
# define STATIC_ASSERT static_assert
# elif defined(_MSC_VER) && _MSC_VER >= 1600
# define STATIC_ASSERT static_assert
# else
# define STATIC_ASSERT(cond,reason) \
{ enum{ STATIC_ASSERT_ENUM = 1/int(cond) }; }
# endif
#endif
/**
* Are denormalized reals of type RealType supported?
**********************************************************************/
#define RANDOMLIB_HASDENORM(RealType) 1
#if defined(_MSC_VER) && defined(RANDOMLIB_SHARED_LIB) && RANDOMLIB_SHARED_LIB
# if RANDOMLIB_SHARED_LIB > 1
# error RANDOMLIB_SHARED_LIB must be 0 or 1
# elif defined(RandomLib_EXPORTS)
# define RANDOMLIB_EXPORT __declspec(dllexport)
# else
# define RANDOMLIB_EXPORT __declspec(dllimport)
# endif
#else
# define RANDOMLIB_EXPORT
#endif
#include <stdexcept>
/**
* \brief Namespace for %RandomLib
*
* All of %RandomLib is defined within the RandomLib namespace. In addtiion
* all the header files are included via %RandomLib/filename. This minimizes
* the likelihood of conflicts with other packages.
**********************************************************************/
namespace RandomLib {
/**
* \brief Exception handling for %RandomLib
*
* A class to handle exceptions. It's derived from std::runtime_error so it
* can be caught by the usual catch clauses.
**********************************************************************/
class RandomErr : public std::runtime_error {
public:
/**
* Constructor
*
* @param[in] msg a string message, which is accessible in the catch
* clause, via what().
**********************************************************************/
RandomErr(const std::string& msg) : std::runtime_error(msg) {}
};
} // namespace RandomLib
#include <RandomLib/RandomCanonical.hpp>
#if !defined(RANDOMLIB_BUILDING_LIBRARY)
namespace RandomLib {
#if !defined(RANDOMLIB_DEFAULT_GENERATOR)
#define RANDOMLIB_DEFAULT_GENERATOR SRandomGenerator32
#endif
/**
* Point Random to one of a specific MT19937 generators.
**********************************************************************/
typedef RANDOMLIB_DEFAULT_GENERATOR RandomGenerator;
/**
* Hook Random to RandomGenerator
**********************************************************************/
typedef RandomCanonical<RandomGenerator> Random;
} // namespace RandomLib
#endif // !defined(RANDOMLIB_BUILDING_LIBRARY)
#endif // RANDOMLIB_RANDOM_HPP

View File

@ -0,0 +1,384 @@
/**
* \file RandomAlgorithm.hpp
* \brief Header for MT19937 and SFMT19937.
*
* This provides an interface to the Mersenne Twister
* <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html">
* MT19937</a> and SIMD oriented Fast Mersenne Twister
* <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html">
* SFMT19937</a> random number engines.
*
* Interface routines written by Charles Karney <charles@karney.com> and
* licensed under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_RANDOMALGORITHM_HPP)
#define RANDOMLIB_RANDOMALGORITHM_HPP 1
#include <RandomLib/RandomType.hpp>
#include <stdexcept>
#include <string>
#if defined(HAVE_SSE2) && HAVE_SSE2
#include <emmintrin.h>
#endif
#if (defined(HAVE_SSE2) && HAVE_SSE2) && (defined(HAVE_ALTIVEC) && HAVE_ALTIVEC)
#error "HAVE_SSE2 and HAVE_ALTIVEC should not both be defined"
#endif
#if defined(_MSC_VER)
// Squelch warnings about casts truncating constants
# pragma warning (push)
# pragma warning (disable: 4310)
#endif
namespace RandomLib {
/**
* \brief The %MT19937 random number engine.
*
* This provides an interface to Mersenne Twister random number engine,
* <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html">
* MT19937</a>. See\n Makoto Matsumoto and Takuji Nishimura,\n Mersenne
* Twister: A 623-Dimensionally Equidistributed Uniform Pseudo-Random Number
* Generator,\n ACM TOMACS 8, 3--30 (1998)
*
* This is adapted from the 32-bit and 64-bit C versions available at
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html and
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt64.html
*
* The template argument give the type \e RandomType of the "natural" result.
* This incorporates the bit width and the C++ type of the result. Although
* the two versions of MT19937 produce different sequences, the
* implementations here are portable across 32-bit and 64-bit architectures.
*
* The class chiefly supplies the method for advancing the state by
* Transition.
*
* @tparam RandomType the type of the results, either Random_u32 or
* Random_u64.
*
* Interface routines written by Charles Karney <charles@karney.com> and
* licensed under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
template<class RandomType> class RANDOMLIB_EXPORT MT19937 {
public:
/**
* The result RandomType
**********************************************************************/
typedef RandomType engine_t;
/**
* The internal numeric type for MT19337::Transition
**********************************************************************/
typedef typename engine_t::type internal_type;
private:
/**
* The unsigned type of engine_t
**********************************************************************/
typedef typename engine_t::type engine_type;
/**
* The width of the engine_t
**********************************************************************/
static const unsigned width = engine_t::width;
enum {
/**
* The Mersenne prime is 2<sup><i>P</i></sup> &minus; 1
**********************************************************************/
P = 19937,
/**
* The short lag for MT19937
**********************************************************************/
M = width == 32 ? 397 : 156,
/**
* The number of ignored bits in the first word of the state
**********************************************************************/
R = ((P + width - 1)/width) * width - P
};
static const engine_type mask = engine_t::mask;
/**
* Magic matrix for MT19937
**********************************************************************/
static const engine_type magic =
width == 32 ? 0x9908b0dfULL : 0xb5026f5aa96619e9ULL;
/**
* Mask for top \e width &minus; \e R bits of a word
**********************************************************************/
static const engine_type upper = mask << R & mask;
/**
* Mask for low \e R bits of a <i>width</i>-bit word
**********************************************************************/
static const engine_type lower = ~upper & mask;
public:
/**
* A version number "EnMT" or "EnMU" to ensure safety of Save/Load. This
* needs to be unique across RandomAlgorithms.
**********************************************************************/
static const unsigned version = 0x456e4d54UL + (engine_t::width/32 - 1);
enum {
/**
* The size of the state. This is the long lag for MT19937.
**********************************************************************/
N = (P + width - 1)/width
};
/**
* Advance state by \e count batches. For speed all \e N words of state
* are advanced together. If \e count is negative, the state is stepped
* backwards. This is the meat of the MT19937 engine.
*
* @param[in] count how many batches to advance.
* @param[in,out] statev the internal state of the random number generator.
**********************************************************************/
static void Transition(long long count, internal_type statev[]) throw();
/**
* Manipulate a word of the state prior to output.
*
* @param[in] y a word of the state.
* @return the result.
**********************************************************************/
static engine_type Generate(engine_type y) throw();
/**
* Convert an arbitrary state into a legal one. This consists of (a)
* turning on one bit if the state is all zero and (b) making 31 bits of
* the state consistent with the other 19937 bits.
*
* @param[in,out] state the state of the generator.
**********************************************************************/
static void NormalizeState(engine_type state[]) throw();
/**
* Check that the state is legal, throwing an exception if it is not. At
* the same time, accumulate a checksum of the state.
*
* @param[in] state the state of the generator.
* @param[in,out] check an accumulated checksum.
**********************************************************************/
static void CheckState(const engine_type state[], Random_u32::type& check);
/**
* Return the name of the engine
*
* @return the name.
**********************************************************************/
static std::string Name() throw() {
return "MT19937<Random_u" + std::string(width == 32 ? "32" : "64") + ">";
}
};
/// \cond SKIP
template<>
inline Random_u32::type MT19937<Random_u32>::Generate(engine_type y) throw() {
y ^= y >> 11;
y ^= y << 7 & engine_type(0x9d2c5680UL);
y ^= y << 15 & engine_type(0xefc60000UL);
y ^= y >> 18;
return y;
}
template<>
inline Random_u64::type MT19937<Random_u64>::Generate(engine_type y) throw() {
// Specific tempering instantiation for width = 64 given in
// http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt64.html
y ^= y >> 29 & engine_type(0x5555555555555555ULL);
y ^= y << 17 & engine_type(0x71d67fffeda60000ULL);
y ^= y << 37 & engine_type(0xfff7eee000000000ULL);
y ^= y >> 43;
return y;
}
/// \endcond
/**
* \brief The SFMT random number engine.
*
* This provides an implementation of the SIMD-oriented Fast Mersenne Twister
* random number engine,
* <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/index.html">
* SFMT</a>. See\n Mutsuo Saito,\n An Application of Finite Field: Design
* and Implementation of 128-bit Instruction-Based Fast Pseudorandom Number
* Generator,\n Master's Thesis, Dept. of Math., Hiroshima University
* (Feb. 2007).\n
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/M062821.pdf
* Mutsuo Saito and Makoto Matsumoto,\n
* SIMD-oriented Fast Mersenne Twister: a 128-bit Pseudorandom Number
* Generator,\n accepted in the proceedings of MCQMC2006\n
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/ARTICLES/sfmt.pdf
*
* The template argument gives the type \e RandomType of the "natural"
* result. This incorporates the bit width and the C++ type of the result.
* The 32-bit and 64-bit versions of SFMT19937 produce the same sequences and
* the differing only in whether how the state is represented. The
* implementation includes a version using 128-bit SSE2 instructions. On
* machines without these instructions, portable implementations using
* traditional operations are provided. With the same starting seed,
* SRandom32::Ran64() and SRandom64::Ran64() produces the same sequences.
* Similarly SRandom64::Ran32() produces every other member of the sequence
* produced by SRandom32::Ran32().
*
* The class chiefly supplies the method for advancing the state by
* Transition.
*
* @tparam RandomType the type of the results, either Random_u32 or
* Random_u64.
*
* Written by Charles Karney <charles@karney.com> and licensed under the
* MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
template<class RandomType> class RANDOMLIB_EXPORT SFMT19937 {
public:
/**
* The result RandomType
**********************************************************************/
typedef RandomType engine_t;
#if defined(HAVE_SSE2) && HAVE_SSE2
typedef __m128i internal_type;
#elif defined(HAVE_ALTIVEC) && HAVE_ALTIVEC
typedef vector unsigned internal_type;
#else
/**
* The internal numeric type for SFMT19337::Transition
**********************************************************************/
typedef typename engine_t::type internal_type;
#endif
private:
/**
* The unsigned type of engine_t
**********************************************************************/
typedef typename engine_t::type engine_type;
/**
* The width of the engine_t
**********************************************************************/
static const unsigned width = engine_t::width;
enum {
/**
* The Mersenne prime is 2<sup><i>P</i></sup> &minus; 1
**********************************************************************/
P = 19937,
/**
* The long lag for SFMT19937 in units of 128-bit words
**********************************************************************/
N128 = (P + 128 - 1)/128,
/**
* How many width words per 128-bit word.
**********************************************************************/
R = 128 / width,
/**
* The short lag for SFMT19937 in units of 128-bit words
**********************************************************************/
M128 = 122,
/**
* The short lag for SFMT19937
**********************************************************************/
M = M128 * R
};
#if (defined(HAVE_SSE2) && HAVE_SSE2) || (defined(HAVE_ALTIVEC) && HAVE_ALTIVEC)
static const Random_u32::type magic0 = 0x1fffefUL;
static const Random_u32::type magic1 = 0x1ecb7fUL;
static const Random_u32::type magic2 = 0x1affffUL;
static const Random_u32::type magic3 = 0x1ffff6UL;
#else
/**
* Magic matrix for SFMT19937. Only the low 21 (= 32 &minus; 11) bits need
* to be set. (11 is the right shift applied to the words before masking.
**********************************************************************/
static const engine_type
magic0 = width == 32 ? 0x1fffefULL : 0x1ecb7f001fffefULL;
static const engine_type
magic1 = width == 32 ? 0x1ecb7fULL : 0x1ffff6001affffULL;
static const engine_type
magic2 = width == 32 ? 0x1affffULL : 0ULL;
static const engine_type
magic3 = width == 32 ? 0x1ffff6ULL : 0ULL;
#endif
/**
* Mask for simulating u32 << 18 with 64-bit words
**********************************************************************/
static const engine_type mask18 = engine_type(0xfffc0000fffc0000ULL);
/**
* Magic constants needed by "period certification"
**********************************************************************/
static const engine_type PARITY0 = 1U;
static const engine_type PARITY1 = width == 32 ? 0U : 0x13c9e68400000000ULL;
static const engine_type PARITY2 = 0U;
static const engine_type PARITY3 = width == 32 ? 0x13c9e684UL : 0U;
/**
* Least significant bit of PARITY
**********************************************************************/
static const unsigned PARITY_LSB = 0;
static const engine_type mask = engine_t::mask;
public:
/**
* A version number "EnSM" or "EnSN" to ensure safety of Save/Load. This
* needs to be unique across RandomAlgorithms.
**********************************************************************/
static const unsigned version = 0x456e534dUL + (engine_t::width/32 - 1);
enum {
/**
* The size of the state. The long lag for SFMT19937
**********************************************************************/
N = N128 * R
};
/**
* Advance state by \e count batches. For speed all \e N words of state
* are advanced together. If \e count is negative, the state is stepped
* backwards. This is the meat of the SFMT19937 engine.
*
* @param[in] count how many batches to advance.
* @param[in,out] statev the internal state of the random number generator.
**********************************************************************/
static void Transition(long long count, internal_type statev[])
throw();
/**
* Manipulate a word of the state prior to output. This is a no-op for
* SFMT19937.
*
* @param[in] y a word of the state.
* @return the result.
**********************************************************************/
static engine_type Generate(engine_type y) throw() { return y; }
/**
* Convert an arbitrary state into a legal one. This consists a "period
* certification to ensure that the period of the generator is at least
* 2<sup><i>P</i></sup> &minus; 1.
*
* @param[in,out] state the state of the generator.
**********************************************************************/
static void NormalizeState(engine_type state[]) throw();
/**
* Check that the state is legal, throwing an exception if it is not. This
* merely verifies that the state is not all zero. At the same time,
* accumulate a checksum of the state.
*
* @param[in] state the state of the generator.
* @param[in,out] check an accumulated checksum.
**********************************************************************/
static void CheckState(const engine_type state[], Random_u32::type& check);
/**
* Return the name of the engine
*
* @return the name.
**********************************************************************/
static std::string Name() throw() {
return "SFMT19937<Random_u" +
std::string(width == 32 ? "32" : "64") + ">";
}
};
} // namespace RandomLib
#if defined(_MSC_VER)
# pragma warning (pop)
#endif
#endif // RANDOMLIB_RANDOMALGORITHM_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,640 @@
/**
* \file RandomEngine.hpp
* \brief Header for RandomEngine.
*
* Copyright (c) Charles Karney (2006-2012) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_RANDOMENGINE_HPP)
#define RANDOMLIB_RANDOMENGINE_HPP 1
#include <RandomLib/RandomSeed.hpp>
#include <RandomLib/RandomAlgorithm.hpp>
#include <RandomLib/RandomMixer.hpp>
#include <limits>
#include <string>
#include <algorithm>
#if defined(HAVE_SSE2) && HAVE_SSE2 && defined(_MSC_VER) && !defined(_WIN64)
#include <new>
#endif
#if !defined(RANDOMLIB_BUILDING_LIBRARY) && \
defined(HAVE_BOOST_SERIALIZATION) && HAVE_BOOST_SERIALIZATION
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/split_member.hpp>
#include <boost/serialization/vector.hpp>
#endif
namespace RandomLib {
/**
* \brief Uniform random number generator.
*
* This implements a generic random number generator. Such a generator
* requires two data holders RandomSeed, to hold the seed, and RandomEngine,
* to hold the state. In addition we need two piece of machinery, a "Mixer"
* to convert the seed into an initial state and an "Algorithm" to advance the
* state.
*
* @tparam Algorithm the random number algorithm.
* @tparam Mixer the way seeds are turned into state.
*
* RandomSeed is responsible for setting and reporting the seed.
*
* Mixer has no state and implements only static methods. It needs to have
* the following public interface
* - typedef mixer_t: a RandomType giving the output type
* - unsigned version: an identifying version number
* - static std::string Name(): an identifying name for the mixer
* - static method SeedToState: converts a seed into n words of state.
*
* Algorithm has no state and implements only static methods. It needs to
* have the following public interface
* - typedef engine_t: a RandomType giving the output type
* - typedef internal_type: a integer type used by Transition. This is
* usually the same as engine_t::type. However it allows the use of
* vector instructions on some platforms. We require that engine_t::type
* and internal_type line up properly in a union so that there is no need
* to convert the data explicitly between internal_type and
* engine_t::type.
* - unsigned version: an identifying version number
* - static std::string Name(): an identifying name for the mixer
* - enum N: the size of the state in units of engine_t.
* - static method Transition: steps the generator forwards or backwards.
* - static method Generate: tempers the state immediately prior to output
* - static method NormalizeState: force the initial state (the result of
* the Mixer) into a legal state.
* - static method CheckState accumulates the checksum for the state into
* check. In addition it throws an exception if the state is bad.
*
* RandomEngine is the glue that holds everything together. It repacks
* the mixer_t data from Mixer into engine_t if necessary. It deals with
* delivering individual random results, stepping the state forwards and
* backwards, leapfrogging the generator, I/O of the generator, etc.
*
* Written by Charles Karney <charles@karney.com> and licensed under the
* MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
template<class Algorithm, class Mixer>
class RANDOMLIB_EXPORT RandomEngine : public RandomSeed {
private:
/**
* The result RandomType (carried over from the \e Algorithm).
**********************************************************************/
typedef typename Algorithm::engine_t result_t;
/**
* The RandomType used by the \e Mixer.
**********************************************************************/
typedef typename Mixer::mixer_t mixer_t;
/**
* The internal_type used by the Algorithm::Transition().
**********************************************************************/
typedef typename Algorithm::internal_type engine_type;
public:
/**
* The number of random bits produced by Ran().
**********************************************************************/
enum {
width = result_t::width
};
/**
* A type large enough to hold \e width bits. This is used for the
* internal state of the generator and the result returned by Ran().
**********************************************************************/
typedef typename result_t::type result_type;
/**
* The minimum result returned by Ran() = 0.
**********************************************************************/
static const result_type min = result_t::min;
/**
* The maximum result returned by Ran() = 2<sup><i>w</i></sup> &minus; 1.
**********************************************************************/
static const result_type max = result_t::max;
protected:
/**
* The mask for the result_t.
**********************************************************************/
static const result_type mask = result_t::mask;
private:
/**
* A version number "RandLib0" to ensure safety of Save/Load. The first 7
* bytes can be regarded as a "signature" and the 8th byte a version
* number.
**********************************************************************/
static const u64::type version = 0x52616e644c696230ULL; // 'RandLib0'
/**
* Marker for uninitialized object
**********************************************************************/
static const unsigned UNINIT = 0xffffffffU;
enum {
/**
* The size of the state in units of result_type
**********************************************************************/
N = Algorithm::N,
/**
* The size of the state in units of mixer_t::type
**********************************************************************/
NU = (N * width + mixer_t::width - 1) / mixer_t::width,
/**
* The size of the state in units of engine_type.
**********************************************************************/
NV = N * sizeof(result_type) / sizeof(engine_type)
};
/**
* \brief Union for the state.
*
* A union to hold the state in the result_type, mixer_t::type, and
* engine_type representations.
**********************************************************************/
union {
/**
* the result_type representation returned by Ran()
**********************************************************************/
result_type _state[N];
/**
* the mixer_t::type representation returned by Mixer::SeedToState.
**********************************************************************/
typename mixer_t::type _stateu[NU];
/**
* the engine_type representation returned by Algorithm::Transition.
**********************************************************************/
engine_type _statev[NV];
};
/**
* The index for the next random value
**********************************************************************/
unsigned _ptr;
/**
* How many times has Transition() been called
**********************************************************************/
long long _rounds;
/**
* Stride for leapfrogging
**********************************************************************/
unsigned _stride;
public:
/**
* \name Constructors
**********************************************************************/
///@{
/**
* Initialize from a vector. Only the low \e 32 bits of each element are
* used.
*
* @tparam IntType the integral type of the elements of the vector.
* @param[in] v the vector of elements.
**********************************************************************/
template<typename IntType>
explicit RandomEngine(const std::vector<IntType>& v) { Reseed(v); }
/**
* Initialize from a pair of iterators setting seed to [\e a, \e b). The
* iterator must produce results which can be converted into seed_type.
* Only the low \e 32 bits of each element are used.
*
* @tparam InputIterator the type of the iterator.
* @param[in] a the beginning iterator.
* @param[in] b the ending iterator.
**********************************************************************/
template<typename InputIterator>
RandomEngine(InputIterator a, InputIterator b) { Reseed(a, b); }
/**
* Initialize with seed [\e n]. Only the low \e width bits of \e n are
* used.
*
* @param[in] n the new seed to use.
**********************************************************************/
explicit RandomEngine(seed_type n) { Reseed(n); }
/**
* Initialize with seed []. This can be followed by a call to Reseed() to
* select a unique seed.
**********************************************************************/
RandomEngine() { unsigned long s[1]; Reseed(s, s); }
/**
* Initialize from a string. See Reseed(const std::string& s)
*
* @param[in] s the string to be decoded into a seed.
**********************************************************************/
explicit RandomEngine(const std::string& s) { Reseed(s); }
///@}
/**
* \name Functions for returning random data
**********************************************************************/
///@{
/**
* Return \e width bits of randomness. This is the natural unit of random
* data produced random number generator.
*
* @return the next random number of width \e width.
**********************************************************************/
result_type Ran() throw() {
if (_ptr >= N)
Next();
result_type y = _state[_ptr];
_ptr += _stride;
return Algorithm::Generate(y);
}
/**
* Return 32 bits of randomness.
*
* @return a 32-bit random number.
**********************************************************************/
u32::type Ran32() throw() {
// return width > 32 ? u32::cast(Ran()) : Ran();
return u32::cast(Ran());
}
/**
* Return 64 bits of randomness.
*
* @return a 64-bit random number.
**********************************************************************/
u64::type Ran64() throw() {
const u64::type x = Ran();
return width > 32 ? x : u64::cast(Ran()) << (64 - width) | x;
}
/**
* Return \e width bits of randomness. Result is in [0,
* 2<sup><i>w</i></sup>). (This just calls Ran().)
*
* @return the next random number of width \e width.
**********************************************************************/
result_type operator()() throw() { return Ran(); }
///@}
#if defined(HAVE_SSE2) && HAVE_SSE2 && defined(_MSC_VER) && !defined(_WIN64)
/**
* new operator with alignment (needed for Visual Studio)
**********************************************************************/
void* operator new(size_t n) {
void* p = _aligned_malloc(n, __alignof(RandomEngine));
if (p == 0) throw std::bad_alloc();
return p;
}
/**
* delete operator with alignment (needed for Visual Studio)
**********************************************************************/
void operator delete(void* p) { _aligned_free(p); }
/**
* new[] operator with alignment (needed for Visual Studio)
**********************************************************************/
void* operator new[](size_t n) {
void* p = _aligned_malloc(n, __alignof(RandomEngine));
if (p == 0) throw std::bad_alloc();
return p;
}
/**
* delete[] operator with alignment (needed for Visual Studio)
**********************************************************************/
void operator delete[](void* p) { _aligned_free(p); }
#endif
/**
* \name Comparing Random objects
**********************************************************************/
///@{
/**
* Test equality of two Random objects. This test that the seeds match and
* that they have produced the same number of random numbers.
*
* @param[in] r the RandomEngine object to compare.
* @return true if the RandomEngine objects produce the same results.
**********************************************************************/
bool operator==(const RandomEngine& r) const throw()
// Ensure that the two Random objects behave the same way. Note however
// that the internal states may still be different, e.g., the following all
// result in Random objects which are == (with Count() == 0) but which all
// have different internal states:
//
// Random r(0); _ptr == UNINIT
// r.StepCount( 1); r.StepCount(-1); _ptr == 0, _rounds == 0
// r.StepCount(-1); r.StepCount( 1); _ptr == N, _rounds == -1
{ return Count() == r.Count() && _seed == r._seed &&
_stride == r._stride; }
/**
* Test inequality of two Random objects. See Random::operator==
*
* @param[in] r the RandomEngine object to compare.
* @return true if the RandomEngine objects produce different results.
**********************************************************************/
bool operator!=(const RandomEngine& r) const throw()
{ return !operator==(r); }
///@}
/**
* \name Interchanging Random objects
**********************************************************************/
///@{
/**
* Swap with another Random object.
*
* @param[in,out] t the RandomEngine object to swap with.
**********************************************************************/
void swap(RandomEngine& t) throw() {
_seed.swap(t._seed);
std::swap(_ptr, t._ptr);
std::swap(_stride, t._stride);
std::swap(_rounds, t._rounds);
std::swap_ranges(_state, _state + N, t._state);
}
///@}
/**
* \name Writing to and reading from a stream
**********************************************************************/
///@{
/**
* Save the state of the Random object to an output stream. Format is a
* sequence of unsigned 32-bit integers written either in decimal (\e bin
* false, text format) or in network order with most significant byte first
* (\e bin true, binary format). Data consists of:
*
* - RandomLib magic string + version (2 words)
* - Algorithm version (1 word)
* - Mixer version (1 word)
* - _seed.size() (1 word)
* - _seed data (_seed.size() words)
* - _ptr (1 word)
* - _stride (1 word)
* - if _ptr != UNINIT, _rounds (2 words)
* - if _ptr != UNINIT, _state (N words or 2 N words)
* - checksum
*
* Shortest possible saved result consists of 8 words. This corresponds to
* RandomSeed() = [] and Count() = 0.
*
* @param[in,out] os the output stream.
* @param[in] bin if true (the default) save in binary mode.
**********************************************************************/
void Save(std::ostream& os, bool bin = true) const;
/**
* Restore the state of the Random object from an input stream. If \e bin,
* read in binary, else use text format. See documentation of
* RandomEngine::Save for the format. Include error checking on data to
* make sure the input has not been corrupted. If an error occurs while
* reading, the Random object is unchanged.
*
* @param[in,out] is the input stream.
* @param[in] bin if true (the default) load in binary mode.
* @exception RandomErr if the state read from \e is is illegal.
**********************************************************************/
void Load(std::istream& is, bool bin = true) {
// Read state into temporary so as not to change object on error.
RandomEngine t(is, bin);
_seed.reserve(t._seed.size());
*this = t;
}
///@}
/**
* \name Basic I/O
**********************************************************************/
///@{
/**
* Write the state of a generator to stream \e os as text
*
* @param[in,out] os the output stream.
* @param[in] r the RandomEngine object to be saved.
**********************************************************************/
friend std::ostream& operator<<(std::ostream& os, const RandomEngine& r) {
r.Save(os, false);
return os;
}
/**
* Read the state of a generator from stream \e is as text
*
* @param[in,out] is the output stream.
* @param[in] r the RandomEngine object to be loaded.
* @exception RandomErr if the state read from \e is is illegal.
**********************************************************************/
friend std::istream& operator>>(std::istream& is, RandomEngine& r) {
r.Load(is, false);
return is;
}
///@}
/**
* \name Examining and advancing the Random generator
**********************************************************************/
///@{
/**
* Return the number of random numbers used. This needs to return a long
* long result since it can reasonably exceed 2<sup>31</sup>. (On a 1GHz
* machine, it takes about a minute to produce 2<sup>32</sup> random
* numbers.) More precisely this is the (zero-based) index of the next
* random number to be produced. (This distinction is important when
* leapfrogging is in effect.)
*
* @return the count of random numbers used.
**********************************************************************/
long long Count() const throw()
{ return _ptr == UNINIT ? 0 : _rounds * N + _ptr; }
/**
* Step the generator forwards or backwards so that the value returned
* by Count() is \e n
*
* @param[in] n the new count.
**********************************************************************/
void SetCount(long long n) throw() { StepCount(n - Count()); }
/**
* Step the generator forward \e n steps. \e n can be negative.
*
* @param[in] n how much to step the generator forward.
**********************************************************************/
void StepCount(long long n) throw();
/**
* Resets the sequence. Equivalent to SetCount(0), but works by
* reinitializing the Random object from its seed, rather than by stepping
* the sequence backwards. In addition, this undoes leapfrogging.
**********************************************************************/
void Reset() throw() { _ptr = UNINIT; _stride = 1; }
///@}
/**
* \name Leapfrogging
**********************************************************************/
///@{
/**
* Set leapfrogging stride to a positive number \e n and increment Count()
* by \e k < \e n. If the current Count() is \e i, then normally the next
* 3 random numbers would have (zero-based) indices \e i, \e i + 1, \e i +
* 2, and the new Count() is \e i + 2. However, after SetStride(\e n, \e
* k) the next 3 random numbers have indices \e i + \e k, \e i + \e k + \e
* n, \e i + \e k + 2\e n, and the new Count() is \e i + \e k + 3\e n.
* With leapfrogging in effect, the time to produce raw random numbers is
* roughly proportional to 1 + (\e n &minus; 1)/3. Reseed(...) and Reset()
* both reset the stride back to 1. See \ref parallel for a description of
* how to use this facility.
*
* @param[in] n the stride (default 1).
* @param[in] k the initial increment (default 0).
* @exception RandomErr if \e n is 0 or too large or if \e k is not less
* than \e n.
**********************************************************************/
void SetStride(unsigned n = 1, unsigned k = 0) {
// Limit stride to UNINIT/2. This catches negative numbers that have
// been cast into unsigned. In reality the stride should be no more than
// 10-100.
if (n == 0 || n > UNINIT/2)
throw RandomErr("RandomEngine: Invalid stride");
if (k >= n)
throw RandomErr("RandomEngine: Invalid offset");
_stride = n;
StepCount(k);
}
/**
* Return leapfrogging stride.
*
* @return the stride.
**********************************************************************/
unsigned GetStride() const throw() { return _stride; }
///@}
/**
* Tests basic engine.
*
* @exception RandomErr if any of the tests fail.
**********************************************************************/
static void SelfTest();
/**
* Return the name of the generator. This incorporates the names of the \e
* Algorithm and \e Mixer.
*
* @return the name of the generator.
**********************************************************************/
static std::string Name() {
return "RandomEngine<" + Algorithm::Name() + "," + Mixer::Name() + ">";
}
private:
/**
* Compute initial state from seed
**********************************************************************/
void Init() throw();
/**
* The interface to Transition used by Ran().
**********************************************************************/
void Next() throw() {
if (_ptr == UNINIT)
Init();
_rounds += _ptr/N;
Algorithm::Transition(_ptr/N, _statev);
_ptr %= N;
}
u32::type Check(u64::type v, u32::type e, u32::type m) const;
static result_type SelfTestResult(unsigned) throw() { return 0; }
/**
* Read from an input stream. Potentially corrupts object. This private
* constructor is used by RandomEngine::Load so that it can avoid
* corrupting its state on bad input.
**********************************************************************/
explicit RandomEngine(std::istream& is, bool bin);
#if !defined(RANDOMLIB_BUILDING_LIBRARY) && \
defined(HAVE_BOOST_SERIALIZATION) && HAVE_BOOST_SERIALIZATION
friend class boost::serialization::access;
/**
* Save to a boost archive. Boost versioning isn't very robust. (It
* allows a RandomGenerator32 to be read back in as a RandomGenerator64.
* It doesn't interact well with templates.) So we do our own versioning
* and supplement this with a checksum.
**********************************************************************/
template<class Archive> void save(Archive& ar, const unsigned int) const {
u64::type _version = version;
u32::type _eversion = Algorithm::version,
_mversion = Mixer::version,
_checksum = Check(_version, _eversion, _mversion);
ar & boost::serialization::make_nvp("version" , _version )
& boost::serialization::make_nvp("eversion", _eversion)
& boost::serialization::make_nvp("mversion", _mversion)
& boost::serialization::make_nvp("seed" , _seed )
& boost::serialization::make_nvp("ptr" , _ptr )
& boost::serialization::make_nvp("stride" , _stride );
if (_ptr != UNINIT)
ar & boost::serialization::make_nvp("rounds", _rounds )
& boost::serialization::make_nvp("state" , _state );
ar & boost::serialization::make_nvp("checksum", _checksum);
}
/**
* Load from a boost archive. Do this safely so that the current object is
* not corrupted if the archive is bogus.
**********************************************************************/
template<class Archive> void load(Archive& ar, const unsigned int) {
u64::type _version;
u32::type _eversion, _mversion, _checksum;
ar & boost::serialization::make_nvp("version" , _version )
& boost::serialization::make_nvp("eversion", _eversion )
& boost::serialization::make_nvp("mversion", _mversion );
RandomEngine<Algorithm, Mixer> t(std::vector<seed_type>(0));
ar & boost::serialization::make_nvp("seed" , t._seed )
& boost::serialization::make_nvp("ptr" , t._ptr )
& boost::serialization::make_nvp("stride" , t._stride );
if (t._ptr != UNINIT)
ar & boost::serialization::make_nvp("rounds", t._rounds )
& boost::serialization::make_nvp("state" , t._state );
ar & boost::serialization::make_nvp("checksum", _checksum );
if (t.Check(_version, _eversion, _mversion) != _checksum)
throw RandomErr("RandomEngine: Checksum failure");
_seed.reserve(t._seed.size());
*this = t;
}
/**
* Glue the boost save and load functionality together---a bit of boost
* magic.
**********************************************************************/
template<class Archive>
void serialize(Archive &ar, const unsigned int file_version)
{ boost::serialization::split_member(ar, *this, file_version); }
#endif // HAVE_BOOST_SERIALIZATION
};
typedef RandomEngine<MT19937 <Random_u32>, MixerSFMT> MRandomGenerator32;
typedef RandomEngine<MT19937 <Random_u64>, MixerSFMT> MRandomGenerator64;
typedef RandomEngine<SFMT19937<Random_u32>, MixerSFMT> SRandomGenerator32;
typedef RandomEngine<SFMT19937<Random_u64>, MixerSFMT> SRandomGenerator64;
} // namespace RandomLib
namespace std {
/**
* Swap two RandomEngines. This is about 3x faster than the default swap.
*
* @tparam Algorithm the algorithm for the RandomEngine.
* @tparam Mixer the mixer for the RandomEngine.
* @param[in,out] r the first RandomEngine to swap.
* @param[in,out] s the second RandomEngine to swap.
**********************************************************************/
template<class Algorithm, class Mixer>
void swap(RandomLib::RandomEngine<Algorithm, Mixer>& r,
RandomLib::RandomEngine<Algorithm, Mixer>& s) throw() {
r.swap(s);
}
} // namespace std
#endif // RANDOMLIB_RANDOMENGINE_HPP

View File

@ -0,0 +1,258 @@
/**
* \file RandomMixer.hpp
* \brief Header for Mixer classes.
*
* Mixer classes convert a seed vector into a random generator state. An
* important property of this method is that "close" seeds should produce
* "widely separated" states. This allows the seeds to be set is some
* systematic fashion to produce a set of uncorrelated random number
* sequences.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_RANDOMMIXER_HPP)
#define RANDOMLIB_RANDOMMIXER_HPP 1
#include <vector>
#include <string>
#include <RandomLib/RandomSeed.hpp>
namespace RandomLib {
/**
* \brief The original %MT19937 mixing functionality
*
* This implements the functionality of init_by_array in MT19937
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/CODES/mt19937ar.c
* and init_by_array64 in MT19937_64
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/VERSIONS/C-LANG/mt19937-64.c
* with the following changes:
* - in the case of an zero-length seed array, behave in the same way if
* MT19937 and MT19937_64 are called without initialization in which case,
* e.g., init_genrand(5489UL) is called. (init_by_array does not allow
* calling with a zero-length seed.)
* - init_by_array64 accepts a seed array of 64-bit unsigned ints. Here with
* seed is an array of 32-bit unsigned ints and these are repacked into
* 64-bit quantities internally using a LSB convention. Thus, to mimic the
* MT19937_64 sample invocation with a seed array {0x12345ULL, 0x23456ULL,
* 0x34567ULL, 0x45678ULL}, MixerMT0<Random_u64>::SeedToState needs to
* be invoked with a seed vector [0x12345UL, 0, 0x23456UL, 0, 0x34567UL, 0,
* 0x45678UL, 0]. (Actually the last 0 is unnecessary.)
*
* The template parameter \e RandomType switches between the 32-bit and
* 64-bit versions.
*
* MixerMT0 is specific to the MT19937 generators and should not be used
* for other generators (e.g., SFMT19937). In addition, MixerMT0 has
* known defects and should only be used to check the operation of the
* MT19937 engines against the original implementation. These defects are
* described in the MixerMT1 which is a modification of MixerMT0
* which corrects these defects. For production use MixerMT1 or,
* preferably, MixerSFMT should be used.
*
* @tparam RandomType the type of the results, either Random_u32 or
* Random_u64.
**********************************************************************/
template<class RandomType> class RANDOMLIB_EXPORT MixerMT0 {
public:
/**
* The RandomType controlling the output of MixerMT0::SeedToState
**********************************************************************/
typedef RandomType mixer_t;
/**
* A version number which should be unique to this RandomMixer. This
* prevents RandomEngine::Load from loading a saved generator with a
* different RandomMixer. Here the version is "MxMT" or "MxMU".
**********************************************************************/
static const unsigned version = 0x4d784d54UL + (mixer_t::width == 64);
private:
/**
* The unsigned type corresponding to mixer_t.
**********************************************************************/
typedef typename mixer_t::type mixer_type;
/**
* The mask for mixer_t.
**********************************************************************/
static const mixer_type mask = mixer_t::mask;
public:
/**
* Mix the seed vector, \e seed, into the state array, \e state, of size \e
* n.
*
* @param[in] seed the input seed vector.
* @param[out] state the generator state.
* @param[in] n the size of the state.
**********************************************************************/
static void SeedToState(const std::vector<RandomSeed::seed_type>& seed,
mixer_type state[], unsigned n) throw();
/**
* Return the name of this class.
*
* @return the name.
**********************************************************************/
static std::string Name() {
return "MixerMT0<Random_u" +
std::string(mixer_t::width == 32 ? "32" : "64") + ">";
}
private:
static const mixer_type a0 = 5489ULL;
static const mixer_type a1 = 19650218ULL;
static const mixer_type
b = mixer_t::width == 32 ? 1812433253ULL : 6364136223846793005ULL;
static const mixer_type
c = mixer_t::width == 32 ? 1664525ULL : 3935559000370003845ULL;
static const mixer_type
d = mixer_t::width == 32 ? 1566083941ULL : 2862933555777941757ULL;
};
/**
* \brief The modified %MT19937 mixing functionality
*
* MixerMT0 has two defects
* - The zeroth word of the state is set to a constant (independent of the
* seed). This is a relatively minor defect which halves the accessible
* state space for MT19937 (but the resulting state space is still huge).
* (Actually, for the 64-bit version, it reduces the accessible states by
* 2<sup>33</sup>. On the other hand the 64-bit has better mixing
* properties.)
* - Close seeds, for example, [1] and [1,0], result in the same state. This
* is a potentially serious flaw which might result is identical random
* number sequences being generated instead of independent sequences.
*
* MixerMT1 fixes these defects in a straightforward manner. The
* resulting algorithm was included in one of the proposals for Random Number
* Generation for C++0X, see Brown, et al.,
* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2079.pdf
*
* The template parameter \e RandomType switches between the 32-bit and
* 64-bit versions.
*
* MixerMT1 still has a weakness in that it doesn't thoroughly mix the
* state. This is illustrated by an example given to me by Makoto Matsumoto:
* Consider a seed of length \e N and suppose we consider all \e
* W<sup><i>N</i>/2</sup> values for the first half of the seed (here \e W =
* 2<sup><i>width</i></sup>). MixerMT1 has a bottleneck in the way that
* the state is initialized which results in the second half of the state
* only taking on \e W<sup>2</sup> possible values. MixerSFMT mixes the
* seed into the state much more thoroughly.
*
* @tparam RandomType the type of the results, either Random_u32 or
* Random_u64.
**********************************************************************/
template<class RandomType> class RANDOMLIB_EXPORT MixerMT1 {
public:
/**
* The RandomType controlling the output of MixerMT1::SeedToState
**********************************************************************/
typedef RandomType mixer_t;
/**
* A version number which should be unique to this RandomMixer. This
* prevents RandomEngine::Load from loading a saved generator with a
* different RandomMixer. Here the version is "MxMV" or "MxMW".
**********************************************************************/
static const unsigned version = 0x4d784d56UL + (mixer_t::width == 64);
private:
/**
* The unsigned type corresponding to mixer_t.
**********************************************************************/
typedef typename mixer_t::type mixer_type;
/**
* The mask for mixer_t.
**********************************************************************/
static const mixer_type mask = mixer_t::mask;
public:
/**
* Mix the seed vector, \e seed, into the state array, \e state, of size \e
* n.
*
* @param[in] seed the input seed vector.
* @param[out] state the generator state.
* @param[in] n the size of the state.
**********************************************************************/
static void SeedToState(const std::vector<RandomSeed::seed_type>& seed,
mixer_type state[], unsigned n) throw();
/**
* Return the name of this class.
*
* @return the name.
**********************************************************************/
static std::string Name() {
return "MixerMT1<Random_u" +
std::string(mixer_t::width == 32 ? "32" : "64") + ">";
}
private:
static const mixer_type a = 5489ULL;
static const mixer_type
b = mixer_t::width == 32 ? 1812433253ULL : 6364136223846793005ULL;
static const mixer_type
c = mixer_t::width == 32 ? 1664525ULL : 3935559000370003845ULL;
static const mixer_type
d = mixer_t::width == 32 ? 1566083941ULL : 2862933555777941757ULL;
};
/**
* \brief The SFMT mixing functionality
*
* MixerSFMT is adapted from SFMT's init_by_array Mutsuo Saito given in
* http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/SFMT-src-1.2.tar.gz
* and is part of the C++11 standard; see P. Becker, Working Draft, Standard
* for Programming Language C++, Oct. 2007, Sec. 26.4.7.1,
* http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2461.pdf
*
* MixerSFMT contains a single change is to allow it to function properly
* when the size of the state is small.
*
* MixerSFMT mixes the seed much more thoroughly than MixerMT1 and, in
* particular, it removes the mixing bottleneck present in MixerMT1.
* Thus it is the recommended mixing scheme for all production work.
**********************************************************************/
class RANDOMLIB_EXPORT MixerSFMT {
public:
/**
* The RandomType controlling the output of MixerSFMT::SeedToState
**********************************************************************/
typedef Random_u32 mixer_t;
/**
* A version number which should be unique to this RandomMixer. This
* prevents RandomEngine::Load from loading a saved generator with a
* different RandomMixer. Here the version is "MxSM".
**********************************************************************/
static const unsigned version = 0x4d78534dUL;
private:
/**
* The unsigned type corresponding to mixer_t.
**********************************************************************/
typedef mixer_t::type mixer_type;
/**
* The mask for mixer_t.
**********************************************************************/
static const mixer_type mask = mixer_t::mask;
public:
/**
* Mix the seed vector, \e seed, into the state array, \e state, of size \e
* n.
*
* @param[in] seed the input seed vector.
* @param[out] state the generator state.
* @param[in] n the size of the state.
**********************************************************************/
static void SeedToState(const std::vector<RandomSeed::seed_type>& seed,
mixer_type state[], unsigned n) throw();
/**
* Return the name of this class.
*
* @return the name.
**********************************************************************/
static std::string Name() { return "MixerSFMT"; }
private:
static const mixer_type a = 0x8b8b8b8bUL;
static const mixer_type b = 1664525UL;
static const mixer_type c = 1566083941UL;
};
} // namespace RandomLib
#endif // RANDOMLIB_RANDOMMIXER_HPP

View File

@ -0,0 +1,472 @@
/**
* \file RandomNumber.hpp
* \brief Header for RandomNumber
*
* Infinite precision random numbers.
*
* Copyright (c) Charles Karney (2006-2013) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_RANDOMNUMBER_HPP)
#define RANDOMLIB_RANDOMNUMBER_HPP 1
#include <vector>
#include <iomanip>
#include <limits>
#include <cmath> // for std::pow
#include <RandomLib/UniformInteger.hpp>
namespace RandomLib {
/**
* \brief Infinite precision random numbers.
*
* Implement infinite precision random numbers. Integer part is non-random.
* Fraction part consists of any some number of digits in base
* 2<sup><i>b</i></sup>. If \e m digits have been generated then the
* fraction is uniformly distributed in the open interval
* &sum;<sub><i>k</i>=1</sub><sup><i>m</i></sup>
* <i>f</i><sub><i>k</i>&minus;1</sub>/2<sup><i>kb</i></sup> +
* (0,1)/2<sup><i>mb</i></sup>. When a RandomNumber is first constructed the
* integer part is zero and \e m = 0, and the number represents (0,1). A
* RandomNumber is able to represent all numbers in the symmetric open
* interval (&minus;2<sup>31</sup>, 2<sup>31</sup>). In this implementation,
* \e b must one of 1, 2, 3, 4, 8, 12, 16, 20, 24, 28, or 32. (This
* restriction allows printing in hexadecimal and can easily be relaxed.
* There's also no essential reason why the base should be a power of 2.)
*
* @tparam bits the number of bits in each digit.
**********************************************************************/
template<int bits = 1> class RandomNumber {
public:
/**
* Constructor sets number to a random number uniformly distributed in
* (0,1).
**********************************************************************/
RandomNumber() throw() : _n(0), _s(1) {}
/**
* Swap with another RandomNumber. This is a fast way of doing an
* assignment.
*
* @param[in,out] t the RandomNumber to swap with.
**********************************************************************/
void swap(RandomNumber& t) throw() {
if (this != &t) {
std::swap(_n, t._n);
std::swap(_s, t._s);
_f.swap(t._f);
}
}
/**
* Return to initial state, uniformly distributed in (0,1).
**********************************************************************/
void Init() throw() {
STATIC_ASSERT(bits > 0 && bits <= w && (bits < 4 || bits % 4 == 0),
"RandomNumber: unsupported value for bits");
_n = 0;
_s = 1;
_f.clear();
}
/**
* @return the sign of the RandomNumber (&plusmn; 1).
**********************************************************************/
int Sign() const throw() { return _s; }
/**
* Change the sign of the RandomNumber.
**********************************************************************/
void Negate() throw() { _s *= -1; }
/**
* @return the floor of the RandomNumber.
**********************************************************************/
int Floor() const throw() { return _s > 0 ? int(_n) : -1 - int(_n); }
/**
* @return the ceiling of the RandomNumber.
**********************************************************************/
int Ceiling() const throw() { return _s > 0 ? 1 + int(_n) : - int(_n); }
/**
* @return the unsigned integer component of the RandomNumber.
**********************************************************************/
unsigned UInteger() const throw() { return _n; }
/**
* Add integer \e k to the RandomNumber.
*
* @param[in] k the integer to add.
**********************************************************************/
void AddInteger(int k) throw() {
k += Floor(); // The new floor
int ns = k < 0 ? -1 : 1; // The new sign
if (ns != _s) // If sign changes, set f = 1 - f
for (size_t k = 0; k < Size(); ++k)
_f[k] = ~_f[k] & mask;
_n = ns > 0 ? k : -(k + 1);
}
/**
* Compare with another RandomNumber, *this &lt; \e t
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in,out] t a RandomNumber to compare.
* @return true if *this &lt; \e t.
**********************************************************************/
template<class Random> bool LessThan(Random& r, RandomNumber& t) {
if (this == &t) return false; // same object
if (_s != t._s) return _s < t._s;
if (_n != t._n) return (_s < 0) ^ (_n < t._n);
for (unsigned k = 0; ; ++k) {
// Impose an order on the evaluation of the digits.
const unsigned x = Digit(r,k);
const unsigned y = t.Digit(r,k);
if (x != y) return (_s < 0) ^ (x < y);
// Two distinct numbers are never equal
}
}
/**
* Compare RandomNumber with two others, *this &gt; max(\e u, \e v)
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in,out] u first RandomNumber to compare.
* @param[in,out] v second RandomNumber to compare.
* @return true if *this &gt; max(\e u, \e v).
**********************************************************************/
template<class Random> bool GreaterPair(Random& r,
RandomNumber& u, RandomNumber& v) {
// cmps is set to false as soon as u <= *this, and likewise for cmpt.
bool cmpu = this != &u, cmpv = this != &v && &u != &v;
if (!(cmpu || cmpv)) return true;
// Check signs first
if (cmpu) {
if (u._s > _s) return false; // u > *this
if (u._s < _s) cmpu = false;
}
if (cmpv) {
if (v._s > _s) return false; // v > *this
if (v._s < _s) cmpv = false;
}
if (!(cmpu || cmpv)) return true; // u <= *this && v <= *this
// Check integer parts
if (cmpu) {
if ((_s < 0) ^ (u._n > _n)) return false; // u > *this
if ((_s < 0) ^ (u._n < _n)) cmpu = false;
}
if (cmpv) {
if ((_s < 0) ^ (v._n > _n)) return false; // v > *this
if ((_s < 0) ^ (v._n < _n)) cmpv = false;
}
if (!(cmpu || cmpv)) return true; // u <= *this && v <= *this
// Check fractions
for (unsigned k = 0; ; ++k) {
// Impose an order on the evaluation of the digits. Note that this is
// asymmetric on interchange of u and v; since u is tested first, more
// digits of u are generated than v (on average).
const unsigned x = Digit(r,k);
if (cmpu) {
const unsigned y = u.Digit(r,k);
if ((_s < 0) ^ (y > x)) return false; // u > *this
if ((_s < 0) ^ (y < x)) cmpu = false;
}
if (cmpv) {
const unsigned y = v.Digit(r,k);
if ((_s < 0) ^ (y > x)) return false; // v > *this
if ((_s < 0) ^ (y < x)) cmpv = false;
}
if (!(cmpu || cmpv)) return true; // u <= *this && v <= *this
}
}
/**
* Compare with a fraction, *this &lt; <i>p</i>/<i>q</i>
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in] p the numerator of the fraction.
* @param[in] q the denominator of the fraction (require \e q &gt; 0).
* @return true if *this &lt; <i>p</i>/<i>q</i>.
**********************************************************************/
template<class Random, typename IntType>
bool LessThan(Random& r, IntType p, IntType q) {
for (int k = 0;; ++k) {
if (p <= 0) return false;
if (p >= q) return true;
// Here p is in [1,q-1]. Need to avoid overflow in computation of
// (q-1)<<bits and (2^bits-1)*q
p = (p << bits) - Digit(r,k) * q;
}
}
/**
* Compare with a paritally sampled fraction
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in] p0 the starting point for the numerator.
* @param[in] c the stride for the fraction (require \e c &gt; 0).
* @param[in] q the denominator of the fraction (require \e q &gt; 0).
* @param[in,out] j the increment for the numerator.
* @return true if *this &lt; (<i>p</i><sub>0</sub> + <i>cj</i>)/<i>q</i>.
**********************************************************************/
template<class Random, typename IntType>
bool LessThan(Random& r, IntType p0, IntType c, IntType q,
UniformInteger<IntType, bits>& j) {
for (int k = 0;; ++k) {
if (j. LessThanEqual(r, - p0, c)) return false;
if (j.GreaterThanEqual(r, q - p0, c)) return true;
p0 = (p0 << bits) - IntType(Digit(r,k)) * q;
c <<= bits;
}
}
/**
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in] k the index of a digit of the fraction
* @return digit number \e k, generating it if necessary.
**********************************************************************/
template<class Random> unsigned Digit(Random& r, unsigned k) {
ExpandTo(r, k + 1);
return _f[k];
}
/**
* Add one digit to the fraction.
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
**********************************************************************/
template<class Random> void AddDigit(Random& r)
{ _f.push_back(RandomDigit(r)); }
/**
* @param[in] k the index of a digit of the fraction
* @return a const reference to digit number \e k, without generating new
* digits.
* @exception std::out_of_range if the digit hasn't been generated.
**********************************************************************/
const unsigned& RawDigit(unsigned k) const throw()
{ return (const unsigned&)(_f.at(k)); }
/**
* @param[in] k the index of a digit of the fraction
* @return a non-const reference to digit number \e k, without generating
* new digits.
* @exception std::out_of_range if the digit hasn't been generated.
**********************************************************************/
unsigned& RawDigit(unsigned k) throw()
{ return (unsigned&)(_f.at(k)); }
/**
* Return to initial state, uniformly distributed in \e n + (0,1). This is
* similar to Init but also returns the memory used by the object to the
* system. Normally Init should be used.
**********************************************************************/
void Clear() {
std::vector<unsigned> z(0);
_n = 0;
_s = 1;
_f.swap(z);
}
/**
* @return the number of digits in fraction
**********************************************************************/
unsigned Size() const throw() { return unsigned(_f.size()); }
/**
* Return the fraction part of the RandomNumber as a floating point number
* of type RealType rounded to the nearest multiple of
* 1/2<sup><i>p</i></sup>, where \e p =
* std::numeric_limits<RealType>::digits, and, if necessary, creating
* additional digits of the number.
*
* @tparam RealType the floating point type to convert to.
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator for generating the necessary digits.
* @return the fraction of the RandomNumber rounded to a RealType.
**********************************************************************/
template<typename RealType, typename Random> RealType Fraction(Random& r) {
STATIC_ASSERT(!std::numeric_limits<RealType>::is_integer,
"RandomNumber::Fraction: invalid real type RealType");
const int d = std::numeric_limits<RealType>::digits;
const int k = (d + bits - 1)/bits;
const int kg = (d + bits)/bits; // For guard bit
RealType y = 0;
if (Digit(r, kg - 1) & (1U << (kg * bits - d - 1)))
// if guard bit is set, round up.
y += std::pow(RealType(2), -d);
const RealType fact = std::pow(RealType(2), -bits);
RealType mult = RealType(1);
for (int i = 0; i < k; ++i) {
mult *= fact;
y += mult * RealType(i < k - 1 ? RawDigit(i) :
RawDigit(i) & (~0U << (k * bits - d)));
}
return y;
}
/**
* Return the value of the RandomNumber rounded to nearest floating point
* number of type RealType and, if necessary, creating additional digits of
* the number.
*
* @tparam RealType the floating point type to convert to.
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator for generating the necessary digits.
* @return the value of the RandomNumber rounded to a RealType.
**********************************************************************/
template<typename RealType, class Random> RealType Value(Random& r) {
// Ignore the possibility of overflow here (OK because int doesn't
// currently overflow any real type). Assume the real type supports
// denormalized numbers. Need to treat rounding explicitly since the
// missing digits always imply rounding up.
STATIC_ASSERT(!std::numeric_limits<RealType>::is_integer,
"RandomNumber::Value: invalid real type RealType");
const int digits = std::numeric_limits<RealType>::digits,
min_exp = std::numeric_limits<RealType>::min_exponent;
RealType y;
int lead; // Position of leading bit (0.5 = position 0)
if (_n) lead = highest_bit_idx(_n);
else {
int i = 0;
while ( Digit(r, i) == 0 && i < (-min_exp)/bits ) ++i;
lead = highest_bit_idx(RawDigit(i)) - (i + 1) * bits;
// To handle denormalized numbers set lead = max(lead, min_exp)
lead = lead > min_exp ? lead : min_exp;
}
int trail = lead - digits; // Position of guard bit (0.5 = position 0)
if (trail > 0) {
y = RealType(_n & (~0U << trail));
if (_n & (1U << (trail - 1)))
y += std::pow(RealType(2), trail);
} else {
y = RealType(_n);
int k = (-trail)/bits; // Byte with guard bit
if (Digit(r, k) & (1U << ((k + 1) * bits + trail - 1)))
// If guard bit is set, round bit (some subsequent bit will be 1).
y += std::pow(RealType(2), trail);
// Byte with trailing bit (can be negative)
k = (-trail - 1 + bits)/bits - 1;
const RealType fact = std::pow(RealType(2), -bits);
RealType mult = RealType(1);
for (int i = 0; i <= k; ++i) {
mult *= fact;
y += mult *
RealType(i < k ? RawDigit(i) :
RawDigit(i) & (~0U << ((k + 1) * bits + trail)));
}
}
if (_s < 0) y *= -1;
return y;
}
/**
* Return the range of possible values for the RandomNumber as pair of
* doubles. This doesn't create any additional digits of the result and
* doesn't try to control roundoff.
*
* @return a pair denoting the range with first being the lower limit and
* second being the upper limit.
**********************************************************************/
std::pair<double, double> Range() const throw() {
double y = _n;
const double fact = std::pow(double(2), -bits);
double mult = double(1);
for (unsigned i = 0; i < Size(); ++i) {
mult *= fact;
y += mult * RawDigit(i);
}
return std::pair<double, double>(_s > 0 ? y : -(y + mult),
_s > 0 ? (y + mult) : -y);
}
/**
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @return a random digit in [0, 2<sup><i>bits</i></sup>).
**********************************************************************/
template<class Random> static unsigned RandomDigit(Random& r) throw()
{ return unsigned(r.template Integer<bits>()); }
private:
/**
* The integer part
**********************************************************************/
unsigned _n;
/**
* The sign
**********************************************************************/
int _s;
/**
* The fraction part
**********************************************************************/
std::vector<unsigned> _f;
/**
* Fill RandomNumber to \e k digits.
**********************************************************************/
template<class Random> void ExpandTo(Random& r, size_t k) {
size_t l = _f.size();
if (k <= l)
return;
_f.resize(k);
for (size_t i = l; i < k; ++i)
_f[i] = RandomDigit(r);
}
/**
* Return index [0..32] of highest bit set. Return 0 if x = 0, 32 is if x
* = ~0. (From Algorithms for programmers by Joerg Arndt.)
**********************************************************************/
static int highest_bit_idx(unsigned x) throw() {
if (x == 0) return 0;
int r = 1;
if (x & 0xffff0000U) { x >>= 16; r += 16; }
if (x & 0x0000ff00U) { x >>= 8; r += 8; }
if (x & 0x000000f0U) { x >>= 4; r += 4; }
if (x & 0x0000000cU) { x >>= 2; r += 2; }
if (x & 0x00000002U) { r += 1; }
return r;
}
/**
* The number of bits in unsigned.
**********************************************************************/
static const int w = std::numeric_limits<unsigned>::digits;
public:
/**
* A mask for the digits.
**********************************************************************/
static const unsigned mask =
bits == w ? ~0U : ~(~0U << (bits < w ? bits : 0));
};
/**
* \relates RandomNumber
* Print a RandomNumber. Format is n.dddd... where the base for printing is
* 2<sup>max(4,<i>b</i>)</sup>. The ... represents an infinite sequence of
* ungenerated random digits (uniformly distributed). Thus with \e b = 1,
* 0.0... = (0,1/2), 0.00... = (0,1/4), 0.11... = (3/4,1), etc.
**********************************************************************/
template<int bits>
std::ostream& operator<<(std::ostream& os, const RandomNumber<bits>& n) {
const std::ios::fmtflags oldflags = os.flags();
RandomNumber<bits> t = n;
os << (t.Sign() > 0 ? "+" : "-");
unsigned i = t.UInteger();
os << std::hex << std::setfill('0');
if (i == 0)
os << "0";
else {
bool first = true;
const int w = std::numeric_limits<unsigned>::digits;
const unsigned mask = RandomNumber<bits>::mask;
for (int s = ((w + bits - 1)/bits) * bits - bits; s >= 0; s -= bits) {
unsigned d = mask & (i >> s);
if (d || !first) {
if (first) {
os << d;
first = false;
}
else
os << std::setw((bits+3)/4) << d;
}
}
}
os << ".";
unsigned s = t.Size();
for (unsigned i = 0; i < s; ++i)
os << std::setw((bits+3)/4) << t.RawDigit(i);
os << "..." << std::setfill(' ');
os.flags(oldflags);
return os;
}
} // namespace RandomLib
#endif // RANDOMLIB_RANDOMNUMBER_HPP

View File

@ -0,0 +1,77 @@
/**
* \file RandomPower2.hpp
* \brief Header for RandomPower2.
*
* Return and multiply by powers of two.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_RANDOMPOWER2_HPP)
#define RANDOMLIB_RANDOMPOWER2_HPP 1
#include <cmath> // For std::pow
namespace RandomLib {
/**
* \brief Return or multiply by powers of 2
*
* With some compilers it's fastest to do a table lookup of powers of
* 2. If RANDOMLIB_POWERTABLE is 1, a lookup table is used. If
* RANDOMLIB_POWERTABLE is 0, then std::pow is used.
**********************************************************************/
class RANDOMLIB_EXPORT RandomPower2 {
public:
/**
* Return powers of 2 (either using a lookup table or std::pow)
*
* @param[in] n the integer power.
* @return 2<sup><i>n</i></sup>.
**********************************************************************/
template<typename RealType> static inline RealType pow2(int n) throw() {
#if RANDOMLIB_POWERTABLE
return RealType(power2[n - minpow]);
#else
return std::pow(RealType(2), n);
#endif
}
/**
* Multiply a real by a power of 2
*
* @tparam RealType the type of \e x.
* @param[in] x the real number.
* @param[in] n the power (positive or negative).
* @return \e x 2<sup><i>n</i></sup>.
**********************************************************************/
template<typename RealType>
static inline RealType shiftf(RealType x, int n) throw()
// std::ldexp(x, n); is equivalent, but slower
{ return x * pow2<RealType>(n); }
// Constants
enum {
/**
* Minimum power in RandomPower2::power2
**********************************************************************/
#if RANDOMLIB_LONGDOUBLEPREC > 64
minpow = -120,
#else
minpow = -64,
#endif
maxpow = 64 /**< Maximum power in RandomPower2::power2. */
};
private:
#if RANDOMLIB_POWERTABLE
/**
* Table of powers of two
**********************************************************************/
static const float power2[maxpow - minpow + 1]; // Powers of two
#endif
};
} // namespace RandomLib
#endif // RANDOMLIB_RANDOMPOWER2_HPP

View File

@ -0,0 +1,251 @@
/**
* \file RandomSeed.hpp
* \brief Header for RandomSeed
*
* This provides a base class for random generators.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_RANDOMSEED_HPP)
#define RANDOMLIB_RANDOMSEED_HPP 1
#include <iostream>
#include <stdexcept>
#include <vector>
#include <iterator>
#include <algorithm> // For std::transform
#include <sstream> // For VectorToString
#include <RandomLib/RandomType.hpp>
#if defined(_MSC_VER)
// Squelch warnings about dll vs vector
#pragma warning (push)
#pragma warning (disable: 4251)
#endif
namespace RandomLib {
/**
* \brief A base class for random generators
*
* This provides facilities for managing the seed and for converting the seed
* into random generator state.
*
* The seed is taken to be a vector of unsigned longs of arbitrary length.
* (Only the low 32 bit of each element of the vector are used.) The class
* provides several methods for setting the seed, static functions for
* producing "random" and "unique" seeds, and facilities for converting the
* seed to a string so that it can be printed easily.
*
* The seeding algorithms are those used by
* <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html">
* MT19937</a> with some modifications to make all states accessible and to
* minimize the likelihood of different seeds giving the same state.
*
* Finally some low-level routines are provided to facilitate the creation of
* I/O methods for the random generator.
*
* A random generator class can be written based on this class. The
* generator class would use the base class methods for setting the seed and
* for converting the seed into state. It would provide the machinery for
* advancing the state and for producing random data. It is also responsible
* for the routine to save and restore the generator state (including the
* seed).
*
* Written by Charles Karney <charles@karney.com> and licensed under the
* MIT/X11 License. The seeding algorithms are adapted from those of
* <a href="http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html">
* MT19937</a>. For more information, see http://randomlib.sourceforge.net/
**********************************************************************/
class RANDOMLIB_EXPORT RandomSeed {
public:
typedef Random_u32 u32;
typedef Random_u64 u64;
virtual ~RandomSeed() throw() = 0;
/**
* A type large enough to hold the seed words. This is needs to hold 32
* bits and is an unsigned long for portability.
**********************************************************************/
typedef RandomType<32, unsigned long> seed_t;
typedef seed_t::type seed_type;
/**
* \name Resetting the seed
**********************************************************************/
///@{
/**
* Set the seed to a vector \e v. Only the low \e 32 bits of each element
* are used.
*
* @tparam IntType the integral type of the elements of the vector.
* @param[in] v the vector of elements.
**********************************************************************/
template<typename IntType> void Reseed(const std::vector<IntType>& v) {
Reseed(v.begin(), v.end());
}
/**
* Set the seed to [\e a, \e b) from a pair of iterators. The iterator
* must produce results which can be converted into seed_type. Only the
* low 32 bits of each element are used.
*
* @tparam InputIterator the type of the iterator.
* @param[in] a the beginning iterator.
* @param[in] b the ending iterator.
**********************************************************************/
template<typename InputIterator>
void Reseed(InputIterator a, InputIterator b) {
// Read new seed into temporary so as not to change object on error.
std::vector<seed_type> t;
std::transform(a, b, back_inserter(t),
seed_t::cast<typename std::iterator_traits<InputIterator>
::value_type>);
_seed.swap(t);
Reset();
}
/**
* Set the seed to [\e n]. Only the low 32 bits of \e n are used.
*
* @param[in] n the new seed to use.
**********************************************************************/
void Reseed(seed_type n) {
// Reserve space for new seed so as not to change object on error.
_seed.reserve(1);
_seed.resize(1);
_seed[0] = seed_t::cast(n);
Reset();
}
/**
* Set the seed to [SeedVector()]. This is the standard way to reseed with
* a "unique" seed.
**********************************************************************/
void Reseed() { Reseed(SeedVector()); }
/**
* Set the seed from the string \e s using Random::StringToVector.
*
* @param[in] s the string to be decoded into a seed.
**********************************************************************/
void Reseed(const std::string& s) {
// Read new seed into temporary so as not to change object on error.
std::vector<seed_type> t = StringToVector(s);
_seed.swap(t);
Reset();
}
///@}
/**
* \name Examining the seed
**********************************************************************/
///@{
/**
* Return reference to the seed vector (read-only).
*
* @return the seed vector.
**********************************************************************/
const std::vector<seed_type>& Seed() const throw() { return _seed; }
/**
* Format the current seed suitable for printing.
*
* @return the seedd as a string.
**********************************************************************/
std::string SeedString() const { return VectorToString(_seed); }
///@}
/**
* \name Resetting the random seed
**********************************************************************/
///@{
/**
* Resets the sequence to its just-seeded state. This needs to be declared
* virtual here so that the Reseed functions can call it after saving the
* seed.
**********************************************************************/
virtual void Reset() throw() = 0;
///@}
/**
* \name Static functions for seed management
**********************************************************************/
///@{
/**
* Return a 32 bits of data suitable for seeding the random generator. The
* result is obtained by combining data from /dev/urandom, gettimeofday,
* time, and getpid to provide a reasonably "random" word of data.
* Usually, it is safer to seed the random generator with SeedVector()
* instead of SeedWord().
*
* @return a single "more-or-less random" seed_type to be used as a seed.
**********************************************************************/
static seed_type SeedWord();
/**
* Return a vector of unsigned longs suitable for seeding the random
* generator. The vector is almost certainly unique; however, the results
* of successive calls to Random::SeedVector() will be correlated. If
* several Random objects are required within a single program execution,
* call Random::SeedVector once, print it out (!), push_back additional
* data to identify the instance (e.g., loop index, thread ID, etc.), and
* use the result to seed the Random object. The number of elements
* included in the vector may depend on the operating system. Additional
* elements may be added in future versions of this library.
*
* @return a "unique" vector of seed_type to be uses as a seed.
**********************************************************************/
static std::vector<seed_type> SeedVector();
/**
* Convert a vector into a string suitable for printing or as an argument
* for Random::Reseed(const std::string& s).
*
* @tparam IntType the integral type of the elements of the vector.
* @param[in] v the vector to be converted.
* @return the resulting string.
**********************************************************************/
template<typename IntType>
static std::string VectorToString(const std::vector<IntType>& v) {
std::ostringstream os;
os << "[";
for (typename std::vector<IntType>::const_iterator n = v.begin();
n != v.end(); ++n) {
if (n != v.begin())
os << ",";
// Normalize in case this is called by user.
os << seed_t::cast(*n);
}
os << "]";
return os.str();
}
/**
* Convert a string into a vector of seed_type suitable for printing or as
* an argument for Random::Reseed(const std::vector<seed_type>& v). Reads
* consecutive digits in string. Thus "[1,2,3]" => [1,2,3]; "-0.123e-4" =>
* [0,123,4], etc. strtoul understands C's notation for octal and
* hexadecimal, for example "012 10 0xa" => [10,10,10]. Reading of a
* number stops at the first illegal character for the base. Thus
* "2006-04-08" => [2006,4,0,8] (i.e., 08 becomes two numbers). Note that
* input numbers greater than ULONG_MAX overflow to ULONG_MAX, which
* probably will result in the number being interpreted as LONG_MASK.
*
* @param[in] s the string to be converted.
* @return the resulting vector of seed_type.
**********************************************************************/
static std::vector<seed_type> StringToVector(const std::string& s);
///@}
protected:
/**
* The seed vector
**********************************************************************/
std::vector<seed_type> _seed;
};
inline RandomSeed::~RandomSeed() throw() {}
} // namespace RandomLib
#if defined(_MSC_VER)
#pragma warning (pop)
#endif
#endif // RANDOMLIB_RANDOMSEED_HPP

View File

@ -0,0 +1,335 @@
/**
* \file RandomSelect.hpp
* \brief Header for RandomSelect.
*
* An implementation of the Walker algorithm for selecting from a finite set.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_RANDOMSELECT_HPP)
#define RANDOMLIB_RANDOMSELECT_HPP 1
#include <vector>
#include <limits>
#include <stdexcept>
#if defined(_MSC_VER)
// Squelch warnings about constant conditional expressions
# pragma warning (push)
# pragma warning (disable: 4127)
#endif
namespace RandomLib {
/**
* \brief Random selection from a discrete set.
*
* An implementation of Walker algorithm for selecting from a finite set
* (following Knuth, TAOCP, Vol 2, Sec 3.4.1.A). This provides a rapid way
* of selecting one of several choices depending on a discrete set weights.
* Original citation is\n A. J. Walker,\n An Efficient Method for Generating
* Discrete Random Variables and General Distributions,\n ACM TOMS 3,
* 253--256 (1977).
*
* There are two changes here in the setup algorithm as given by Knuth:
*
* - The probabilities aren't sorted at the beginning of the setup; nor are
* they maintained in a sorted order. Instead they are just partitioned on
* the mean. This improves the setup time from O(\e k<sup>2</sup>) to O(\e
* k).
*
* - The internal calculations are carried out with type \e NumericType. If
* the input weights are of integer type, then choosing an integer type for
* \e NumericType yields an exact solution for the returned distribution
* (assuming that the underlying random generator is exact.)
*
* Example:
* \code
#include <RandomLib/RandomSelect.hpp>
// Weights for throwing a pair of dice
unsigned w[] = { 0, 0, 1, 2, 3, 4, 5, 6, 5, 4, 3, 2, 1 };
// Initialize selection
RandomLib::RandomSelect<unsigned> sel(w, w + 13);
RandomLib::Random r; // Initialize random numbers
std::cout << "Seed set to " << r.SeedString() << "\n";
std::cout << "Throw a pair of dice 100 times:";
for (unsigned i = 0; i < 100; ++i)
std::cout << " " << sel(r);
std::cout << "\n";
\endcode
*
* @tparam NumericType the numeric type to use (default double).
**********************************************************************/
template<typename NumericType = double> class RandomSelect {
public:
/**
* Initialize in a cleared state (equivalent to having a single
* choice).
**********************************************************************/
RandomSelect() : _k(0), _wsum(0), _wmax(0) {}
/**
* Initialize with a weight vector \e w of elements of type \e WeightType.
* Internal calculations are carried out with type \e NumericType. \e
* NumericType needs to allow Choices() * MaxWeight() to be represented.
* Sensible combinations are:
* - \e WeightType integer, \e NumericType integer with
* digits(\e NumericType) &ge; digits(\e WeightType)
* - \e WeightType integer, \e NumericType real
* - \e WeightType real, \e NumericType real with digits(\e NumericType)
* &ge; digits(\e WeightType)
*
* @tparam WeightType the type of the weights.
* @param[in] w the vector of weights.
* @exception RandomErr if any of the weights are negative or if the total
* weight is not positive.
**********************************************************************/
template<typename WeightType>
RandomSelect(const std::vector<WeightType>& w) { Init(w.begin(), w.end()); }
/**
* Initialize with a weight given by a pair of iterators [\e a, \e b).
*
* @tparam InputIterator the type of the iterator.
* @param[in] a the beginning iterator.
* @param[in] b the ending iterator.
* @exception RandomErr if any of the weights are negative or if the total
* weight is not positive.
**********************************************************************/
template<typename InputIterator>
RandomSelect(InputIterator a, InputIterator b);
/**
* Clear the state (equivalent to having a single choice).
**********************************************************************/
void Init() throw()
{ _k = 0; _wsum = 0; _wmax = 0; _Q.clear(); _Y.clear(); }
/**
* Re-initialize with a weight vector \e w. Leave state unaltered in the
* case of an error.
*
* @tparam WeightType the type of the weights.
* @param[in] w the vector of weights.
**********************************************************************/
template<typename WeightType>
void Init(const std::vector<WeightType>& w) { Init(w.begin(), w.end()); }
/**
* Re-initialize with a weight given as a pair of iterators [\e a, \e b).
* Leave state unaltered in the case of an error.
*
* @tparam InputIterator the type of the iterator.
* @param[in] a the beginning iterator.
* @param[in] b the ending iterator.
**********************************************************************/
template<typename InputIterator>
void Init(InputIterator a, InputIterator b) {
RandomSelect<NumericType> t(a, b);
_Q.reserve(t._k);
_Y.reserve(t._k);
*this = t;
}
/**
* Return an index into the weight vector with probability proportional to
* the weight.
*
* @tparam Random the type of RandomCanonical generator.
* @param[in,out] r the RandomCanonical generator.
* @return the random index into the weight vector.
**********************************************************************/
template<class Random>
unsigned operator()(Random& r) const throw() {
if (_k <= 1)
return 0; // Special cases
const unsigned K = r.template Integer<unsigned>(_k);
// redundant casts to type NumericType to prevent warning from MS Project
return (std::numeric_limits<NumericType>::is_integer ?
r.template Prob<NumericType>(NumericType(_Q[K]),
NumericType(_wsum)) :
r.template Prob<NumericType>(NumericType(_Q[K]))) ?
K : _Y[K];
}
/**
* @return the sum of the weights.
**********************************************************************/
NumericType TotalWeight() const throw() { return _wsum; }
/**
* @return the maximum weight.
**********************************************************************/
NumericType MaxWeight() const throw() { return _wmax; }
/**
* @param[in] i the index in to the weight vector.
* @return the weight for sample \e i. Weight(i) / TotalWeight() gives the
* probability of sample \e i.
**********************************************************************/
NumericType Weight(unsigned i) const throw() {
if (i >= _k)
return NumericType(0);
else if (_k == 1)
return _wsum;
const NumericType n = std::numeric_limits<NumericType>::is_integer ?
_wsum : NumericType(1);
NumericType p = _Q[i];
for (unsigned j = _k; j;)
if (_Y[--j] == i)
p += n - _Q[j];
// If NumericType is integral, then p % _k == 0.
// assert(!std::numeric_limits<NumericType>::is_integer || p % _k == 0);
return (p / NumericType(_k)) * (_wsum / n);
}
/**
* @return the number of choices, i.e., the length of the weight vector.
**********************************************************************/
unsigned Choices() const throw() { return _k; }
private:
/**
* Size of weight vector
**********************************************************************/
unsigned _k;
/**
* Vector of cutoffs
**********************************************************************/
std::vector<NumericType> _Q;
/**
* Vector of aliases
**********************************************************************/
std::vector<unsigned> _Y;
/**
* The sum of the weights
**********************************************************************/
NumericType _wsum;
/**
* The maximum weight
**********************************************************************/
NumericType _wmax;
};
template<typename NumericType> template<typename InputIterator>
RandomSelect<NumericType>::RandomSelect(InputIterator a, InputIterator b) {
typedef typename std::iterator_traits<InputIterator>::value_type
WeightType;
// Disallow WeightType = real, NumericType = integer
STATIC_ASSERT(std::numeric_limits<WeightType>::is_integer ||
!std::numeric_limits<NumericType>::is_integer,
"RandomSelect: inconsistent WeightType and NumericType");
// If WeightType and NumericType are the same type, NumericType as precise
// as WeightType
STATIC_ASSERT(std::numeric_limits<WeightType>::is_integer !=
std::numeric_limits<NumericType>::is_integer ||
std::numeric_limits<NumericType>::digits >=
std::numeric_limits<WeightType>::digits,
"RandomSelect: NumericType insufficiently precise");
_wsum = 0;
_wmax = 0;
std::vector<NumericType> p;
for (InputIterator wptr = a; wptr != b; ++wptr) {
// Test *wptr < 0 without triggering compiler warning when *wptr =
// unsigned
if (!(*wptr > 0 || *wptr == 0))
// This also catches NaNs
throw RandomErr("RandomSelect: Illegal weight");
NumericType w = NumericType(*wptr);
if (w > (std::numeric_limits<NumericType>::max)() - _wsum)
throw RandomErr("RandomSelect: Overflow");
_wsum += w;
_wmax = w > _wmax ? w : _wmax;
p.push_back(w);
}
_k = unsigned(p.size());
if (_wsum <= 0)
throw RandomErr("RandomSelect: Zero total weight");
if (_k <= 1) {
// We treat k <= 1 as a special case in operator()
_Q.clear();
_Y.clear();
return;
}
if ((std::numeric_limits<NumericType>::max)()/NumericType(_k) <
NumericType(_wmax))
throw RandomErr("RandomSelect: Overflow");
std::vector<unsigned> j(_k);
_Q.resize(_k);
_Y.resize(_k);
// Pointers to the next empty low and high slots
unsigned u = 0;
unsigned v = _k - 1;
// Scale input and store in p and setup index array j. Note _wsum =
// mean(p). We could scale out _wsum here, but the following is exact when
// w[i] are low integers.
for (unsigned i = 0; i < _k; ++i) {
p[i] *= NumericType(_k);
j[p[i] > _wsum ? v-- : u++] = i;
}
// Pointers to the next low and high slots to use. Work towards the
// middle. This simplifies the loop exit test to u == v.
u = 0;
v = _k - 1;
// For integer NumericType, store the unnormalized probability in _Q and
// select using the exact Prob(_Q[k], _wsum). For real NumericType, store
// the normalized probability and select using Prob(_Q[k]). There will be
// a round off error in performing the division; but there is also the
// potential for round off errors in performing the arithmetic on p. There
// is therefore no point in simulating the division exactly using the
// slower Prob(real, real).
const NumericType n = std::numeric_limits<NumericType>::is_integer ?
NumericType(1) : _wsum;
while (true) {
// A loop invariant here is mean(p[j[u..v]]) == _wsum
_Q[j[u]] = p[j[u]] / n;
// If all arithmetic were exact this assignment could be:
// if (p[j[u]] < _wsum) _Y[j[u]] = j[v];
// But the following is safer:
_Y[j[u]] = j[p[j[u]] < _wsum ? v : u];
if (u == v) {
// The following assertion may fail because of roundoff errors
// assert( p[j[u]] == _wsum );
break;
}
// Update p, u, and v maintaining the loop invariant
p[j[v]] = p[j[v]] - (_wsum - p[j[u]]);
if (p[j[v]] > _wsum)
++u;
else
j[u] = j[v--];
}
return;
}
} // namespace RandomLib
#if defined(_MSC_VER)
# pragma warning (pop)
#endif
#endif // RANDOMLIB_RANDOMSELECT_HPP

View File

@ -0,0 +1,137 @@
/**
* \file RandomType.hpp
* \brief Class to hold bit-width and unsigned type
*
* This provides a simple class to couple a bit-width and an unsigned type
* capable of holding all the bits. In addition is offers static methods for
* I/O and checksumming.
*
* Copyright (c) Charles Karney (2006-2011) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_RANDOMTYPE_HPP)
#define RANDOMLIB_RANDOMTYPE_HPP 1
#include <limits>
#include <string>
#include <iostream>
namespace RandomLib {
/**
* \brief Class to hold bit-width and unsigned type
*
* This provides a simple class to couple a bit-width and an unsigned type
* capable of holding all the bits. In addition is offers static methods for
* I/O and checksumming.
*
* @tparam bits the number of significant bits.
* @tparam UIntType the C++ unsigned integer type capable of holding the bits.
**********************************************************************/
template<int bits, typename UIntType>
class RANDOMLIB_EXPORT RandomType {
public:
/**
* The unsigned C++ type
**********************************************************************/
typedef UIntType type;
/**
* The number of significant bits
**********************************************************************/
static const unsigned width = bits;
/**
* A mask for the significant bits.
**********************************************************************/
static const type mask =
~type(0) >> (std::numeric_limits<type>::digits - width);
/**
* The minimum representable value
**********************************************************************/
static const type min = type(0);
/**
* The maximum representable value
**********************************************************************/
static const type max = mask;
/**
* A combined masking and casting operation
*
* @tparam IntType the integer type of the \e x.
* @param[in] x the input integer.
* @return the masked and casted result.
**********************************************************************/
template<typename IntType> static type cast(IntType x) throw()
{ return type(x) & mask; }
/**
* Read a data value from a stream of 32-bit quantities (binary or text)
*
* @param[in,out] is the input stream.
* @param[in] bin true if the stream is binary.
* @param[out] x the data value read from the stream.
**********************************************************************/
static void Read32(std::istream& is, bool bin, type& x);
/**
* Write the data value to a stream of 32-bit quantities (binary or text)
*
* @param[in,out] os the output stream.
* @param[in] bin true if the stream is binary.
* @param[in,out] cnt controls the use of spaces and newlines for text
* output.
* @param[in] x the data value to be written to the stream.
*
* \e cnt should be zero on the first invocation of a series of writes.
* This function increments it by one on each call.
**********************************************************************/
static void Write32(std::ostream& os, bool bin, int& cnt, type x);
/**
* Accumulate a checksum of a integer into a 32-bit check. This implements
* a very simple checksum and is intended to avoid accidental corruption
* only.
*
* @param[in] n the number to be included in the checksum.
* @param[in,out] check the running checksum.
**********************************************************************/
static void CheckSum(type n, uint32_t& check) throw();
};
/**
* The standard unit for 32-bit quantities
**********************************************************************/
typedef RandomType<32, uint32_t> Random_u32;
/**
* The standard unit for 64-bit quantities
**********************************************************************/
typedef RandomType<64, uint64_t> Random_u64;
/**
* The integer type of constructing bitsets. This used to be unsigned long.
* C++11 has made this unsigned long long.
**********************************************************************/
#if defined(_MSC_VER) && _MSC_VER >= 1600
typedef unsigned long long bitset_uint_t;
#else
typedef unsigned long bitset_uint_t;
#endif
/// \cond SKIP
// Accumulate a checksum of a 32-bit quantity into check
template<>
inline void Random_u32::CheckSum(Random_u32::type n, Random_u32::type& check)
throw() {
// Circular shift left by one bit and add new word.
check = (check << 1 | (check >> 31 & Random_u32::type(1))) + n;
check &= Random_u32::mask;
}
// Accumulate a checksum of a 64-bit quantity into check
template<>
inline void Random_u64::CheckSum(Random_u64::type n, Random_u32::type& check)
throw() {
Random_u32::CheckSum(Random_u32::cast(n >> 32), check);
Random_u32::CheckSum(Random_u32::cast(n ), check);
}
/// \endcond
} // namespace RandomLib
#endif // RANDOMLIB_RANDOMTYPE_HPP

View File

@ -0,0 +1,253 @@
/**
* \file UniformInteger.hpp
* \brief Header for UniformInteger
*
* Partially sample a uniform integer distribution.
*
* Copyright (c) Charles Karney (2013) <charles@karney.com> and licensed
* under the MIT/X11 License. For more information, see
* http://randomlib.sourceforge.net/
**********************************************************************/
#if !defined(RANDOMLIB_UNIFORMINTEGER_HPP)
#define RANDOMLIB_UNIFORMINTEGER_HPP 1
#include <limits>
namespace RandomLib {
/**
* \brief The partial uniform integer distribution.
*
* A class to sample in [0, \e m). For background, see:
* - D. E. Knuth and A. C. Yao, The Complexity of Nonuniform Random Number
* Generation, in "Algorithms and Complexity" (Academic Press, 1976),
* pp. 357--428.
* - J. Lumbroso, Optimal Discrete Uniform Generation from Coin Flips,
* and Applications, http://arxiv.org/abs/1304.1916 (2013)
* .
* Lumbroso's algorithm is a realization of the Knuth-Yao method for the case
* of uniform probabilities. This class generalizes the method to accept
* random digits in a base, \e b = 2<sup>\e bits</sup>. An important
* additional feature is that only sufficient random digits are drawn to
* narrow the allowed range to a power of b. Thus after
* <code>UniformInteger<int,1> u(r,5)</code>, \e u represents \verbatim
range prob
[0,4) 8/15
[0,2) 2/15
[2,4) 2/15
4 1/5 \endverbatim
* <code>u.Min()</code> and <code>u.Max()</code> give the extent of the
* closed range. The number of additional random digits needed to fix the
* value is given by <code>u.Entropy()</code>. The comparison operations may
* require additional digits to be drawn and so the range might be narrowed
* down. If you need a definite value then use <code>u(r)</code>.
*
* The DiscreteNormalAlt class uses UniformInteger to achieve an
* asymptotically ideal scaling wherein the number of random bits required
* per sample is constant + log<sub>2</sub>&sigma;. If Lumbroso's algorithm
* for sampling in [0,\e m) were used the log<sub>2</sub>&sigma; term would
* be multiplied by about 1.4.
*
* It is instructive to look at the Knuth-Yao discrete distribution
* generating (DDG) tree for the case \e m = 5 (the binary expansion of 1/5
* is 0.00110011...); Lumbroso's algorithm implements this tree.
* \image html ky-5.png "Knuth-Yao for \e m = 5"
*
* UniformInteger collapses all of the full subtrees above to their parent
* nodes to yield this tree where now some of the outcomes are ranges.
* \image html ky-5-collapse.png "Collapsed Knuth-Yao for \e m = 5"
*
* Averaging over many samples, the maximum number of digits required to
* construct a UniformInteger, i.e., invoking
* <code>UniformInteger(r,m)</code>, is (2\e b &minus; 1)/(\e b &minus; 1).
* (Note that this does not increase as \e m increases.) The maximum number
* of digits required to sample specific integers, i.e., invoking
* <code>UniformInteger(r,m)(r)</code>, is <i>b</i>/(\e b &minus; 1) +
* log<sub>\e b</sub>\e m. The worst cases are when \e m is slightly more
* than a power of \e b.
*
* The number of random bits required for sampling is shown as a function of
* the fractional part of log<sub>2</sub>\e m below. The red line shows what
* Lumbroso calls the "toll", the number of bits in excess of the entropy
* that are required for sampling.
* \image html
* uniform-bits.png "Random bits to sample in [0,\e m) for \e b = 2"
*
* @tparam IntType the type of the integer (must be signed).
* @tparam bits the number of bits in each digit used for sampling;
* the base for sampling is \e b = 2<sup>\e bits</sup>.
**********************************************************************/
template<typename IntType = int, int bits = 1> class UniformInteger {
public:
/**
* Constructor creating a partially sampled integer in [0, \e m)
*
* @param[in] r random object.
* @param[in] m constructed object represents an integer in [0, \e m).
* @param[in] flip if true, rearrange the ranges so that the widest ones
* are at near the upper end of [0, \e m) (default false).
*
* The samples enough random digits to obtain a uniform range whose size is
* a power of the base. The range can subsequently be narrowed by sampling
* additional digits.
**********************************************************************/
template<class Random>
UniformInteger(Random& r, IntType m, bool flip = false);
/**
* @return the minimum of the current range.
**********************************************************************/
IntType Min() const { return _a; }
/**
* @return the maximum of the current range.
**********************************************************************/
IntType Max() const { return _a + (IntType(1) << (_l * bits)) - 1; }
/**
* @return the entropy of the current range (in units of random digits).
*
* Max() + 1 - Min() = 2<sup>Entropy() * \e bits</sup>.
**********************************************************************/
IntType Entropy() const { return _l; }
/**
* Sample until the entropy vanishes, i.e., Min() = Max().
*
* @return the resulting integer sample.
**********************************************************************/
template<class Random> IntType operator()(Random& r)
{ while (_l) Refine(r); return _a; }
/**
* Negate the range, [Min(), Max()] &rarr; [&minus;Max(), &minus;Min()].
**********************************************************************/
void Negate() { _a = -Max(); }
/**
* Add a constant to the range
*
* @param[in] c the constant to be added.
*
* [Min(), Max()] &rarr; [Min() + \e c, Max() + \e c].
**********************************************************************/
void Add(IntType c) { _a += c; }
/**
* Compare with a fraction, *this &lt; <i>p</i>/<i>q</i>
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in] p the numerator of the fraction.
* @param[in] q the denominator of the fraction (require \e q &gt; 0).
* @return true if *this &lt; <i>p</i>/<i>q</i>.
**********************************************************************/
// test j < p/q (require q > 0)
template<class Random> bool LessThan(Random& r, IntType p, IntType q) {
for (;;) {
if ( (q * Max() < p)) return true;
if (!(q * Min() < p)) return false;
Refine(r);
}
}
/**
* Compare with a fraction, *this &le; <i>p</i>/<i>q</i>
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in] p the numerator of the fraction.
* @param[in] q the denominator of the fraction (require \e q &gt; 0).
* @return true if *this &le; <i>p</i>/<i>q</i>.
**********************************************************************/
template<class Random>
bool LessThanEqual(Random& r, IntType p, IntType q)
{ return LessThan(r, p + 1, q); }
/**
* Compare with a fraction, *this &gt; <i>p</i>/<i>q</i>
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in] p the numerator of the fraction.
* @param[in] q the denominator of the fraction (require \e q &gt; 0).
* @return true if *this &gt; <i>p</i>/<i>q</i>.
**********************************************************************/
template<class Random>
bool GreaterThan(Random& r, IntType p, IntType q)
{ return !LessThanEqual(r, p, q); }
/**
* Compare with a fraction, *this &ge; <i>p</i>/<i>q</i>
*
* @tparam Random the type of the random generator.
* @param[in,out] r a random generator.
* @param[in] p the numerator of the fraction.
* @param[in] q the denominator of the fraction (require \e q &gt; 0).
* @return true if *this &ge; <i>p</i>/<i>q</i>.
**********************************************************************/
template<class Random>
bool GreaterThanEqual(Random& r, IntType p, IntType q)
{ return !LessThan(r, p, q); }
/**
* Check that overflow will not happen.
*
* @param[in] mmax the largest \e m in the constructor.
* @param[in] qmax the largest \e q in LessThan().
* @return true if overflow will not happen.
*
* It is important that this check be carried out. If overflow occurs,
* incorrect results are obtained and the constructor may never terminate.
**********************************************************************/
static bool Check(IntType mmax, IntType qmax) {
return ( mmax - 1 <= ((std::numeric_limits<IntType>::max)() >> bits) &&
mmax - 1 <= (std::numeric_limits<IntType>::max)() / qmax );
}
private:
IntType _a, _l; // current range is _a + [0, 2^(bits*_l)).
template<class Random> static unsigned RandomDigit(Random& r) throw()
{ return unsigned(r.template Integer<bits>()); }
template<class Random> void Refine(Random& r) // only gets called if _l > 0.
{ _a += IntType(RandomDigit(r) << (bits * --_l)); }
};
template<typename IntType, int bits> template<class Random>
UniformInteger<IntType, bits>::UniformInteger(Random& r, IntType m, bool flip)
{
STATIC_ASSERT(std::numeric_limits<IntType>::is_integer,
"UniformInteger: invalid integer type IntType");
STATIC_ASSERT(std::numeric_limits<IntType>::is_signed,
"UniformInteger: IntType must be a signed type");
STATIC_ASSERT(bits > 0 && bits < std::numeric_limits<IntType>::digits &&
bits <= std::numeric_limits<unsigned>::digits,
"UniformInteger: bits out of range");
m = m < 1 ? 1 : m;
for (IntType v = 1, c = 0;;) {
_l = 0; _a = c;
for (IntType w = v, a = c, d = 1;;) {
// play out Lumbroso's algorithm without drawing random digits with w
// playing the role of v and c represented by the range [a, a + d).
// Return if both ends of range qualify as return values at the same
// time. Otherwise, fail and draw another random digit.
if (w >= m) {
IntType j = (a / m) * m; a -= j; w -= j;
if (w >= m) {
if (a + d <= m) { _a = !flip ? a : m - a - d; return; }
break;
}
}
w <<= bits; a <<= bits; d <<= bits; ++_l;
}
IntType j = (v / m) * m; v -= j; c -= j;
v <<= bits; c <<= bits; c += IntType(RandomDigit(r));
}
}
/**
* \relates UniformInteger
* Print a UniformInteger. Format is [\e min,\e max] unless the entropy is
* zero, in which case it's \e val.
**********************************************************************/
template<typename IntType, int bits>
std::ostream& operator<<(std::ostream& os,
const UniformInteger<IntType, bits>& u) {
if (u.Entropy())
os << "[" << u.Min() << "," << u.Max() << "]";
else
os << u.Min();
return os;
}
} // namespace RandomLib
#endif // RANDOMLIB_UNIFORMINTEGER_HPP

View File

@ -50,21 +50,15 @@
-# Define the appropriate symbol for the converter you wish to use and -# Define the appropriate symbol for the converter you wish to use and
include the SimpleIni.h header file. If no specific converter is defined include the SimpleIni.h header file. If no specific converter is defined
then the default converter is used. The default conversion mode uses then the default converter is used. The default conversion mode uses
SI_CONVERT_WIN32 on Windows and SI_CONVERT_GENERIC on all other SI_CONVERT_WIN32 on Windows and SI_CONVERT_ICU on all other
platforms. If you are using ICU then SI_CONVERT_ICU is supported on all
platforms. platforms.
-# Declare an instance the appropriate class. Note that the following -# Declare an instance the appropriate class. Note that the following
definitions are just shortcuts for commonly used types. Other types definitions are just shortcuts for commonly used types. Other types
(PRUnichar, unsigned short, unsigned char) are also possible. (PRUnichar, unsigned short, unsigned char) are also possible.
<table> <table>
<tr><th>Interface <th>Case-sensitive <th>Load UTF-8 <th>Load MBCS <th>Typedef <tr><th>Interface <th>Case-sensitive <th>Load UTF-8 <th>Load MBCS <th>Typedef
<tr><th>SI_CONVERT_GENERIC
<tr><td>char <td>No <td>Yes <td>Yes #1 <td>CSimpleIniA
<tr><td>char <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseA
<tr><td>wchar_t <td>No <td>Yes <td>Yes <td>CSimpleIniW
<tr><td>wchar_t <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseW
<tr><th>SI_CONVERT_WIN32 <tr><th>SI_CONVERT_WIN32
<tr><td>char <td>No <td>No #2 <td>Yes <td>CSimpleIniA <tr><td>char <td>No <td>No #1 <td>Yes <td>CSimpleIniA
<tr><td>char <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseA <tr><td>char <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseA
<tr><td>wchar_t <td>No <td>Yes <td>Yes <td>CSimpleIniW <tr><td>wchar_t <td>No <td>Yes <td>Yes <td>CSimpleIniW
<tr><td>wchar_t <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseW <tr><td>wchar_t <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseW
@ -74,8 +68,7 @@
<tr><td>UChar <td>No <td>Yes <td>Yes <td>CSimpleIniW <tr><td>UChar <td>No <td>Yes <td>Yes <td>CSimpleIniW
<tr><td>UChar <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseW <tr><td>UChar <td>Yes <td>Yes <td>Yes <td>CSimpleIniCaseW
</table> </table>
#1 On Windows you are better to use CSimpleIniA with SI_CONVERT_WIN32.<br> #1 Only affects Windows. On Windows this uses MBCS functions and
#2 Only affects Windows. On Windows this uses MBCS functions and
so may fold case incorrectly leading to uncertain results. so may fold case incorrectly leading to uncertain results.
-# Call LoadData() or LoadFile() to load and parse the INI configuration file -# Call LoadData() or LoadFile() to load and parse the INI configuration file
-# Access and modify the data of the file using the following functions -# Access and modify the data of the file using the following functions
@ -149,12 +142,11 @@
@section notes NOTES @section notes NOTES
- To load UTF-8 data on Windows 95, you need to use Microsoft Layer for - To load UTF-8 data on Windows 95, you need to use Microsoft Layer for
Unicode, or SI_CONVERT_GENERIC, or SI_CONVERT_ICU. Unicode, or SI_CONVERT_ICU.
- When using SI_CONVERT_GENERIC, ConvertUTF.c must be compiled and linked.
- When using SI_CONVERT_ICU, ICU header files must be on the include - When using SI_CONVERT_ICU, ICU header files must be on the include
path and icuuc.lib must be linked in. path and icuuc.lib must be linked in.
- To load a UTF-8 file on Windows AND expose it with SI_CHAR == char, - To load a UTF-8 file on Windows AND expose it with SI_CHAR == char,
you should use SI_CONVERT_GENERIC. you should use SI_CONVERT_ICU.
- The collation (sorting) order used for sections and keys returned from - The collation (sorting) order used for sections and keys returned from
iterators is NOT DEFINED. If collation order of the text is important iterators is NOT DEFINED. If collation order of the text is important
then it should be done yourself by either supplying a replacement then it should be done yourself by either supplying a replacement
@ -321,12 +313,6 @@ public:
return *this; return *this;
} }
#if defined(_MSC_VER) && _MSC_VER <= 1200
/** STL of VC6 doesn't allow me to specify my own comparator for list::sort() */
bool operator<(const Entry & rhs) const { return LoadOrder()(*this, rhs); }
bool operator>(const Entry & rhs) const { return LoadOrder()(rhs, *this); }
#endif
/** Strict less ordering by name of key only */ /** Strict less ordering by name of key only */
struct KeyOrder : std::binary_function<Entry, Entry, bool> { struct KeyOrder : std::binary_function<Entry, Entry, bool> {
bool operator()(const Entry & lhs, const Entry & rhs) const { bool operator()(const Entry & lhs, const Entry & rhs) const {
@ -344,6 +330,16 @@ public:
return KeyOrder()(lhs.pItem, rhs.pItem); return KeyOrder()(lhs.pItem, rhs.pItem);
} }
}; };
/** Like LoadOrder, but empty name always goes first */
struct LoadOrderEmptyFirst : std::binary_function<Entry, Entry, bool> {
bool operator()(const Entry & lhs, const Entry & rhs) const {
if (*lhs.pItem == 0 || *rhs.pItem == 0) {
return *lhs.pItem < *rhs.pItem;
}
return LoadOrder()(lhs, rhs);
}
};
}; };
/** map keys to values */ /** map keys to values */
@ -2407,15 +2403,13 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Save(
a_oOutput.Write(SI_UTF8_SIGNATURE); a_oOutput.Write(SI_UTF8_SIGNATURE);
} }
// get all of the sections sorted in load order // get all of the sections sorted in load order with root section first
TNamesDepend oSections; TNamesDepend oSections;
GetAllSections(oSections); GetAllSections(oSections);
#if defined(_MSC_VER) && _MSC_VER <= 1200 #if defined(__BORLANDC__)
oSections.sort(); oSections.sort(Entry::LoadOrderEmptyFirst());
#elif defined(__BORLANDC__)
oSections.sort(Entry::LoadOrder());
#else #else
oSections.sort(typename Entry::LoadOrder()); oSections.sort(typename Entry::LoadOrderEmptyFirst());
#endif #endif
// write the file comment if we have one // write the file comment if we have one
@ -2462,9 +2456,7 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Save(
// get all of the keys sorted in load order // get all of the keys sorted in load order
TNamesDepend oKeys; TNamesDepend oKeys;
GetAllKeys(iSection->pItem, oKeys); GetAllKeys(iSection->pItem, oKeys);
#if defined(_MSC_VER) && _MSC_VER <= 1200 #if defined(__BORLANDC__)
oKeys.sort();
#elif defined(__BORLANDC__)
oKeys.sort(Entry::LoadOrder()); oKeys.sort(Entry::LoadOrder());
#else #else
oKeys.sort(typename Entry::LoadOrder()); oKeys.sort(typename Entry::LoadOrder());
@ -2662,17 +2654,15 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::DeleteString(
// SimpleIni.h, set the converter that you wish you use by defining one of the // SimpleIni.h, set the converter that you wish you use by defining one of the
// following symbols. // following symbols.
// //
// SI_CONVERT_GENERIC Use the Unicode reference conversion library in
// the accompanying files ConvertUTF.h/c
// SI_CONVERT_ICU Use the IBM ICU conversion library. Requires // SI_CONVERT_ICU Use the IBM ICU conversion library. Requires
// ICU headers on include path and icuuc.lib // ICU headers on include path and icuuc.lib
// SI_CONVERT_WIN32 Use the Win32 API functions for conversion. // SI_CONVERT_WIN32 Use the Win32 API functions for conversion.
#if !defined(SI_CONVERT_GENERIC) && !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU) #if !defined(SI_CONVERT_WIN32) && !defined(SI_CONVERT_ICU)
# ifdef _WIN32 # ifdef _WIN32
# define SI_CONVERT_WIN32 # define SI_CONVERT_WIN32
# else # else
# define SI_CONVERT_GENERIC # define SI_CONVERT_ICU
# endif # endif
#endif #endif
@ -2835,214 +2825,6 @@ public:
}; };
// ---------------------------------------------------------------------------
// SI_CONVERT_GENERIC
// ---------------------------------------------------------------------------
#ifdef SI_CONVERT_GENERIC
#define SI_Case SI_GenericCase
#define SI_NoCase SI_GenericNoCase
#include <wchar.h>
#include "ConvertUTF.h"
/**
* Converts UTF-8 to a wchar_t (or equivalent) using the Unicode reference
* library functions. This can be used on all platforms.
*/
template<class SI_CHAR>
class SI_ConvertW {
bool m_bStoreIsUtf8;
protected:
SI_ConvertW() { }
public:
SI_ConvertW(bool a_bStoreIsUtf8) : m_bStoreIsUtf8(a_bStoreIsUtf8) { }
/* copy and assignment */
SI_ConvertW(const SI_ConvertW & rhs) { operator=(rhs); }
SI_ConvertW & operator=(const SI_ConvertW & rhs) {
m_bStoreIsUtf8 = rhs.m_bStoreIsUtf8;
return *this;
}
/** Calculate the number of SI_CHAR required for converting the input
* from the storage format. The storage format is always UTF-8 or MBCS.
*
* @param a_pInputData Data in storage format to be converted to SI_CHAR.
* @param a_uInputDataLen Length of storage format data in bytes. This
* must be the actual length of the data, including
* NULL byte if NULL terminated string is required.
* @return Number of SI_CHAR required by the string when
* converted. If there are embedded NULL bytes in the
* input data, only the string up and not including
* the NULL byte will be converted.
* @return -1 cast to size_t on a conversion error.
*/
size_t SizeFromStore(
const char * a_pInputData,
size_t a_uInputDataLen)
{
SI_ASSERT(a_uInputDataLen != (size_t) -1);
if (m_bStoreIsUtf8) {
// worst case scenario for UTF-8 to wchar_t is 1 char -> 1 wchar_t
// so we just return the same number of characters required as for
// the source text.
return a_uInputDataLen;
}
#if defined(SI_NO_MBSTOWCS_NULL) || (!defined(_MSC_VER) && !defined(_linux))
// fall back processing for platforms that don't support a NULL dest to mbstowcs
// worst case scenario is 1:1, this will be a sufficient buffer size
(void)a_pInputData;
return a_uInputDataLen;
#else
// get the actual required buffer size
return mbstowcs(NULL, a_pInputData, a_uInputDataLen);
#endif
}
/** Convert the input string from the storage format to SI_CHAR.
* The storage format is always UTF-8 or MBCS.
*
* @param a_pInputData Data in storage format to be converted to SI_CHAR.
* @param a_uInputDataLen Length of storage format data in bytes. This
* must be the actual length of the data, including
* NULL byte if NULL terminated string is required.
* @param a_pOutputData Pointer to the output buffer to received the
* converted data.
* @param a_uOutputDataSize Size of the output buffer in SI_CHAR.
* @return true if all of the input data was successfully
* converted.
*/
bool ConvertFromStore(
const char * a_pInputData,
size_t a_uInputDataLen,
SI_CHAR * a_pOutputData,
size_t a_uOutputDataSize)
{
if (m_bStoreIsUtf8) {
// This uses the Unicode reference implementation to do the
// conversion from UTF-8 to wchar_t. The required files are
// ConvertUTF.h and ConvertUTF.c which should be included in
// the distribution but are publically available from unicode.org
// at http://www.unicode.org/Public/PROGRAMS/CVTUTF/
ConversionResult retval;
const UTF8 * pUtf8 = (const UTF8 *) a_pInputData;
if (sizeof(wchar_t) == sizeof(UTF32)) {
UTF32 * pUtf32 = (UTF32 *) a_pOutputData;
retval = ConvertUTF8toUTF32(
&pUtf8, pUtf8 + a_uInputDataLen,
&pUtf32, pUtf32 + a_uOutputDataSize,
lenientConversion);
}
else if (sizeof(wchar_t) == sizeof(UTF16)) {
UTF16 * pUtf16 = (UTF16 *) a_pOutputData;
retval = ConvertUTF8toUTF16(
&pUtf8, pUtf8 + a_uInputDataLen,
&pUtf16, pUtf16 + a_uOutputDataSize,
lenientConversion);
}
return retval == conversionOK;
}
// convert to wchar_t
size_t retval = mbstowcs(a_pOutputData,
a_pInputData, a_uOutputDataSize);
return retval != (size_t)(-1);
}
/** Calculate the number of char required by the storage format of this
* data. The storage format is always UTF-8 or MBCS.
*
* @param a_pInputData NULL terminated string to calculate the number of
* bytes required to be converted to storage format.
* @return Number of bytes required by the string when
* converted to storage format. This size always
* includes space for the terminating NULL character.
* @return -1 cast to size_t on a conversion error.
*/
size_t SizeToStore(
const SI_CHAR * a_pInputData)
{
if (m_bStoreIsUtf8) {
// worst case scenario for wchar_t to UTF-8 is 1 wchar_t -> 6 char
size_t uLen = 0;
while (a_pInputData[uLen]) {
++uLen;
}
return (6 * uLen) + 1;
}
else {
size_t uLen = wcstombs(NULL, a_pInputData, 0);
if (uLen == (size_t)(-1)) {
return uLen;
}
return uLen + 1; // include NULL terminator
}
}
/** Convert the input string to the storage format of this data.
* The storage format is always UTF-8 or MBCS.
*
* @param a_pInputData NULL terminated source string to convert. All of
* the data will be converted including the
* terminating NULL character.
* @param a_pOutputData Pointer to the buffer to receive the converted
* string.
* @param a_uOutputDataSize Size of the output buffer in char.
* @return true if all of the input data, including the
* terminating NULL character was successfully
* converted.
*/
bool ConvertToStore(
const SI_CHAR * a_pInputData,
char * a_pOutputData,
size_t a_uOutputDataSize
)
{
if (m_bStoreIsUtf8) {
// calc input string length (SI_CHAR type and size independent)
size_t uInputLen = 0;
while (a_pInputData[uInputLen]) {
++uInputLen;
}
++uInputLen; // include the NULL char
// This uses the Unicode reference implementation to do the
// conversion from wchar_t to UTF-8. The required files are
// ConvertUTF.h and ConvertUTF.c which should be included in
// the distribution but are publically available from unicode.org
// at http://www.unicode.org/Public/PROGRAMS/CVTUTF/
ConversionResult retval;
UTF8 * pUtf8 = (UTF8 *) a_pOutputData;
if (sizeof(wchar_t) == sizeof(UTF32)) {
const UTF32 * pUtf32 = (const UTF32 *) a_pInputData;
retval = ConvertUTF32toUTF8(
&pUtf32, pUtf32 + uInputLen,
&pUtf8, pUtf8 + a_uOutputDataSize,
lenientConversion);
}
else if (sizeof(wchar_t) == sizeof(UTF16)) {
const UTF16 * pUtf16 = (const UTF16 *) a_pInputData;
retval = ConvertUTF16toUTF8(
&pUtf16, pUtf16 + uInputLen,
&pUtf8, pUtf8 + a_uOutputDataSize,
lenientConversion);
}
return retval == conversionOK;
}
else {
size_t retval = wcstombs(a_pOutputData,
a_pInputData, a_uOutputDataSize);
return retval != (size_t) -1;
}
}
};
#endif // SI_CONVERT_GENERIC
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// SI_CONVERT_ICU // SI_CONVERT_ICU
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
@ -3245,7 +3027,13 @@ public:
# endif # endif
#endif #endif
#ifdef NOMINMAX
#include <windows.h> #include <windows.h>
#else
#define NOMINMAX
#include <windows.h>
#undef NOMINMAX
#endif
#ifdef SI_NO_MBCS #ifdef SI_NO_MBCS
# define SI_NoCase SI_GenericNoCase # define SI_NoCase SI_GenericNoCase
#else // !SI_NO_MBCS #else // !SI_NO_MBCS

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More