Initial commit

This commit is contained in:
InoriRus 2021-12-01 19:29:27 +10:00
parent b1e7dcdc5d
commit 43f49c8763
1843 changed files with 1111694 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
# Visual Studio 2015 cache/options directory
.vs/
.idea/

2
_Build/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
#
/_*/

View File

@ -0,0 +1,41 @@
@ECHO OFF
ECHO 1.Debug
ECHO 2.Debug Final
ECHO 3.Release
ECHO 4.Release Final
ECHO 5.Exit
ECHO.
CHOICE /C 12345 /M "Enter your choice:"
@ECHO ON
GOTO choice-%errorlevel%
:choice-1
mkdir _BuildToolsDebugNinjaClang
cd _BuildToolsDebugNinjaClang
cmake -G "Ninja" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -D CMAKE_BUILD_TYPE=Debug -D KYTY_PROJECT_NAME:STRING=Build_Tools ../../source
GOTO End
:choice-2
mkdir _BuildToolsDebugFinalNinjaClang
cd _BuildToolsDebugFinalNinjaClang
cmake -G "Ninja" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -D CMAKE_BUILD_TYPE=Debug -D KYTY_PROJECT_NAME:STRING=Build_Tools -D KYTY_FINAL=1 ../../source
GOTO End
:choice-3
mkdir _BuildToolsReleaseNinjaClang
cd _BuildToolsReleaseNinjaClang
cmake -G "Ninja" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -D CMAKE_BUILD_TYPE=Release -D KYTY_PROJECT_NAME:STRING=Build_Tools ../../source
GOTO End
:choice-4
mkdir _BuildToolsReleaseFinalNinjaClang
cd _BuildToolsReleaseFinalNinjaClang
cmake -G "Ninja" -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -D CMAKE_BUILD_TYPE=Release -D KYTY_PROJECT_NAME:STRING=Build_Tools -D KYTY_FINAL=1 ../../source
GOTO End
:choice-5
:End

View File

@ -0,0 +1,41 @@
@ECHO OFF
ECHO 1.Debug
ECHO 2.Debug Final
ECHO 3.Release
ECHO 4.Release Final
ECHO 5.Exit
ECHO.
CHOICE /C 12345 /M "Enter your choice:"
@ECHO ON
GOTO choice-%errorlevel%
:choice-1
mkdir _DebugEclipseMinGW
cd _DebugEclipseMinGW
cmake -G "Eclipse CDT4 - MinGW Makefiles" -DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -D CMAKE_BUILD_TYPE=Debug ../../source
GOTO End
:choice-2
mkdir _DebugFinalEclipseMinGW
cd _DebugFinalEclipseMinGW
cmake -G "Eclipse CDT4 - MinGW Makefiles" -DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -D CMAKE_BUILD_TYPE=Debug -D KYTY_FINAL=1 ../../source
GOTO End
:choice-3
mkdir _ReleaseEclipseMinGW
cd _ReleaseEclipseMinGW
cmake -G "Eclipse CDT4 - MinGW Makefiles" -DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -D CMAKE_BUILD_TYPE=Release ../../source
GOTO End
:choice-4
mkdir _ReleaseFinalEclipseMinGW
cd _ReleaseFinalEclipseMinGW
cmake -G "Eclipse CDT4 - MinGW Makefiles" -DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -D CMAKE_BUILD_TYPE=Release -D KYTY_FINAL=1 ../../source
GOTO End
:choice-5
:End

View File

@ -0,0 +1,41 @@
@ECHO OFF
ECHO 1.Debug
ECHO 2.Debug Final
ECHO 3.Release
ECHO 4.Release Final
ECHO 5.Exit
ECHO.
CHOICE /C 12345 /M "Enter your choice:"
@ECHO ON
GOTO choice-%errorlevel%
:choice-1
mkdir _DebugEclipseMinGWClang
cd _DebugEclipseMinGWClang
cmake -G "Eclipse CDT4 - MinGW Makefiles" -DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -D CMAKE_BUILD_TYPE=Debug ../../source
GOTO End
:choice-2
mkdir _DebugFinalEclipseMinGWClang
cd _DebugFinalEclipseMinGWClang
cmake -G "Eclipse CDT4 - MinGW Makefiles" -DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -D CMAKE_BUILD_TYPE=Debug -D KYTY_FINAL=1 ../../source
GOTO End
:choice-3
mkdir _ReleaseEclipseMinGWClang
cd _ReleaseEclipseMinGWClang
cmake -G "Eclipse CDT4 - MinGW Makefiles" -DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -D CMAKE_BUILD_TYPE=Release ../../source
GOTO End
:choice-4
mkdir _ReleaseFinalEclipseMinGWClang
cd _ReleaseFinalEclipseMinGWClang
cmake -G "Eclipse CDT4 - MinGW Makefiles" -DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -D CMAKE_BUILD_TYPE=Release -D KYTY_FINAL=1 ../../source
GOTO End
:choice-5
:End

View File

@ -0,0 +1,41 @@
@ECHO OFF
ECHO 1.Debug
ECHO 2.Debug Final
ECHO 3.Release
ECHO 4.Release Final
ECHO 5.Exit
ECHO.
CHOICE /C 12345 /M "Enter your choice:"
@ECHO ON
GOTO choice-%errorlevel%
:choice-1
mkdir _DebugEclipseNinja
cd _DebugEclipseNinja
cmake -G "Eclipse CDT4 - Ninja" -DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -D CMAKE_BUILD_TYPE=Debug ../../source
GOTO End
:choice-2
mkdir _DebugFinalEclipseNinja
cd _DebugFinalEclipseNinja
cmake -G "Eclipse CDT4 - Ninja" -DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -D CMAKE_BUILD_TYPE=Debug -D KYTY_FINAL=1 ../../source
GOTO End
:choice-3
mkdir _ReleaseEclipseNinja
cd _ReleaseEclipseNinja
cmake -G "Eclipse CDT4 - Ninja" -DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -D CMAKE_BUILD_TYPE=Release ../../source
GOTO End
:choice-4
mkdir _ReleaseFinalEclipseNinja
cd _ReleaseFinalEclipseNinja
cmake -G "Eclipse CDT4 - Ninja" -DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -D CMAKE_BUILD_TYPE=Release -D KYTY_FINAL=1 ../../source
GOTO End
:choice-5
:End

View File

@ -0,0 +1,41 @@
@ECHO OFF
ECHO 1.Debug
ECHO 2.Debug Final
ECHO 3.Release
ECHO 4.Release Final
ECHO 5.Exit
ECHO.
CHOICE /C 12345 /M "Enter your choice:"
@ECHO ON
GOTO choice-%errorlevel%
:choice-1
mkdir _DebugEclipseNinjaClang
cd _DebugEclipseNinjaClang
cmake -G "Eclipse CDT4 - Ninja" -DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -D CMAKE_BUILD_TYPE=Debug ../../source
GOTO End
:choice-2
mkdir _DebugFinalEclipseNinjaClang
cd _DebugFinalEclipseNinjaClang
cmake -G "Eclipse CDT4 - Ninja" -DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -D CMAKE_BUILD_TYPE=Debug -D KYTY_FINAL=1 ../../source
GOTO End
:choice-3
mkdir _ReleaseEclipseNinjaClang
cd _ReleaseEclipseNinjaClang
cmake -G "Eclipse CDT4 - Ninja" -DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -D CMAKE_BUILD_TYPE=Release ../../source
GOTO End
:choice-4
mkdir _ReleaseFinalEclipseNinjaClang
cd _ReleaseFinalEclipseNinjaClang
cmake -G "Eclipse CDT4 - Ninja" -DCMAKE_ECLIPSE_GENERATE_LINKED_RESOURCES=FALSE -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -D CMAKE_BUILD_TYPE=Release -D KYTY_FINAL=1 ../../source
GOTO End
:choice-5
:End

1
__bin/.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
fc_script.exe filter=lfs diff=lfs merge=lfs -text

BIN
__bin/fc_script.exe (Stored with Git LFS) Normal file

Binary file not shown.

176
source/.clang-format Normal file
View File

@ -0,0 +1,176 @@
---
Language: Cpp
# BasedOnStyle: LLVM
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: Consecutive
AlignConsecutiveAssignments: Consecutive
AlignConsecutiveBitFields: Consecutive
AlignConsecutiveDeclarations: Consecutive
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortEnumsOnASingleLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: WithoutElse
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
AttributeMacros:
- __capability
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: Always
AfterEnum: true
AfterFunction: true
AfterNamespace: false
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: true
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeConceptDeclarations: true
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 140
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
- FOR
- FOR_HASH
StatementAttributeLikeMacros:
- Q_EMIT
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^"(Kyty)/'
Priority: 1
SortPriority: 0
CaseSensitive: false
- Regex: '^"(Emulator)/'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^"(gtest)/'
Priority: 4
SortPriority: 0
CaseSensitive: false
- Regex: '^<'
Priority: 5
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 3
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: true
IndentCaseBlocks: false
IndentGotoLabels: true
IndentPPDirectives: None
IndentExternBlock: AfterExternBlock
IndentRequires: false
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 60
PenaltyIndentedWhitespace: 0
PointerAlignment: Left
ReflowComments: true
SortIncludes: true
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: false
SpaceBeforeInheritanceColon: false
SpaceBeforeParens: ControlStatements
SpaceAroundPointerQualifiers: Default
SpaceBeforeRangeBasedForLoopColon: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
BitFieldColonSpacing: Both
Standard: Latest
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 4
UseCRLF: true
UseTab: ForIndentation
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME
...

52
source/.clang-tidy Normal file
View File

@ -0,0 +1,52 @@
Checks: '-*,bugprone-*,cert-*,clang-analyzer-*,google-*,llvm-*,-llvm-header-guard,misc-*,modernize-*,-modernize-use-trailing-return-type,-modernize-avoid-c-arrays,performance-*,portability-*,readability-*,-readability-magic-numbers,-readability-uppercase-literal-suffix,cppcoreguidelines-*,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-owning-memory,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-avoid-c-arrays,hicpp-*,-hicpp-vararg,-hicpp-no-array-decay,-hicpp-avoid-c-arrays,-hicpp-uppercase-literal-suffix,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-pro-type-static-cast-downcast,-modernize-pass-by-value,-cert-dcl50-cpp,-misc-no-recursion,-cppcoreguidelines-avoid-non-const-global-variables,-performance-no-int-to-ptr'
CheckOptions:
- key: readability-function-cognitive-complexity.Threshold
value: 50
- key: readability-redundant-access-specifiers.CheckFirstDeclaration
value: 1
- key: misc-non-private-member-variables-in-classes.IgnorePublicMemberVariables
value: 1
- key: cppcoreguidelines-pro-type-member-init.IgnoreArrays
value: 1
- key: cppcoreguidelines-macro-usage.AllowedRegexp
value: (KYTY_*)|(EXIT*)|(ASSERT*)
- key: readability-identifier-naming.ClassCase
value: CamelCase
- key: readability-identifier-naming.MemberCase
value: lower_case
- key: readability-identifier-naming.PrivateMemberPrefix
value: 'm_'
- key: readability-identifier-naming.ProtectedMemberPrefix
value: 'm_'
- key: readability-identifier-naming.PublicMethodCase
value: CamelCase
- key: readability-identifier-naming.PublicMemberCase
value: aNy_CasE
- key: readability-identifier-naming.StructCase
value: CamelCase
- key: readability-identifier-naming.ConstantCase
value: UPPER_CASE
- key: readability-identifier-naming.EnumConstantCase
value: CamelCase
- key: readability-identifier-naming.EnumCase
value: CamelCase
- key: readability-identifier-naming.TemplateParameterCase
value: CamelCase
- key: readability-identifier-naming.ValueTemplateParameterCase
value: CamelCase
- key: readability-identifier-naming.LocalConstantCase
value: lower_case
- key: readability-identifier-naming.GlobalConstantCase
value: lower_case
- key: readability-identifier-naming.GlobalConstantPrefix
value: 'g_'
- key: readability-identifier-naming.GlobalVariableCase
value: lower_case
- key: readability-identifier-naming.GlobalVariablePrefix
value: 'g_'
- key: readability-identifier-naming.VariableCase
value: lower_case
- key: readability-identifier-naming.ParameterCase
value: lower_case
- key: readability-identifier-naming.ConstexprVariableCase
value: UPPER_CASE

1
source/.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
doc/** filter=lfs diff=lfs merge=lfs -text

1
source/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.pro.user

11
source/3rdparty/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,11 @@
add_subdirectory(lua)
add_subdirectory(sdl2)
add_subdirectory(rijndael)
add_subdirectory(lzma)
add_subdirectory(vulkan)
add_subdirectory(sqlite)
add_subdirectory(zstd)
add_subdirectory(easy_profiler)
if (CLANG AND MSVC)
add_subdirectory(winpthread)
endif()

View File

@ -0,0 +1,39 @@
file(GLOB easy_profiler_src
src/base_block_descriptor.cpp
src/block.cpp
src/block_descriptor.cpp
src/easy_socket.cpp
src/event_trace_win.cpp
src/nonscoped_block.cpp
src/profile_manager.cpp
src/profiler.cpp
src/reader.cpp
src/serialized_block.cpp
src/thread_storage.cpp
src/writer.cpp
)
if (MINGW)
if (CLANG)
set_source_files_properties(${easy_profiler_src} PROPERTIES COMPILE_FLAGS "-DBUILD_WITH_EASY_PROFILER -DEASY_PROFILER_STATIC -DEASY_DEFAULT_PORT=28077 -DEASY_PROFILER_VERSION_MAJOR=2 -DEASY_PROFILER_VERSION_MINOR=1 -DEASY_PROFILER_VERSION_PATCH=0 -DSTRSAFE_NO_DEPRECATE -Wno-unused-variable -Wno-writable-strings -Wno-braced-scalar-init -Wno-defaulted-function-deleted -Wno-unknown-pragmas -Wno-reorder-ctor -femulated-tls")
else()
set_source_files_properties(${easy_profiler_src} PROPERTIES COMPILE_FLAGS "-DBUILD_WITH_EASY_PROFILER -DEASY_PROFILER_STATIC -DEASY_DEFAULT_PORT=28077 -DEASY_PROFILER_VERSION_MAJOR=2 -DEASY_PROFILER_VERSION_MINOR=1 -DEASY_PROFILER_VERSION_PATCH=0 -DSTRSAFE_NO_DEPRECATE -Wno-reorder-ctor -Wno-reorder -Wno-unknown-pragmas -Wno-format -Wno-class-memaccess")
endif()
endif()
if (MSVC)
if (CLANG)
set_source_files_properties(${easy_profiler_src} PROPERTIES COMPILE_FLAGS "-DBUILD_WITH_EASY_PROFILER -DEASY_PROFILER_STATIC -DEASY_DEFAULT_PORT=28077 -DEASY_PROFILER_VERSION_MAJOR=2 -DEASY_PROFILER_VERSION_MINOR=1 -DEASY_PROFILER_VERSION_PATCH=0 -DSTRSAFE_NO_DEPRECATE -Wno-reorder-ctor -Wno-defaulted-function-deleted -Wno-braced-scalar-init -Wno-writable-strings -D_WINSOCK_DEPRECATED_NO_WARNINGS -D_CRT_SECURE_NO_WARNINGS -Wno-format")
else()
set_source_files_properties(${easy_profiler_src} PROPERTIES COMPILE_FLAGS "-DEASY_PROFILER_STATIC")
endif()
endif()
add_library(easy_profiler_obj OBJECT ${easy_profiler_src})
add_library(easy_profiler STATIC $<TARGET_OBJECTS:easy_profiler_obj>)
target_include_directories(easy_profiler PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_include_directories(easy_profiler_obj PRIVATE $<TARGET_PROPERTY:easy_profiler,INTERFACE_INCLUDE_DIRECTORIES>)

View File

@ -0,0 +1,18 @@
Copyright (c) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
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

@ -0,0 +1,330 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_ARBITRARY_VALUE_H
#define EASY_PROFILER_ARBITRARY_VALUE_H
#include <easy/details/arbitrary_value_public_types.h>
//
// USING_EASY_PROFILER is defined in details/profiler_in_use.h
// if defined BUILD_WITH_EASY_PROFILER and not defined DISABLE_EASY_PROFILER
//
//
// BUILD_WITH_EASY_PROFILER is defined in CMakeLists.txt if your project is linked to easy_profiler.
//
//
// DISABLE_EASY_PROFILER may be defined manually in source-file before #include <easy/profiler.h>
// to disable profiler for certain source-file or project.
//
#ifdef USING_EASY_PROFILER
/** Macro used to create a unique Value Identification Number.
Use this if you want to change the same value from different places in your code.
Otherwise do not mind.
\code
struct A {
int someCount;
};
void foo(const A& a) {
EASY_VALUE("foo count", a.someCount); // Value ID is automatically set to (uint64_t)&a.someCount
// This notation is completely the same as EASY_VALUE("foo count", a.someCount, EASY_VIN(a.someCount));
}
void bar(const A& b) {
EASY_VALUE("bar count", b.someCount); // Same ID as for "foo count" if &b == &a (and different ID otherwise)
}
void baz(const A& c) {
EASY_VALUE("baz count", c.someCount, EASY_VIN(EASY_FUNC_NAME)); // Different ID from "foo count" and "bar count"
EASY_VALUE("qux count", 100500, EASY_VIN(EASY_FUNC_NAME)); // Same ID as for "baz count"
}
\endcode
\ingroup profiler
*/
# define EASY_VIN(member) ::profiler::ValueId(member)
/** Macro used to identify global value which would be recognized by it's name in GUI.
\code
struct A {
int someCount;
};
struct B {
int someOtherCount;
};
void foo(const A& a) {
EASY_VALUE("Count", a.someCount, EASY_GLOBAL_VIN);
}
void bar(const B& b) {
EASY_VALUE("Count", b.someOtherCount, EASY_GLOBAL_VIN); // Same ID as for foo::"Count" despite of &b != &a
}
\endcode
\ingroup profiler
*/
# define EASY_GLOBAL_VIN ::profiler::ValueId()
/** Macro used to identify unique value.
\code
struct A {
int someCount;
};
void foo(const A& a) {
// All these values would have different IDs despite of names, pointers and values are the same
EASY_VALUE("foo count", a.someCount, EASY_UNIQUE_VIN);
EASY_VALUE("foo count", a.someCount, EASY_UNIQUE_VIN);
EASY_VALUE("foo count", a.someCount, EASY_UNIQUE_VIN);
}
\endcode
\ingroup profiler
*/
# define EASY_UNIQUE_VIN ::profiler::ValueId(EASY_UNIQUE_DESC(__LINE__))
/** Macro used to store single arbitrary value.
\note Also stores a time-stamp of it's occurrence like an Event.
\note To store a dynamic array (which size is unknown at compile time), please, use EASY_ARRAY macro.
\note Currently arbitrary values support only compile-time names.
\sa EASY_ARRAY, EASY_TEXT, EASY_STRING
\ingroup profiler
*/
# define EASY_VALUE(name, value, ...)\
EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), ::profiler::registerDescription(\
::profiler::extract_enable_flag(__VA_ARGS__), EASY_UNIQUE_LINE_ID, EASY_COMPILETIME_NAME(name),\
__FILE__, __LINE__, ::profiler::BlockType::Value, ::profiler::extract_color(__VA_ARGS__), false));\
::profiler::setValue(EASY_UNIQUE_DESC(__LINE__), value, ::profiler::extract_value_id(value, ## __VA_ARGS__));
/** Macro used to store an array of arbitrary values.
\note Also stores a time-stamp of it's occurrence like an Event.
\note Currently arbitrary values support only compile-time names.
\warning Max data size (sizeof(value) * size) is MAX_BLOCK_DATA_SIZE. Passing bigger size has undefined behavior.
\sa EASY_VALUE, EASY_TEXT, EASY_STRING, MAX_BLOCK_DATA_SIZE
\ingroup profiler
*/
# define EASY_ARRAY(name, value, size, ...)\
EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), ::profiler::registerDescription(\
::profiler::extract_enable_flag(__VA_ARGS__), EASY_UNIQUE_LINE_ID, EASY_COMPILETIME_NAME(name),\
__FILE__, __LINE__, ::profiler::BlockType::Value, ::profiler::extract_color(__VA_ARGS__), false));\
::profiler::setValue(EASY_UNIQUE_DESC(__LINE__), value, ::profiler::extract_value_id(value, ## __VA_ARGS__), size);
/** Macro used to store custom text.
Could be C-string or std::string.
\note Also stores a time-stamp of it's occurrence like an Event.
\note Currently arbitrary values support only compile-time names.
\warning Max string length is MAX_BLOCK_DATA_SIZE (including trailing '\0'). Passing bigger size has undefined behavior.
\sa EASY_VALUE, EASY_ARRAY, EASY_STRING, MAX_BLOCK_DATA_SIZE
\ingroup profiler
*/
# define EASY_TEXT(name, text, ...)\
EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), ::profiler::registerDescription(\
::profiler::extract_enable_flag(__VA_ARGS__), EASY_UNIQUE_LINE_ID, EASY_COMPILETIME_NAME(name),\
__FILE__, __LINE__, ::profiler::BlockType::Value, ::profiler::extract_color(__VA_ARGS__), false));\
::profiler::setText(EASY_UNIQUE_DESC(__LINE__), text, ::profiler::extract_value_id(text , ## __VA_ARGS__));
/** Macro used to store custom text of specified length.
Same as EASY_TEXT, but with explicitly specified length.
Use this for C-strings of known length (compile-time or run-time).
\note Recommendation (not a requirement): Take into account a zero-terminator '\0' symbol (e.g. strlen("BlaBla") + 1).
\note Also stores a time-stamp of it's occurrence like an Event.
\note Currently arbitrary values support only compile-time names.
\warning Max string length is MAX_BLOCK_DATA_SIZE (including trailing '\0'). Passing bigger size has undefined behavior.
\sa EASY_VALUE, EASY_ARRAY, EASY_TEXT, MAX_BLOCK_DATA_SIZE
\ingroup profiler
*/
# define EASY_STRING(name, text, size, ...)\
EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), ::profiler::registerDescription(\
::profiler::extract_enable_flag(__VA_ARGS__), EASY_UNIQUE_LINE_ID, EASY_COMPILETIME_NAME(name),\
__FILE__, __LINE__, ::profiler::BlockType::Value, ::profiler::extract_color(__VA_ARGS__), false));\
::profiler::setText(EASY_UNIQUE_DESC(__LINE__), text, ::profiler::extract_value_id(text, ## __VA_ARGS__), size);
namespace profiler
{
extern "C" PROFILER_API void storeValue(const BaseBlockDescriptor* _desc, DataType _type, const void* _data,
uint16_t _size, bool _isArray, ValueId _vin);
template <class T>
inline void setValue(const BaseBlockDescriptor* _desc, T _value, ValueId _vin)
{
static_assert(!::std::is_pointer<T>::value,
"You should not pass pointers into EASY_VALUE. Pass a reference instead.");
using Type = typename ::std::remove_reference<typename ::std::remove_cv<T>::type>::type;
static_assert(StdToDataType<Type>::data_type != DataType::TypesCount,
"You should use standard builtin scalar types as profiler::Value type!");
storeValue(_desc, StdToDataType<Type>::data_type, &_value, static_cast<uint16_t>(sizeof(Type)), false, _vin);
}
///< WARNING: Passing _arraySize > (MAX_BLOCK_DATA_SIZE / sizeof(T)) may cause undefined behavior!
template <class T>
inline void setValue(const BaseBlockDescriptor* _desc, const T* _valueArray, ValueId _vin, uint16_t _arraySize)
{
static_assert(StdToDataType<T>::data_type != DataType::TypesCount,
"You should use standard builtin scalar types as profiler::Value type!");
storeValue(_desc, StdToDataType<T>::data_type, _valueArray, static_cast<uint16_t>(sizeof(T) * _arraySize), true, _vin);
}
template <class T, size_t N>
inline void setValue(const BaseBlockDescriptor* _desc, const T (&_value)[N], ValueId _vin)
{
static_assert(StdToDataType<T>::data_type != DataType::TypesCount,
"You should use standard builtin scalar types as profiler::Value type!");
static_assert(sizeof(_value) <= MAX_BLOCK_DATA_SIZE, "Maximum arbitrary values data size exceeded.");
storeValue(_desc, StdToDataType<T>::data_type, _value, static_cast<uint16_t>(sizeof(_value)), true, _vin);
}
///< WARNING: Passing _textLength > MAX_BLOCK_DATA_SIZE may cause undefined behavior!
inline void setText(const BaseBlockDescriptor* _desc, const char* _text, ValueId _vin, uint16_t _textLength)
{
storeValue(_desc, DataType::String, _text, _textLength, true, _vin);
}
///< WARNING: Passing _text with length > MAX_BLOCK_DATA_SIZE may cause undefined behavior!
inline void setText(const BaseBlockDescriptor* _desc, const char* _text, ValueId _vin)
{
storeValue(_desc, DataType::String, _text, static_cast<uint16_t>(strlen(_text) + 1), true, _vin);
}
///< WARNING: Passing _text with length > MAX_BLOCK_DATA_SIZE may cause undefined behavior!
inline void setText(const BaseBlockDescriptor* _desc, const ::std::string& _text, ValueId _vin)
{
storeValue(_desc, DataType::String, _text.c_str(), static_cast<uint16_t>(_text.size() + 1), true, _vin);
}
template <size_t N>
inline void setText(const BaseBlockDescriptor* _desc, const char (&_text)[N], ValueId _vin)
{
static_assert(N <= MAX_BLOCK_DATA_SIZE, "Maximum arbitrary values data size exceeded.");
storeValue(_desc, DataType::String, &_text[0], static_cast<uint16_t>(N), true, _vin);
}
} // end of namespace profiler.
#else
# if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
# endif
# define EASY_GLOBAL_VIN
# define EASY_UNIQUE_VIN
# define EASY_VIN(member)
# define EASY_VALUE(...)
# define EASY_ARRAY(...)
# define EASY_TEXT(...)
# define EASY_STRING(...)
namespace profiler
{
inline void storeValue(const BaseBlockDescriptor*, DataType, const void*, uint16_t, bool, ValueId) {}
template <class T>
inline void setValue(const BaseBlockDescriptor*, T, ValueId) {}
template <class T>
inline void setValue(const BaseBlockDescriptor*, const T*, ValueId, uint16_t) {}
template <class T, size_t N>
inline void setValue(const BaseBlockDescriptor*, const T (&)[N], ValueId) {}
inline void setText(const BaseBlockDescriptor*, const char*, ValueId, uint16_t) {}
inline void setText(const BaseBlockDescriptor*, const char*, ValueId) {}
inline void setText(const BaseBlockDescriptor*, const ::std::string&, ValueId) {}
template <size_t N>
inline void setText(const BaseBlockDescriptor*, const char (&)[N], ValueId) {}
} // end of namespace profiler.
# if defined(__clang__)
# pragma clang diagnostic pop
# endif
#endif // USING_EASY_PROFILER
#endif // EASY_PROFILER_ARBITRARY_VALUE_H

View File

@ -0,0 +1,134 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_ARBITRARY_VALUE_AUX_H
#define EASY_PROFILER_ARBITRARY_VALUE_AUX_H
#include <stdint.h>
#include <type_traits>
#include <easy/details/easy_compiler_support.h>
struct ThreadStorage;
namespace profiler
{
using vin_t = uint64_t;
class ValueId EASY_FINAL
{
friend ::ThreadStorage;
const void* m_id;
public:
#if defined(_MSC_VER) && _MSC_VER <= 1800
inline EASY_CONSTEXPR_FCN ValueId(const ValueId& _another) : m_id(_another.m_id) {}
inline EASY_CONSTEXPR_FCN ValueId(ValueId&& _another) : m_id(_another.m_id) {}
#else
inline EASY_CONSTEXPR_FCN ValueId(const ValueId&) = default;
inline EASY_CONSTEXPR_FCN ValueId(ValueId&&) = default;
#endif
explicit inline EASY_CONSTEXPR_FCN ValueId() : m_id(nullptr) {}
explicit inline EASY_CONSTEXPR_FCN ValueId(const void* _member) : m_id(_member) {}
template <class T>
explicit inline EASY_CONSTEXPR_FCN ValueId(const T& _member) : m_id(&_member) {}
template <class T, size_t N>
explicit inline EASY_CONSTEXPR_FCN ValueId(const T (&_member)[N]) : m_id(_member) {}
ValueId& operator = (const ValueId&) = delete;
ValueId& operator = (ValueId&&) = delete;
};
namespace {
template <class ... TArgs>
inline EASY_CONSTEXPR_FCN bool subextract_value_id(TArgs...);
template <>
inline EASY_CONSTEXPR_FCN bool subextract_value_id<>() { return false; }
template <class T>
inline EASY_CONSTEXPR_FCN bool subextract_value_id(T) { return false; }
inline EASY_CONSTEXPR_FCN ValueId subextract_value_id(ValueId _value) { return _value; }
template <class ... TArgs>
inline EASY_CONSTEXPR_FCN ValueId subextract_value_id(ValueId _value, TArgs...) { return _value; }
template <class T, class ... TArgs>
inline EASY_CONSTEXPR_FCN auto subextract_value_id(T, TArgs... _args) -> decltype(subextract_value_id(_args...)) {
return subextract_value_id(_args...);
}
struct GetFirst {
template <class T, class ... TArgs>
static EASY_CONSTEXPR_FCN ValueId get(const T& _first, TArgs...) { return ValueId(_first); }
template <class T, size_t N, class ... TArgs>
static EASY_CONSTEXPR_FCN ValueId get(const T (&_first)[N], TArgs...) { return ValueId(_first); }
};
struct GetRest {
template <class T, class ... TArgs>
static EASY_CONSTEXPR_FCN ValueId get(const T&, TArgs... _args) { return subextract_value_id(_args...); }
};
} // end of noname namespace.
template <class T, class ... TArgs>
inline EASY_CONSTEXPR_FCN ValueId extract_value_id(const T& _first, TArgs... _args) {
return ::std::conditional<::std::is_same<ValueId, decltype(subextract_value_id(_args...))>::value, GetRest, GetFirst>
::type::get(_first, _args...);
}
template <class T, size_t N, class ... TArgs>
inline EASY_CONSTEXPR_FCN ValueId extract_value_id(const T (&_first)[N], TArgs... _args) {
return ::std::conditional<::std::is_same<ValueId, decltype(subextract_value_id(_args...))>::value, GetRest, GetFirst>
::type::get(_first, _args...);
}
} // end of namespace profiler.
#endif // EASY_PROFILER_ARBITRARY_VALUE_AUX_H

View File

@ -0,0 +1,103 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_ARBITRARY_VALUE_PUBLIC_TYPES_H
#define EASY_PROFILER_ARBITRARY_VALUE_PUBLIC_TYPES_H
#include <easy/details/arbitrary_value_aux.h>
#include <easy/details/profiler_public_types.h>
#include <string>
#include <string.h>
namespace profiler
{
enum class DataType : uint8_t
{
Bool = 0,
Char,
Int8,
Uint8,
Int16,
Uint16,
Int32,
Uint32,
Int64,
Uint64,
Float,
Double,
String,
TypesCount
}; // end of enum class DataType.
template <DataType dataType> struct StdType;
template <class T> struct StdToDataType EASY_FINAL {
EASY_STATIC_CONSTEXPR auto data_type = DataType::TypesCount;
};
# define EASY_DATATYPE_CONVERSION(DataTypeName, StdTypeName)\
template <> struct StdType<DataTypeName> EASY_FINAL { using value_type = StdTypeName; };\
template <> struct StdToDataType<StdTypeName> EASY_FINAL { EASY_STATIC_CONSTEXPR auto data_type = DataTypeName; }
EASY_DATATYPE_CONVERSION(DataType::Bool , bool );
EASY_DATATYPE_CONVERSION(DataType::Char , char );
EASY_DATATYPE_CONVERSION(DataType::Int8 , int8_t );
EASY_DATATYPE_CONVERSION(DataType::Uint8 , uint8_t );
EASY_DATATYPE_CONVERSION(DataType::Int16 , int16_t );
EASY_DATATYPE_CONVERSION(DataType::Uint16, uint16_t);
EASY_DATATYPE_CONVERSION(DataType::Int32 , int32_t );
EASY_DATATYPE_CONVERSION(DataType::Uint32, uint32_t);
EASY_DATATYPE_CONVERSION(DataType::Int64 , int64_t );
EASY_DATATYPE_CONVERSION(DataType::Uint64, uint64_t);
EASY_DATATYPE_CONVERSION(DataType::Float , float );
EASY_DATATYPE_CONVERSION(DataType::Double, double );
# undef EASY_DATATYPE_CONVERSION
template <> struct StdType<DataType::String> EASY_FINAL { using value_type = char; };
template <> struct StdToDataType<const char*> EASY_FINAL { EASY_STATIC_CONSTEXPR auto data_type = DataType::String; };
} // end of namespace profiler.
#endif //EASY_PROFILER_ARBITRARY_VALUE_PUBLIC_TYPES_H

View File

@ -0,0 +1,254 @@
/************************************************************************
* file name : easy_compiler_support.h
* ----------------- :
* creation time : 2016/09/22
* authors : Victor Zarubkin, Sergey Yagovtsev
* emails : v.s.zarubkin@gmail.com, yse.sey@gmail.com
* ----------------- :
* description : This file contains auxiliary profiler macros for different compiler support.
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
* :
* : Licensed under either of
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* : at your option.
* :
* : 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.
* :
* : The Apache License, Version 2.0 (the "License")
* :
* : You may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
************************************************************************/
#ifndef EASY_PROFILER_COMPILER_SUPPORT_H
#define EASY_PROFILER_COMPILER_SUPPORT_H
#include <cstddef>
#if defined(_WIN32) && !defined(EASY_PROFILER_STATIC)
// Visual Studio and MinGW
# ifdef _BUILD_PROFILER
# define PROFILER_API __declspec(dllexport)
# else
# define PROFILER_API __declspec(dllimport)
# endif
#endif
#ifdef __cplusplus
# if __cplusplus >= 201703L
# define EASY_STD 17
# elif __cplusplus >= 201402L
# define EASY_STD 14
# else
# define EASY_STD 11
# endif
#else
# define EASY_STD 11
#endif
#if defined(_MSC_VER)
//////////////////////////////////////////////////////////////////////////
// Visual Studio
# if defined(EASY_OPTION_PRETTY_PRINT_FUNCTIONS) && EASY_OPTION_PRETTY_PRINT_FUNCTIONS != 0
# define EASY_FUNC_NAME __FUNCSIG__
# else
# define EASY_FUNC_NAME __FUNCTION__
# endif
# if _MSC_VER <= 1800
// There is no support for C++11 thread_local keyword prior to Visual Studio 2015. Use __declspec(thread) instead.
// There is also no support for C++11 magic statics feature :( So it becomes slightly harder to initialize static vars - additional "if" for each profiler block.
# define EASY_THREAD_LOCAL __declspec(thread)
# define EASY_LOCAL_STATIC_PTR(VarType, VarName, VarInitializer)\
__declspec(thread) static VarType VarName = 0;\
if (!VarName)\
VarName = VarInitializer
// No constexpr support before Visual Studio 2015
# define EASY_CONSTEXPR const
# define EASY_STATIC_CONSTEXPR static const
# define EASY_CONSTEXPR_FCN
// No noexcept support before Visual Studio 2015
# define EASY_NOEXCEPT throw()
// No alignof support before Visual Studio 2015
# define EASY_ALIGNOF(x) __alignof(x)
# endif
# if EASY_STD > 11 && _MSC_VER >= 1900
# define EASY_LAMBDA_MOVE_CAPTURE
# endif
# define EASY_FORCE_INLINE __forceinline
#elif defined(__clang__)
//////////////////////////////////////////////////////////////////////////
// Clang Compiler
# define EASY_COMPILER_VERSION (__clang_major__ * 10 + __clang_minor__)
# if EASY_COMPILER_VERSION < 33 || (defined(__APPLE_CC__) && __APPLE_CC__ < 8000)
// There is no support for C++11 thread_local keyword prior to Clang v3.3 and Apple LLVM clang 8.0. Use __thread instead.
# define EASY_THREAD_LOCAL __thread
# endif
# if EASY_COMPILER_VERSION < 31
// No constexpr support before Clang v3.1
# define EASY_CONSTEXPR const
# define EASY_STATIC_CONSTEXPR static const
# define EASY_CONSTEXPR_FCN
# endif
# if EASY_COMPILER_VERSION < 29
// There is no support for C++11 magic statics feature prior to clang 2.9. It becomes slightly harder to initialize static vars - additional "if" for each profiler block.
# define EASY_LOCAL_STATIC_PTR(VarType, VarName, VarInitializer)\
EASY_THREAD_LOCAL static VarType VarName = 0;\
if (!VarName)\
VarName = VarInitializer
// There is no support for C++11 final keyword prior to Clang v2.9
# define EASY_FINAL
# endif
# if EASY_STD > 11 && EASY_COMPILER_VERSION >= 34
# define EASY_LAMBDA_MOVE_CAPTURE
# endif
# define EASY_FORCE_INLINE inline __attribute__((always_inline))
# undef EASY_COMPILER_VERSION
#elif defined(__GNUC__)
//////////////////////////////////////////////////////////////////////////
// GNU Compiler
# define EASY_COMPILER_VERSION (__GNUC__ * 10 + __GNUC_MINOR__)
# if EASY_COMPILER_VERSION < 48
// There is no support for C++11 thread_local keyword prior to gcc 4.8. Use __thread instead.
# define EASY_THREAD_LOCAL __thread
# endif
# if EASY_COMPILER_VERSION < 46
// No constexpr support before GCC v4.6
# define EASY_CONSTEXPR const
# define EASY_STATIC_CONSTEXPR static const
# define EASY_CONSTEXPR_FCN
// No noexcept support before GCC v4.6
# define EASY_NOEXCEPT throw()
# endif
# if EASY_COMPILER_VERSION < 43
// There is no support for C++11 magic statics feature prior to gcc 4.3. It becomes slightly harder to initialize static vars - additional "if" for each profiler block.
# define EASY_LOCAL_STATIC_PTR(VarType, VarName, VarInitializer)\
EASY_THREAD_LOCAL static VarType VarName = 0;\
if (!VarName)\
VarName = VarInitializer
# endif
# if EASY_COMPILER_VERSION < 47
// There is no support for C++11 final keyword prior to gcc 4.7
# define EASY_FINAL
# endif
# if EASY_STD > 11 && EASY_COMPILER_VERSION >= 49
# define EASY_LAMBDA_MOVE_CAPTURE
# endif
# define EASY_FORCE_INLINE inline __attribute__((always_inline))
# undef EASY_COMPILER_VERSION
#else
//////////////////////////////////////////////////////////////////////////
// TODO: Add other compilers support
static_assert(false, "EasyProfiler is not configured for using your compiler type. Please, contact developers.");
#endif
// END
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// Default values
#ifndef EASY_FUNC_NAME
# if defined(EASY_OPTION_PRETTY_PRINT_FUNCTIONS) && EASY_OPTION_PRETTY_PRINT_FUNCTIONS != 0
# define EASY_FUNC_NAME __PRETTY_FUNCTION__
# else
# define EASY_FUNC_NAME __func__
# endif
#endif
#ifndef EASY_THREAD_LOCAL
# define EASY_THREAD_LOCAL thread_local
# define EASY_CXX11_TLS_AVAILABLE
#endif
#ifndef EASY_LOCAL_STATIC_PTR
# define EASY_LOCAL_STATIC_PTR(VarType, VarName, VarInitializer) static VarType VarName = VarInitializer
# define EASY_MAGIC_STATIC_AVAILABLE
#endif
#ifndef EASY_FINAL
# define EASY_FINAL final
#endif
#ifndef EASY_FORCE_INLINE
# define EASY_FORCE_INLINE inline
#endif
#ifndef EASY_CONSTEXPR
# define EASY_CONSTEXPR constexpr
# define EASY_STATIC_CONSTEXPR static constexpr
# define EASY_CONSTEXPR_FCN constexpr
# define EASY_CONSTEXPR_AVAILABLE
#endif
#ifndef EASY_NOEXCEPT
# define EASY_NOEXCEPT noexcept
# define EASY_NOEXCEPT_AVAILABLE
#endif
#ifndef EASY_ALIGNOF
# define EASY_ALIGNOF(x) alignof(x)
#endif
#ifndef PROFILER_API
# define PROFILER_API
#endif
//////////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER_COMPILER_SUPPORT_H

View File

@ -0,0 +1,218 @@
/************************************************************************
* file name : profiler_aux.h
* ----------------- :
* creation time : 2016/06/11
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : This file contains auxiliary profiler macros and funcitons.
* ----------------- :
* change log : * 2016/06/11 Victor Zarubkin: Moved sources from profiler.h
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
* :
* : Licensed under either of
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* : at your option.
* :
* : 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.
* :
* : The Apache License, Version 2.0 (the "License")
* :
* : You may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
************************************************************************/
#ifndef EASY_PROFILER_AUX_H
#define EASY_PROFILER_AUX_H
#include <stdint.h>
#include <easy/details/easy_compiler_support.h>
#include <easy/details/profiler_colors.h>
#include <easy/details/profiler_in_use.h>
//////////////////////////////////////////////////////////////////////////
namespace profiler {
enum EasyBlockStatus : uint8_t {
OFF = 0, ///< The block is OFF
ON = 1, ///< The block is ON (but if it's parent block is off recursively then this block will be off too)
FORCE_ON = ON | 2, ///< The block is ALWAYS ON (even if it's parent has turned off all children)
OFF_RECURSIVE = 4, ///< The block is OFF and all of it's children by call-stack are also OFF.
ON_WITHOUT_CHILDREN = ON | OFF_RECURSIVE, ///< The block is ON but all of it's children are OFF.
FORCE_ON_WITHOUT_CHILDREN = FORCE_ON | OFF_RECURSIVE, ///< The block is ALWAYS ON but all of it's children are OFF.
};
}
//////////////////////////////////////////////////////////////////////////
# define EASY_STRINGIFY(a) #a
# define EASY_STRINGIFICATION(a) EASY_STRINGIFY(a)
# define EASY_TOKEN_JOIN(x, y) x ## y
# define EASY_TOKEN_CONCATENATE(x, y) EASY_TOKEN_JOIN(x, y)
# define EASY_UNIQUE_BLOCK(x) EASY_TOKEN_CONCATENATE(unique_profiler_mark_name_, x)
# define EASY_UNIQUE_FRAME_COUNTER(x) EASY_TOKEN_CONCATENATE(unique_profiler_frame_mark_name_, x)
# define EASY_UNIQUE_DESC(x) EASY_TOKEN_CONCATENATE(unique_profiler_descriptor_, x)
#ifdef USING_EASY_PROFILER
#include <string>
#include <type_traits>
namespace profiler
{
template <const bool> struct NameSwitch;
class ForceConstStr EASY_FINAL
{
friend NameSwitch<true>;
friend NameSwitch<false>;
const char* c_str;
public:
ForceConstStr() = delete;
ForceConstStr(const ForceConstStr&) = delete;
ForceConstStr(ForceConstStr&&) = delete;
ForceConstStr& operator = (const ForceConstStr&) = delete;
ForceConstStr& operator = (ForceConstStr&&) = delete;
explicit EASY_CONSTEXPR_FCN ForceConstStr(const char* _str) : c_str(_str) {}
explicit ForceConstStr(const ::std::string& _str) : c_str(_str.c_str()) {}
};
template <const bool IS_REF> struct NameSwitch EASY_FINAL
{
static const char* runtime_name(const char* name) { return name; }
static const char* runtime_name(const ::std::string& name) { return name.c_str(); }
static EASY_CONSTEXPR_FCN const char* runtime_name(const ForceConstStr&) { return ""; }
template <class T>
static EASY_CONSTEXPR_FCN const char* compiletime_name(const T&, const char* autoGeneratedName) { return autoGeneratedName; }
static EASY_CONSTEXPR_FCN const char* compiletime_name(const char*, const char* autoGeneratedName) { return autoGeneratedName; }
static EASY_CONSTEXPR_FCN const char* compiletime_name(const ForceConstStr& name, const char*) { return name.c_str; }
};
template <> struct NameSwitch<true> EASY_FINAL
{
static EASY_CONSTEXPR_FCN const char* runtime_name(const char*) { return ""; }
static EASY_CONSTEXPR_FCN const char* runtime_name(const ForceConstStr&) { return ""; }
static const char* runtime_name(const ::std::string& name) { return name.c_str(); }
template <class T>
static EASY_CONSTEXPR_FCN const char* compiletime_name(const T&, const char* autoGeneratedName) { return autoGeneratedName; }
static EASY_CONSTEXPR_FCN const char* compiletime_name(const char* name, const char*) { return name; }
static EASY_CONSTEXPR_FCN const char* compiletime_name(const ForceConstStr& name, const char*) { return name.c_str; }
};
//***********************************************
template <class ... TArgs>
inline EASY_CONSTEXPR_FCN color_t extract_color(TArgs...);
template <>
inline EASY_CONSTEXPR_FCN color_t extract_color<>() {
return ::profiler::colors::Default;
}
template <class T>
inline EASY_CONSTEXPR_FCN color_t extract_color(T) {
return ::profiler::colors::Default;
}
template <>
inline EASY_CONSTEXPR_FCN color_t extract_color<color_t>(color_t _color) {
return _color;
}
template <class ... TArgs>
inline EASY_CONSTEXPR_FCN color_t extract_color(color_t _color, TArgs...) {
return _color;
}
template <class T, class ... TArgs>
inline EASY_CONSTEXPR_FCN color_t extract_color(T, TArgs... _args) {
return extract_color(_args...);
}
//***********************************************
template <class ... TArgs>
inline EASY_CONSTEXPR_FCN EasyBlockStatus extract_enable_flag(TArgs...);
template <>
inline EASY_CONSTEXPR_FCN EasyBlockStatus extract_enable_flag<>() {
return ::profiler::ON;
}
template <class T>
inline EASY_CONSTEXPR_FCN EasyBlockStatus extract_enable_flag(T) {
return ::profiler::ON;
}
template <>
inline EASY_CONSTEXPR_FCN EasyBlockStatus extract_enable_flag(EasyBlockStatus _flag) {
return _flag;
}
template <class ... TArgs>
inline EASY_CONSTEXPR_FCN EasyBlockStatus extract_enable_flag(EasyBlockStatus _flag, TArgs...) {
return _flag;
}
template <class T, class ... TArgs>
inline EASY_CONSTEXPR_FCN EasyBlockStatus extract_enable_flag(T, TArgs... _args) {
return extract_enable_flag(_args...);
}
//***********************************************
} // END of namespace profiler.
# define EASY_UNIQUE_LINE_ID __FILE__ ":" EASY_STRINGIFICATION(__LINE__)
# define EASY_COMPILETIME_NAME(name) ::profiler::NameSwitch<::std::is_reference<decltype(name)>::value>::compiletime_name(name, EASY_UNIQUE_LINE_ID)
# define EASY_RUNTIME_NAME(name) ::profiler::NameSwitch<::std::is_reference<decltype(name)>::value>::runtime_name(name)
# define EASY_CONST_NAME(name) ::profiler::ForceConstStr(name)
#else
# define EASY_CONST_NAME(name)
#endif // USING_EASY_PROFILER
//////////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER_AUX_H

View File

@ -0,0 +1,413 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_COLORS_H
#define EASY_PROFILER_COLORS_H
#include <cstdint>
#include <easy/details/easy_compiler_support.h>
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
namespace profiler {
using color_t = uint32_t; // Standard four-byte ARGB color format
namespace colors {
///< Change alpha for color. Only 8 major bytes (0xff000000) used from alpha.
inline EASY_CONSTEXPR_FCN color_t modify_alpha32(color_t _color, color_t _alpha) {
return (_alpha & 0xff000000) | (_color & 0x00ffffff);
}
///< Change alpha for color.
inline EASY_CONSTEXPR_FCN color_t modify_alpha8(color_t _color, uint8_t _alpha) {
return (static_cast<color_t>(_alpha) << 24) | (_color & 0x00ffffff);
}
///< Create color from ARGB components.
inline EASY_CONSTEXPR_FCN color_t color(uint8_t _red, uint8_t _green, uint8_t _blue, uint8_t _alpha = 0xff) {
return (static_cast<color_t>(_alpha) << 24) | (static_cast<color_t>(_red) << 16) | (static_cast<color_t>(_green) << 8) | static_cast<color_t>(_blue);
}
#if !defined(EASY_OPTION_BUILTIN_COLORS) || EASY_OPTION_BUILTIN_COLORS != 0
// Google Material Design colors
// See https://material.google.com/style/color.html
EASY_CONSTEXPR color_t Red50 = 0xffffebee;
EASY_CONSTEXPR color_t Red100 = 0xffffcdd2;
EASY_CONSTEXPR color_t Red200 = 0xffef9a9a;
EASY_CONSTEXPR color_t Red300 = 0xffe57373;
EASY_CONSTEXPR color_t Red400 = 0xffef5350;
EASY_CONSTEXPR color_t Red500 = 0xfff44336;
EASY_CONSTEXPR color_t Red600 = 0xffe53935;
EASY_CONSTEXPR color_t Red700 = 0xffd32f2f;
EASY_CONSTEXPR color_t Red800 = 0xffc62828;
EASY_CONSTEXPR color_t Red900 = 0xffb71c1c;
EASY_CONSTEXPR color_t RedA100 = 0xffff8a80;
EASY_CONSTEXPR color_t RedA200 = 0xffff5252;
EASY_CONSTEXPR color_t RedA400 = 0xffff1744;
EASY_CONSTEXPR color_t RedA700 = 0xffd50000;
EASY_CONSTEXPR color_t Pink50 = 0xfffce4ec;
EASY_CONSTEXPR color_t Pink100 = 0xfff8bbd0;
EASY_CONSTEXPR color_t Pink200 = 0xfff48fb1;
EASY_CONSTEXPR color_t Pink300 = 0xfff06292;
EASY_CONSTEXPR color_t Pink400 = 0xffec407a;
EASY_CONSTEXPR color_t Pink500 = 0xffe91e63;
EASY_CONSTEXPR color_t Pink600 = 0xffd81b60;
EASY_CONSTEXPR color_t Pink700 = 0xffc2185b;
EASY_CONSTEXPR color_t Pink800 = 0xffad1457;
EASY_CONSTEXPR color_t Pink900 = 0xff880e4f;
EASY_CONSTEXPR color_t PinkA100 = 0xffff80ab;
EASY_CONSTEXPR color_t PinkA200 = 0xffff4081;
EASY_CONSTEXPR color_t PinkA400 = 0xfff50057;
EASY_CONSTEXPR color_t PinkA700 = 0xffc51162;
EASY_CONSTEXPR color_t Purple50 = 0xfff3e5f5;
EASY_CONSTEXPR color_t Purple100 = 0xffe1bee7;
EASY_CONSTEXPR color_t Purple200 = 0xffce93d8;
EASY_CONSTEXPR color_t Purple300 = 0xffba68c8;
EASY_CONSTEXPR color_t Purple400 = 0xffab47bc;
EASY_CONSTEXPR color_t Purple500 = 0xff9c27b0;
EASY_CONSTEXPR color_t Purple600 = 0xff8e24aa;
EASY_CONSTEXPR color_t Purple700 = 0xff7b1fa2;
EASY_CONSTEXPR color_t Purple800 = 0xff6a1b9a;
EASY_CONSTEXPR color_t Purple900 = 0xff4a148c;
EASY_CONSTEXPR color_t PurpleA100 = 0xffea80fc;
EASY_CONSTEXPR color_t PurpleA200 = 0xffe040fb;
EASY_CONSTEXPR color_t PurpleA400 = 0xffd500f9;
EASY_CONSTEXPR color_t PurpleA700 = 0xffaa00ff;
EASY_CONSTEXPR color_t DeepPurple50 = 0xffede7f6;
EASY_CONSTEXPR color_t DeepPurple100 = 0xffd1c4e9;
EASY_CONSTEXPR color_t DeepPurple200 = 0xffb39ddb;
EASY_CONSTEXPR color_t DeepPurple300 = 0xff9575cd;
EASY_CONSTEXPR color_t DeepPurple400 = 0xff7e57c2;
EASY_CONSTEXPR color_t DeepPurple500 = 0xff673ab7;
EASY_CONSTEXPR color_t DeepPurple600 = 0xff5e35b1;
EASY_CONSTEXPR color_t DeepPurple700 = 0xff512da8;
EASY_CONSTEXPR color_t DeepPurple800 = 0xff4527a0;
EASY_CONSTEXPR color_t DeepPurple900 = 0xff311b92;
EASY_CONSTEXPR color_t DeepPurpleA100 = 0xffb388ff;
EASY_CONSTEXPR color_t DeepPurpleA200 = 0xff7c4dff;
EASY_CONSTEXPR color_t DeepPurpleA400 = 0xff651fff;
EASY_CONSTEXPR color_t DeepPurpleA700 = 0xff6200ea;
EASY_CONSTEXPR color_t Indigo50 = 0xffe8eaf6;
EASY_CONSTEXPR color_t Indigo100 = 0xffc5cae9;
EASY_CONSTEXPR color_t Indigo200 = 0xff9fa8da;
EASY_CONSTEXPR color_t Indigo300 = 0xff7986cb;
EASY_CONSTEXPR color_t Indigo400 = 0xff5c6bc0;
EASY_CONSTEXPR color_t Indigo500 = 0xff3f51b5;
EASY_CONSTEXPR color_t Indigo600 = 0xff3949ab;
EASY_CONSTEXPR color_t Indigo700 = 0xff303f9f;
EASY_CONSTEXPR color_t Indigo800 = 0xff283593;
EASY_CONSTEXPR color_t Indigo900 = 0xff1a237e;
EASY_CONSTEXPR color_t IndigoA100 = 0xff8c9eff;
EASY_CONSTEXPR color_t IndigoA200 = 0xff536dfe;
EASY_CONSTEXPR color_t IndigoA400 = 0xff3d5afe;
EASY_CONSTEXPR color_t IndigoA700 = 0xff304ffe;
EASY_CONSTEXPR color_t Blue50 = 0xffe3f2fd;
EASY_CONSTEXPR color_t Blue100 = 0xffbbdefb;
EASY_CONSTEXPR color_t Blue200 = 0xff90caf9;
EASY_CONSTEXPR color_t Blue300 = 0xff64b5f6;
EASY_CONSTEXPR color_t Blue400 = 0xff42a5f5;
EASY_CONSTEXPR color_t Blue500 = 0xff2196f3;
EASY_CONSTEXPR color_t Blue600 = 0xff1e88e5;
EASY_CONSTEXPR color_t Blue700 = 0xff1976d2;
EASY_CONSTEXPR color_t Blue800 = 0xff1565c0;
EASY_CONSTEXPR color_t Blue900 = 0xff0d47a1;
EASY_CONSTEXPR color_t BlueA100 = 0xff82b1ff;
EASY_CONSTEXPR color_t BlueA200 = 0xff448aff;
EASY_CONSTEXPR color_t BlueA400 = 0xff2979ff;
EASY_CONSTEXPR color_t BlueA700 = 0xff2962ff;
EASY_CONSTEXPR color_t LightBlue50 = 0xffe1f5fe;
EASY_CONSTEXPR color_t LightBlue100 = 0xffb3e5fc;
EASY_CONSTEXPR color_t LightBlue200 = 0xff81d4fa;
EASY_CONSTEXPR color_t LightBlue300 = 0xff4fc3f7;
EASY_CONSTEXPR color_t LightBlue400 = 0xff29b6f6;
EASY_CONSTEXPR color_t LightBlue500 = 0xff03a9f4;
EASY_CONSTEXPR color_t LightBlue600 = 0xff039be5;
EASY_CONSTEXPR color_t LightBlue700 = 0xff0288d1;
EASY_CONSTEXPR color_t LightBlue800 = 0xff0277bd;
EASY_CONSTEXPR color_t LightBlue900 = 0xff01579b;
EASY_CONSTEXPR color_t LightBlueA100 = 0xff80d8ff;
EASY_CONSTEXPR color_t LightBlueA200 = 0xff40c4ff;
EASY_CONSTEXPR color_t LightBlueA400 = 0xff00b0ff;
EASY_CONSTEXPR color_t LightBlueA700 = 0xff0091ea;
EASY_CONSTEXPR color_t Cyan50 = 0xffe0f7fa;
EASY_CONSTEXPR color_t Cyan100 = 0xffb2ebf2;
EASY_CONSTEXPR color_t Cyan200 = 0xff80deea;
EASY_CONSTEXPR color_t Cyan300 = 0xff4dd0e1;
EASY_CONSTEXPR color_t Cyan400 = 0xff26c6da;
EASY_CONSTEXPR color_t Cyan500 = 0xff00bcd4;
EASY_CONSTEXPR color_t Cyan600 = 0xff00acc1;
EASY_CONSTEXPR color_t Cyan700 = 0xff0097a7;
EASY_CONSTEXPR color_t Cyan800 = 0xff00838f;
EASY_CONSTEXPR color_t Cyan900 = 0xff006064;
EASY_CONSTEXPR color_t CyanA100 = 0xff84ffff;
EASY_CONSTEXPR color_t CyanA200 = 0xff18ffff;
EASY_CONSTEXPR color_t CyanA400 = 0xff00e5ff;
EASY_CONSTEXPR color_t CyanA700 = 0xff00b8d4;
EASY_CONSTEXPR color_t Teal50 = 0xffe0f2f1;
EASY_CONSTEXPR color_t Teal100 = 0xffb2dfdb;
EASY_CONSTEXPR color_t Teal200 = 0xff80cbc4;
EASY_CONSTEXPR color_t Teal300 = 0xff4db6ac;
EASY_CONSTEXPR color_t Teal400 = 0xff26a69a;
EASY_CONSTEXPR color_t Teal500 = 0xff009688;
EASY_CONSTEXPR color_t Teal600 = 0xff00897b;
EASY_CONSTEXPR color_t Teal700 = 0xff00796b;
EASY_CONSTEXPR color_t Teal800 = 0xff00695c;
EASY_CONSTEXPR color_t Teal900 = 0xff004d40;
EASY_CONSTEXPR color_t TealA100 = 0xffa7ffeb;
EASY_CONSTEXPR color_t TealA200 = 0xff64ffda;
EASY_CONSTEXPR color_t TealA400 = 0xff1de9b6;
EASY_CONSTEXPR color_t TealA700 = 0xff00bfa5;
EASY_CONSTEXPR color_t Green50 = 0xffe8f5e9;
EASY_CONSTEXPR color_t Green100 = 0xffc8e6c9;
EASY_CONSTEXPR color_t Green200 = 0xffa5d6a7;
EASY_CONSTEXPR color_t Green300 = 0xff81c784;
EASY_CONSTEXPR color_t Green400 = 0xff66bb6a;
EASY_CONSTEXPR color_t Green500 = 0xff4caf50;
EASY_CONSTEXPR color_t Green600 = 0xff43a047;
EASY_CONSTEXPR color_t Green700 = 0xff388e3c;
EASY_CONSTEXPR color_t Green800 = 0xff2e7d32;
EASY_CONSTEXPR color_t Green900 = 0xff1b5e20;
EASY_CONSTEXPR color_t GreenA100 = 0xffb9f6ca;
EASY_CONSTEXPR color_t GreenA200 = 0xff69f0ae;
EASY_CONSTEXPR color_t GreenA400 = 0xff00e676;
EASY_CONSTEXPR color_t GreenA700 = 0xff00c853;
EASY_CONSTEXPR color_t LightGreen50 = 0xfff1f8e9;
EASY_CONSTEXPR color_t LightGreen100 = 0xffdcedc8;
EASY_CONSTEXPR color_t LightGreen200 = 0xffc5e1a5;
EASY_CONSTEXPR color_t LightGreen300 = 0xffaed581;
EASY_CONSTEXPR color_t LightGreen400 = 0xff9ccc65;
EASY_CONSTEXPR color_t LightGreen500 = 0xff8bc34a;
EASY_CONSTEXPR color_t LightGreen600 = 0xff7cb342;
EASY_CONSTEXPR color_t LightGreen700 = 0xff689f38;
EASY_CONSTEXPR color_t LightGreen800 = 0xff558b2f;
EASY_CONSTEXPR color_t LightGreen900 = 0xff33691e;
EASY_CONSTEXPR color_t LightGreenA100 = 0xffccff90;
EASY_CONSTEXPR color_t LightGreenA200 = 0xffb2ff59;
EASY_CONSTEXPR color_t LightGreenA400 = 0xff76ff03;
EASY_CONSTEXPR color_t LightGreenA700 = 0xff64dd17;
EASY_CONSTEXPR color_t Lime50 = 0xfff9ebe7;
EASY_CONSTEXPR color_t Lime100 = 0xfff0f4c3;
EASY_CONSTEXPR color_t Lime200 = 0xffe6ee9c;
EASY_CONSTEXPR color_t Lime300 = 0xffdce775;
EASY_CONSTEXPR color_t Lime400 = 0xffd4e157;
EASY_CONSTEXPR color_t Lime500 = 0xffcddc39;
EASY_CONSTEXPR color_t Lime600 = 0xffc0ca33;
EASY_CONSTEXPR color_t Lime700 = 0xffafb42b;
EASY_CONSTEXPR color_t Lime800 = 0xff9e9d24;
EASY_CONSTEXPR color_t Lime900 = 0xff827717;
EASY_CONSTEXPR color_t LimeA100 = 0xfff4ff81;
EASY_CONSTEXPR color_t LimeA200 = 0xffeeff41;
EASY_CONSTEXPR color_t LimeA400 = 0xffc6ff00;
EASY_CONSTEXPR color_t LimeA700 = 0xffaeea00;
EASY_CONSTEXPR color_t Yellow50 = 0xfffffde7;
EASY_CONSTEXPR color_t Yellow100 = 0xfffff9c4;
EASY_CONSTEXPR color_t Yellow200 = 0xfffff59d;
EASY_CONSTEXPR color_t Yellow300 = 0xfffff176;
EASY_CONSTEXPR color_t Yellow400 = 0xffffee58;
EASY_CONSTEXPR color_t Yellow500 = 0xffffeb3b;
EASY_CONSTEXPR color_t Yellow600 = 0xfffdd835;
EASY_CONSTEXPR color_t Yellow700 = 0xfffbc02d;
EASY_CONSTEXPR color_t Yellow800 = 0xfff9a825;
EASY_CONSTEXPR color_t Yellow900 = 0xfff57f17;
EASY_CONSTEXPR color_t YellowA100 = 0xffffff8d;
EASY_CONSTEXPR color_t YellowA200 = 0xffffff00;
EASY_CONSTEXPR color_t YellowA400 = 0xffffea00;
EASY_CONSTEXPR color_t YellowA700 = 0xffffd600;
EASY_CONSTEXPR color_t Amber50 = 0xfffff8e1;
EASY_CONSTEXPR color_t Amber100 = 0xffffecb3;
EASY_CONSTEXPR color_t Amber200 = 0xffffe082;
EASY_CONSTEXPR color_t Amber300 = 0xffffd54f;
EASY_CONSTEXPR color_t Amber400 = 0xffffca28;
EASY_CONSTEXPR color_t Amber500 = 0xffffc107;
EASY_CONSTEXPR color_t Amber600 = 0xffffb300;
EASY_CONSTEXPR color_t Amber700 = 0xffffa000;
EASY_CONSTEXPR color_t Amber800 = 0xffff8f00;
EASY_CONSTEXPR color_t Amber900 = 0xffff6f00;
EASY_CONSTEXPR color_t AmberA100 = 0xffffe57f;
EASY_CONSTEXPR color_t AmberA200 = 0xffffd740;
EASY_CONSTEXPR color_t AmberA400 = 0xffffc400;
EASY_CONSTEXPR color_t AmberA700 = 0xffffab00;
EASY_CONSTEXPR color_t Orange50 = 0xfffff3e0;
EASY_CONSTEXPR color_t Orange100 = 0xffffe0b2;
EASY_CONSTEXPR color_t Orange200 = 0xffffcc80;
EASY_CONSTEXPR color_t Orange300 = 0xffffb74d;
EASY_CONSTEXPR color_t Orange400 = 0xffffa726;
EASY_CONSTEXPR color_t Orange500 = 0xffff9800;
EASY_CONSTEXPR color_t Orange600 = 0xfffb8c00;
EASY_CONSTEXPR color_t Orange700 = 0xfff57c00;
EASY_CONSTEXPR color_t Orange800 = 0xffef6c00;
EASY_CONSTEXPR color_t Orange900 = 0xffe65100;
EASY_CONSTEXPR color_t OrangeA100 = 0xffffd180;
EASY_CONSTEXPR color_t OrangeA200 = 0xffffab40;
EASY_CONSTEXPR color_t OrangeA400 = 0xffff9100;
EASY_CONSTEXPR color_t OrangeA700 = 0xffff6d00;
EASY_CONSTEXPR color_t DeepOrange50 = 0xfffbe9e7;
EASY_CONSTEXPR color_t DeepOrange100 = 0xffffccbc;
EASY_CONSTEXPR color_t DeepOrange200 = 0xffffab91;
EASY_CONSTEXPR color_t DeepOrange300 = 0xffff8a65;
EASY_CONSTEXPR color_t DeepOrange400 = 0xffff7043;
EASY_CONSTEXPR color_t DeepOrange500 = 0xffff5722;
EASY_CONSTEXPR color_t DeepOrange600 = 0xfff4511e;
EASY_CONSTEXPR color_t DeepOrange700 = 0xffe64a19;
EASY_CONSTEXPR color_t DeepOrange800 = 0xffd84315;
EASY_CONSTEXPR color_t DeepOrange900 = 0xffbf360c;
EASY_CONSTEXPR color_t DeepOrangeA100 = 0xffff9e80;
EASY_CONSTEXPR color_t DeepOrangeA200 = 0xffff6e40;
EASY_CONSTEXPR color_t DeepOrangeA400 = 0xffff3d00;
EASY_CONSTEXPR color_t DeepOrangeA700 = 0xffdd2c00;
EASY_CONSTEXPR color_t Brown50 = 0xffefebe9;
EASY_CONSTEXPR color_t Brown100 = 0xffd7ccc8;
EASY_CONSTEXPR color_t Brown200 = 0xffbcaaa4;
EASY_CONSTEXPR color_t Brown300 = 0xffa1887f;
EASY_CONSTEXPR color_t Brown400 = 0xff8d6e63;
EASY_CONSTEXPR color_t Brown500 = 0xff795548;
EASY_CONSTEXPR color_t Brown600 = 0xff6d4c41;
EASY_CONSTEXPR color_t Brown700 = 0xff5d4037;
EASY_CONSTEXPR color_t Brown800 = 0xff4e342e;
EASY_CONSTEXPR color_t Brown900 = 0xff3e2723;
EASY_CONSTEXPR color_t Grey50 = 0xfffafafa;
EASY_CONSTEXPR color_t Grey100 = 0xfff5f5f5;
EASY_CONSTEXPR color_t Grey200 = 0xffeeeeee;
EASY_CONSTEXPR color_t Grey300 = 0xffe0e0e0;
EASY_CONSTEXPR color_t Grey400 = 0xffbdbdbd;
EASY_CONSTEXPR color_t Grey500 = 0xff9e9e9e;
EASY_CONSTEXPR color_t Grey600 = 0xff757575;
EASY_CONSTEXPR color_t Grey700 = 0xff616161;
EASY_CONSTEXPR color_t Grey800 = 0xff424242;
EASY_CONSTEXPR color_t Grey900 = 0xff212121;
EASY_CONSTEXPR color_t BlueGrey50 = 0xffeceff1;
EASY_CONSTEXPR color_t BlueGrey100 = 0xffcfd8dc;
EASY_CONSTEXPR color_t BlueGrey200 = 0xffb0bec5;
EASY_CONSTEXPR color_t BlueGrey300 = 0xff90a4ae;
EASY_CONSTEXPR color_t BlueGrey400 = 0xff78909c;
EASY_CONSTEXPR color_t BlueGrey500 = 0xff607d8b;
EASY_CONSTEXPR color_t BlueGrey600 = 0xff546e7a;
EASY_CONSTEXPR color_t BlueGrey700 = 0xff455a64;
EASY_CONSTEXPR color_t BlueGrey800 = 0xff37474f;
EASY_CONSTEXPR color_t BlueGrey900 = 0xff263238;
EASY_CONSTEXPR color_t Black = 0xff000000;
EASY_CONSTEXPR color_t White = 0xffffffff;
EASY_CONSTEXPR color_t Null = 0x00000000;
EASY_CONSTEXPR color_t Red = Red500;
EASY_CONSTEXPR color_t DarkRed = Red900;
EASY_CONSTEXPR color_t Coral = Red200;
EASY_CONSTEXPR color_t RichRed = 0xffff0000;
EASY_CONSTEXPR color_t Pink = Pink500;
EASY_CONSTEXPR color_t Rose = PinkA100;
EASY_CONSTEXPR color_t Purple = Purple500;
EASY_CONSTEXPR color_t Magenta = PurpleA200;
EASY_CONSTEXPR color_t DarkMagenta = PurpleA700;
EASY_CONSTEXPR color_t DeepPurple = DeepPurple500;
EASY_CONSTEXPR color_t Indigo = Indigo500;
EASY_CONSTEXPR color_t Blue = Blue500;
EASY_CONSTEXPR color_t DarkBlue = Blue900;
EASY_CONSTEXPR color_t RichBlue = 0xff0000ff;
EASY_CONSTEXPR color_t LightBlue = LightBlue500;
EASY_CONSTEXPR color_t SkyBlue = LightBlueA100;
EASY_CONSTEXPR color_t Navy = LightBlue800;
EASY_CONSTEXPR color_t Cyan = Cyan500;
EASY_CONSTEXPR color_t DarkCyan = Cyan900;
EASY_CONSTEXPR color_t Teal = Teal500;
EASY_CONSTEXPR color_t DarkTeal = Teal900;
EASY_CONSTEXPR color_t Green = Green500;
EASY_CONSTEXPR color_t DarkGreen = Green900;
EASY_CONSTEXPR color_t RichGreen = 0xff00ff00;
EASY_CONSTEXPR color_t LightGreen = LightGreen500;
EASY_CONSTEXPR color_t Mint = LightGreen900;
EASY_CONSTEXPR color_t Lime = Lime500;
EASY_CONSTEXPR color_t Olive = Lime900;
EASY_CONSTEXPR color_t Yellow = Yellow500;
EASY_CONSTEXPR color_t RichYellow = YellowA200;
EASY_CONSTEXPR color_t Amber = Amber500;
EASY_CONSTEXPR color_t Gold = Amber300;
EASY_CONSTEXPR color_t PaleGold = AmberA100;
EASY_CONSTEXPR color_t Orange = Orange500;
EASY_CONSTEXPR color_t Skin = Orange100;
EASY_CONSTEXPR color_t DeepOrange = DeepOrange500;
EASY_CONSTEXPR color_t Brick = DeepOrange900;
EASY_CONSTEXPR color_t Brown = Brown500;
EASY_CONSTEXPR color_t DarkBrown = Brown900;
EASY_CONSTEXPR color_t CreamWhite = Orange50;
EASY_CONSTEXPR color_t Wheat = Amber100;
EASY_CONSTEXPR color_t Grey = Grey500;
EASY_CONSTEXPR color_t Dark = Grey900;
EASY_CONSTEXPR color_t Silver = Grey300;
EASY_CONSTEXPR color_t BlueGrey = BlueGrey500;
EASY_CONSTEXPR color_t Default = Wheat;
#else
EASY_CONSTEXPR color_t Default = 0xffffecb3;
#endif // #if !defined(EASY_OPTION_BUILTIN_COLORS) || EASY_OPTION_BUILTIN_COLORS == 0
} // END of namespace colors.
} // END of namespace profiler.
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER_COLORS_H

View File

@ -0,0 +1,70 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_IN_USE_H
#define EASY_PROFILER_IN_USE_H
//
// BUILD_WITH_EASY_PROFILER is defined in CMakeLists.txt if your project is linked to easy_profiler.
//
//
// DISABLE_EASY_PROFILER may be defined manually in source-file before #include <easy/profiler.h>
// to disable profiler for certain source-file or project.
//
#if defined(BUILD_WITH_EASY_PROFILER) && !defined(DISABLE_EASY_PROFILER)
/**
\defgroup profiler EasyProfiler
*/
/** Indicates that EasyProfiler is used.
\ingroup profiler
*/
# define USING_EASY_PROFILER
#endif
#endif // EASY_PROFILER_IN_USE_H

View File

@ -0,0 +1,205 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_PUBLIC_TYPES_H
#define EASY_PROFILER_PUBLIC_TYPES_H
#include <easy/details/profiler_aux.h>
class NonscopedBlock;
class ProfileManager;
struct ThreadStorage;
namespace profiler {
using timestamp_t = uint64_t;
using thread_id_t = uint64_t;
using block_id_t = uint32_t;
enum class BlockType : uint8_t
{
Event = 0,
Block,
Value,
TypesCount
};
using block_type_t = BlockType;
enum Duration : uint8_t
{
TICKS = 0, ///< CPU ticks
MICROSECONDS ///< Microseconds
};
//***********************************************
#pragma pack(push,1)
class PROFILER_API BaseBlockDescriptor
{
friend ::ProfileManager;
friend ::ThreadStorage;
protected:
block_id_t m_id; ///< This descriptor id (We can afford this spending because there are much more blocks than descriptors)
int32_t m_line; ///< Line number in the source file
color_t m_color; ///< Color of the block packed into 1-byte structure
block_type_t m_type; ///< Type of the block (See BlockType)
EasyBlockStatus m_status; ///< If false then blocks with such id() will not be stored by profiler during profile session
explicit BaseBlockDescriptor(block_id_t _id, EasyBlockStatus _status, int _line, block_type_t _block_type, color_t _color) EASY_NOEXCEPT;
public:
BaseBlockDescriptor() = delete;
inline block_id_t id() const EASY_NOEXCEPT { return m_id; }
inline int32_t line() const EASY_NOEXCEPT { return m_line; }
inline color_t color() const EASY_NOEXCEPT { return m_color; }
inline block_type_t type() const EASY_NOEXCEPT { return m_type; }
inline EasyBlockStatus status() const EASY_NOEXCEPT { return m_status; }
}; // END of class BaseBlockDescriptor.
//***********************************************
class PROFILER_API Event
{
friend ::ProfileManager;
protected:
timestamp_t m_begin;
timestamp_t m_end;
public:
Event() = delete;
Event(const Event&) = default;
explicit Event(timestamp_t _begin_time) EASY_NOEXCEPT;
explicit Event(timestamp_t _begin_time, timestamp_t _end_time) EASY_NOEXCEPT;
inline timestamp_t begin() const EASY_NOEXCEPT { return m_begin; }
inline timestamp_t end() const EASY_NOEXCEPT { return m_end; }
inline timestamp_t duration() const EASY_NOEXCEPT { return m_end - m_begin; }
}; // END class Event.
class PROFILER_API BaseBlockData : public Event
{
friend ::ProfileManager;
protected:
block_id_t m_id;
public:
BaseBlockData() = delete;
BaseBlockData(const BaseBlockData&) = default;
explicit BaseBlockData(timestamp_t _begin_time, block_id_t _id) EASY_NOEXCEPT;
explicit BaseBlockData(timestamp_t _begin_time, timestamp_t _end_time, block_id_t _id) EASY_NOEXCEPT;
inline block_id_t id() const EASY_NOEXCEPT { return m_id; }
inline void setId(block_id_t _id) EASY_NOEXCEPT { m_id = _id; }
}; // END of class BaseBlockData.
#pragma pack(pop)
//***********************************************
class PROFILER_API Block : public BaseBlockData
{
friend ::ProfileManager;
friend ::ThreadStorage;
friend ::NonscopedBlock;
const char* m_name;
EasyBlockStatus m_status;
bool m_isScoped;
private:
void start();
void start(timestamp_t _time) EASY_NOEXCEPT;
void finish();
void finish(timestamp_t _time) EASY_NOEXCEPT;
inline bool finished() const EASY_NOEXCEPT { return m_end >= m_begin; }
inline EasyBlockStatus status() const EASY_NOEXCEPT { return m_status; }
inline void setStatus(EasyBlockStatus _status) EASY_NOEXCEPT { m_status = _status; }
public:
Block(const Block&) = delete;
Block& operator = (const Block&) = delete;
Block(Block&& that) EASY_NOEXCEPT;
Block(const BaseBlockDescriptor* _desc, const char* _runtimeName, bool _scoped = true) EASY_NOEXCEPT;
Block(timestamp_t _begin_time, block_id_t _id, const char* _runtimeName) EASY_NOEXCEPT;
Block(timestamp_t _begin_time, timestamp_t _end_time, block_id_t _id, const char* _runtimeName) EASY_NOEXCEPT;
~Block();
inline const char* name() const EASY_NOEXCEPT { return m_name; }
}; // END of class Block.
//***********************************************
class PROFILER_API ThreadGuard EASY_FINAL
{
friend ::ProfileManager;
thread_id_t m_id = 0;
public:
~ThreadGuard();
}; // END of class ThreadGuard.
EASY_CONSTEXPR uint16_t MAX_BLOCK_DATA_SIZE = 2048 + 512 + 256; ///< Estimated maximum size of block dynamic name or EASY_VALUE data size
} // END of namespace profiler.
#endif // EASY_PROFILER_PUBLIC_TYPES_H

View File

@ -0,0 +1,161 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_NET_H
#define EASY_NET_H
#include <easy/details/easy_compiler_support.h>
#include <stdint.h>
namespace profiler { namespace net {
EASY_CONSTEXPR uint32_t EASY_MESSAGE_SIGN = 20160909;
#pragma pack(push,1)
enum class MessageType : uint8_t
{
Undefined = 0,
Request_Start_Capture,
Reply_Capturing_Started,
Request_Stop_Capture,
Reply_Blocks,
Reply_Blocks_End,
Connection_Accepted,
Request_Blocks_Description,
Reply_Blocks_Description,
Reply_Blocks_Description_End,
Change_Block_Status,
Change_Event_Tracing_Status,
Change_Event_Tracing_Priority,
Ping,
Request_MainThread_FPS,
Reply_MainThread_FPS,
};
struct Message
{
uint32_t magic_number = EASY_MESSAGE_SIGN;
MessageType type = MessageType::Undefined;
bool isEasyNetMessage() const EASY_NOEXCEPT {
return EASY_MESSAGE_SIGN == magic_number;
}
explicit Message(MessageType _t) EASY_NOEXCEPT : type(_t) { }
Message() = default;
};
struct DataMessage : public Message
{
uint32_t size = 0; // bytes
explicit DataMessage(MessageType _t = MessageType::Reply_Blocks) : Message(_t) {}
explicit DataMessage(uint32_t _s, MessageType _t = MessageType::Reply_Blocks) : Message(_t), size(_s) {}
const char* data() const { return reinterpret_cast<const char*>(this) + sizeof(DataMessage); }
};
struct BlockStatusMessage : public Message
{
uint32_t id;
uint8_t status;
explicit BlockStatusMessage(uint32_t _id, uint8_t _status)
: Message(MessageType::Change_Block_Status), id(_id), status(_status) { }
BlockStatusMessage() = delete;
};
struct EasyProfilerStatus : public Message
{
bool isProfilerEnabled;
bool isEventTracingEnabled;
bool isLowPriorityEventTracing;
explicit EasyProfilerStatus(bool _enabled, bool _ETenabled, bool _ETlowp)
: Message(MessageType::Connection_Accepted)
, isProfilerEnabled(_enabled)
, isEventTracingEnabled(_ETenabled)
, isLowPriorityEventTracing(_ETlowp)
{
}
EasyProfilerStatus() = delete;
};
struct BoolMessage : public Message
{
bool flag = false;
explicit BoolMessage(MessageType _t, bool _flag = false)
: Message(_t), flag(_flag) { }
BoolMessage() = default;
};
struct TimestampMessage : public Message
{
uint32_t maxValue = 0;
uint32_t avgValue = 0;
explicit TimestampMessage(MessageType _t, uint32_t _maxValue, uint32_t _avgValue)
: Message(_t), maxValue(_maxValue), avgValue(_avgValue) { }
TimestampMessage() = default;
};
#pragma pack(pop)
}//net
}//profiler
#endif // EASY_NET_H

View File

@ -0,0 +1,76 @@
#ifndef EASY_PROPROTOCOL_H
#define EASY_PROPROTOCOL_H
///C++
#include <string>
#include <vector>
#include <memory>
///this
#include <easy/serialized_block.h>
//#include <easy/profiler.h>
///for actual version vistit https://github.com/yse/easy_profiler/wiki/.prof-file-format-v1.3.0
namespace profiler {
namespace reader {
struct BlockDescriptor;
struct BlocksInfo //12
{
uint32_t totalBlocksCount; //4 bytes
uint64_t totalBlocksMemory; //8 bytes
};
struct DescriptorsInfo //12
{
uint32_t allDescriptorsCount; //4 bytes
uint64_t allDescriptorsMemory; //8 bytes
};
struct FileHeader //64
{
uint32_t signature; //4
uint32_t version; //4
uint64_t processId; //8
int64_t cpuFrequency; //8
uint64_t beginTime; //8
uint64_t endTime; //8
BlocksInfo serializedBlocksInfo; //12
DescriptorsInfo blocksDescriptorInfo; //12
};
struct BlockInfo
{
uint64_t beginTime;
uint64_t endTime;
const BlockDescriptor* descriptor;
uint32_t blockIndex;
};
struct ContextSwitchEvent
{
uint64_t beginTime;
uint64_t endTime;
uint64_t targetThreadId;
std::string targetProcess; ///< Contains process id and process name
};
struct BlockDescriptor
{
uint32_t parentId; ///< This will differ from id if this descriptor was created from runtime named block
uint32_t id;
int lineNumber;
uint32_t argbColor;
uint8_t blockType;
uint8_t status;
std::string blockName;
std::string fileName;
};
} //namespace reader
} //namespace profiler
#endif

View File

@ -0,0 +1,130 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_SOCKET_H
#define EASY_PROFILER_SOCKET_H
#include <stdint.h>
#include <easy/details/easy_compiler_support.h>
#ifndef _WIN32
// Unix
# include <sys/types.h>
# include <sys/socket.h>
# include <netdb.h>
# include <stdio.h>
# include <unistd.h>
# include <fcntl.h>
# include <netinet/in.h> //for android-build
#else
// Windows
# define WIN32_LEAN_AND_MEAN
# include <winsock2.h>
# include <windows.h>
# include <ws2tcpip.h>
# include <stdlib.h>
#endif
class PROFILER_API EasySocket EASY_FINAL
{
public:
#ifdef _WIN32
typedef SOCKET socket_t;
#else
typedef int socket_t;
#endif
enum class ConnectionState : int8_t
{
Disconnected = -1,
Unknown,
Connected,
Connecting
};
private:
socket_t m_socket = 0;
socket_t m_replySocket = 0;
int m_wsaret = -1;
struct hostent* m_server = nullptr;
struct sockaddr_in m_serverAddress;
ConnectionState m_state = ConnectionState::Unknown;
public:
EasySocket();
~EasySocket();
void setReceiveTimeout(int milliseconds);
int send(const void* buf, size_t nbyte);
int receive(void* buf, size_t nbyte);
int listen(int count = 5);
int accept();
int bind(uint16_t portno);
bool setAddress(const char* serv, uint16_t port);
int connect();
void flush();
void init();
ConnectionState state() const;
bool isDisconnected() const;
bool isConnected() const;
private:
void checkResult(int result);
bool checkSocket(socket_t s) const;
void setBlocking(socket_t s, bool blocking);
}; // end of class EasySocket.
#endif // EASY_PROFILER_SOCKET_H

View File

@ -0,0 +1,911 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_H
#define EASY_PROFILER_H
#include <easy/details/profiler_public_types.h>
#define MAX_DYNAMIC_BLOCK_NAME_SIZE_ESTIMATED MAX_BLOCK_DATA_SIZE
#if defined ( __clang__ )
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
#endif
//
// USING_EASY_PROFILER is defined in details/profiler_in_use.h
// if defined BUILD_WITH_EASY_PROFILER and not defined DISABLE_EASY_PROFILER
//
//
// BUILD_WITH_EASY_PROFILER is defined in CMakeLists.txt if your project is linked to easy_profiler.
//
//
// DISABLE_EASY_PROFILER may be defined manually in source-file before #include <easy/profiler.h>
// to disable profiler for certain source-file or project.
//
#ifdef USING_EASY_PROFILER
// EasyProfiler core API:
/** Macro for beginning of a scoped block with custom name and color.
\code
#include <easy/profiler.h>
void foo()
{
// some code ...
EASY_BLOCK("Check something", profiler::OFF); // Disabled block (There is possibility to enable this block later via GUI)
if(something){
EASY_BLOCK("Calling bar()"); // Block with default color
bar();
}
else{
EASY_BLOCK("Calling baz()", profiler::colors::Red); // Red block
baz();
}
EASY_END_BLOCK; // End of "Check something" block (Even if "Check something" is disabled, this EASY_END_BLOCK will not end any other block).
EASY_BLOCK("Some another block", profiler::colors::Blue, profiler::ON_WITHOUT_CHILDREN); // Block with Blue color without
// some another code...
EASY_BLOCK("Calculate sum"); // This block will not be profiled because it's parent is ON_WITHOUT_CHILDREN
int sum = 0;
for (int i = 0; i < 10; ++i)
sum += i;
EASY_END_BLOCK; // End of "Calculate sum" block
}
\endcode
Block will be automatically completed by destructor.
\ingroup profiler
*/
# define EASY_BLOCK(name, ...)\
EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), ::profiler::registerDescription(::profiler::extract_enable_flag(__VA_ARGS__),\
EASY_UNIQUE_LINE_ID, EASY_COMPILETIME_NAME(name), __FILE__, __LINE__, ::profiler::BlockType::Block, ::profiler::extract_color(__VA_ARGS__),\
::std::is_base_of<::profiler::ForceConstStr, decltype(name)>::value));\
::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));\
::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__));
/** Macro for beginning of a non-scoped block with custom name and color.
You must end such block manually with EASY_END_BLOCK.
\code
#include <easy/profiler.h>
void foo() {
EASY_NONSCOPED_BLOCK("Callback"); // Begin block which would not be finished when function returns.
// some code ...
}
void bar() {
// some another code...
EASY_END_BLOCK; // This, as always, ends last opened block. You have to take care about blocks order by yourself.
}
void baz() {
foo(); // non-scoped block begins here
// some code...
bar(); // non-scoped block ends here
}
\endcode
Block will be automatically completed by destructor.
\ingroup profiler
*/
#define EASY_NONSCOPED_BLOCK(name, ...)\
EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), ::profiler::registerDescription(::profiler::extract_enable_flag(__VA_ARGS__),\
EASY_UNIQUE_LINE_ID, EASY_COMPILETIME_NAME(name), __FILE__, __LINE__, ::profiler::BlockType::Block, ::profiler::extract_color(__VA_ARGS__),\
::std::is_base_of<::profiler::ForceConstStr, decltype(name)>::value));\
::profiler::beginNonScopedBlock(EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));
/** Macro for beginning of a block with function name and custom color.
\code
#include <easy/profiler.h>
void foo(){
EASY_FUNCTION(); // Block with name="foo" and default color
//some code...
}
void bar(){
EASY_FUNCTION(profiler::colors::Green); // Green block with name="bar"
//some code...
}
void baz(){
EASY_FUNCTION(profiler::FORCE_ON); // Force enabled block with name="baz" and default color (This block will be profiled even if it's parent is OFF_RECURSIVE)
// som code...
}
\endcode
Name of the block automatically created with function name.
\ingroup profiler
*/
# define EASY_FUNCTION(...) EASY_BLOCK(EASY_FUNC_NAME, ## __VA_ARGS__)
/** Macro for completion of last opened block explicitly.
\code
#include <easy/profiler.h>
int foo()
{
// some code ...
int sum = 0;
EASY_BLOCK("Calculating sum");
for (int i = 0; i < 10; ++i){
sum += i;
}
EASY_END_BLOCK;
// some antoher code here ...
return sum;
}
\endcode
\ingroup profiler
*/
# define EASY_END_BLOCK ::profiler::endBlock();
/** Macro for creating event marker with custom name and color.
Event marker is a block with zero duration and special type.
\warning Event marker ends immediately and calling EASY_END_BLOCK after EASY_EVENT
will end previously opened EASY_BLOCK or EASY_FUNCTION.
\ingroup profiler
*/
# define EASY_EVENT(name, ...)\
EASY_LOCAL_STATIC_PTR(const ::profiler::BaseBlockDescriptor*, EASY_UNIQUE_DESC(__LINE__), ::profiler::registerDescription(\
::profiler::extract_enable_flag(__VA_ARGS__), EASY_UNIQUE_LINE_ID, EASY_COMPILETIME_NAME(name),\
__FILE__, __LINE__, ::profiler::BlockType::Event, ::profiler::extract_color(__VA_ARGS__),\
::std::is_base_of<::profiler::ForceConstStr, decltype(name)>::value));\
::profiler::storeEvent(EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));
/** Macro for enabling profiler.
\ingroup profiler
*/
# define EASY_PROFILER_ENABLE ::profiler::setEnabled(true);
/** Macro for disabling profiler.
\ingroup profiler
*/
# define EASY_PROFILER_DISABLE ::profiler::setEnabled(false);
/** Macro for current thread registration.
\note If this thread has been already registered then nothing happens.
\ingroup profiler
*/
# define EASY_THREAD(name)\
EASY_THREAD_LOCAL static const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = nullptr;\
if (!EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__))\
EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = ::profiler::registerThread(name);
/** Macro for current thread registration and creating a thread guard object.
\note If this thread has been already registered then nothing happens.
\note Also creates thread guard which marks thread as "expired" on it's destructor
and creates "ThreadFinished" profiler event.
\ingroup profiler
*/
# define EASY_THREAD_SCOPE(name)\
static EASY_THREAD_LOCAL const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = nullptr;\
::profiler::ThreadGuard EASY_TOKEN_CONCATENATE(unique_profiler_thread_guard, __LINE__);\
if (!EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__))\
EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = ::profiler::registerThreadScoped(name,\
EASY_TOKEN_CONCATENATE(unique_profiler_thread_guard, __LINE__));
/** Macro for main thread registration.
This is just for user's comfort. There is no difference for EasyProfiler GUI between different threads.
\ingroup profiler
*/
# define EASY_MAIN_THREAD EASY_THREAD("Main")
/** Enable or disable event tracing (context switch events).
\note Default value is controlled by EASY_OPTION_EVENT_TRACING_ENABLED macro.
\note Change will take effect on the next call to EASY_PROFILER_ENABLE.
\sa EASY_PROFILER_ENABLE, EASY_OPTION_EVENT_TRACING_ENABLED
\ingroup profiler
*/
# define EASY_SET_EVENT_TRACING_ENABLED(isEnabled) ::profiler::setEventTracingEnabled(isEnabled);
/** Set event tracing thread priority (low or normal).
Event tracing with low priority will affect your application performance much more less, but
it can be late to gather information about thread/process (thread could be finished to the moment
when event tracing thread will be awaken) and you will not see process name and process id
information in GUI for such threads. You will still be able to see all context switch events.
Event tracing with normal priority could gather more information about processes but potentially
it could affect performance as it has more work to do. Usually you will not notice any performance
breakdown, but if you care about that then you change set event tracing priority level to low.
\sa EASY_OPTION_LOW_PRIORITY_EVENT_TRACING
\ingroup profiler
*/
# define EASY_SET_LOW_PRIORITY_EVENT_TRACING(isLowPriority) ::profiler::setLowPriorityEventTracing(isLowPriority);
/** Macro for setting temporary log-file path for Unix event tracing system.
\note Default value is "/tmp/cs_profiling_info.log".
\ingroup profiler
*/
# define EASY_EVENT_TRACING_SET_LOG(filename) ::profiler::setContextSwitchLogFilename(filename);
/** Macro returning current path to the temporary log-file for Unix event tracing system.
\ingroup profiler
*/
# define EASY_EVENT_TRACING_LOG ::profiler::getContextSwitchLogFilename();
// EasyProfiler settings:
/** If != 0 then EasyProfiler will measure time for blocks storage expansion.
If 0 then EasyProfiler will be compiled without blocks of code responsible
for measuring these events.
These are "EasyProfiler.ExpandStorage" blocks on a diagram.
\ingroup profiler
*/
# ifndef EASY_OPTION_MEASURE_STORAGE_EXPAND
# define EASY_OPTION_MEASURE_STORAGE_EXPAND 0
# endif
# if EASY_OPTION_MEASURE_STORAGE_EXPAND != 0
/** If true then "EasyProfiler.ExpandStorage" blocks are enabled by default and will be
writed to output file or translated over the net.
If false then you need to enable these blocks via GUI if you want to see them.
\ingroup profiler
*/
# ifndef EASY_OPTION_STORAGE_EXPAND_BLOCKS_ON
# define EASY_OPTION_STORAGE_EXPAND_BLOCKS_ON true
# endif
# endif // EASY_OPTION_MEASURE_STORAGE_EXPAND != 0
/** If true then EasyProfiler event tracing is enabled by default
and will be turned on and off when you call profiler::setEnabled().
Otherwise, it have to be turned on via GUI and then it will be
turned on/off with next calls of profiler::setEnabled().
\ingroup profiler
*/
# ifndef EASY_OPTION_EVENT_TRACING_ENABLED
# define EASY_OPTION_EVENT_TRACING_ENABLED true
# endif
/** If true then EasyProfiler.ETW thread (Event tracing for Windows) will have low priority by default.
\sa EASY_SET_LOW_PRIORITY_EVENT_TRACING
\note You can always change priority level via GUI or API while profiling session is not launched.
You don't need to rebuild or restart your application for that.
\ingroup profiler
*/
# ifndef EASY_OPTION_LOW_PRIORITY_EVENT_TRACING
# define EASY_OPTION_LOW_PRIORITY_EVENT_TRACING true
# endif
/** If != 0 then EasyProfiler will print error messages into stderr.
Otherwise, no log messages will be printed.
\ingroup profiler
*/
# ifndef EASY_OPTION_LOG_ENABLED
# define EASY_OPTION_LOG_ENABLED 0
# endif
/** If != 0 then EasyProfiler will start listening thread immediately on ProfileManager initialization.
\sa startListen
\ingroup profiler
*/
# ifndef EASY_OPTION_START_LISTEN_ON_STARTUP
# define EASY_OPTION_START_LISTEN_ON_STARTUP 0
# endif
#else // #ifdef BUILD_WITH_EASY_PROFILER
# define EASY_BLOCK(...)
# define EASY_NONSCOPED_BLOCK(...)
# define EASY_FUNCTION(...)
# define EASY_END_BLOCK
# define EASY_PROFILER_ENABLE
# define EASY_PROFILER_DISABLE
# define EASY_EVENT(...)
# define EASY_THREAD(...)
# define EASY_THREAD_SCOPE(...)
# define EASY_MAIN_THREAD
# define EASY_SET_EVENT_TRACING_ENABLED(isEnabled)
# define EASY_SET_LOW_PRIORITY_EVENT_TRACING(isLowPriority)
# ifndef _WIN32
# define EASY_EVENT_TRACING_SET_LOG(filename)
# define EASY_EVENT_TRACING_LOG ""
# endif
# ifndef EASY_OPTION_MEASURE_STORAGE_EXPAND
# define EASY_OPTION_MEASURE_STORAGE_EXPAND 0
# endif
# ifndef EASY_OPTION_EVENT_TRACING_ENABLED
# define EASY_OPTION_EVENT_TRACING_ENABLED false
# endif
# ifndef EASY_OPTION_LOW_PRIORITY_EVENT_TRACING
# define EASY_OPTION_LOW_PRIORITY_EVENT_TRACING true
# endif
# ifndef EASY_OPTION_LOG_ENABLED
# define EASY_OPTION_LOG_ENABLED 0
# endif
# ifndef EASY_OPTION_START_LISTEN_ON_STARTUP
# define EASY_OPTION_START_LISTEN_ON_STARTUP 0
# endif
#endif // #ifndef BUILD_WITH_EASY_PROFILER
# ifndef EASY_DEFAULT_PORT
# define EASY_DEFAULT_PORT 28077
# endif
/** Alias for EASY_PROFILER_ENABLE.
Added for clarification.
\sa EASY_PROFILER_ENABLE
\ingroup profiler
*/
#define EASY_START_CAPTURE EASY_PROFILER_ENABLE
/** Alias for EASY_PROFILER_DISABLE.
Added for clarification.
\sa EASY_PROFILER_DISABLE
\ingroup profiler
*/
#define EASY_STOP_CAPTURE EASY_PROFILER_DISABLE
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
namespace profiler {
EASY_CONSTEXPR uint16_t DEFAULT_PORT = EASY_DEFAULT_PORT;
//////////////////////////////////////////////////////////////////////
// Core API
// Note: It is better to use macros defined above than a direct calls to API.
// But some API functions does not have macro wrappers...
#ifdef USING_EASY_PROFILER
extern "C" {
/** Returns current time in ticks.
You can use it if you want to store block explicitly.
\retval Current CPU time in ticks.
\ingroup profiler
*/
PROFILER_API timestamp_t now();
/** Convert ticks to nanoseconds.
\retval _ticks converted to nanoseconds.
\ingroup profiler
*/
PROFILER_API timestamp_t toNanoseconds(timestamp_t _ticks);
/** Convert ticks to microseconds.
\retval _ticks converted to microseconds.
\ingroup profiler
*/
PROFILER_API timestamp_t toMicroseconds(timestamp_t _ticks);
/** Registers static description of a block.
It is general information which is common for all such blocks.
Includes color, block type (see BlockType), file-name, line-number, compile-time name of a block and enable-flag.
\note This API function is used by EASY_EVENT, EASY_BLOCK, EASY_FUNCTION macros.
There is no need to invoke this function explicitly.
\retval Pointer to registered block description.
\ingroup profiler
*/
PROFILER_API const BaseBlockDescriptor* registerDescription(EasyBlockStatus _status, const char* _autogenUniqueId, const char* _compiletimeName, const char* _filename, int _line, block_type_t _block_type, color_t _color, bool _copyName = false);
/** Stores event in the blocks list.
An event ends instantly and has zero duration.
\note There is no need to invoke this function explicitly - use EASY_EVENT macro instead.
\param _desc Reference to the previously registered description.
\param _runtimeName Standard zero-terminated string which will be copied to the events buffer.
\note _runtimeName must be an empty string ("") if you do not want to set name to the event at run-time.
\ingroup profiler
*/
PROFILER_API void storeEvent(const BaseBlockDescriptor* _desc, const char* _runtimeName = "");
/** Stores block explicitly in the blocks list.
Use this function for additional flexibility if you want to set block duration manually.
\param _desc Reference to the previously registered description.
\param _runtimeName Standard zero-terminated string which will be copied to the events buffer.
\param _beginTime begin time of the block
\param _endTime end time of the block
\note _runtimeName must be an empty string ("") if you do not want to set name to the block at run-time.
\ingroup profiler
*/
PROFILER_API void storeBlock(const BaseBlockDescriptor* _desc, const char* _runtimeName, timestamp_t _beginTime, timestamp_t _endTime);
/** Begins scoped block.
\ingroup profiler
*/
PROFILER_API void beginBlock(Block& _block);
/** Begins non-scoped block.
\param _desc Reference to the previously registered description (see registerDescription).
\param _runtimeName Standard zero-terminated string which will be copied to the block buffer when block will end.
\note There is no need to invoke this function explicitly - use EASY_NONSCOPED_BLOCK macro instead.
EASY_NONSCOPED_BLOCK macro could be used for higher flexibility if you have to begin block in one
function and end it in another one.
\note _runtimeName must be an empty string ("") if you do not want to set name to the block at run-time.
\note _runtimeName is copied only when block ends so you must ensure it's validity until block end.
\warning You have to end this block explicitly.
\ingroup profiler
*/
PROFILER_API void beginNonScopedBlock(const BaseBlockDescriptor* _desc, const char* _runtimeName = "");
/** Ends last started block.
Use this only if you want to finish block explicitly.
\ingroup profiler
*/
PROFILER_API void endBlock();
/** Enable or disable profiler.
AKA start or stop profiling (capturing blocks).
\ingroup profiler
*/
PROFILER_API void setEnabled(bool _isEnable);
PROFILER_API bool isEnabled();
/** Save all gathered blocks into file.
\note This also disables profiler.
\retval Number of saved blocks. If 0 then nothing was profiled or an error occurred.
\ingroup profiler
*/
PROFILER_API uint32_t dumpBlocksToFile(const char* _filename);
/** Register current thread and give it a name.
Also creates a scoped ThreadGuard which would unregister thread on it's destructor.
This helps for memory management while using an old compiler whitout thread_local support.
\note Only first call of registerThread() for the current thread will have an effect.
\note Use this function if you want to build your source code with an old compiler (MSVC < 2013, GCC < 4.8, Clang < 3.3).
Otherwise there is no need in this function because a thread_local ThreadGuard created inside.
\retval Registered name of the thread. It may differ from _name if the thread was registered before.
\sa registerThread, ThreadGuard
\ingroup profiler
*/
PROFILER_API const char* registerThreadScoped(const char* _name, ThreadGuard&);
/** Register current thread and give it a name.
\note Only first call of registerThread() for the current thread will have an effect.
\retval Registered name of the thread. It may differ from _name if the thread was registered before.
\ingroup profiler
*/
PROFILER_API const char* registerThread(const char* _name);
/** Enable or disable event tracing.
\note This change will take an effect on the next call of setEnabled(true);
\sa setEnabled, EASY_SET_EVENT_TRACING_ENABLED
\ingroup profiler
*/
PROFILER_API void setEventTracingEnabled(bool _isEnable);
PROFILER_API bool isEventTracingEnabled();
/** Set event tracing thread priority (low or normal).
\note This change will take effect on the next call of setEnabled(true);
\sa setEnabled, EASY_SET_LOW_PRIORITY_EVENT_TRACING
\ingroup profiler
*/
PROFILER_API void setLowPriorityEventTracing(bool _isLowPriority);
PROFILER_API bool isLowPriorityEventTracing();
/** Set temporary log-file path for Unix event tracing system.
\note Default value is "/tmp/cs_profiling_info.log".
\ingroup profiler
*/
PROFILER_API void setContextSwitchLogFilename(const char* _name);
/** Returns current path to the temporary log-file for Unix event tracing system.
\ingroup profiler
*/
PROFILER_API const char* getContextSwitchLogFilename();
/** Start listening for network commands.
Launches a separate listening thread which would listen to the network commands (start, stop, etc.).
The listening thread sends all profiled blocks via network after receiving network command 'stop'.
\ingroup profiler
*/
PROFILER_API void startListen(uint16_t _port = ::profiler::DEFAULT_PORT);
/** Stops listening thread.
\note This would be invoked automatically on application exit.
\note Does not send any messages to the network, just stops thread.
\ingroup profiler
*/
PROFILER_API void stopListen();
/** Check if listening thread launched.
\ingroup profiler
*/
PROFILER_API bool isListening();
/** Returns current major version.
\ingroup profiler
*/
PROFILER_API uint8_t versionMajor();
/** Returns current minor version.
\ingroup profiler
*/
PROFILER_API uint8_t versionMinor();
/** Returns current version patch.
\ingroup profiler
*/
PROFILER_API uint16_t versionPatch();
/** Returns current version in 32-bit integer format.
\note Format is: 0x MAJ-MAJ MIN-MIN PATCH-PATCH-PATCH-PATCH
For example v1.3.0 is: 0x01030000
\ingroup profiler
*/
PROFILER_API uint32_t version();
/** Returns current version string.
Example: "v1.3.0"
\ingroup profiler
*/
PROFILER_API const char* versionName();
/** Returns true if current thread has been marked as Main.
Otherwise, returns false.
\ingroup profiler
*/
PROFILER_API bool isMainThread();
/** Returns last frame duration for current thread.
\param _durationCast desired duration units (could be cpu-ticks or microseconds)
\ingroup profiler
*/
PROFILER_API timestamp_t this_thread_frameTime(Duration _durationCast = ::profiler::MICROSECONDS);
/** Returns local max of frame duration for current thread.
Local max is maximum frame duration since last frameTimeLocalMax() call.
\param _durationCast desired duration units (could be cpu-ticks or microseconds)
\ingroup profiler
*/
PROFILER_API timestamp_t this_thread_frameTimeLocalMax(Duration _durationCast = ::profiler::MICROSECONDS);
/** Returns local average of frame duration for current thread.
Local average is average frame duration since last frameTimeLocalAvg() call.
\param _durationCast desired duration units (could be cpu-ticks or microseconds)
\ingroup profiler
*/
PROFILER_API timestamp_t this_thread_frameTimeLocalAvg(Duration _durationCast = ::profiler::MICROSECONDS);
/** Returns last frame duration for main thread.
\param _durationCast desired duration units (could be cpu-ticks or microseconds)
\ingroup profiler
*/
PROFILER_API timestamp_t main_thread_frameTime(Duration _durationCast = ::profiler::MICROSECONDS);
/** Returns local max of frame duration for main thread.
Local max is maximum frame duration since last frameTimeLocalMax() call.
\param _durationCast desired duration units (could be cpu-ticks or microseconds)
\ingroup profiler
*/
PROFILER_API timestamp_t main_thread_frameTimeLocalMax(Duration _durationCast = ::profiler::MICROSECONDS);
/** Returns local average of frame duration for main thread.
Local average is average frame duration since last frameTimeLocalAvg() call.
\param _durationCast desired duration units (could be cpu-ticks or microseconds)
\ingroup profiler
*/
PROFILER_API timestamp_t main_thread_frameTimeLocalAvg(Duration _durationCast = ::profiler::MICROSECONDS);
}
#else
inline EASY_CONSTEXPR_FCN timestamp_t now() { return 0; }
inline EASY_CONSTEXPR_FCN timestamp_t toNanoseconds(timestamp_t) { return 0; }
inline EASY_CONSTEXPR_FCN timestamp_t toMicroseconds(timestamp_t) { return 0; }
inline const BaseBlockDescriptor* registerDescription(EasyBlockStatus, const char*, const char*, const char*, int, block_type_t, color_t, bool = false)
{ return reinterpret_cast<const BaseBlockDescriptor*>(0xbad); }
inline void endBlock() { }
inline void setEnabled(bool) { }
inline EASY_CONSTEXPR_FCN bool isEnabled() { return false; }
inline void storeEvent(const BaseBlockDescriptor*, const char* = "") { }
inline void storeBlock(const BaseBlockDescriptor*, const char*, timestamp_t, timestamp_t) { }
inline void beginBlock(Block&) { }
inline void beginNonScopedBlock(const BaseBlockDescriptor*, const char* = "") { }
inline uint32_t dumpBlocksToFile(const char*) { return 0; }
inline const char* registerThreadScoped(const char*, ThreadGuard&) { return ""; }
inline const char* registerThread(const char*) { return ""; }
inline void setEventTracingEnabled(bool) { }
inline EASY_CONSTEXPR_FCN bool isEventTracingEnabled() { return false; }
inline void setLowPriorityEventTracing(bool) { }
inline EASY_CONSTEXPR_FCN bool isLowPriorityEventTracing() { return false; }
inline void setContextSwitchLogFilename(const char*) { }
inline EASY_CONSTEXPR_FCN const char* getContextSwitchLogFilename() { return ""; }
inline void startListen(uint16_t = ::profiler::DEFAULT_PORT) { }
inline void stopListen() { }
inline EASY_CONSTEXPR_FCN bool isListening() { return false; }
inline EASY_CONSTEXPR_FCN uint8_t versionMajor() { return 0; }
inline EASY_CONSTEXPR_FCN uint8_t versionMinor() { return 0; }
inline EASY_CONSTEXPR_FCN uint16_t versionPatch() { return 0; }
inline EASY_CONSTEXPR_FCN uint32_t version() { return 0; }
inline EASY_CONSTEXPR_FCN const char* versionName() { return "v0.0.0_disabled"; }
inline EASY_CONSTEXPR_FCN bool isMainThread() { return false; }
inline EASY_CONSTEXPR_FCN timestamp_t this_thread_frameTime(Duration = ::profiler::MICROSECONDS) { return 0; }
inline EASY_CONSTEXPR_FCN timestamp_t this_thread_frameTimeLocalMax(Duration = ::profiler::MICROSECONDS) { return 0; }
inline EASY_CONSTEXPR_FCN timestamp_t this_thread_frameTimeLocalAvg(Duration = ::profiler::MICROSECONDS) { return 0; }
inline EASY_CONSTEXPR_FCN timestamp_t main_thread_frameTime(Duration = ::profiler::MICROSECONDS) { return 0; }
inline EASY_CONSTEXPR_FCN timestamp_t main_thread_frameTimeLocalMax(Duration = ::profiler::MICROSECONDS) { return 0; }
inline EASY_CONSTEXPR_FCN timestamp_t main_thread_frameTimeLocalAvg(Duration = ::profiler::MICROSECONDS) { return 0; }
#endif
/** API functions binded to current thread.
\ingroup profiler
*/
namespace this_thread {
inline const char* registrate(const char* _name) {
return ::profiler::registerThread(_name);
}
inline const char* registrate(const char* _name, ThreadGuard& _threadGuard) {
return ::profiler::registerThreadScoped(_name, _threadGuard);
}
inline timestamp_t frameTime(Duration _durationCast = ::profiler::MICROSECONDS) {
return ::profiler::this_thread_frameTime(_durationCast);
}
inline timestamp_t frameTimeLocalMax(Duration _durationCast = ::profiler::MICROSECONDS) {
return ::profiler::this_thread_frameTimeLocalMax(_durationCast);
}
inline timestamp_t frameTimeLocalAvg(Duration _durationCast = ::profiler::MICROSECONDS) {
return ::profiler::this_thread_frameTimeLocalAvg(_durationCast);
}
inline bool isMain() {
return ::profiler::isMainThread();
}
} // END of namespace this_thread.
/** API functions binded to main thread.
Could be called from any thread.
\ingroup profiler
*/
namespace main_thread {
inline timestamp_t frameTime(Duration _durationCast = ::profiler::MICROSECONDS) {
return ::profiler::main_thread_frameTime(_durationCast);
}
inline timestamp_t frameTimeLocalMax(Duration _durationCast = ::profiler::MICROSECONDS) {
return ::profiler::main_thread_frameTimeLocalMax(_durationCast);
}
inline timestamp_t frameTimeLocalAvg(Duration _durationCast = ::profiler::MICROSECONDS) {
return ::profiler::main_thread_frameTimeLocalAvg(_durationCast);
}
/** Always returns true.
*/
inline EASY_CONSTEXPR_FCN bool isMain() {
return true;
}
} // END of namespace main_thread.
/** Alias for isEnabled().
Added for clarification.
\sa isEnabled
\ingroup profiler
*/
EASY_FORCE_INLINE bool isCapturing() { return isEnabled(); }
/** Alias for EASY_PROFILER_ENABLE.
Added for clarification.
\sa EASY_PROFILER_ENABLE
\ingroup profiler
*/
EASY_FORCE_INLINE void startCapture() { EASY_PROFILER_ENABLE; }
/** Alias for EASY_PROFILER_DISABLE.
Added for clarification.
\sa EASY_PROFILER_DISABLE
\ingroup profiler
*/
EASY_FORCE_INLINE void stopCapture() { EASY_PROFILER_DISABLE; }
/** Alias for now().
\ingroup profiler
*/
EASY_FORCE_INLINE timestamp_t currentTime() { return now(); }
//////////////////////////////////////////////////////////////////////
} // END of namespace profiler.
#if defined ( __clang__ )
# pragma clang diagnostic pop
#endif
#endif // EASY_PROFILER_H

View File

@ -0,0 +1,422 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_READER_H
#define EASY_PROFILER_READER_H
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <atomic>
#include <functional>
#include <iostream>
#include <unordered_map>
#include <string>
#include <vector>
#include <easy/serialized_block.h>
#include <easy/details/arbitrary_value_public_types.h>
#include <easy/utility.h>
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace profiler {
using processid_t = uint64_t;
using calls_number_t = uint32_t;
using block_index_t = uint32_t;
#pragma pack(push, 1)
struct BlockStatistics EASY_FINAL
{
profiler::timestamp_t total_duration; ///< Total duration of all block calls
profiler::timestamp_t median_duration; ///< Median duration of all block calls
profiler::timestamp_t total_children_duration; ///< Total duration of all children of all block calls
profiler::block_index_t min_duration_block; ///< Will be used in GUI to jump to the block with min duration
profiler::block_index_t max_duration_block; ///< Will be used in GUI to jump to the block with max duration
profiler::block_index_t parent_block; ///< Index of block which is "parent" for "per_parent_stats" or "frame" for "per_frame_stats" or thread-id for "per_thread_stats"
profiler::calls_number_t calls_number; ///< Block calls number
explicit BlockStatistics(profiler::timestamp_t _duration, profiler::block_index_t _block_index, profiler::block_index_t _parent_index)
: total_duration(_duration)
, median_duration(0)
, total_children_duration(0)
, min_duration_block(_block_index)
, max_duration_block(_block_index)
, parent_block(_parent_index)
, calls_number(1)
{
}
//BlockStatistics() = default;
inline profiler::timestamp_t average_duration() const
{
return total_duration / calls_number;
}
}; // END of struct BlockStatistics.
#pragma pack(pop)
extern "C" PROFILER_API void release_stats(BlockStatistics*& _stats);
//////////////////////////////////////////////////////////////////////////
class BlocksTree EASY_FINAL
{
using This = BlocksTree;
public:
using blocks_t = std::vector<This>;
using children_t = std::vector<profiler::block_index_t>;
children_t children; ///< List of children blocks. May be empty.
union {
profiler::SerializedBlock* node; ///< Pointer to serialized data for regular block (id, name, begin, end etc.)
profiler::SerializedCSwitch* cs; ///< Pointer to serialized data for context switch (thread_id, name, begin, end etc.)
profiler::ArbitraryValue* value; ///< Pointer to serialized data for arbitrary value
};
profiler::BlockStatistics* per_parent_stats; ///< Pointer to statistics for this block within the parent (may be nullptr for top-level blocks)
profiler::BlockStatistics* per_frame_stats; ///< Pointer to statistics for this block within the frame (may be nullptr for top-level blocks)
profiler::BlockStatistics* per_thread_stats; ///< Pointer to statistics for this block within the bounds of all frames per current thread
uint8_t depth; ///< Maximum number of sublevels (maximum children depth)
BlocksTree(const This&) = delete;
This& operator = (const This&) = delete;
BlocksTree() EASY_NOEXCEPT
: node(nullptr)
, per_parent_stats(nullptr)
, per_frame_stats(nullptr)
, per_thread_stats(nullptr)
, depth(0)
{
}
BlocksTree(This&& that) EASY_NOEXCEPT
: BlocksTree()
{
make_move(std::forward<This&&>(that));
}
This& operator = (This&& that) EASY_NOEXCEPT
{
make_move(std::forward<This&&>(that));
return *this;
}
~BlocksTree() EASY_NOEXCEPT
{
release_stats(per_thread_stats);
release_stats(per_parent_stats);
release_stats(per_frame_stats);
}
bool operator < (const This& other) const EASY_NOEXCEPT
{
if (node == nullptr || other.node == nullptr)
return false;
return node->begin() < other.node->begin();
}
void shrink_to_fit() EASY_NOEXCEPT
{
//for (auto& child : children)
// child.shrink_to_fit();
// shrink version 1:
//children.shrink_to_fit();
// shrink version 2:
//children_t new_children;
//new_children.reserve(children.size());
//std::move(children.begin(), children.end(), std::back_inserter(new_children));
//new_children.swap(children);
}
private:
void make_move(This&& that) EASY_NOEXCEPT
{
if (per_thread_stats != that.per_thread_stats)
release_stats(per_thread_stats);
if (per_parent_stats != that.per_parent_stats)
release_stats(per_parent_stats);
if (per_frame_stats != that.per_frame_stats)
release_stats(per_frame_stats);
children = std::move(that.children);
node = that.node;
per_parent_stats = that.per_parent_stats;
per_frame_stats = that.per_frame_stats;
per_thread_stats = that.per_thread_stats;
depth = that.depth;
that.node = nullptr;
that.per_parent_stats = nullptr;
that.per_frame_stats = nullptr;
that.per_thread_stats = nullptr;
}
}; // END of class BlocksTree.
//////////////////////////////////////////////////////////////////////////
struct Bookmark EASY_FINAL
{
EASY_STATIC_CONSTEXPR size_t BaseSize = sizeof(profiler::timestamp_t) +
sizeof(profiler::color_t) + 1;
std::string text;
profiler::timestamp_t pos;
profiler::color_t color;
};
using bookmarks_t = std::vector<Bookmark>;
//////////////////////////////////////////////////////////////////////////
class BlocksTreeRoot EASY_FINAL
{
using This = BlocksTreeRoot;
public:
BlocksTree::children_t children; ///< List of children indexes
BlocksTree::children_t sync; ///< List of context-switch events
BlocksTree::children_t events; ///< List of events indexes
std::string thread_name; ///< Name of this thread
profiler::timestamp_t profiled_time; ///< Profiled time of this thread (sum of all children duration)
profiler::timestamp_t wait_time; ///< Wait time of this thread (sum of all context switches)
profiler::thread_id_t thread_id; ///< System Id of this thread
profiler::block_index_t frames_number; ///< Total frames number (top-level blocks)
profiler::block_index_t blocks_number; ///< Total blocks number including their children
uint8_t depth; ///< Maximum stack depth (number of levels)
BlocksTreeRoot(const This&) = delete;
This& operator = (const This&) = delete;
BlocksTreeRoot() EASY_NOEXCEPT
: profiled_time(0), wait_time(0), thread_id(0), frames_number(0), blocks_number(0), depth(0)
{
}
BlocksTreeRoot(This&& that) EASY_NOEXCEPT
: children(std::move(that.children))
, sync(std::move(that.sync))
, events(std::move(that.events))
, thread_name(std::move(that.thread_name))
, profiled_time(that.profiled_time)
, wait_time(that.wait_time)
, thread_id(that.thread_id)
, frames_number(that.frames_number)
, blocks_number(that.blocks_number)
, depth(that.depth)
{
}
This& operator = (This&& that) EASY_NOEXCEPT
{
children = std::move(that.children);
sync = std::move(that.sync);
events = std::move(that.events);
thread_name = std::move(that.thread_name);
profiled_time = that.profiled_time;
wait_time = that.wait_time;
thread_id = that.thread_id;
frames_number = that.frames_number;
blocks_number = that.blocks_number;
depth = that.depth;
return *this;
}
inline bool got_name() const EASY_NOEXCEPT
{
return !thread_name.empty();
}
inline const char* name() const EASY_NOEXCEPT
{
return thread_name.c_str();
}
bool operator < (const This& other) const EASY_NOEXCEPT
{
return thread_id < other.thread_id;
}
}; // END of class BlocksTreeRoot.
struct BeginEndTime
{
profiler::timestamp_t beginTime;
profiler::timestamp_t endTime;
};
using blocks_t = profiler::BlocksTree::blocks_t;
using thread_blocks_tree_t = std::unordered_map<profiler::thread_id_t, profiler::BlocksTreeRoot, ::estd::hash<profiler::thread_id_t> >;
using block_getter_fn = std::function<const profiler::BlocksTree&(profiler::block_index_t)>;
//////////////////////////////////////////////////////////////////////////
class PROFILER_API SerializedData EASY_FINAL
{
uint64_t m_size;
char* m_data;
public:
SerializedData(const SerializedData&) = delete;
SerializedData& operator = (const SerializedData&) = delete;
SerializedData();
SerializedData(SerializedData&& that);
~SerializedData();
void set(uint64_t _size);
void extend(uint64_t _size);
SerializedData& operator = (SerializedData&& that);
char* operator [] (uint64_t i);
const char* operator [] (uint64_t i) const;
bool empty() const;
uint64_t size() const;
char* data();
const char* data() const;
void clear();
void swap(SerializedData& other);
private:
void set(char* _data, uint64_t _size);
}; // END of class SerializedData.
//////////////////////////////////////////////////////////////////////////
using descriptors_list_t = std::vector<SerializedBlockDescriptor*>;
} // END of namespace profiler.
extern "C" {
PROFILER_API profiler::block_index_t fillTreesFromFile(std::atomic<int>& progress, const char* filename,
profiler::BeginEndTime& begin_end_time,
profiler::SerializedData& serialized_blocks,
profiler::SerializedData& serialized_descriptors,
profiler::descriptors_list_t& descriptors,
profiler::blocks_t& _blocks,
profiler::thread_blocks_tree_t& threaded_trees,
profiler::bookmarks_t& bookmarks,
uint32_t& descriptors_count,
uint32_t& version,
profiler::processid_t& pid,
bool gather_statistics,
std::ostream& _log);
PROFILER_API profiler::block_index_t fillTreesFromStream(std::atomic<int>& progress, std::istream& str,
profiler::BeginEndTime& begin_end_time,
profiler::SerializedData& serialized_blocks,
profiler::SerializedData& serialized_descriptors,
profiler::descriptors_list_t& descriptors,
profiler::blocks_t& _blocks,
profiler::thread_blocks_tree_t& threaded_trees,
profiler::bookmarks_t& bookmarks,
uint32_t& descriptors_count,
uint32_t& version,
profiler::processid_t& pid,
bool gather_statistics,
std::ostream& _log);
PROFILER_API bool readDescriptionsFromStream(std::atomic<int>& progress, std::istream& str,
profiler::SerializedData& serialized_descriptors,
profiler::descriptors_list_t& descriptors,
std::ostream& _log);
}
inline profiler::block_index_t fillTreesFromFile(const char* filename, profiler::BeginEndTime& begin_end_time,
profiler::SerializedData& serialized_blocks,
profiler::SerializedData& serialized_descriptors,
profiler::descriptors_list_t& descriptors, profiler::blocks_t& _blocks,
profiler::thread_blocks_tree_t& threaded_trees,
profiler::bookmarks_t& bookmarks,
uint32_t& descriptors_count,
uint32_t& version,
profiler::processid_t& pid,
bool gather_statistics,
std::ostream& _log)
{
std::atomic<int> progress(0);
return fillTreesFromFile(progress, filename, begin_end_time, serialized_blocks, serialized_descriptors,
descriptors, _blocks, threaded_trees, bookmarks, descriptors_count, version, pid,
gather_statistics, _log);
}
inline bool readDescriptionsFromStream(std::istream& str,
profiler::SerializedData& serialized_descriptors,
profiler::descriptors_list_t& descriptors,
std::ostream& _log)
{
std::atomic<int> progress(0);
return readDescriptionsFromStream(progress, str, serialized_descriptors, descriptors, _log);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER_READER_H

View File

@ -0,0 +1,293 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_SERIALIZED_BLOCK_H
#define EASY_PROFILER_SERIALIZED_BLOCK_H
#include <easy/details/profiler_public_types.h>
#include <easy/details/arbitrary_value_public_types.h>
class CSwitchBlock;
namespace profiler {
template <DataType dataType, bool isArray>
struct Value;
template <bool isArray>
struct Value<DataType::TypesCount, isArray>;
//////////////////////////////////////////////////////////////////////////
class PROFILER_API SerializedBlock EASY_FINAL : public BaseBlockData
{
friend ::ProfileManager;
friend ::ThreadStorage;
public:
inline const char* data() const { return reinterpret_cast<const char*>(this); }
///< Run-time block name is stored right after main BaseBlockData data
inline const char* name() const { return data() + sizeof(BaseBlockData); }
SerializedBlock(const SerializedBlock&) = delete;
SerializedBlock& operator = (const SerializedBlock&) = delete;
SerializedBlock(SerializedBlock&&) = delete;
SerializedBlock& operator = (SerializedBlock&&) = delete;
~SerializedBlock() = delete;
private:
explicit SerializedBlock(const Block& block, uint16_t name_length);
}; // END of SerializedBlock.
//////////////////////////////////////////////////////////////////////////
#pragma pack(push, 1)
class PROFILER_API CSwitchEvent : public Event
{
thread_id_t m_thread_id;
public:
CSwitchEvent() = default;
CSwitchEvent(const CSwitchEvent&) = default;
explicit CSwitchEvent(timestamp_t _begin_time, thread_id_t _tid) EASY_NOEXCEPT;
inline thread_id_t tid() const EASY_NOEXCEPT { return m_thread_id; }
}; // END of class CSwitchEvent.
#pragma pack(pop)
class PROFILER_API SerializedCSwitch EASY_FINAL : public CSwitchEvent
{
friend ::ProfileManager;
friend ::ThreadStorage;
public:
inline const char* data() const { return reinterpret_cast<const char*>(this); }
///< Run-time block name is stored right after main CSwitchEvent data
inline const char* name() const { return data() + sizeof(CSwitchEvent); }
SerializedCSwitch(const SerializedCSwitch&) = delete;
SerializedCSwitch& operator = (const SerializedCSwitch&) = delete;
SerializedCSwitch(SerializedCSwitch&&) = delete;
SerializedCSwitch& operator = (SerializedCSwitch&&) = delete;
~SerializedCSwitch() = delete;
private:
explicit SerializedCSwitch(const CSwitchBlock& block, uint16_t name_length);
}; // END of SerializedCSwitch.
//////////////////////////////////////////////////////////////////////////
#pragma pack(push, 1)
class PROFILER_API SerializedBlockDescriptor EASY_FINAL : public BaseBlockDescriptor
{
uint16_t m_nameLength; ///< Length of the name including trailing '\0' sybmol
public:
inline const char* data() const {
return reinterpret_cast<const char*>(this);
}
///< Name is stored right after m_nameLength
inline const char* name() const {
static const auto shift = sizeof(BaseBlockDescriptor) + sizeof(decltype(m_nameLength));
return data() + shift;
}
///< File name is stored right after the name
inline const char* file() const {
return name() + m_nameLength;
}
inline void setStatus(EasyBlockStatus _status) EASY_NOEXCEPT {
m_status = _status;
}
// Instances of this class can not be created or destroyed directly
SerializedBlockDescriptor() = delete;
SerializedBlockDescriptor(const SerializedBlockDescriptor&) = delete;
SerializedBlockDescriptor& operator = (const SerializedBlockDescriptor&) = delete;
SerializedBlockDescriptor(SerializedBlockDescriptor&&) = delete;
SerializedBlockDescriptor& operator = (SerializedBlockDescriptor&&) = delete;
~SerializedBlockDescriptor() = delete;
}; // END of SerializedBlockDescriptor.
//#pragma pack(pop)
//////////////////////////////////////////////////////////////////////////
//#pragma pack(push, 1)
class PROFILER_API ArbitraryValue : protected BaseBlockData
{
friend ::ThreadStorage;
protected:
char m_nameStub; ///< Artificial padding which is used to imitate SerializedBlock::name() == 0 behavior
char m_padding; ///< Padding to the bound of 2 bytes
uint16_t m_size;
DataType m_type;
bool m_isArray;
vin_t m_value_id;
explicit ArbitraryValue(timestamp_t _timestamp, vin_t _vin, block_id_t _id,
uint16_t _size, DataType _type, bool _isArray)
: BaseBlockData(_timestamp, _timestamp, _id)
, m_nameStub(0)
, m_padding(0)
, m_size(_size)
, m_type(_type)
, m_isArray(_isArray)
, m_value_id(_vin)
{
}
public:
using BaseBlockData::id;
using Event::begin;
~ArbitraryValue() = delete;
const char* data() const {
return reinterpret_cast<const char*>(this) + sizeof(ArbitraryValue);
}
uint16_t data_size() const {
return m_size;
}
vin_t value_id() const {
return m_value_id;
}
DataType type() const {
return m_type;
}
bool isArray() const {
return m_isArray;
}
template <DataType dataType>
const Value<dataType, false>* toValue() const {
return m_type == dataType ? static_cast<const Value<dataType, false>*>(this) : nullptr;
}
template <class T>
const Value<StdToDataType<T>::data_type, false>* toValue() const {
static_assert(StdToDataType<T>::data_type != DataType::TypesCount,
"You should use standard builtin scalar types as profiler::Value type!");
return toValue<StdToDataType<T>::data_type>();
}
template <DataType dataType>
const Value<dataType, true>* toArray() const {
return m_isArray && m_type == dataType ? static_cast<const Value<dataType, true>*>(this) : nullptr;
}
template <class T>
const Value<StdToDataType<T>::data_type, true>* toArray() const {
static_assert(StdToDataType<T>::data_type != DataType::TypesCount,
"You should use standard builtin scalar types as profiler::Value type!");
return toArray<StdToDataType<T>::data_type>();
}
}; // end of class ArbitraryValue.
#pragma pack(pop)
//////////////////////////////////////////////////////////////////////////
template <DataType dataType>
struct Value<dataType, false> EASY_FINAL : public ArbitraryValue {
using value_type = typename StdType<dataType>::value_type;
value_type value() const { return *reinterpret_cast<const value_type*>(data()); }
~Value() = delete;
};
template <DataType dataType>
struct Value<dataType, true> EASY_FINAL : public ArbitraryValue {
using value_type = typename StdType<dataType>::value_type;
const value_type* value() const { return reinterpret_cast<const value_type*>(data()); }
uint16_t size() const { return m_size / sizeof(value_type); }
value_type operator [] (int i) const { return value()[i]; }
value_type at(int i) const { return value()[i]; }
~Value() = delete;
};
template <>
struct Value<DataType::String, true> EASY_FINAL : public ArbitraryValue {
using value_type = char;
const char* value() const { return data(); }
uint16_t size() const { return m_size; }
char operator [] (int i) const { return data()[i]; }
char at(int i) const { return data()[i]; }
const char* c_str() const { return data(); }
~Value() = delete;
};
//////////////////////////////////////////////////////////////////////////
template <DataType dataType>
using SingleValue = Value<dataType, false>;
template <DataType dataType>
using ArrayValue = Value<dataType, true>;
using StringValue = Value<DataType::String, true>;
//////////////////////////////////////////////////////////////////////////
} // END of namespace profiler.
#endif // EASY_PROFILER_SERIALIZED_BLOCK_H

View File

@ -0,0 +1,69 @@
#ifndef EASY_PROFILER_UTILITY_H
#define EASY_PROFILER_UTILITY_H
#include <easy/details/easy_compiler_support.h>
#include <algorithm>
#include <utility>
#include <math.h>
namespace estd {
//////////////////////////////////////////////////////////////////////////
namespace detail {
template <class T, bool BiggerThanPtr> struct hasher {
using type = const T&;
EASY_FORCE_INLINE size_t operator () (type value) const { return ::std::hash<T> {}(value); } };
template <class T> struct hasher<T, false> {
using type = T;
EASY_FORCE_INLINE size_t operator () (type value) const { return static_cast<size_t>(value); } };
}
template <class T> struct hash EASY_FINAL : public ::estd::detail::hasher<T, (sizeof(T) > sizeof(void*))> {
using Parent = ::estd::detail::hasher<T, (sizeof(T) > sizeof(void*))>;
#if defined(_MSC_VER) && _MSC_VER >= 1910
// TODO: Try to compile "using Parent::operator();" in MSVC 2017
size_t operator () (typename Parent::type value) const { return Parent::operator () (value); }
#else
using Parent::operator();
#endif
};
template <class T> struct hash<T*> EASY_FINAL {
EASY_FORCE_INLINE size_t operator () (const T* value) const { return reinterpret_cast<size_t>(value); } };
template <class T> struct hash<const T*> EASY_FINAL {
EASY_FORCE_INLINE size_t operator () (const T* value) const { return reinterpret_cast<size_t>(value); } };
//////////////////////////////////////////////////////////////////////////
template <class T, class Q, class W>
inline EASY_CONSTEXPR_FCN Q clamp(T min_value, Q value, W max_value) {
return static_cast<Q>(min_value < value ? (value < max_value ? value : max_value) : min_value);
}
template <class T>
EASY_FORCE_INLINE EASY_CONSTEXPR_FCN T sqr(T value) {
return value * value;
}
template <class T>
EASY_FORCE_INLINE EASY_CONSTEXPR_FCN int sign(T value) { return value < 0 ? -1 : 1; }
template <class T>
inline EASY_CONSTEXPR_FCN T absmin(T a, T b) { return abs(a) < abs(b) ? a : b; }
template <int N, class T>
inline T logn(T value) {
EASY_STATIC_CONSTEXPR double div = 1.0 / log2((double)N);
return log2(value) * div;
}
//////////////////////////////////////////////////////////////////////////
} // end of namespace estd.
#endif // EASY_PROFILER_UTILITY_H

View File

@ -0,0 +1,109 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_WRITER_H
#define EASY_PROFILER_WRITER_H
#include <easy/reader.h>
extern "C" {
PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic<int>& progress, const char* filename,
const profiler::SerializedData& serialized_descriptors,
const profiler::descriptors_list_t& descriptors,
profiler::block_id_t descriptors_count,
const profiler::thread_blocks_tree_t& trees,
const profiler::bookmarks_t& bookmarks,
profiler::block_getter_fn block_getter,
profiler::timestamp_t begin_time,
profiler::timestamp_t end_time,
profiler::processid_t pid,
std::ostream& log);
PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<int>& progress, std::ostream& str,
const profiler::SerializedData& serialized_descriptors,
const profiler::descriptors_list_t& descriptors,
profiler::block_id_t descriptors_count,
const profiler::thread_blocks_tree_t& trees,
const profiler::bookmarks_t& bookmarks,
profiler::block_getter_fn block_getter,
profiler::timestamp_t begin_time,
profiler::timestamp_t end_time,
profiler::processid_t pid,
std::ostream& log);
}
inline profiler::block_index_t writeTreesToFile(const char* filename,
const profiler::SerializedData& serialized_descriptors,
const profiler::descriptors_list_t& descriptors,
profiler::block_id_t descriptors_count,
const profiler::thread_blocks_tree_t& trees,
const profiler::bookmarks_t& bookmarks,
profiler::block_getter_fn block_getter,
profiler::timestamp_t begin_time,
profiler::timestamp_t end_time,
profiler::processid_t pid,
std::ostream& log)
{
std::atomic<int> progress(0);
return writeTreesToFile(progress, filename, serialized_descriptors, descriptors, descriptors_count, trees,
bookmarks, std::move(block_getter), begin_time, end_time, pid, log);
}
inline profiler::block_index_t writeTreesToStream(std::ostream& str,
const profiler::SerializedData& serialized_descriptors,
const profiler::descriptors_list_t& descriptors,
profiler::block_id_t descriptors_count,
const profiler::thread_blocks_tree_t& trees,
const profiler::bookmarks_t& bookmarks,
profiler::block_getter_fn block_getter,
profiler::timestamp_t begin_time,
profiler::timestamp_t end_time,
profiler::processid_t pid,
std::ostream& log)
{
std::atomic<int> progress(0);
return writeTreesToStream(progress, str, serialized_descriptors, descriptors, descriptors_count, trees,
bookmarks, std::move(block_getter), begin_time, end_time, pid, log);
}
#endif //EASY_PROFILER_WRITER_H

View File

@ -0,0 +1,274 @@
/************************************************
* creation time : 2017/08/20
* author : Blake Martin
* email : rationalcoder@gmail.com
************************************************/
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_ALIGNMENT_HELPERS_H
#define EASY_PROFILER_ALIGNMENT_HELPERS_H
#include <cstddef>
#include <cstdint>
#include <easy/details/easy_compiler_support.h>
//! Checks if a pointer is aligned.
//! \param ptr The pointer to check.
//! \param alignment The alignement (must be a power of 2)
//! \returns true if the memory is aligned.
//!
template <uint32_t ALIGNMENT>
EASY_FORCE_INLINE bool is_aligned(void* ptr)
{
static_assert((ALIGNMENT & 1) == 0, "Alignment must be a power of two.");
return ((uintptr_t)ptr & (ALIGNMENT-1)) == 0;
}
EASY_FORCE_INLINE void unaligned_zero16(void* ptr)
{
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
*(uint16_t*)ptr = 0;
#else
((char*)ptr)[0] = 0;
((char*)ptr)[1] = 0;
#endif
}
EASY_FORCE_INLINE void unaligned_zero32(void* ptr)
{
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
*(uint32_t*)ptr = 0;
#else
((char*)ptr)[0] = 0;
((char*)ptr)[1] = 0;
((char*)ptr)[2] = 0;
((char*)ptr)[3] = 0;
#endif
}
EASY_FORCE_INLINE void unaligned_zero64(void* ptr)
{
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
// Assume unaligned is more common.
if (!is_aligned<alignof(uint64_t)>(ptr)) {
((char*)ptr)[0] = 0;
((char*)ptr)[1] = 0;
((char*)ptr)[2] = 0;
((char*)ptr)[3] = 0;
((char*)ptr)[4] = 0;
((char*)ptr)[5] = 0;
((char*)ptr)[6] = 0;
((char*)ptr)[7] = 0;
}
else
#endif
*(uint64_t*)ptr = 0;
}
template <typename T>
EASY_FORCE_INLINE void unaligned_store16(void* ptr, T val)
{
static_assert(sizeof(T) == 2, "16 bit type required.");
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
*(T*)ptr = val;
#else
const char* const temp = (const char*)&val;
((char*)ptr)[0] = temp[0];
((char*)ptr)[1] = temp[1];
#endif
}
template <typename T>
EASY_FORCE_INLINE void unaligned_store32(void* ptr, T val)
{
static_assert(sizeof(T) == 4, "32 bit type required.");
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
*(T*)ptr = val;
#else
const char* const temp = (const char*)&val;
((char*)ptr)[0] = temp[0];
((char*)ptr)[1] = temp[1];
((char*)ptr)[2] = temp[2];
((char*)ptr)[3] = temp[3];
#endif
}
template <typename T>
EASY_FORCE_INLINE void unaligned_store64(void* ptr, T val)
{
static_assert(sizeof(T) == 8, "64 bit type required.");
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
// Assume unaligned is more common.
if (!is_aligned<alignof(T)>(ptr)) {
const char* const temp = (const char*)&val;
((char*)ptr)[0] = temp[0];
((char*)ptr)[1] = temp[1];
((char*)ptr)[2] = temp[2];
((char*)ptr)[3] = temp[3];
((char*)ptr)[4] = temp[4];
((char*)ptr)[5] = temp[5];
((char*)ptr)[6] = temp[6];
((char*)ptr)[7] = temp[7];
}
else
#endif
*(T*)ptr = val;
}
template <typename T>
EASY_FORCE_INLINE T unaligned_load16(const void* ptr)
{
static_assert(sizeof(T) == 2, "16 bit type required.");
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
return *(const T*)ptr;
#else
T value;
((char*)&value)[0] = ((const char*)ptr)[0];
((char*)&value)[1] = ((const char*)ptr)[1];
return value;
#endif
}
template <typename T>
EASY_FORCE_INLINE T unaligned_load16(const void* ptr, T* val)
{
static_assert(sizeof(T) == 2, "16 bit type required.");
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
*val = *(const T*)ptr;
#else
((char*)val)[0] = ((const char*)ptr)[0];
((char*)val)[1] = ((const char*)ptr)[1];
#endif
return *val;
}
template <typename T>
EASY_FORCE_INLINE T unaligned_load32(const void* ptr)
{
static_assert(sizeof(T) == 4, "32 bit type required.");
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
return *(const T*)ptr;
#else
T value;
((char*)&value)[0] = ((const char*)ptr)[0];
((char*)&value)[1] = ((const char*)ptr)[1];
((char*)&value)[2] = ((const char*)ptr)[2];
((char*)&value)[3] = ((const char*)ptr)[3];
return value;
#endif
}
template <typename T>
EASY_FORCE_INLINE T unaligned_load32(const void* ptr, T* val)
{
static_assert(sizeof(T) == 4, "32 bit type required.");
#ifndef EASY_ENABLE_STRICT_ALIGNMENT
*val = *(const T*)ptr;
#else
((char*)&val)[0] = ((const char*)ptr)[0];
((char*)&val)[1] = ((const char*)ptr)[1];
((char*)&val)[2] = ((const char*)ptr)[2];
((char*)&val)[3] = ((const char*)ptr)[3];
#endif
return *val;
}
template <typename T>
EASY_FORCE_INLINE T unaligned_load64(const void* ptr)
{
static_assert(sizeof(T) == 8, "64 bit type required.");
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
if (!is_aligned<alignof(T)>(ptr)) {
T value;
((char*)&value)[0] = ((const char*)ptr)[0];
((char*)&value)[1] = ((const char*)ptr)[1];
((char*)&value)[2] = ((const char*)ptr)[2];
((char*)&value)[3] = ((const char*)ptr)[3];
((char*)&value)[4] = ((const char*)ptr)[4];
((char*)&value)[5] = ((const char*)ptr)[5];
((char*)&value)[6] = ((const char*)ptr)[6];
((char*)&value)[7] = ((const char*)ptr)[7];
return value;
}
#endif
return *(const T*)ptr;
}
template <typename T>
EASY_FORCE_INLINE T unaligned_load64(const void* ptr, T* val)
{
static_assert(sizeof(T) == 8, "64 bit type required.");
#ifdef EASY_ENABLE_STRICT_ALIGNMENT
if (!is_aligned<alignof(T)>(ptr)) {
((char*)&val)[0] = ((const char*)ptr)[0];
((char*)&val)[1] = ((const char*)ptr)[1];
((char*)&val)[2] = ((const char*)ptr)[2];
((char*)&val)[3] = ((const char*)ptr)[3];
((char*)&val)[4] = ((const char*)ptr)[4];
((char*)&val)[5] = ((const char*)ptr)[5];
((char*)&val)[6] = ((const char*)ptr)[6];
((char*)&val)[7] = ((const char*)ptr)[7];
}
else
#endif
*val = *(const T*)ptr;
return *val;
}
#endif //EASY_PROFILER_ALIGNMENT_HELPERS_H

View File

@ -0,0 +1,59 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#include <easy/details/profiler_public_types.h>
namespace profiler
{
BaseBlockDescriptor::BaseBlockDescriptor(block_id_t _id, EasyBlockStatus _status, int _line,
block_type_t _block_type, color_t _color) EASY_NOEXCEPT
: m_id(_id)
, m_line(_line)
, m_type(_block_type)
, m_color(_color)
, m_status(_status)
{
}
} // end of namespace profiler.

View File

@ -0,0 +1,243 @@
/************************************************************************
* file name : block.cpp
* ----------------- :
* creation time : 2016/02/16
* authors : Sergey Yagovtsev, Victor Zarubkin
* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of profiling blocks
* :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
* :
* : Licensed under either of
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* : at your option.
* :
* : 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.
* :
* : The Apache License, Version 2.0 (the "License")
* :
* : You may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
************************************************************************/
#include <easy/profiler.h>
#include "profile_manager.h"
#include "current_time.h"
namespace profiler {
#ifndef EASY_PROFILER_API_DISABLED
Event::Event(timestamp_t _begin_time) EASY_NOEXCEPT : m_begin(_begin_time), m_end(0)
{
}
Event::Event(timestamp_t _begin_time, timestamp_t _end_time) EASY_NOEXCEPT : m_begin(_begin_time), m_end(_end_time)
{
}
BaseBlockData::BaseBlockData(timestamp_t _begin_time, block_id_t _descriptor_id) EASY_NOEXCEPT
: Event(_begin_time)
, m_id(_descriptor_id)
{
}
BaseBlockData::BaseBlockData(timestamp_t _begin_time, timestamp_t _end_time, block_id_t _descriptor_id) EASY_NOEXCEPT
: Event(_begin_time, _end_time)
, m_id(_descriptor_id)
{
}
Block::Block(Block&& that) EASY_NOEXCEPT
: BaseBlockData(that.m_begin, that.m_id)
, m_name(that.m_name)
, m_status(that.m_status)
, m_isScoped(that.m_isScoped)
{
m_end = that.m_end;
that.m_end = that.m_begin;
}
Block::Block(timestamp_t _begin_time, block_id_t _descriptor_id, const char* _runtimeName) EASY_NOEXCEPT
: BaseBlockData(_begin_time, _descriptor_id)
, m_name(_runtimeName)
, m_status(::profiler::ON)
, m_isScoped(true)
{
}
Block::Block(timestamp_t _begin_time, timestamp_t _end_time, block_id_t _descriptor_id, const char* _runtimeName) EASY_NOEXCEPT
: BaseBlockData(_begin_time, _end_time, _descriptor_id)
, m_name(_runtimeName)
, m_status(::profiler::ON)
, m_isScoped(true)
{
}
Block::Block(const BaseBlockDescriptor* _descriptor, const char* _runtimeName, bool _scoped) EASY_NOEXCEPT
: BaseBlockData(1ULL, _descriptor->id())
, m_name(_runtimeName)
, m_status(_descriptor->status())
, m_isScoped(_scoped)
{
}
void Block::start()
{
m_begin = profiler::clock::now();
}
void Block::start(timestamp_t _time) EASY_NOEXCEPT
{
m_begin = _time;
}
void Block::finish()
{
m_end = profiler::clock::now();
}
void Block::finish(timestamp_t _time) EASY_NOEXCEPT
{
m_end = _time;
}
Block::~Block()
{
if (!finished())
::profiler::endBlock();
}
#else
Event::Event(timestamp_t) EASY_NOEXCEPT : m_begin(0), m_end(0)
{
}
Event::Event(timestamp_t, timestamp_t) EASY_NOEXCEPT : m_begin(0), m_end(0)
{
}
BaseBlockData::BaseBlockData(timestamp_t, block_id_t) EASY_NOEXCEPT
: Event(0, 0)
, m_id(~0U)
{
}
BaseBlockData::BaseBlockData(timestamp_t, timestamp_t, block_id_t) EASY_NOEXCEPT
: Event(0, 0)
, m_id(~0U)
{
}
Block::Block(Block&& that) EASY_NOEXCEPT
: BaseBlockData(0, ~0U)
, m_name("")
, m_status(::profiler::OFF)
, m_isScoped(that.m_isScoped)
{
}
Block::Block(timestamp_t, block_id_t, const char*) EASY_NOEXCEPT
: BaseBlockData(0, ~0U)
, m_name("")
, m_status(::profiler::OFF)
, m_isScoped(true)
{
}
Block::Block(timestamp_t, timestamp_t, block_id_t, const char*) EASY_NOEXCEPT
: BaseBlockData(0, ~0U)
, m_name("")
, m_status(::profiler::OFF)
, m_isScoped(true)
{
}
Block::Block(const BaseBlockDescriptor*, const char*, bool _scoped) EASY_NOEXCEPT
: BaseBlockData(0, ~0U)
, m_name("")
, m_status(::profiler::OFF)
, m_isScoped(_scoped)
{
}
void Block::start()
{
}
void Block::start(timestamp_t) EASY_NOEXCEPT
{
}
void Block::finish()
{
}
void Block::finish(timestamp_t) EASY_NOEXCEPT
{
}
Block::~Block()
{
}
#endif
//////////////////////////////////////////////////////////////////////////
CSwitchEvent::CSwitchEvent(timestamp_t _begin_time, thread_id_t _tid) EASY_NOEXCEPT
: Event(_begin_time)
, m_thread_id(_tid)
{
}
} // END of namespace profiler.
CSwitchBlock::CSwitchBlock(profiler::timestamp_t _begin_time, profiler::thread_id_t _tid, const char* _runtimeName) EASY_NOEXCEPT
: profiler::CSwitchEvent(_begin_time, _tid)
, m_name(_runtimeName)
{
}
//////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,92 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#include <memory.h>
#include "block_descriptor.h"
#if EASY_BLOCK_DESC_FULL_COPY == 0
# define EASY_BLOCK_DESC_STRING_LEN(s) static_cast<uint16_t>(strlen(s) + 1)
# define EASY_BLOCK_DESC_STRING_VAL(s) s
#else
# define EASY_BLOCK_DESC_STRING_LEN(s) static_cast<uint16_t>(s.size() + 1)
# define EASY_BLOCK_DESC_STRING_VAL(s) s.c_str()
#endif
BlockDescriptor::BlockDescriptor(profiler::block_id_t _id, profiler::EasyBlockStatus _status, const char* _name,
const char* _filename, int _line, profiler::block_type_t _block_type,
profiler::color_t _color)
: Parent(_id, _status, _line, _block_type, _color)
, m_filename(_filename)
, m_name(_name)
{
}
const char* BlockDescriptor::name() const
{
return EASY_BLOCK_DESC_STRING_VAL(m_name);
}
const char* BlockDescriptor::filename() const
{
return EASY_BLOCK_DESC_STRING_VAL(m_filename);
}
uint16_t BlockDescriptor::nameSize() const
{
return EASY_BLOCK_DESC_STRING_LEN(m_name);
}
uint16_t BlockDescriptor::filenameSize() const
{
return EASY_BLOCK_DESC_STRING_LEN(m_filename);
}
void BlockDescriptor::destroy(BlockDescriptor* instance)
{
#if EASY_BLOCK_DESC_FULL_COPY == 0
if (instance != nullptr)
instance->~BlockDescriptor();
free(instance);
#else
delete instance;
#endif
}

View File

@ -0,0 +1,86 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_BLOCK_DESCRIPTOR_H
#define EASY_PROFILER_BLOCK_DESCRIPTOR_H
#include <string>
#include <easy/details/profiler_public_types.h>
#ifndef EASY_BLOCK_DESC_FULL_COPY
# define EASY_BLOCK_DESC_FULL_COPY 1
#endif
class BlockDescriptor : public profiler::BaseBlockDescriptor
{
friend ProfileManager;
using Parent = profiler::BaseBlockDescriptor;
#if EASY_BLOCK_DESC_FULL_COPY == 0
using string_t = const char*;
#else
using string_t = std::string;
#endif
string_t m_filename; ///< Source file name where this block is declared
string_t m_name; ///< Static name of all blocks of the same type (blocks can have dynamic name) which is, in pair with descriptor id, a unique block identifier
public:
BlockDescriptor() = delete;
BlockDescriptor(const BlockDescriptor&) = delete;
BlockDescriptor& operator = (const BlockDescriptor&) = delete;
BlockDescriptor(profiler::block_id_t _id, profiler::EasyBlockStatus _status, const char* _name,
const char* _filename, int _line, profiler::block_type_t _block_type, profiler::color_t _color);
const char* name() const;
const char* filename() const;
uint16_t nameSize() const;
uint16_t filenameSize() const;
static void destroy(BlockDescriptor* instance);
}; // END of class BlockDescriptor.
#endif //EASY_PROFILER_BLOCK_DESCRIPTOR_H

View File

@ -0,0 +1,414 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_CHUNK_ALLOCATOR_H
#define EASY_PROFILER_CHUNK_ALLOCATOR_H
#include <easy/details/easy_compiler_support.h>
#include <cstring>
#include <ostream>
#include "alignment_helpers.h"
//////////////////////////////////////////////////////////////////////////
#ifndef EASY_ENABLE_ALIGNMENT
# define EASY_ENABLE_ALIGNMENT 0
#endif
#ifndef EASY_ALIGNMENT_SIZE
# define EASY_ALIGNMENT_SIZE EASY_ALIGNOF(std::max_align_t)
#endif
EASY_CONSTEXPR auto EASY_ALIGN_SIZE = EASY_ALIGNMENT_SIZE;
#if EASY_ENABLE_ALIGNMENT == 0
# define EASY_ALIGNED(TYPE, VAR, A) TYPE VAR
# define EASY_MALLOC(MEMSIZE, A) malloc(MEMSIZE)
# define EASY_FREE(MEMPTR) free(MEMPTR)
#else
// MSVC and GNUC aligned versions of malloc are defined in malloc.h
# include <malloc.h>
# if defined(_MSC_VER)
# define EASY_ALIGNED(TYPE, VAR, A) __declspec(align(A)) TYPE VAR
# define EASY_MALLOC(MEMSIZE, A) _aligned_malloc(MEMSIZE, A)
# define EASY_FREE(MEMPTR) _aligned_free(MEMPTR)
# elif defined(__GNUC__)
# define EASY_ALIGNED(TYPE, VAR, A) TYPE VAR __attribute__((aligned(A)))
# define EASY_MALLOC(MEMSIZE, A) memalign(A, MEMSIZE)
# define EASY_FREE(MEMPTR) free(MEMPTR)
# else
# define EASY_ALIGNED(TYPE, VAR, A) TYPE VAR
# define EASY_MALLOC(MEMSIZE, A) malloc(MEMSIZE)
# define EASY_FREE(MEMPTR) free(MEMPTR)
# endif
#endif
//////////////////////////////////////////////////////////////////////////
template <const uint16_t N>
class chunk_allocator
{
static_assert(N != 0, "chunk_allocator<N> N must be a positive value");
struct chunk { EASY_ALIGNED(char, data[N], EASY_ALIGNMENT_SIZE); chunk* prev = nullptr; };
struct chunk_list
{
chunk* last;
chunk_list(const chunk_list&) = delete;
chunk_list(chunk_list&&) = delete;
chunk_list() : last(nullptr)
{
static_assert(sizeof(char) == 1, "easy_profiler logic error: sizeof(char) != 1 for this platform! Please, contact easy_profiler authors to resolve your problem.");
emplace_back();
}
~chunk_list()
{
do free_last(); while (last != nullptr);
}
void clear_all_except_last()
{
while (last->prev != nullptr)
free_last();
zero_last_chunk_size();
}
void emplace_back()
{
auto prev = last;
last = ::new (EASY_MALLOC(sizeof(chunk), EASY_ALIGNMENT_SIZE)) chunk();
last->prev = prev;
zero_last_chunk_size();
}
/** Invert current chunks list to enable to iterate over chunks list in direct order.
This method is used by serialize().
*/
void invert()
{
chunk* next = nullptr;
while (last->prev != nullptr) {
auto p = last->prev;
last->prev = next;
next = last;
last = p;
}
last->prev = next;
}
private:
void free_last()
{
auto p = last;
last = last->prev;
EASY_FREE(p);
}
void zero_last_chunk_size()
{
// Although there is no need for unaligned access stuff b/c a new chunk will
// usually be at least 8 byte aligned (and we only need 2 byte alignment),
// this is the only way I have been able to get rid of the GCC strict-aliasing warning
// without using std::memset. It's an extra line, but is just as fast as *(uint16_t*)last->data = 0;
char* const data = last->data;
*(uint16_t*)data = (uint16_t)0;
}
};
// Used in serialize(): workaround for no constexpr support in MSVC 2013.
EASY_STATIC_CONSTEXPR int_fast32_t MaxChunkOffset = N - sizeof(uint16_t);
EASY_STATIC_CONSTEXPR uint16_t OneBeforeN = static_cast<uint16_t>(N - 1);
chunk_list m_chunks; ///< List of chunks.
chunk* m_markedChunk; ///< Chunk marked by last closed frame
uint32_t m_size; ///< Number of elements stored(# of times allocate() has been called.)
uint32_t m_markedSize; ///< Number of elements to the moment when put_mark() has been called.
uint16_t m_chunkOffset; ///< Number of bytes used in the current chunk.
uint16_t m_markedChunkOffset; ///< Last byte in marked chunk for serializing.
public:
chunk_allocator(const chunk_allocator&) = delete;
chunk_allocator(chunk_allocator&&) = delete;
chunk_allocator() : m_markedChunk(nullptr), m_size(0), m_markedSize(0), m_chunkOffset(0), m_markedChunkOffset(0)
{
}
/** Allocate n bytes.
Automatically checks if there is enough preserved memory to store additional n bytes
and allocates additional buffer if needed.
*/
void* allocate(uint16_t n)
{
++m_size;
if (!need_expand(n))
{
// Temp to avoid extra load due to this* aliasing.
uint16_t chunkOffset = m_chunkOffset;
char* data = m_chunks.last->data + chunkOffset;
chunkOffset += n + sizeof(uint16_t);
m_chunkOffset = chunkOffset;
unaligned_store16(data, n);
data += sizeof(uint16_t);
// If there is enough space for at least another payload size,
// set it to zero.
if (chunkOffset < OneBeforeN)
unaligned_zero16(data + n);
return data;
}
m_chunkOffset = n + sizeof(uint16_t);
m_chunks.emplace_back();
char* data = m_chunks.last->data;
unaligned_store16(data, n);
data += sizeof(uint16_t);
// We assume here that it takes more than one element to fill a chunk.
unaligned_zero16(data + n);
return data;
}
/** Check if current storage is not enough to store additional n bytes.
*/
bool need_expand(uint16_t n) const
{
return (m_chunkOffset + n + sizeof(uint16_t)) > N;
}
uint32_t size() const
{
return m_size;
}
bool empty() const
{
return m_size == 0;
}
uint32_t markedSize() const
{
return m_markedSize;
}
bool markedEmpty() const
{
return m_markedSize == 0;
}
void clear()
{
m_size = 0;
m_markedSize = 0;
m_chunkOffset = 0;
m_markedChunk = nullptr;
m_chunks.clear_all_except_last(); // There is always at least one chunk
}
/** Serialize data to stream.
\warning Data will be cleared after serialization.
*/
void serialize(std::ostream& _outputStream)
{
// Chunks are stored in reversed order (stack).
// To be able to iterate them in direct order we have to invert the chunks list.
m_chunks.invert();
// Each chunk is an array of N bytes that can hold between
// 1(if the list isn't empty) and however many elements can fit in a chunk,
// where an element consists of a payload size + a payload as follows:
// elementStart[0..1]: size as a uint16_t
// elementStart[2..size-1]: payload.
// The maximum chunk offset is N-sizeof(uint16_t) b/c, if we hit that (or go past),
// there is either no space left, 1 byte left, or 2 bytes left, all of which are
// too small to cary more than a zero-sized element.
chunk* current = m_chunks.last;
bool isMarked;
do {
isMarked = (current == m_markedChunk);
const char* data = current->data;
const int_fast32_t maxOffset = isMarked ? m_markedChunkOffset : MaxChunkOffset;
int_fast32_t chunkOffset = 0; // signed int so overflow is not checked.
auto payloadSize = unaligned_load16<uint16_t>(data);
while (chunkOffset < maxOffset && payloadSize != 0)
{
const uint16_t chunkSize = sizeof(uint16_t) + payloadSize;
_outputStream.write(data, chunkSize);
data += chunkSize;
chunkOffset += chunkSize;
unaligned_load16(data, &payloadSize);
}
current = current->prev;
} while (current != nullptr && !isMarked);
clear();
}
void put_mark()
{
m_markedChunk = m_chunks.last;
m_markedSize = m_size;
m_markedChunkOffset = m_chunkOffset;
}
void* marked_allocate(uint16_t n)
{
chunk* marked = m_markedChunk;
if (marked == nullptr || (marked == m_chunks.last && m_markedSize == m_size))
{
auto data = allocate(n);
put_mark();
return data;
}
++m_markedSize;
uint16_t chunkOffset = m_markedChunkOffset;
if ((chunkOffset + n + sizeof(uint16_t)) <= N)
{
// Temp to avoid extra load due to this* aliasing.
char* data = marked->data + chunkOffset;
chunkOffset += n + sizeof(uint16_t);
m_markedChunkOffset = chunkOffset;
unaligned_store16(data, n);
data += sizeof(uint16_t);
// If there is enough space for at least another payload size,
// set it to zero.
if (chunkOffset < OneBeforeN)
unaligned_zero16(data + n);
if (marked == m_chunks.last && chunkOffset > m_chunkOffset)
m_chunkOffset = chunkOffset;
return data;
}
chunkOffset = n + sizeof(uint16_t);
m_markedChunkOffset = chunkOffset;
chunk* last = m_chunks.last;
if (marked == last)
{
m_chunks.emplace_back();
last = m_chunks.last;
m_chunkOffset = chunkOffset;
m_size = m_markedSize;
}
else
{
do last = last->prev; while (last->prev != m_markedChunk);
}
m_markedChunk = last;
char* data = last->data;
unaligned_store16(data, n);
data += sizeof(uint16_t);
// We assume here that it takes more than one element to fill a chunk.
unaligned_zero16(data + n);
return data;
}
}; // END of class chunk_allocator.
//////////////////////////////////////////////////////////////////////////
template <const uint16_t N, bool, bool>
struct aligned_size;
template <const uint16_t N, bool dummy>
struct aligned_size<N, true, dummy> {
EASY_STATIC_CONSTEXPR uint16_t Size = N;
};
template <const uint16_t N>
struct aligned_size<N, false, true> {
EASY_STATIC_CONSTEXPR uint16_t Size = static_cast<uint16_t>(N - (N % EASY_ALIGN_SIZE));
};
template <const uint16_t N>
struct aligned_size<N, false, false> {
EASY_STATIC_CONSTEXPR uint16_t Size = static_cast<uint16_t>(N + EASY_ALIGN_SIZE - (N % EASY_ALIGN_SIZE));
};
template <const size_t N>
struct get_aligned_size {
EASY_STATIC_CONSTEXPR uint16_t Size =
aligned_size<static_cast<uint16_t>(N), (N % EASY_ALIGN_SIZE) == 0, (N > (65536 - EASY_ALIGN_SIZE))>::Size;
};
static_assert(get_aligned_size<EASY_ALIGN_SIZE - 3>::Size == EASY_ALIGN_SIZE, "wrong get_aligned_size");
static_assert(get_aligned_size<2 * EASY_ALIGN_SIZE - 3>::Size == 2 * EASY_ALIGN_SIZE, "wrong get_aligned_size");
static_assert(get_aligned_size<65530>::Size == 65536 - EASY_ALIGN_SIZE, "wrong get_aligned_size");
static_assert(get_aligned_size<65526>::Size == 65536 - EASY_ALIGN_SIZE, "wrong get_aligned_size");
static_assert(get_aligned_size<65536 - EASY_ALIGN_SIZE>::Size == 65536 - EASY_ALIGN_SIZE, "wrong get_aligned_size");
static_assert(get_aligned_size<65536 + 3 - EASY_ALIGN_SIZE * 2>::Size == 65536 - EASY_ALIGN_SIZE, "wrong get_aligned_size");
//////////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER_CHUNK_ALLOCATOR_H

View File

@ -0,0 +1,86 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_CURRENT_THREAD_H
#define EASY_PROFILER_CURRENT_THREAD_H
#include <easy/details/profiler_public_types.h>
#ifdef _WIN32
# include <Windows.h>
#elif defined(__APPLE__)
# include <pthread.h>
# include <Availability.h>
#elif defined(__QNX__)
# include <sys/mman.h>
# include <process.h>
# define __NR_gettid SYS_gettid
#else
# include <sys/types.h>
# include <unistd.h>
# include <sys/syscall.h>
#endif
inline profiler::thread_id_t getCurrentThreadId()
{
#ifdef _WIN32
return (profiler::thread_id_t)::GetCurrentThreadId();
#elif defined(__APPLE__)
# if (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_6) || \
(defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0)
static EASY_THREAD_LOCAL uint64_t _id = 0;
if (!_id)
pthread_threadid_np(NULL, &_id);
return (profiler::thread_id_t)_id;
# else
return (profiler::thread_id_t)pthread_self();
# endif
#elif defined(__QNX__)
EASY_THREAD_LOCAL static const profiler::thread_id_t _id = (profiler::thread_id_t)gettid();
return _id;
#else
EASY_THREAD_LOCAL static const profiler::thread_id_t _id = (profiler::thread_id_t)syscall(__NR_gettid);
return _id;
#endif
}
#endif // EASY_PROFILER_CURRENT_THREAD_H

View File

@ -0,0 +1,180 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_CURRENT_TIME_H
#define EASY_PROFILER_CURRENT_TIME_H
#include <easy/details/profiler_public_types.h>
#if defined(_MSC_VER) && _MSC_VER <= 1800
// std::chrono for MSVC2013 is broken - it has very low resolution of 16ms
// restrict usage of std::chrono
# if EASY_CHRONO_HIGHRES_CLOCK
# undef EASY_CHRONO_HIGHRES_CLOCK
# endif
# if EASY_CHRONO_STEADY_CLOCK
# undef EASY_CHRONO_STEADY_CLOCK
# endif
#endif
#if EASY_CHRONO_HIGHRES_CLOCK
# include <chrono>
# define EASY_CHRONO_CLOCK std::chrono::high_resolution_clock
#elif EASY_CHRONO_STEADY_CLOCK
# include <chrono>
# define EASY_CHRONO_CLOCK std::chrono::steady_clock
#elif defined(_WIN32)
# include <Windows.h>
#else
# include <chrono>
# include <time.h>
# ifdef __ARM_ARCH
# include <sys/time.h>
# endif//__ARM_ARCH
#endif
# ifdef __mips__
# include <sys/time.h>
# endif//__mips__
namespace profiler { namespace clock {
static inline profiler::timestamp_t now()
{
#if EASY_CHRONO_HIGHRES_CLOCK || EASY_CHRONO_STEADY_CLOCK
return (profiler::timestamp_t)EASY_CHRONO_CLOCK::now().time_since_epoch().count();
#elif defined(_WIN32)
//see https://msdn.microsoft.com/library/windows/desktop/dn553408(v=vs.85).aspx
LARGE_INTEGER elapsedMicroseconds;
if (!QueryPerformanceCounter(&elapsedMicroseconds))
return 0;
return (profiler::timestamp_t)elapsedMicroseconds.QuadPart;
#else// not _WIN32
#if (defined(__GNUC__) || defined(__ICC))
// part of code from google/benchmark library (Licensed under the Apache License, Version 2.0)
// see https://github.com/google/benchmark/blob/master/src/cycleclock.h#L111
#if defined(__i386__)
int64_t ret;
__asm__ volatile("rdtsc" : "=A"(ret));
return ret;
#elif defined(__x86_64__) || defined(__amd64__)
uint64_t low, high;
__asm__ volatile("rdtsc" : "=a"(low), "=d"(high));
return (high << 32) | low;
#elif defined(__powerpc__) || defined(__ppc__)
// This returns a time-base, which is not always precisely a cycle-count.
int64_t tbl, tbu0, tbu1;
asm("mftbu %0" : "=r"(tbu0));
asm("mftb %0" : "=r"(tbl));
asm("mftbu %0" : "=r"(tbu1));
tbl &= -static_cast<int64>(tbu0 == tbu1);
// high 32 bits in tbu1; low 32 bits in tbl (tbu0 is garbage)
return (tbu1 << 32) | tbl;
#elif defined(__sparc__)
int64_t tick;
asm(".byte 0x83, 0x41, 0x00, 0x00");
asm("mov %%g1, %0" : "=r"(tick));
return tick;
#elif defined(__ia64__)
int64_t itc;
asm("mov %0 = ar.itc" : "=r"(itc));
return itc;
#elif defined(_MSC_VER) && defined(_M_IX86)
// Older MSVC compilers (like 7.x) don't seem to support the
// __rdtsc intrinsic properly, so I prefer to use _asm instead
// when I know it will work. Otherwise, I'll use __rdtsc and hope
// the code is being compiled with a non-ancient compiler.
_asm rdtsc
#elif defined(_MSC_VER)
return __rdtsc();
#elif defined(__aarch64__)
// System timer of ARMv8 runs at a different frequency than the CPU's.
// The frequency is fixed, typically in the range 1-50MHz. It can be
// read at CNTFRQ special register. We assume the OS has set up
// the virtual timer properly.
int64_t virtual_timer_value;
asm volatile("mrs %0, cntvct_el0" : "=r"(virtual_timer_value));
return virtual_timer_value;
#elif defined(__ARM_ARCH)
#if (__ARM_ARCH >= 6) // V6 is the earliest arch that has a standard cyclecount
uint32_t pmccntr;
uint32_t pmuseren;
uint32_t pmcntenset;
// Read the user mode perf monitor counter access permissions.
asm volatile("mrc p15, 0, %0, c9, c14, 0" : "=r"(pmuseren));
if (pmuseren & 1) { // Allows reading perfmon counters for user mode code.
asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r"(pmcntenset));
if (pmcntenset & 0x80000000ul) { // Is it counting?
asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r"(pmccntr));
// The counter is set up to count every 64th cycle
return static_cast<int64_t>(pmccntr) * 64; // Should optimize to << 6
}
}
#endif
struct timeval tv;
gettimeofday(&tv, nullptr);
return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
#elif defined(__mips__)
// mips apparently only allows rdtsc for superusers, so we fall
// back to gettimeofday. It's possible clock_gettime would be better.
struct timeval tv;
gettimeofday(&tv, nullptr);
return static_cast<int64_t>(tv.tv_sec) * 1000000 + tv.tv_usec;
#else
#warning You need to define fast now() for your OS and CPU
return std::chrono::high_resolution_clock::now().time_since_epoch().count();
#define EASY_CHRONO_CLOCK std::chrono::high_resolution_clock
#endif
#else // not _WIN32, __GNUC__, __ICC
#warning You need to define fast now() for your OS and CPU
return std::chrono::high_resolution_clock::now().time_since_epoch().count();
#define EASY_CHRONO_CLOCK std::chrono::high_resolution_clock
#endif
#endif
}
} } // end of namespace profiler::clock.
#endif // EASY_PROFILER_CURRENT_TIME_H

View File

@ -0,0 +1,438 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#include <easy/easy_socket.h>
#include <string.h>
#include <thread>
#include <limits>
#if defined(__QNX__)
# include <sys/time.h>
#endif
#if defined(_WIN32)
# pragma comment (lib, "Ws2_32.lib")
# pragma comment (lib, "Mswsock.lib")
# pragma comment (lib, "AdvApi32.lib")
# ifdef max
# undef max
# endif
#else
# include <errno.h>
# include <sys/ioctl.h>
#endif
/////////////////////////////////////////////////////////////////
#if defined(_WIN32)
const int SOCK_ABORTED = WSAECONNABORTED;
const int SOCK_RESET = WSAECONNRESET;
const int SOCK_IN_PROGRESS = WSAEINPROGRESS;
#else
const int SOCK_ABORTED = ECONNABORTED;
const int SOCK_RESET = ECONNRESET;
const int SOCK_IN_PROGRESS = EINPROGRESS;
const int SOCK_BROKEN_PIPE = EPIPE;
const int SOCK_ENOENT = ENOENT;
#endif
const int SEND_BUFFER_SIZE = 64 * 1024 * 1024;
/////////////////////////////////////////////////////////////////
static int closeSocket(EasySocket::socket_t s)
{
#if defined(_WIN32)
return ::closesocket(s);
#else
return ::close(s);
#endif
}
/////////////////////////////////////////////////////////////////
bool EasySocket::checkSocket(socket_t s) const
{
return s > 0;
}
void EasySocket::setBlocking(EasySocket::socket_t s, bool blocking)
{
#if defined(_WIN32)
u_long iMode = blocking ? 0 : 1;//0 - blocking, 1 - non blocking
::ioctlsocket(s, FIONBIO, &iMode);
#else
int iMode = blocking ? 0 : 1;//0 - blocking, 1 - non blocking
::ioctl(s, FIONBIO, (char*)&iMode);
#endif
}
int EasySocket::bind(uint16_t port)
{
if (!checkSocket(m_socket))
return -1;
struct sockaddr_in server_address;
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = INADDR_ANY;
server_address.sin_port = htons(port);
auto res = ::bind(m_socket, (struct sockaddr *)&server_address, sizeof(server_address));
return res;
}
void EasySocket::flush()
{
if (m_socket)
closeSocket(m_socket);
if (m_replySocket != m_socket && m_replySocket != 0) {
// we do not need to close uninitialized reply socket
closeSocket(m_replySocket);
}
#if defined(_WIN32)
m_socket = 0;
m_replySocket = 0;
#else
m_wsaret = 0;
#endif
}
void EasySocket::checkResult(int result)
{
if (result >= 0)
{
m_state = ConnectionState::Connected;
return;
}
if (result == -1) // is this check necessary?
{
#if defined(_WIN32)
const int error_code = WSAGetLastError();
#else
const int error_code = errno;
#endif
switch (error_code)
{
case SOCK_ABORTED:
case SOCK_RESET:
#if !defined(_WIN32)
case SOCK_BROKEN_PIPE:
case SOCK_ENOENT:
#endif
#if defined (__APPLE__)
case ECONNREFUSED:
#endif
m_state = ConnectionState::Disconnected;
break;
case SOCK_IN_PROGRESS:
m_state = ConnectionState::Connecting;
break;
default:
break;
}
}
}
void EasySocket::init()
{
if (m_wsaret != 0)
return;
#if !defined(_WIN32)
const int protocol = 0;
#else
const int protocol = IPPROTO_TCP;
#endif
m_socket = ::socket(AF_INET, SOCK_STREAM, protocol);
if (!checkSocket(m_socket))
return;
setBlocking(m_socket, true);
#if !defined(_WIN32)
m_wsaret = 1;
#endif
const int opt = 1;
::setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(int));
}
EasySocket::ConnectionState EasySocket::state() const
{
return m_state;
}
bool EasySocket::isDisconnected() const
{
return static_cast<int>(m_state) <= 0;
}
bool EasySocket::isConnected() const
{
return m_state == ConnectionState::Connected;
}
EasySocket::EasySocket()
{
#if defined(_WIN32)
WSADATA wsaData;
m_wsaret = WSAStartup(0x101, &wsaData);
#else
m_wsaret = 0;
#endif
init();
}
EasySocket::~EasySocket()
{
flush();
#if defined(_WIN32)
if (m_wsaret == 0)
WSACleanup();
#endif
}
void EasySocket::setReceiveTimeout(int milliseconds)
{
if (!isConnected() || !checkSocket(m_replySocket))
return;
if (milliseconds <= 0)
milliseconds = std::numeric_limits<int>::max() / 1000;
#if defined(_WIN32)
const DWORD timeout = static_cast<DWORD>(milliseconds);
::setsockopt(m_replySocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&timeout, sizeof(DWORD));
#else
struct timeval tv;
if (milliseconds >= 1000)
{
const int s = milliseconds / 1000;
const int us = (milliseconds - s * 1000) * 1000;
tv.tv_sec = s;
tv.tv_usec = us;
}
else
{
tv.tv_sec = 0;
tv.tv_usec = milliseconds * 1000;
}
::setsockopt(m_replySocket, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof (struct timeval));
#endif
}
int EasySocket::send(const void* buffer, size_t nbytes)
{
if (!checkSocket(m_replySocket))
return -1;
#if defined(_WIN32) || defined(__APPLE__)
const int res = ::send(m_replySocket, (const char*)buffer, (int)nbytes, 0);
#else
const int res = (int)::send(m_replySocket, buffer, nbytes, MSG_NOSIGNAL);
#endif
checkResult(res);
return res;
}
int EasySocket::receive(void* buffer, size_t nbytes)
{
if (!checkSocket(m_replySocket))
return -1;
#if defined(_WIN32)
const int res = ::recv(m_replySocket, (char*)buffer, (int)nbytes, 0);
#else
const int res = (int)::read(m_replySocket, buffer, nbytes);
#endif
checkResult(res);
if (res == 0)
m_state = ConnectionState::Disconnected;
return res;
}
int EasySocket::listen(int count)
{
if (!checkSocket(m_socket))
return -1;
const int res = ::listen(m_socket, count);
checkResult(res);
return res;
}
int EasySocket::accept()
{
if (!checkSocket(m_socket))
return -1;
fd_set fdread;
FD_ZERO (&fdread);
FD_SET (m_socket, &fdread);
fd_set fdwrite = fdread;
fd_set fdexcl = fdread;
struct timeval tv { 0, 500 };
const int rc = ::select((int)m_socket + 1, &fdread, &fdwrite, &fdexcl, &tv);
if (rc <= 0)
return -1; // there is no connection for accept
m_replySocket = ::accept(m_socket, nullptr, nullptr);
checkResult((int)m_replySocket);
if (checkSocket(m_replySocket))
{
::setsockopt(m_replySocket, SOL_SOCKET, SO_SNDBUF, (char*)&SEND_BUFFER_SIZE, sizeof(int));
//const int flag = 1;
//const int result = setsockopt(m_replySocket,IPPROTO_TCP,TCP_NODELAY,(char *)&flag,sizeof(int));
#if defined(__APPLE__)
// Apple doesn't have MSG_NOSIGNAL, work around it
const int value = 1;
::setsockopt(m_replySocket, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value));
#endif
//setBlocking(m_replySocket,true);
}
return (int)m_replySocket;
}
bool EasySocket::setAddress(const char* address, uint16_t port)
{
m_server = ::gethostbyname(address);
if (m_server == nullptr)
return false;
memset((char*)&m_serverAddress, 0, sizeof(m_serverAddress));
m_serverAddress.sin_family = AF_INET;
memcpy((char*)&m_serverAddress.sin_addr.s_addr, (char*)m_server->h_addr, (size_t)m_server->h_length);
m_serverAddress.sin_port = htons(port);
return true;
}
int EasySocket::connect()
{
if (m_server == nullptr || m_socket <= 0)
return -1;
int res = 0;
//TODO: more intelligence
#if !defined(_WIN32)
setBlocking(m_socket, false);
const int sleepMs = 20;
const int waitSec = 1;
const int waitMs = waitSec * 1000 / sleepMs;
for (int counter = 0; counter++ < waitMs;)
{
res = ::connect(m_socket, (struct sockaddr*)&m_serverAddress, sizeof(m_serverAddress));
#if defined(__APPLE__)
// on Apple, treat EISCONN error as success
if (res == -1 && errno == EISCONN)
{
res = 0;
break;
}
#endif
checkResult(res);
if (res == 0)
{
break;
}
if (m_state == ConnectionState::Connecting)
{
std::this_thread::sleep_for(std::chrono::milliseconds(sleepMs));
continue;
}
if (isDisconnected())
{
break;
}
}
setBlocking(m_socket, true);
#else
res = ::connect(m_socket, (struct sockaddr*)&m_serverAddress, sizeof(m_serverAddress));
checkResult(res);
#endif
if (res == 0)
{
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 0;
::setsockopt(m_socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(struct timeval));
#if defined(__APPLE__)
// Apple doesn't have MSG_NOSIGNAL, work around it
const int value = 1;
setsockopt(m_socket, SOL_SOCKET, SO_NOSIGPIPE, &value, sizeof(value));
#endif
m_replySocket = m_socket;
}
return res;
}

View File

@ -0,0 +1,23 @@
#ifndef EASY_PROFILER__EVENT_TRACE_STATUS__H_
#define EASY_PROFILER__EVENT_TRACE_STATUS__H_
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
enum class EventTracingEnableStatus : unsigned char
{
LaunchedSuccessfully = 0,
PermissionDenied,
AlreadyLaunched,
BadPropertiesSize,
OpenTraceFailed,
UnknownError,
};
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER__EVENT_TRACE_STATUS__H_

View File

@ -0,0 +1,587 @@
/************************************************************************
* file name : event_trace_win.cpp
* ----------------- :
* creation time : 2016/09/04
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of EasyEventTracer class used for tracing
* : Windows system events to get context switches.
* ----------------- :
* change log : * 2016/09/04 Victor Zarubkin: initial commit.
* :
* : * 2016/09/13 Victor Zarubkin: get process id and process name
* : of the owner of thread with id == CSwitch::NewThreadId.
* :
* : * 2016/09/17 Victor Zarubkin: added log messages printing.
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
* :
* : Licensed under either of
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* : at your option.
* :
* : 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.
* :
* : The Apache License, Version 2.0 (the "License")
* :
* : You may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
************************************************************************/
#ifdef _WIN32
#include <memory.h>
#include <chrono>
#include <unordered_map>
#include <easy/profiler.h>
#include "profile_manager.h"
#include "current_time.h"
#include "event_trace_win.h"
#include <Psapi.h>
#ifdef __MINGW32__
#include <processthreadsapi.h>
#endif
//#include <Shellapi.h>
#if EASY_OPTION_LOG_ENABLED != 0
# include <iostream>
# ifndef EASY_ERRORLOG
# define EASY_ERRORLOG std::cerr
# endif
# ifndef EASY_LOG
# define EASY_LOG std::cerr
# endif
# ifndef EASY_ERROR
# define EASY_ERROR(LOG_MSG) EASY_ERRORLOG << "EasyProfiler ERROR: " << LOG_MSG
# endif
# ifndef EASY_WARNING
# define EASY_WARNING(LOG_MSG) EASY_ERRORLOG << "EasyProfiler WARNING: " << LOG_MSG
# endif
# ifndef EASY_LOGMSG
# define EASY_LOGMSG(LOG_MSG) EASY_LOG << "EasyProfiler INFO: " << LOG_MSG
# endif
# ifndef EASY_LOG_ONLY
# define EASY_LOG_ONLY(CODE) CODE
# endif
#else
# ifndef EASY_ERROR
# define EASY_ERROR(LOG_MSG)
# endif
# ifndef EASY_WARNING
# define EASY_WARNING(LOG_MSG)
# endif
# ifndef EASY_LOGMSG
# define EASY_LOGMSG(LOG_MSG)
# endif
# ifndef EASY_LOG_ONLY
# define EASY_LOG_ONLY(CODE)
# endif
#endif
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
extern const profiler::color_t EASY_COLOR_INTERNAL_EVENT;
#ifdef __MINGW32__
static std::atomic<uint64_t> TRACING_END_TIME = ATOMIC_VAR_INIT(~0ULL);
static char KERNEL_LOGGER[] = KERNEL_LOGGER_NAME;
#else
static std::atomic_uint64_t TRACING_END_TIME = ATOMIC_VAR_INIT(~0ULL);
#endif
/**
* Retrieve the process name of the given process.
*
* This method is NOT thread-safe: the returned string has to be copied somewhere before this
* method can be used by another thread or call.
*
* getProcessName() owns the returned string.
*
* \param len the process name string length [output].
*
* \return the process name string.
*/
static const char* getProcessName(HANDLE hProcess, std::size_t& len)
{
static TCHAR buf[MAX_PATH] = {};
len = static_cast<std::size_t>(GetModuleBaseName(hProcess, 0, buf, MAX_PATH));
if (len == 0)
return nullptr;
#if UNICODE
static char charbuf[MAX_PATH] = {};
len = std::wcstombs(charbuf, buf, len);
return charbuf;
#else
return buf;
#endif
}
EASY_CONSTEXPR decltype(EVENT_DESCRIPTOR::Opcode) SWITCH_CONTEXT_OPCODE = 36;
EASY_CONSTEXPR int RAW_TIMESTAMP_TIME_TYPE = 1;
//////////////////////////////////////////////////////////////////////////
struct ProcessInfo {
std::string name;
processid_t id = 0;
int8_t valid = 0;
};
//////////////////////////////////////////////////////////////////////////
// CSwitch class
// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa964744(v=vs.85).aspx
// EventType = 36
struct CSwitch
{
uint32_t NewThreadId;
uint32_t OldThreadId;
int8_t NewThreadPriority;
int8_t OldThreadPriority;
uint8_t PreviousCState;
int8_t SpareByte;
int8_t OldThreadWaitReason;
int8_t OldThreadWaitMode;
int8_t OldThreadState;
int8_t OldThreadWaitIdealProcessor;
uint32_t NewThreadWaitTime;
uint32_t Reserved;
};
//////////////////////////////////////////////////////////////////////////
struct do_not_calc_hash {
template <class T> inline size_t operator()(T _value) const {
return static_cast<size_t>(_value);
}
};
using thread_process_info_map = std::unordered_map<decltype(CSwitch::NewThreadId), ProcessInfo*, do_not_calc_hash>;
using process_info_map = std::unordered_map<processid_t, ProcessInfo, do_not_calc_hash>;
// Using static is safe because easyProcessTraceEvent() is called from one thread
static process_info_map PROCESS_INFO_TABLE;
static thread_process_info_map THREAD_PROCESS_INFO_TABLE;
//////////////////////////////////////////////////////////////////////////
void WINAPI easyProcessTraceEvent(PEVENT_RECORD _traceEvent)
{
if (_traceEvent->EventHeader.EventDescriptor.Opcode != SWITCH_CONTEXT_OPCODE)
return;
if (sizeof(CSwitch) != _traceEvent->UserDataLength)
return;
EASY_FUNCTION(EASY_COLOR_INTERNAL_EVENT, profiler::OFF);
auto _contextSwitchEvent = reinterpret_cast<CSwitch*>(_traceEvent->UserData);
const auto time = static_cast<profiler::timestamp_t>(_traceEvent->EventHeader.TimeStamp.QuadPart);
if (time > TRACING_END_TIME.load(std::memory_order_acquire))
return;
DWORD pid = 0;
const char* process_name = "";
// Trying to get target process name and id
auto it = THREAD_PROCESS_INFO_TABLE.find(_contextSwitchEvent->NewThreadId);
if (it == THREAD_PROCESS_INFO_TABLE.end())
{
auto hThread = OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, _contextSwitchEvent->NewThreadId);
if (hThread != nullptr)
{
pid = GetProcessIdOfThread(hThread);
auto pinfo = &PROCESS_INFO_TABLE[pid];
if (pinfo->valid == 0)
{
if (pinfo->name.empty())
{
static char numbuf[128] = {};
sprintf(numbuf, "%u", pid);
pinfo->name = numbuf;
pinfo->id = pid;
}
/*
According to documentation, using GetModuleBaseName() requires
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ access rights.
But it works fine with PROCESS_QUERY_LIMITED_INFORMATION instead of PROCESS_QUERY_INFORMATION.
See https://msdn.microsoft.com/en-us/library/windows/desktop/ms683196(v=vs.85).aspx
*/
//auto hProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
//if (hProc == nullptr)
auto hProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProc != nullptr)
{
std::size_t len = 0;
auto processName = getProcessName(hProc, len); // Using thread-unsafe method is safe because processTraceEvent() is called from one thread
if (len != 0)
{
pinfo->name.reserve(pinfo->name.size() + 2 + len);
pinfo->name.append(" ", 1);
pinfo->name.append(processName, len);
pinfo->valid = 1;
}
CloseHandle(hProc);
}
else
{
//auto err = GetLastError();
//printf("OpenProcess(%u) fail: GetLastError() == %u\n", pid, err);
pinfo->valid = -1;
if (pid == 4) {
pinfo->name.reserve(pinfo->name.size() + 8);
pinfo->name.append(" System", 7);
}
}
}
process_name = pinfo->name.c_str();
THREAD_PROCESS_INFO_TABLE[_contextSwitchEvent->NewThreadId] = pinfo;
CloseHandle(hThread);
}
else
{
//printf("Can not OpenThread(%u);\n", _contextSwitchEvent->NewThreadId);
THREAD_PROCESS_INFO_TABLE[_contextSwitchEvent->NewThreadId] = nullptr;
}
}
else
{
auto pinfo = it->second;
if (pinfo != nullptr)
process_name = pinfo->name.c_str();
else if (it->first == 0)
process_name = "System Idle";
else if (it->first == 4)
process_name = "System";
}
ProfileManager::instance().beginContextSwitch(_contextSwitchEvent->OldThreadId, time, _contextSwitchEvent->NewThreadId, process_name);
ProfileManager::instance().endContextSwitch(_contextSwitchEvent->NewThreadId, pid, time);
}
//////////////////////////////////////////////////////////////////////////
EasyEventTracer::Properties::Properties()
{
#if UNICODE
std::wcstombs(sessionName, KERNEL_LOGGER_NAME, sizeof(sessionName));
#else
std::strncpy(sessionName, KERNEL_LOGGER_NAME, sizeof(sessionName));
#endif
}
//////////////////////////////////////////////////////////////////////////
#ifndef EASY_MAGIC_STATIC_AVAILABLE
class EasyEventTracerInstance {
friend EasyEventTracer;
EasyEventTracer instance;
} EASY_EVENT_TRACER;
#endif
EasyEventTracer& EasyEventTracer::instance()
{
#ifndef EASY_MAGIC_STATIC_AVAILABLE
return EASY_EVENT_TRACER.instance;
#else
static EasyEventTracer tracer;
return tracer;
#endif
}
EasyEventTracer::EasyEventTracer()
{
m_lowPriority = ATOMIC_VAR_INIT(EASY_OPTION_LOW_PRIORITY_EVENT_TRACING);
THREAD_PROCESS_INFO_TABLE[0U] = nullptr;
}
EasyEventTracer::~EasyEventTracer()
{
disable();
}
bool EasyEventTracer::isLowPriority() const
{
return m_lowPriority.load(std::memory_order_acquire);
}
void EasyEventTracer::setLowPriority(bool _value)
{
m_lowPriority.store(_value, std::memory_order_release);
}
bool setPrivilege(HANDLE hToken, PTCHAR _privelegeName)
{
bool success = false;
if (hToken)
{
LUID privilegyId;
if (LookupPrivilegeValue(NULL, _privelegeName, &privilegyId))
{
TOKEN_PRIVILEGES tokenPrivilege;
tokenPrivilege.PrivilegeCount = 1;
tokenPrivilege.Privileges[0].Luid = privilegyId;
tokenPrivilege.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
success = AdjustTokenPrivileges(hToken, FALSE, &tokenPrivilege, sizeof(TOKEN_PRIVILEGES), NULL, NULL) != FALSE;
}
}
EASY_LOG_ONLY(
if (!success)
EASY_WARNING("Failed to set " << _privelegeName << " privilege for the application.\n");
)
return success;
}
void EasyEventTracer::setProcessPrivileges()
{
static bool alreadySet = false;
if (alreadySet)
return;
alreadySet = true;
HANDLE hToken = nullptr;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
{
#if EASY_OPTION_LOG_ENABLED != 0
const bool success = setPrivilege(hToken, SE_DEBUG_NAME);
if (!success)
EASY_WARNING("Some context switch events could not get process name.\n");
#else
setPrivilege(hToken, SE_DEBUG_NAME);
#endif
CloseHandle(hToken);
}
EASY_LOG_ONLY(
else {
EASY_WARNING("Failed to open process to adjust privileges.\n");
}
)
}
EventTracingEnableStatus EasyEventTracer::startTrace(bool _force, int _step)
{
using Status = EventTracingEnableStatus;
auto startTraceResult = StartTrace(&m_sessionHandle, KERNEL_LOGGER_NAME, props());
switch (startTraceResult)
{
case ERROR_SUCCESS:
return Status::LaunchedSuccessfully;
case ERROR_ALREADY_EXISTS:
{
if (_force)
{
// Try to stop another event tracing session to force launch self session.
if (_step == 0)
{
/*
According to https://msdn.microsoft.com/en-us/library/windows/desktop/aa363696(v=vs.85).aspx
SessionHandle is ignored (and could be NULL) if SessionName is not NULL,
and you only need to set the Wnode.BufferSize, Wnode.Guid, LoggerNameOffset, and LogFileNameOffset
in EVENT_TRACE_PROPERTIES structure if ControlCode is EVENT_TRACE_CONTROL_STOP.
All data is already set for m_properties to the moment. Simply copy m_properties and use the copy.
This method supposed to be faster than launching console window and executing shell command,
but if that would not work, return to using shell command "logman stop".
*/
// static is safe because we are guarded by spin-lock m_spin
static Properties p;
p.base = m_properties.base; // Use copy of m_properties to make sure m_properties will not be changed
// Stop another session
ControlTrace((TRACEHANDLE)NULL, KERNEL_LOGGER_NAME, reinterpret_cast<EVENT_TRACE_PROPERTIES*>(&p), EVENT_TRACE_CONTROL_STOP);
// Console window variant:
//if (32 >= (int)ShellExecute(NULL, NULL, "logman", "stop \"" KERNEL_LOGGER_NAME "\" -ets", NULL, SW_HIDE))
// return Status::AlreadyLaunched;
}
if (_step < 4)
{
// Command executed successfully. Wait for a few time until tracing session finish.
std::this_thread::sleep_for(std::chrono::milliseconds(500));
return startTrace(true, ++_step);
}
}
EASY_ERROR("Event tracing not launched: ERROR_ALREADY_EXISTS. To stop another session execute cmd: logman stop \"" << KERNEL_LOGGER_NAME << "\" -ets\n");
return Status::AlreadyLaunched;
}
case ERROR_ACCESS_DENIED:
EASY_ERROR("Event tracing not launched: ERROR_ACCESS_DENIED. Try to launch your application as Administrator.\n");
return Status::PermissionDenied;
case ERROR_BAD_LENGTH:
EASY_ERROR("Event tracing not launched: ERROR_BAD_LENGTH. It seems that your KERNEL_LOGGER_NAME differs from \"" << m_properties.sessionName << "\". Try to re-compile easy_profiler or contact EasyProfiler developers.\n");
return Status::BadPropertiesSize;
}
EASY_ERROR("Event tracing not launched: StartTrace() returned " << startTraceResult << std::endl);
return Status::UnknownError;
}
EventTracingEnableStatus EasyEventTracer::enable(bool _force)
{
using Status = EventTracingEnableStatus;
profiler::guard_lock<profiler::spin_lock> lock(m_spin);
if (m_bEnabled)
return Status::LaunchedSuccessfully;
/*
Trying to set debug privilege for current process
to be able to get other process information (process name).
*/
EasyEventTracer::setProcessPrivileges();
// Clear properties
memset(&m_properties, 0, sizeof(m_properties));
m_properties.base.Wnode.BufferSize = sizeof(m_properties);
m_properties.base.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
m_properties.base.Wnode.ClientContext = RAW_TIMESTAMP_TIME_TYPE;
m_properties.base.Wnode.Guid = SystemTraceControlGuid;
m_properties.base.LoggerNameOffset = sizeof(m_properties.base);
m_properties.base.EnableFlags = EVENT_TRACE_FLAG_CSWITCH;
m_properties.base.LogFileMode = EVENT_TRACE_REAL_TIME_MODE;
// Start event tracing
const auto res = startTrace(_force);
if (res != Status::LaunchedSuccessfully)
return res;
memset(&m_trace, 0, sizeof(m_trace));
#ifdef __MINGW32__
m_trace.LoggerName = KERNEL_LOGGER;
#else
m_trace.LoggerName = KERNEL_LOGGER_NAME;
#endif
m_trace.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_EVENT_RECORD | PROCESS_TRACE_MODE_RAW_TIMESTAMP;
m_trace.EventRecordCallback = easyProcessTraceEvent;
m_openedHandle = OpenTrace(&m_trace);
if (m_openedHandle == INVALID_PROCESSTRACE_HANDLE)
{
EASY_ERROR("Event tracing not launched: OpenTrace() returned invalid handle.\n");
return Status::OpenTraceFailed;
}
/*
Have to launch a thread to process events because according to MSDN documentation:
The ProcessTrace function blocks the thread until it delivers all events, the BufferCallback function returns FALSE,
or you call CloseTrace. If the consumer is consuming events in real time, the ProcessTrace function returns after
the controller stops the trace session. (Note that there may be a several-second delay before the function returns.)
https://msdn.microsoft.com/en-us/library/windows/desktop/aa364093(v=vs.85).aspx
*/
m_processThread = std::thread([this](bool _lowPriority)
{
if (_lowPriority) // Set low priority for event tracing thread
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
EASY_THREAD_SCOPE("EasyProfiler.ETW");
ProcessTrace(&m_openedHandle, 1, 0, 0);
}, m_lowPriority.load(std::memory_order_acquire));
m_bEnabled = true;
EASY_LOGMSG("Event tracing launched\n");
return Status::LaunchedSuccessfully;
}
void EasyEventTracer::disable()
{
profiler::guard_lock<profiler::spin_lock> lock(m_spin);
if (!m_bEnabled)
return;
EASY_LOGMSG("Event tracing is stopping...\n");
TRACING_END_TIME.store(profiler::clock::now(), std::memory_order_release);
ControlTrace(m_openedHandle, KERNEL_LOGGER_NAME, props(), EVENT_TRACE_CONTROL_STOP);
CloseTrace(m_openedHandle);
// Wait for ProcessTrace to finish to make sure no processTraceEvent() will be called later.
if (m_processThread.joinable())
m_processThread.join();
m_bEnabled = false;
// processTraceEvent() is not called anymore. Clean static maps is safe.
PROCESS_INFO_TABLE.clear();
THREAD_PROCESS_INFO_TABLE.clear();
THREAD_PROCESS_INFO_TABLE[0U] = nullptr;
TRACING_END_TIME.store(~0ULL, std::memory_order_release);
EASY_LOGMSG("Event tracing stopped\n");
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif // _WIN32

View File

@ -0,0 +1,127 @@
/************************************************************************
* file name : event_trace_win.h
* ----------------- :
* creation time : 2016/09/04
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of EasyEventTracer class used for tracing
* : Windows system events to get context switches.
* ----------------- :
* change log : * 2016/09/04 Victor Zarubkin: initial commit.
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
* :
* : Licensed under either of
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* : at your option.
* :
* : 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.
* :
* : The Apache License, Version 2.0 (the "License")
* :
* : You may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
************************************************************************/
#ifndef EASY_PROFILER_EVENT_TRACE_WINDOWS_H
#define EASY_PROFILER_EVENT_TRACE_WINDOWS_H
#ifdef _WIN32
#define INITGUID // This is to enable using SystemTraceControlGuid in evntrace.h.
#include <Windows.h>
#include <Strsafe.h>
#include <wmistr.h>
#include <evntrace.h>
#include <evntcons.h>
#include <thread>
#include <atomic>
#include "event_trace_status.h"
#include "spin_lock.h"
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
class EasyEventTracer EASY_FINAL
{
#ifndef EASY_MAGIC_STATIC_AVAILABLE
friend class EasyEventTracerInstance;
#endif
#pragma pack(push, 1)
struct Properties {
Properties();
EVENT_TRACE_PROPERTIES base;
char sessionName[sizeof(KERNEL_LOGGER_NAME)];
};
#pragma pack(pop)
std::thread m_processThread;
Properties m_properties;
EVENT_TRACE_LOGFILE m_trace;
profiler::spin_lock m_spin;
std::atomic_bool m_lowPriority;
TRACEHANDLE m_sessionHandle = INVALID_PROCESSTRACE_HANDLE;
TRACEHANDLE m_openedHandle = INVALID_PROCESSTRACE_HANDLE;
bool m_bEnabled = false;
public:
static EasyEventTracer& instance();
~EasyEventTracer();
bool isLowPriority() const;
EventTracingEnableStatus enable(bool _force = false);
void disable();
void setLowPriority(bool _value);
static void setProcessPrivileges();
private:
EasyEventTracer();
inline EVENT_TRACE_PROPERTIES* props()
{
return reinterpret_cast<EVENT_TRACE_PROPERTIES*>(&m_properties);
}
EventTracingEnableStatus startTrace(bool _force, int _step = 0);
}; // END of class EasyEventTracer.
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif // _WIN32
#endif // EASY_PROFILER_EVENT_TRACE_WINDOWS_H

View File

@ -0,0 +1,307 @@
/************************************************************************
* file name : hashed_str.h
* ----------------- :
* creation time : 2016/09/11
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains definition of C-strings with calculated hash-code.
* : These strings may be used as optimized keys for std::unordered_map.
* ----------------- :
* change log : * 2016/09/11 Victor Zarubkin: Initial commit. Moved sources from reader.cpp
* :
* : *
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
* :
* : Licensed under either of
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* : at your option.
* :
* : 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.
* :
* : The Apache License, Version 2.0 (the "License")
* :
* : You may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
************************************************************************/
#ifndef EASY_PROFILER__HASHED_CSTR__H_
#define EASY_PROFILER__HASHED_CSTR__H_
#include <functional>
#include <string.h>
#include <string>
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
namespace profiler {
class hashed_stdstring
{
::std::string m_str;
size_t m_hash;
public:
hashed_stdstring(const char* _str) : m_str(_str), m_hash(::std::hash<::std::string>()(m_str))
{
}
hashed_stdstring(const ::std::string& _str) : m_str(_str), m_hash(::std::hash<::std::string>()(m_str))
{
}
hashed_stdstring(::std::string&& _str) : m_str(::std::forward<::std::string&&>(_str)), m_hash(::std::hash<::std::string>()(m_str))
{
}
hashed_stdstring(hashed_stdstring&& _other) : m_str(::std::move(_other.m_str)), m_hash(_other.m_hash)
{
}
hashed_stdstring(const char* _str, size_t _hash_code) : m_str(_str), m_hash(_hash_code)
{
}
hashed_stdstring(const ::std::string& _str, size_t _hash_code) : m_str(_str), m_hash(_hash_code)
{
}
hashed_stdstring(::std::string&& _str, size_t _hash_code) : m_str(::std::forward<::std::string&&>(_str)), m_hash(_hash_code)
{
}
hashed_stdstring(const hashed_stdstring&) = default;
hashed_stdstring& operator = (const hashed_stdstring&) = default;
hashed_stdstring& operator = (hashed_stdstring&& _other)
{
m_str = ::std::move(_other.m_str);
m_hash = _other.m_hash;
return *this;
}
inline bool operator == (const hashed_stdstring& _other) const
{
return m_hash == _other.m_hash && m_str == _other.m_str;
}
inline bool operator != (const hashed_stdstring& _other) const
{
return !operator == (_other);
}
inline size_t hcode() const
{
return m_hash;
}
inline const char* c_str() const
{
return m_str.c_str();
}
inline size_t size() const
{
return m_str.size();
}
}; // END of class hashed_stdstring.
} // END of namespace profiler.
namespace std {
/** \brief Simply returns precalculated hash of a std::string. */
template <> struct hash<::profiler::hashed_stdstring> {
typedef ::profiler::hashed_stdstring argument_type;
typedef size_t result_type;
inline size_t operator () (const ::profiler::hashed_stdstring& _str) const {
return _str.hcode();
}
};
} // END of namespace std.
#if 0 == 1 //defined(_MSC_VER)// && _MSC_VER >= 1800
# define EASY_PROFILER_HASHED_CSTR_DEFINED
namespace profiler {
/** \brief Simple C-string pointer with length.
It is used as base class for a key in std::unordered_map.
It is used to get better performance than std::string.
It simply stores a pointer and a length, there is no
any memory allocation and copy.
\warning Make sure you know what you are doing. You have to be sure that
pointed C-string will exist until you finish using this cstring.
\ingroup profiler
*/
class cstring
{
protected:
const char* m_str;
size_t m_len;
public:
cstring(const char* _str) : m_str(_str), m_len(strlen(_str))
{
}
cstring(const char* _str, size_t _len) : m_str(_str), m_len(_len)
{
}
cstring(const cstring&) = default;
cstring& operator = (const cstring&) = default;
inline bool operator == (const cstring& _other) const
{
return m_len == _other.m_len && !strncmp(m_str, _other.m_str, m_len);
}
inline bool operator != (const cstring& _other) const
{
return !operator == (_other);
}
inline bool operator < (const cstring& _other) const
{
if (m_len == _other.m_len)
{
return strncmp(m_str, _other.m_str, m_len) < 0;
}
return m_len < _other.m_len;
}
inline const char* c_str() const
{
return m_str;
}
inline size_t size() const
{
return m_len;
}
}; // END of class cstring.
/** \brief cstring with precalculated hash.
This is used to calculate hash for C-string and to cache it
to be used in the future without recurring hash calculatoin.
\note This class is used as a key in std::unordered_map.
\ingroup profiler
*/
class hashed_cstr : public cstring
{
using Parent = cstring;
size_t m_hash;
public:
hashed_cstr(const char* _str) : Parent(_str), m_hash(0)
{
m_hash = ::std::_Hash_seq((const unsigned char *)m_str, m_len);
}
hashed_cstr(const char* _str, size_t _hash_code) : Parent(_str), m_hash(_hash_code)
{
}
hashed_cstr(const char* _str, size_t _len, size_t _hash_code) : Parent(_str, _len), m_hash(_hash_code)
{
}
hashed_cstr(const hashed_cstr&) = default;
hashed_cstr& operator = (const hashed_cstr&) = default;
inline bool operator == (const hashed_cstr& _other) const
{
return m_hash == _other.m_hash && Parent::operator == (_other);
}
inline bool operator != (const hashed_cstr& _other) const
{
return !operator == (_other);
}
inline size_t hcode() const
{
return m_hash;
}
}; // END of class hashed_cstr.
using string_with_hash = hashed_cstr;
} // END of namespace profiler.
namespace std {
/** \brief Simply returns precalculated hash of a C-string. */
template <> struct hash<::profiler::hashed_cstr>
{
using argument_type = ::profiler::hashed_cstr;
using result_type = size_t;
inline size_t operator () (const ::profiler::hashed_cstr& _str) const
{
return _str.hcode();
}
};
} // END of namespace std.
#else ////////////////////////////////////////////////////////////////////
// TODO: Create hashed_cstr for Linux (need to use Linux version of std::_Hash_seq)
namespace profiler {
using string_with_hash = hashed_stdstring;
}
#endif
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER__HASHED_CSTR__H_

View File

@ -0,0 +1,92 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#include "nonscoped_block.h"
#include <cstring>
#include <cstdlib>
NonscopedBlock::NonscopedBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, bool)
: profiler::Block(_desc, _runtimeName, false), m_runtimeName(nullptr)
{
}
NonscopedBlock::~NonscopedBlock()
{
// Actually destructor should not be invoked because StackBuffer do manual memory management
m_end = m_begin; // to restrict profiler::Block to invoke profiler::endBlock() on destructor.
free(m_runtimeName);
}
void NonscopedBlock::copyname()
{
// Here we need to copy m_name to m_runtimeName to ensure that
// it would be alive to the moment we will serialize the block
if ((m_status & profiler::ON) == 0)
return;
if (*m_name != 0)
{
auto len = strlen(m_name);
m_runtimeName = static_cast<char*>(malloc(len + 1));
// memcpy should be faster than strncpy because we know
// actual bytes number and both strings have the same size
memcpy(m_runtimeName, m_name, len);
m_runtimeName[len] = 0;
m_name = m_runtimeName;
}
else
{
m_name = "";
}
}
void NonscopedBlock::destroy()
{
// free memory used by m_runtimeName
free(m_runtimeName);
m_name = "";
}

View File

@ -0,0 +1,73 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_NONSCOPED_BLOCK_H
#define EASY_PROFILER_NONSCOPED_BLOCK_H
#include <easy/details/profiler_public_types.h>
class NonscopedBlock : public profiler::Block
{
char* m_runtimeName; ///< A copy of _runtimeName to make it safe to begin block in one function and end it in another
public:
NonscopedBlock() = delete;
NonscopedBlock(const NonscopedBlock&) = delete;
NonscopedBlock(NonscopedBlock&&) = delete;
NonscopedBlock& operator = (const NonscopedBlock&) = delete;
NonscopedBlock& operator = (NonscopedBlock&&) = delete;
NonscopedBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, bool = false);
~NonscopedBlock();
/** Copy string from m_name to m_runtimeName to make it safe to end block in another function.
Performs any work if block is ON and m_name != ""
*/
void copyname();
void destroy();
}; // END of class NonscopedBlock.
#endif // EASY_PROFILER_NONSCOPED_BLOCK_H

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,226 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_MANAGER_H
#define EASY_PROFILER_MANAGER_H
#include <easy/details/profiler_public_types.h>
#ifdef _WIN32
// Do not move this include to other place!
// It should be included before Windows.h which is included in spin_lock.h
# include <easy/easy_socket.h>
#endif // _WIN32
#include "spin_lock.h"
#include "hashed_cstr.h"
#include "thread_storage.h"
#include <atomic>
#include <map>
#include <ostream>
#include <unordered_map>
#include <thread>
#include <type_traits>
#include <vector>
//////////////////////////////////////////////////////////////////////////
using processid_t = uint64_t;
class BlockDescriptor;
namespace profiler {
class ValueId;
}
class ProfileManager
{
#ifndef EASY_MAGIC_STATIC_AVAILABLE
friend class ProfileManagerInstance;
#endif
ProfileManager();
using atomic_timestamp_t = std::atomic<profiler::timestamp_t>;
using guard_lock_t = profiler::guard_lock<profiler::spin_lock>;
using map_of_threads_stacks = std::map<profiler::thread_id_t, ThreadStorage>;
using block_descriptors_t = std::vector<BlockDescriptor*>;
using descriptors_map_t = std::unordered_map<profiler::string_with_hash, profiler::block_id_t>;
const processid_t m_processId;
#if defined(EASY_CHRONO_CLOCK) || defined(_WIN32)
const int64_t m_cpuFrequency;
#endif
map_of_threads_stacks m_threads;
block_descriptors_t m_descriptors;
descriptors_map_t m_descriptorsMap;
uint64_t m_descriptorsMemorySize;
#if !defined(EASY_CHRONO_CLOCK) && !defined(_WIN32)
std::atomic<int64_t> m_cpuFrequency;
#endif
profiler::timestamp_t m_beginTime;
profiler::timestamp_t m_endTime;
atomic_timestamp_t m_frameMax;
atomic_timestamp_t m_frameAvg;
atomic_timestamp_t m_frameCur;
profiler::spin_lock m_spin;
profiler::spin_lock m_storedSpin;
profiler::spin_lock m_dumpSpin;
std::atomic<profiler::thread_id_t> m_mainThreadId;
std::atomic_bool m_profilerStatus;
std::atomic_bool m_isEventTracingEnabled;
std::atomic_bool m_isAlreadyListening;
std::atomic_bool m_frameMaxReset;
std::atomic_bool m_frameAvgReset;
std::atomic_bool m_stopDumping;
std::string m_csInfoFilename = "/tmp/cs_profiling_info.log";
std::thread m_listenThread;
std::atomic_bool m_stopListen;
public:
ProfileManager(const ProfileManager&) = delete;
ProfileManager(ProfileManager&&) = delete;
ProfileManager& operator = (const ProfileManager&) = delete;
ProfileManager& operator = (ProfileManager&&) = delete;
static ProfileManager& instance();
~ProfileManager();
const profiler::BaseBlockDescriptor* addBlockDescriptor(profiler::EasyBlockStatus _defaultStatus,
const char* _autogenUniqueId,
const char* _name,
const char* _filename,
int _line,
profiler::block_type_t _block_type,
profiler::color_t _color,
bool _copyName = false);
void storeValue(const profiler::BaseBlockDescriptor* _desc, profiler::DataType _type, const void* _data, uint16_t _size, bool _isArray, profiler::ValueId _vin);
bool storeBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName);
bool storeBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, profiler::timestamp_t _beginTime, profiler::timestamp_t _endTime);
void beginBlock(profiler::Block& _block);
void beginNonScopedBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName);
void endBlock();
profiler::timestamp_t maxFrameDuration();
profiler::timestamp_t avgFrameDuration();
profiler::timestamp_t curFrameDuration() const;
void setEnabled(bool isEnable);
EASY_FORCE_INLINE bool isEnabled() const {
return m_profilerStatus.load(std::memory_order_acquire);
}
void setEventTracingEnabled(bool _isEnable);
bool isEventTracingEnabled() const;
uint32_t dumpBlocksToFile(const char* filename);
const char* registerThread(const char* name, profiler::ThreadGuard& threadGuard);
const char* registerThread(const char* name);
void setContextSwitchLogFilename(const char* name);
const char* getContextSwitchLogFilename() const;
void beginContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::thread_id_t _target_thread_id, const char* _target_process, bool _lockSpin = true);
void endContextSwitch(profiler::thread_id_t _thread_id, processid_t _process_id, profiler::timestamp_t _endtime, bool _lockSpin = true);
void startListen(uint16_t _port);
void stopListen();
bool isListening() const;
profiler::timestamp_t ticks2ns(profiler::timestamp_t ticks) const;
profiler::timestamp_t ticks2us(profiler::timestamp_t ticks) const;
static bool isMainThread();
static profiler::timestamp_t this_thread_frameTime(profiler::Duration _durationCast);
static profiler::timestamp_t this_thread_frameTimeLocalMax(profiler::Duration _durationCast);
static profiler::timestamp_t this_thread_frameTimeLocalAvg(profiler::Duration _durationCast);
static profiler::timestamp_t main_thread_frameTime(profiler::Duration _durationCast);
static profiler::timestamp_t main_thread_frameTimeLocalMax(profiler::Duration _durationCast);
static profiler::timestamp_t main_thread_frameTimeLocalAvg(profiler::Duration _durationCast);
private:
void listen(uint16_t _port);
uint32_t dumpBlocksToStream(std::ostream& _outputStream, bool _lockSpin, bool _async);
void setBlockStatus(profiler::block_id_t _id, profiler::EasyBlockStatus _status);
void registerThread();
void beginFrame();
void endFrame();
void enableEventTracer();
void disableEventTracer();
static char checkThreadExpired(ThreadStorage& _registeredThread);
void storeBlockForce(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, ::profiler::timestamp_t& _timestamp);
void storeBlockForce2(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName, ::profiler::timestamp_t _timestamp);
ThreadStorage& _threadStorage(profiler::thread_id_t _thread_id);
ThreadStorage* _findThreadStorage(profiler::thread_id_t _thread_id);
ThreadStorage& threadStorage(profiler::thread_id_t _thread_id)
{
guard_lock_t lock(m_spin);
return _threadStorage(_thread_id);
}
ThreadStorage* findThreadStorage(profiler::thread_id_t _thread_id)
{
guard_lock_t lock(m_spin);
return _findThreadStorage(_thread_id);
}
}; // END of class ProfileManager.
//////////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER_MANAGER_H

View File

@ -0,0 +1,349 @@
/************************************************************************
* file name : profiler.cpp
* ----------------- :
* creation time : 2018/05/06
* authors : Sergey Yagovtsev, Victor Zarubkin
* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of Profile manager and implement access c-function
* :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
* :
* : Licensed under either of
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* : at your option.
* :
* : 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.
* :
* : The Apache License, Version 2.0 (the "License")
* :
* : You may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
************************************************************************/
#include <easy/profiler.h>
#include <easy/arbitrary_value.h>
#include "profile_manager.h"
#include "event_trace_win.h"
#include "current_time.h"
//////////////////////////////////////////////////////////////////////////
#ifndef BUILD_WITH_EASY_PROFILER
# ifndef EASY_PROFILER_API_DISABLED
# define EASY_PROFILER_API_DISABLED
# endif
#endif
#if !defined(EASY_PROFILER_VERSION_MAJOR) || !defined(EASY_PROFILER_VERSION_MINOR) || !defined(EASY_PROFILER_VERSION_PATCH)
# ifdef _WIN32
# error EASY_PROFILER_VERSION_MAJOR and EASY_PROFILER_VERSION_MINOR and EASY_PROFILER_VERSION_PATCH macros must be defined
# else
# error "EASY_PROFILER_VERSION_MAJOR and EASY_PROFILER_VERSION_MINOR and EASY_PROFILER_VERSION_PATCH macros must be defined"
# endif
#endif
#define EASY_PROFILER_PRODUCT_VERSION "v" EASY_STRINGIFICATION(EASY_PROFILER_VERSION_MAJOR) "." \
EASY_STRINGIFICATION(EASY_PROFILER_VERSION_MINOR) "." \
EASY_STRINGIFICATION(EASY_PROFILER_VERSION_PATCH)
extern const uint32_t EASY_PROFILER_SIGNATURE = ('E' << 24) | ('a' << 16) | ('s' << 8) | 'y';
extern const uint32_t EASY_PROFILER_VERSION = (static_cast<uint32_t>(EASY_PROFILER_VERSION_MAJOR) << 24) |
(static_cast<uint32_t>(EASY_PROFILER_VERSION_MINOR) << 16) |
static_cast<uint32_t>(EASY_PROFILER_VERSION_PATCH);
#undef EASY_VERSION_INT
//////////////////////////////////////////////////////////////////////////
extern "C" {
PROFILER_API uint8_t versionMajor()
{
static_assert(0 <= EASY_PROFILER_VERSION_MAJOR && EASY_PROFILER_VERSION_MAJOR <= 255,
"EASY_PROFILER_VERSION_MAJOR must be defined in range [0, 255]");
return EASY_PROFILER_VERSION_MAJOR;
}
PROFILER_API uint8_t versionMinor()
{
static_assert(0 <= EASY_PROFILER_VERSION_MINOR && EASY_PROFILER_VERSION_MINOR <= 255,
"EASY_PROFILER_VERSION_MINOR must be defined in range [0, 255]");
return EASY_PROFILER_VERSION_MINOR;
}
PROFILER_API uint16_t versionPatch()
{
static_assert(0 <= EASY_PROFILER_VERSION_PATCH && EASY_PROFILER_VERSION_PATCH <= 65535,
"EASY_PROFILER_VERSION_PATCH must be defined in range [0, 65535]");
return EASY_PROFILER_VERSION_PATCH;
}
PROFILER_API uint32_t version()
{
return EASY_PROFILER_VERSION;
}
PROFILER_API const char* versionName()
{
#ifdef EASY_PROFILER_API_DISABLED
return EASY_PROFILER_PRODUCT_VERSION "_disabled";
#else
return EASY_PROFILER_PRODUCT_VERSION;
#endif
}
//////////////////////////////////////////////////////////////////////////
#if !defined(EASY_PROFILER_API_DISABLED)
PROFILER_API profiler::timestamp_t now()
{
return profiler::clock::now();
}
PROFILER_API profiler::timestamp_t toNanoseconds(profiler::timestamp_t _ticks)
{
return ProfileManager::instance().ticks2ns(_ticks);
}
PROFILER_API profiler::timestamp_t toMicroseconds(profiler::timestamp_t _ticks)
{
return ProfileManager::instance().ticks2us(_ticks);
}
PROFILER_API const profiler::BaseBlockDescriptor*
registerDescription(profiler::EasyBlockStatus _status, const char* _autogenUniqueId, const char* _name,
const char* _filename, int _line, profiler::block_type_t _block_type, profiler::color_t _color,
bool _copyName)
{
return ProfileManager::instance().addBlockDescriptor(_status, _autogenUniqueId, _name, _filename, _line,
_block_type, _color, _copyName);
}
PROFILER_API void endBlock()
{
ProfileManager::instance().endBlock();
}
PROFILER_API void setEnabled(bool isEnable)
{
ProfileManager::instance().setEnabled(isEnable);
}
PROFILER_API bool isEnabled()
{
return ProfileManager::instance().isEnabled();
}
PROFILER_API void storeValue(const profiler::BaseBlockDescriptor* _desc, profiler::DataType _type, const void* _data,
uint16_t _size, bool _isArray, profiler::ValueId _vin)
{
ProfileManager::instance().storeValue(_desc, _type, _data, _size, _isArray, _vin);
}
PROFILER_API void storeEvent(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName)
{
ProfileManager::instance().storeBlock(_desc, _runtimeName);
}
PROFILER_API void storeBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName,
profiler::timestamp_t _beginTime, profiler::timestamp_t _endTime)
{
ProfileManager::instance().storeBlock(_desc, _runtimeName, _beginTime, _endTime);
}
PROFILER_API void beginBlock(profiler::Block& _block)
{
ProfileManager::instance().beginBlock(_block);
}
PROFILER_API void beginNonScopedBlock(const profiler::BaseBlockDescriptor* _desc, const char* _runtimeName)
{
ProfileManager::instance().beginNonScopedBlock(_desc, _runtimeName);
}
PROFILER_API uint32_t dumpBlocksToFile(const char* filename)
{
return ProfileManager::instance().dumpBlocksToFile(filename);
}
PROFILER_API const char* registerThreadScoped(const char* name, profiler::ThreadGuard& threadGuard)
{
return ProfileManager::instance().registerThread(name, threadGuard);
}
PROFILER_API const char* registerThread(const char* name)
{
return ProfileManager::instance().registerThread(name);
}
PROFILER_API void setEventTracingEnabled(bool _isEnable)
{
ProfileManager::instance().setEventTracingEnabled(_isEnable);
}
PROFILER_API bool isEventTracingEnabled()
{
return ProfileManager::instance().isEventTracingEnabled();
}
# ifdef _WIN32
PROFILER_API void setLowPriorityEventTracing(bool _isLowPriority)
{
EasyEventTracer::instance().setLowPriority(_isLowPriority);
}
PROFILER_API bool isLowPriorityEventTracing()
{
return EasyEventTracer::instance().isLowPriority();
}
# else
PROFILER_API void setLowPriorityEventTracing(bool) { }
PROFILER_API bool isLowPriorityEventTracing() { return false; }
# endif
PROFILER_API void setContextSwitchLogFilename(const char* name)
{
return ProfileManager::instance().setContextSwitchLogFilename(name);
}
PROFILER_API const char* getContextSwitchLogFilename()
{
return ProfileManager::instance().getContextSwitchLogFilename();
}
PROFILER_API void startListen(uint16_t _port)
{
return ProfileManager::instance().startListen(_port);
}
PROFILER_API void stopListen()
{
return ProfileManager::instance().stopListen();
}
PROFILER_API bool isListening()
{
return ProfileManager::instance().isListening();
}
PROFILER_API bool isMainThread()
{
return ProfileManager::isMainThread();
}
PROFILER_API profiler::timestamp_t this_thread_frameTime(profiler::Duration _durationCast)
{
return ProfileManager::this_thread_frameTime(_durationCast);
}
PROFILER_API profiler::timestamp_t this_thread_frameTimeLocalMax(profiler::Duration _durationCast)
{
return ProfileManager::this_thread_frameTimeLocalMax(_durationCast);
}
PROFILER_API profiler::timestamp_t this_thread_frameTimeLocalAvg(profiler::Duration _durationCast)
{
return ProfileManager::this_thread_frameTimeLocalAvg(_durationCast);
}
PROFILER_API profiler::timestamp_t main_thread_frameTime(profiler::Duration _durationCast)
{
return ProfileManager::main_thread_frameTime(_durationCast);
}
PROFILER_API profiler::timestamp_t main_thread_frameTimeLocalMax(profiler::Duration _durationCast)
{
return ProfileManager::main_thread_frameTimeLocalMax(_durationCast);
}
PROFILER_API profiler::timestamp_t main_thread_frameTimeLocalAvg(profiler::Duration _durationCast)
{
return ProfileManager::main_thread_frameTimeLocalAvg(_durationCast);
}
#else // EASY_PROFILER_API_DISABLED
PROFILER_API profiler::timestamp_t now() { return 0; }
PROFILER_API profiler::timestamp_t toNanoseconds(profiler::timestamp_t) { return 0; }
PROFILER_API profiler::timestamp_t toMicroseconds(profiler::timestamp_t) { return 0; }
PROFILER_API const profiler::BaseBlockDescriptor* registerDescription(profiler::EasyBlockStatus, const char*,
const char*, const char*, int,
profiler::block_type_t, profiler::color_t, bool)
{
return reinterpret_cast<const profiler::BaseBlockDescriptor*>(0xbad);
}
PROFILER_API void endBlock() { }
PROFILER_API void setEnabled(bool) { }
PROFILER_API bool isEnabled() { return false; }
PROFILER_API void storeValue(const profiler::BaseBlockDescriptor*, profiler::DataType, const void*, uint16_t, bool,
profiler::ValueId)
{
}
PROFILER_API void storeEvent(const profiler::BaseBlockDescriptor*, const char*) { }
PROFILER_API void storeBlock(const profiler::BaseBlockDescriptor*, const char*, profiler::timestamp_t,
profiler::timestamp_t)
{
}
PROFILER_API void beginBlock(profiler::Block&) { }
PROFILER_API void beginNonScopedBlock(const profiler::BaseBlockDescriptor*, const char*) { }
PROFILER_API uint32_t dumpBlocksToFile(const char*) { return 0; }
PROFILER_API const char* registerThreadScoped(const char*, profiler::ThreadGuard&) { return ""; }
PROFILER_API const char* registerThread(const char*) { return ""; }
PROFILER_API void setEventTracingEnabled(bool) { }
PROFILER_API bool isEventTracingEnabled() { return false; }
PROFILER_API void setLowPriorityEventTracing(bool) { }
PROFILER_API bool isLowPriorityEventTracing(bool) { return false; }
PROFILER_API void setContextSwitchLogFilename(const char*) { }
PROFILER_API const char* getContextSwitchLogFilename() { return ""; }
PROFILER_API void startListen(uint16_t) { }
PROFILER_API void stopListen() { }
PROFILER_API bool isListening() { return false; }
PROFILER_API bool isMainThread() { return false; }
PROFILER_API profiler::timestamp_t this_thread_frameTime(profiler::Duration) { return 0; }
PROFILER_API profiler::timestamp_t this_thread_frameTimeLocalMax(profiler::Duration) { return 0; }
PROFILER_API profiler::timestamp_t this_thread_frameTimeLocalAvg(profiler::Duration) { return 0; }
PROFILER_API profiler::timestamp_t main_thread_frameTime(profiler::Duration) { return 0; }
PROFILER_API profiler::timestamp_t main_thread_frameTimeLocalMax(profiler::Duration) { return 0; }
PROFILER_API profiler::timestamp_t main_thread_frameTimeLocalAvg(profiler::Duration) { return 0; }
#endif // EASY_PROFILER_API_DISABLED
} // end extern "C".

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,68 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#include <string.h>
#include <easy/serialized_block.h>
#include "thread_storage.h"
namespace profiler
{
SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length)
: BaseBlockData(block)
{
char* pName = const_cast<char*>(name());
if (name_length != 0)
strncpy(pName, block.name(), name_length);
pName[name_length] = 0;
}
SerializedCSwitch::SerializedCSwitch(const CSwitchBlock& block, uint16_t name_length)
: CSwitchEvent(block)
{
char* pName = const_cast<char*>(name());
if (name_length != 0)
strncpy(pName, block.name(), name_length);
pName[name_length] = 0;
}
} // end of namespace profiler.

View File

@ -0,0 +1,126 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_SPIN_LOCK_H
#define EASY_PROFILER_SPIN_LOCK_H
#define EASY_USE_CRITICAL_SECTION // Use CRITICAL_SECTION instead of std::atomic_flag
#if defined(_WIN32) && defined(EASY_USE_CRITICAL_SECTION)
#include <Windows.h>
#else
#include <atomic>
#endif
namespace profiler {
#if defined(_WIN32) && defined(EASY_USE_CRITICAL_SECTION)
// std::atomic_flag on Windows works slower than critical section, so we will use it instead of std::atomic_flag...
// By the way, Windows critical sections are slower than std::atomic_flag on Unix.
class spin_lock { CRITICAL_SECTION m_lock; public:
void lock() {
EnterCriticalSection(&m_lock);
}
void unlock() {
LeaveCriticalSection(&m_lock);
}
spin_lock() {
InitializeCriticalSection(&m_lock);
}
~spin_lock() {
DeleteCriticalSection(&m_lock);
}
};
#else
// std::atomic_flag on Unix works fine and very fast (almost instant!)
class spin_lock { ::std::atomic_flag m_lock; public:
void lock() {
while (m_lock.test_and_set(::std::memory_order_acquire));
}
void unlock() {
m_lock.clear(::std::memory_order_release);
}
spin_lock() {
m_lock.clear();
}
};
#endif
template <class T>
class guard_lock
{
T& m_lock;
bool m_isLocked = false;
public:
explicit guard_lock(T& m) : m_lock(m) {
m_lock.lock();
m_isLocked = true;
}
~guard_lock() {
unlock();
}
inline void unlock() {
if (m_isLocked) {
m_lock.unlock();
m_isLocked = false;
}
}
};
} // END of namespace profiler.
#ifdef EASY_USE_CRITICAL_SECTION
# undef EASY_USE_CRITICAL_SECTION
#endif
#endif // EASY_PROFILER_SPIN_LOCK_H

View File

@ -0,0 +1,141 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_STACK_BUFFER_H
#define EASY_PROFILER_STACK_BUFFER_H
#include <algorithm>
#include <cstdlib>
#include <list>
#include "nonscoped_block.h"
#ifdef max
#undef max
#endif
template <class T>
inline void destroy_elem(T*)
{
}
inline void destroy_elem(NonscopedBlock* _elem)
{
_elem->destroy();
}
template <class T>
class StackBuffer
{
struct chunk { int8_t data[sizeof(T)]; };
std::list<chunk> m_overflow; ///< List of additional stack elements if current capacity of buffer is not enough
T* m_buffer; ///< Contiguous buffer used for stack
uint32_t m_size; ///< Current size of stack
uint32_t m_capacity; ///< Current capacity of m_buffer
uint32_t m_maxcapacity; ///< Maximum used capacity including m_buffer and m_overflow
public:
StackBuffer() = delete;
StackBuffer(const StackBuffer&) = delete;
StackBuffer(StackBuffer&&) = delete;
explicit StackBuffer(uint32_t N)
: m_buffer(static_cast<T*>(malloc(N * sizeof(T))))
, m_size(0)
, m_capacity(N)
, m_maxcapacity(N)
{
}
~StackBuffer()
{
for (uint32_t i = 0; i < m_size; ++i)
destroy_elem(m_buffer + i);
free(m_buffer);
for (auto& elem : m_overflow)
destroy_elem(reinterpret_cast<T*>(elem.data + 0));
}
template <class ... TArgs>
T& push(TArgs ... _args)
{
if (m_size < m_capacity)
return *(::new (m_buffer + m_size++) T(_args...));
m_overflow.emplace_back();
const uint32_t cap = m_capacity + static_cast<uint32_t>(m_overflow.size());
if (m_maxcapacity < cap)
m_maxcapacity = cap;
return *(::new (m_overflow.back().data + 0) T(_args...));
}
void pop()
{
if (m_overflow.empty())
{
// m_size should not be equal to 0 here because ProfileManager behavior does not allow such situation
destroy_elem(m_buffer + --m_size);
if (m_size == 0 && m_maxcapacity > m_capacity)
{
// When stack gone empty we can resize buffer to use enough space in the future
free(m_buffer);
m_maxcapacity = m_capacity = std::max(m_maxcapacity, m_capacity << 1);
m_buffer = static_cast<T*>(malloc(m_capacity * sizeof(T)));
}
return;
}
destroy_elem(reinterpret_cast<T*>(m_overflow.back().data + 0));
m_overflow.pop_back();
}
}; // END of class StackBuffer.
#endif // EASY_PROFILER_STACK_BUFFER_H

View File

@ -0,0 +1,237 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#include <algorithm>
#include "thread_storage.h"
#include "current_thread.h"
#include "current_time.h"
#ifdef min
#undef min
#endif
#ifdef max
#undef max
#endif
namespace {
EASY_CONSTEXPR uint16_t BASE_SIZE = static_cast<uint16_t>(sizeof(profiler::BaseBlockData) + 1U);
#if EASY_OPTION_TRUNCATE_LONG_RUNTIME_NAMES != 0
EASY_CONSTEXPR uint16_t MAX_BLOCK_NAME_LENGTH = BLOCK_CHUNK_SIZE - BASE_SIZE;
#endif
#if EASY_OPTION_CHECK_MAX_VALUE_DATA_SIZE != 0
EASY_CONSTEXPR uint16_t MAX_VALUE_DATA_SIZE = BLOCK_CHUNK_SIZE - static_cast<uint16_t>(sizeof(profiler::ArbitraryValue));
#endif
profiler::vin_t ptr2vin(const void* ptr)
{
static_assert(sizeof(uintptr_t) == sizeof(void*),
"Can not cast void* to uintptr_t. Different sizes.");
static_assert(sizeof(profiler::vin_t) >= sizeof(uintptr_t),
"Can not cast uintptr_t to vin_t. Possible truncation.");
return static_cast<profiler::vin_t>(reinterpret_cast<uintptr_t>(ptr));
}
} // end of namespace <noname>.
ThreadStorage::ThreadStorage()
: nonscopedBlocks(16)
, frameStartTime(0)
, id(getCurrentThreadId())
, stackSize(0)
, allowChildren(true)
, named(false)
, guarded(false)
, frameOpened(false)
{
expired = ATOMIC_VAR_INIT(0);
}
void ThreadStorage::storeValue(
profiler::timestamp_t _timestamp,
profiler::block_id_t _id,
profiler::DataType _type,
const void* _data,
uint16_t _size,
bool _isArray,
profiler::ValueId _vin
) {
#if EASY_OPTION_CHECK_MAX_VALUE_DATA_SIZE != 0
if (_size > MAX_VALUE_DATA_SIZE)
{
return;
}
#endif
const uint16_t serializedDataSize = _size + static_cast<uint16_t>(sizeof(profiler::ArbitraryValue));
void* data = blocks.closedList.allocate(serializedDataSize);
::new (data) profiler::ArbitraryValue(_timestamp, ptr2vin(_vin.m_id), _id, _size, _type, _isArray);
char* cdata = reinterpret_cast<char*>(data);
memcpy(cdata + sizeof(profiler::ArbitraryValue), _data, _size);
blocks.frameMemorySize += serializedDataSize;
putMarkIfEmpty();
}
void ThreadStorage::storeBlock(const profiler::Block& block)
{
#if EASY_OPTION_MEASURE_STORAGE_EXPAND != 0
EASY_LOCAL_STATIC_PTR(const BaseBlockDescriptor*, desc, \
MANAGER.addBlockDescriptor(EASY_OPTION_STORAGE_EXPAND_BLOCKS_ON ? profiler::ON : profiler::OFF, EASY_UNIQUE_LINE_ID, "EasyProfiler.ExpandStorage", \
__FILE__, __LINE__, profiler::BlockType::Block, EASY_COLOR_INTERNAL_EVENT));
EASY_THREAD_LOCAL static profiler::timestamp_t beginTime = 0ULL;
EASY_THREAD_LOCAL static profiler::timestamp_t endTime = 0ULL;
#endif
#if EASY_OPTION_TRUNCATE_LONG_RUNTIME_NAMES != 0
const uint16_t nameLength = std::min(static_cast<uint16_t>(strlen(block.name())), MAX_BLOCK_NAME_LENGTH);
#else
const uint16_t nameLength = static_cast<uint16_t>(strlen(block.name()));
#endif
#if EASY_OPTION_MEASURE_STORAGE_EXPAND == 0
const
#endif
auto serializedDataSize = static_cast<uint16_t>(BASE_SIZE + nameLength);
#if EASY_OPTION_MEASURE_STORAGE_EXPAND != 0
const bool expanded = (desc->m_status & profiler::ON) && blocks.closedList.need_expand(serializedDataSize);
if (expanded) beginTime = profiler::clock::now();
#endif
void* data = blocks.closedList.allocate(serializedDataSize);
#if EASY_OPTION_MEASURE_STORAGE_EXPAND != 0
if (expanded) endTime = profiler::clock::now();
#endif
::new (data) profiler::SerializedBlock(block, nameLength);
blocks.frameMemorySize += serializedDataSize;
#if EASY_OPTION_MEASURE_STORAGE_EXPAND != 0
if (expanded)
{
profiler::Block b(beginTime, desc->id(), "");
b.finish(endTime);
serializedDataSize = static_cast<uint16_t>(sizeof(profiler::BaseBlockData) + 1);
data = blocks.closedList.allocate(serializedDataSize);
::new (data) profiler::SerializedBlock(b, 0);
blocks.frameMemorySize += serializedDataSize;
}
#endif
}
void ThreadStorage::storeBlockForce(const profiler::Block& block)
{
const auto nameLength = static_cast<uint16_t>(strlen(block.name()));
const auto serializedDataSize = static_cast<uint16_t>(sizeof(profiler::BaseBlockData) + nameLength + 1);
void* data = blocks.closedList.marked_allocate(serializedDataSize);
::new (data) profiler::SerializedBlock(block, nameLength);
blocks.usedMemorySize += serializedDataSize;
}
void ThreadStorage::storeCSwitch(const CSwitchBlock& block)
{
const auto nameLength = static_cast<uint16_t>(strlen(block.name()));
const auto serializedDataSize = static_cast<uint16_t>(sizeof(profiler::CSwitchEvent) + nameLength + 1);
void* data = sync.closedList.allocate(serializedDataSize);
::new (data) profiler::SerializedCSwitch(block, nameLength);
sync.usedMemorySize += serializedDataSize;
}
void ThreadStorage::clearClosed()
{
blocks.clearClosed();
sync.clearClosed();
}
void ThreadStorage::popSilent()
{
if (!blocks.openedList.empty())
{
profiler::Block& top = blocks.openedList.back();
top.m_end = top.m_begin;
if (!top.m_isScoped)
nonscopedBlocks.pop();
blocks.openedList.pop_back();
}
}
void ThreadStorage::beginFrame()
{
if (!frameOpened)
{
frameStartTime = profiler::clock::now();
frameOpened = true;
}
}
profiler::timestamp_t ThreadStorage::endFrame()
{
frameOpened = false;
return profiler::clock::now() - frameStartTime;
}
void ThreadStorage::putMark()
{
blocks.closedList.put_mark();
blocks.usedMemorySize += blocks.frameMemorySize;
blocks.frameMemorySize = 0;
}
void ThreadStorage::putMarkIfEmpty()
{
if (!frameOpened)
putMark();
}

View File

@ -0,0 +1,150 @@
/**
Lightweight profiler library for c++
Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
Licensed under either of
* MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.
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.
The Apache License, Version 2.0 (the "License");
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
**/
#ifndef EASY_PROFILER_THREAD_STORAGE_H
#define EASY_PROFILER_THREAD_STORAGE_H
#include <atomic>
#include <functional>
#include <string>
#include <vector>
#include <easy/details/profiler_public_types.h>
#include <easy/details/arbitrary_value_public_types.h>
#include <easy/serialized_block.h>
#include "chunk_allocator.h"
#include "stack_buffer.h"
//////////////////////////////////////////////////////////////////////////
template <class T, const uint16_t N>
struct BlocksList
{
BlocksList(const BlocksList&) = delete;
BlocksList(BlocksList&&) = delete;
BlocksList() = default;
std::vector<T> openedList;
chunk_allocator<N> closedList;
uint64_t usedMemorySize = 0;
uint64_t frameMemorySize = 0;
void clearClosed()
{
//closedList.clear();
usedMemorySize = 0;
frameMemorySize = 0;
}
}; // END of struct BlocksList.
//////////////////////////////////////////////////////////////////////////
class CSwitchBlock : public profiler::CSwitchEvent
{
const char* m_name;
public:
CSwitchBlock(profiler::timestamp_t _begin_time, profiler::thread_id_t _tid, const char* _runtimeName) EASY_NOEXCEPT;
inline const char* name() const EASY_NOEXCEPT { return m_name; }
};
//////////////////////////////////////////////////////////////////////////
EASY_CONSTEXPR uint16_t BLOCKS_IN_CHUNK = 128U;
EASY_CONSTEXPR uint16_t SIZEOF_BLOCK = sizeof(profiler::BaseBlockData) + 1U + sizeof(uint16_t); // SerializedBlock stores BaseBlockData + at least 1 character for name ('\0') + 2 bytes for size of serialized data
EASY_CONSTEXPR uint16_t SIZEOF_CSWITCH = sizeof(profiler::CSwitchEvent) + 1U + sizeof(uint16_t); // SerializedCSwitch also stores additional 4 bytes to be able to save 64-bit thread_id
static_assert(((int)SIZEOF_BLOCK * (int)BLOCKS_IN_CHUNK) < 65536, "Chunk size for profiler::Block must be less than 65536");
static_assert(((int)SIZEOF_CSWITCH * (int)BLOCKS_IN_CHUNK) < 65536, "Chunk size for CSwitchBlock must be less than 65536");
EASY_CONSTEXPR uint16_t BLOCK_CHUNK_SIZE = get_aligned_size<SIZEOF_BLOCK * BLOCKS_IN_CHUNK>::Size;
EASY_CONSTEXPR uint16_t CSWITCH_CHUNK_SIZE = get_aligned_size<SIZEOF_BLOCK * BLOCKS_IN_CHUNK>::Size;
static_assert((BLOCK_CHUNK_SIZE % EASY_ALIGN_SIZE) == 0, "BLOCK_CHUNK_SIZE not aligned");
static_assert((CSWITCH_CHUNK_SIZE % EASY_ALIGN_SIZE) == 0, "CSWITCH_CHUNK_SIZE not aligned");
static_assert(BLOCK_CHUNK_SIZE > 2048, "wrong BLOCK_CHUNK_SIZE");
static_assert(CSWITCH_CHUNK_SIZE > 2048, "wrong CSWITCH_CHUNK_SIZE");
struct ThreadStorage EASY_FINAL
{
using BlocksStorage = BlocksList<std::reference_wrapper<profiler::Block>, BLOCK_CHUNK_SIZE>;
using ContextSwitchStorage = BlocksList<CSwitchBlock, CSWITCH_CHUNK_SIZE>;
StackBuffer<NonscopedBlock> nonscopedBlocks;
BlocksStorage blocks;
ContextSwitchStorage sync;
std::string name; ///< Thread name
profiler::timestamp_t frameStartTime; ///< Current frame start time. Used to calculate FPS.
const profiler::thread_id_t id; ///< Thread ID
std::atomic<char> expired; ///< Is thread expired
int32_t stackSize; ///< Current thread stack depth. Used when switching profiler state to begin collecting blocks only when new frame would be opened.
bool allowChildren; ///< False if one of previously opened blocks has OFF_RECURSIVE or ON_WITHOUT_CHILDREN status
bool named; ///< True if thread name was set
bool guarded; ///< True if thread has been registered using ThreadGuard
bool frameOpened; ///< Is new frame opened (this does not depend on profiling status) \sa profiledFrameOpened
void storeValue(profiler::timestamp_t _timestamp, profiler::block_id_t _id, profiler::DataType _type, const void* _data, uint16_t _size, bool _isArray, profiler::ValueId _vin);
void storeBlock(const profiler::Block& _block);
void storeBlockForce(const profiler::Block& _block);
void storeCSwitch(const CSwitchBlock& _block);
void clearClosed();
void popSilent();
void beginFrame();
profiler::timestamp_t endFrame();
void putMark();
void putMarkIfEmpty();
ThreadStorage();
ThreadStorage(const ThreadStorage&) = delete;
ThreadStorage(ThreadStorage&&) = delete;
}; // END of struct ThreadStorage.
//////////////////////////////////////////////////////////////////////////
#endif // EASY_PROFILER_THREAD_STORAGE_H

View File

@ -0,0 +1,564 @@
/************************************************************************
* file name : writer.cpp
* ----------------- :
* creation time : 2018/05/08
* authors : Sergey Yagovtsev, Victor Zarubkin
* emails : yse.sey@gmail.com, v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of fillTreesFromFile function
* : which reads profiler file and fill profiler blocks tree.
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016-2019 Sergey Yagovtsev, Victor Zarubkin
* :
* : Licensed under either of
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* : at your option.
* :
* : 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.
* :
* : The Apache License, Version 2.0 (the "License")
* :
* : You may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
************************************************************************/
#include <fstream>
#include <iterator>
#include <algorithm>
#include <easy/writer.h>
#include <easy/profiler.h>
#include "alignment_helpers.h"
//////////////////////////////////////////////////////////////////////////
extern const uint32_t EASY_PROFILER_SIGNATURE;
extern const uint32_t EASY_PROFILER_VERSION;
EASY_CONSTEXPR auto BaseCSwitchSize = sizeof(profiler::SerializedCSwitch) + 1;
//////////////////////////////////////////////////////////////////////////
struct BlocksRange
{
profiler::block_index_t begin;
profiler::block_index_t end;
BlocksRange(profiler::block_index_t size = 0)
: begin(0), end(size)
{
}
BlocksRange(profiler::block_index_t beginIndex, profiler::block_index_t endIndex)
: begin(beginIndex), end(endIndex)
{
}
};
struct BlocksMemoryAndCount
{
uint64_t usedMemorySize = 0; // memory size used by profiler blocks
profiler::block_index_t blocksCount = 0;
BlocksMemoryAndCount() = default;
BlocksMemoryAndCount& operator += (const BlocksMemoryAndCount& another)
{
usedMemorySize += another.usedMemorySize;
blocksCount += another.blocksCount;
return *this;
}
};
struct BlocksAndCSwitchesRange
{
BlocksMemoryAndCount blocksMemoryAndCount;
BlocksMemoryAndCount cswitchesMemoryAndCount;
BlocksRange blocks;
BlocksRange cswitches;
};
//////////////////////////////////////////////////////////////////////////
template <typename T>
static void write(std::ostream& _stream, const char* _data, T _size)
{
_stream.write(_data, _size);
}
template <class T>
static void write(std::ostream& _stream, const T& _data)
{
_stream.write((const char*)&_data, sizeof(T));
}
static bool update_progress_write(std::atomic<int>& progress, int new_value, std::ostream& _log)
{
auto oldprogress = progress.exchange(new_value, std::memory_order_release);
if (oldprogress < 0)
{
_log << "Writing was interrupted";
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
static BlocksRange findRange(const profiler::BlocksTree::children_t& children, profiler::timestamp_t beginTime,
profiler::timestamp_t endTime, const profiler::block_getter_fn& getter)
{
const auto size = static_cast<profiler::block_index_t>(children.size());
BlocksRange range(size);
if (size == 0)
return range;
if (beginTime <= getter(children.front()).node->begin() && getter(children.back()).node->end() <= endTime)
return range; // All blocks inside range
auto first_it = std::lower_bound(children.begin(), children.end(), beginTime,
[&](profiler::block_index_t element, profiler::timestamp_t value)
{
return getter(element).node->end() < value;
});
for (; first_it != children.end(); ++first_it)
{
const auto& child = getter(*first_it);
if (child.node->begin() >= beginTime || child.node->end() > beginTime)
break;
}
if (first_it != children.end() && getter(*first_it).node->begin() <= endTime)
{
auto last_it = std::lower_bound(children.begin(), children.end(), endTime,
[&](profiler::block_index_t element, profiler::timestamp_t value)
{
return getter(element).node->begin() <= value;
});
if (last_it != children.end() && getter(*last_it).node->end() >= beginTime)
{
const auto begin = static_cast<profiler::block_index_t>(std::distance(children.begin(), first_it));
const auto end = static_cast<profiler::block_index_t>(std::distance(children.begin(), last_it));
if (begin <= end)
{
range.begin = begin;
range.end = end;
}
}
}
return range;
}
static BlocksRange findRange(const profiler::bookmarks_t& bookmarks, profiler::timestamp_t beginTime, profiler::timestamp_t endTime)
{
const auto size = static_cast<profiler::block_index_t>(bookmarks.size());
BlocksRange range(size);
if (size == 0)
return range;
if (beginTime <= bookmarks.front().pos && bookmarks.back().pos <= endTime)
return range; // All blocks inside range
auto first_it = std::lower_bound(bookmarks.begin(), bookmarks.end(), beginTime,
[](const profiler::Bookmark& element, profiler::timestamp_t value)
{
return element.pos < value;
});
for (; first_it != bookmarks.end(); ++first_it)
{
const auto& bookmark = *first_it;
if (bookmark.pos >= beginTime)
break;
}
if (first_it != bookmarks.end() && first_it->pos <= endTime)
{
auto last_it = std::lower_bound(bookmarks.begin(), bookmarks.end(), endTime,
[](const profiler::Bookmark& element, profiler::timestamp_t value)
{
return element.pos <= value;
});
if (last_it != bookmarks.end() && last_it->pos >= beginTime)
{
const auto begin = static_cast<profiler::block_index_t>(std::distance(bookmarks.begin(), first_it));
const auto end = static_cast<profiler::block_index_t>(std::distance(bookmarks.begin(), last_it));
if (begin <= end)
{
range.begin = begin;
range.end = end;
}
}
}
return range;
}
static BlocksMemoryAndCount calculateUsedMemoryAndBlocksCount(const profiler::BlocksTree::children_t& children,
const BlocksRange& range,
const profiler::block_getter_fn& getter,
const profiler::descriptors_list_t& descriptors,
bool contextSwitches)
{
BlocksMemoryAndCount memoryAndCount;
if (!contextSwitches)
{
for (auto i = range.begin; i < range.end; ++i)
{
const auto& child = getter(children[i]);
// Calculate self memory consumption
const auto& desc = *descriptors[child.node->id()];
uint64_t usedMemorySize = 0;
if (desc.type() == profiler::BlockType::Value)
usedMemorySize = sizeof(profiler::ArbitraryValue) + child.value->data_size();
else
usedMemorySize = sizeof(profiler::SerializedBlock) + strlen(child.node->name()) + 1;
// Calculate children memory consumption
const BlocksRange childRange(0, static_cast<profiler::block_index_t>(child.children.size()));
const auto childrenMemoryAndCount = calculateUsedMemoryAndBlocksCount(child.children, childRange,
getter, descriptors,
false);
// Accumulate memory and count
memoryAndCount += childrenMemoryAndCount;
memoryAndCount.usedMemorySize += usedMemorySize;
++memoryAndCount.blocksCount;
}
}
else
{
for (auto i = range.begin; i < range.end; ++i)
{
const auto& child = getter(children[i]);
const uint64_t usedMemorySize = BaseCSwitchSize + strlen(child.cs->name());
memoryAndCount.usedMemorySize += usedMemorySize;
++memoryAndCount.blocksCount;
}
}
return memoryAndCount;
}
//////////////////////////////////////////////////////////////////////////
static void serializeBlocks(std::ostream& output, std::vector<char>& buffer,
const profiler::BlocksTree::children_t& children, const BlocksRange& range,
const profiler::block_getter_fn& getter, const profiler::descriptors_list_t& descriptors)
{
for (auto i = range.begin; i < range.end; ++i)
{
const auto& child = getter(children[i]);
// Serialize children
const BlocksRange childRange(0, static_cast<profiler::block_index_t>(child.children.size()));
serializeBlocks(output, buffer, child.children, childRange, getter, descriptors);
// Serialize self
const auto& desc = *descriptors[child.node->id()];
uint16_t usedMemorySize = 0;
if (desc.type() == profiler::BlockType::Value)
{
usedMemorySize = static_cast<uint16_t>(sizeof(profiler::ArbitraryValue)) + child.value->data_size();
buffer.resize(usedMemorySize + sizeof(uint16_t));
unaligned_store16(buffer.data(), usedMemorySize);
memcpy(buffer.data() + sizeof(uint16_t), child.value, static_cast<size_t>(usedMemorySize));
}
else
{
usedMemorySize = static_cast<uint16_t>(sizeof(profiler::SerializedBlock)
+ strlen(child.node->name()) + 1);
buffer.resize(usedMemorySize + sizeof(uint16_t));
unaligned_store16(buffer.data(), usedMemorySize);
memcpy(buffer.data() + sizeof(uint16_t), child.node, static_cast<size_t>(usedMemorySize));
if (child.node->id() != desc.id())
{
// This block id is dynamic. Restore it's value like it was before in the input .prof file
auto block = reinterpret_cast<profiler::SerializedBlock*>(buffer.data() + sizeof(uint16_t));
block->setId(desc.id());
}
}
write(output, buffer.data(), buffer.size());
}
}
static void serializeContextSwitches(std::ostream& output, std::vector<char>& buffer,
const profiler::BlocksTree::children_t& children, const BlocksRange& range,
const profiler::block_getter_fn& getter)
{
for (auto i = range.begin; i < range.end; ++i)
{
const auto& child = getter(children[i]);
const auto usedMemorySize = static_cast<uint16_t>(BaseCSwitchSize + strlen(child.cs->name()));
buffer.resize(usedMemorySize + sizeof(uint16_t));
unaligned_store16(buffer.data(), usedMemorySize);
memcpy(buffer.data() + sizeof(uint16_t), child.cs, static_cast<size_t>(usedMemorySize));
write(output, buffer.data(), buffer.size());
}
}
static void serializeDescriptors(std::ostream& output, std::vector<char>& buffer,
const profiler::descriptors_list_t& descriptors,
profiler::block_id_t descriptors_count)
{
const size_t size = std::min(descriptors.size(), static_cast<size_t>(descriptors_count));
for (size_t i = 0; i < size; ++i)
{
const auto& desc = *descriptors[i];
if (desc.id() != i)
break;
const auto usedMemorySize = static_cast<uint16_t>(sizeof(profiler::SerializedBlockDescriptor)
+ strlen(desc.name()) + strlen(desc.file()) + 2);
buffer.resize(usedMemorySize + sizeof(uint16_t));
unaligned_store16(buffer.data(), usedMemorySize);
memcpy(buffer.data() + sizeof(uint16_t), &desc, static_cast<size_t>(usedMemorySize));
write(output, buffer.data(), buffer.size());
}
}
static void serializeBookmarks(std::ostream& output, const profiler::bookmarks_t& bookmarks, const BlocksRange& range)
{
for (auto i = range.begin; i < range.end; ++i)
{
const auto& bookmark = bookmarks[i];
const auto usedMemorySize = static_cast<uint16_t>(profiler::Bookmark::BaseSize + bookmark.text.size());
write(output, usedMemorySize);
write(output, bookmark.pos);
write(output, bookmark.color);
write(output, bookmark.text.c_str(), bookmark.text.size() + 1);
}
}
//////////////////////////////////////////////////////////////////////////
extern "C" PROFILER_API profiler::block_index_t writeTreesToFile(std::atomic<int>& progress, const char* filename,
const profiler::SerializedData& serialized_descriptors,
const profiler::descriptors_list_t& descriptors,
profiler::block_id_t descriptors_count,
const profiler::thread_blocks_tree_t& trees,
const profiler::bookmarks_t& bookmarks,
profiler::block_getter_fn block_getter,
profiler::timestamp_t begin_time,
profiler::timestamp_t end_time,
profiler::processid_t pid,
std::ostream& log)
{
if (!update_progress_write(progress, 0, log))
return 0;
std::ofstream outFile(filename, std::fstream::binary);
if (!outFile.is_open())
{
log << "Can not open file " << filename;
return 0;
}
// Write data to file
auto result = writeTreesToStream(progress, outFile, serialized_descriptors, descriptors, descriptors_count, trees,
bookmarks, std::move(block_getter), begin_time, end_time, pid, log);
return result;
}
//////////////////////////////////////////////////////////////////////////
extern "C" PROFILER_API profiler::block_index_t writeTreesToStream(std::atomic<int>& progress, std::ostream& str,
const profiler::SerializedData& serialized_descriptors,
const profiler::descriptors_list_t& descriptors,
profiler::block_id_t descriptors_count,
const profiler::thread_blocks_tree_t& trees,
const profiler::bookmarks_t& bookmarks,
profiler::block_getter_fn block_getter,
profiler::timestamp_t begin_time,
profiler::timestamp_t end_time,
profiler::processid_t pid,
std::ostream& log)
{
if (trees.empty() || serialized_descriptors.empty() || descriptors_count == 0)
{
log << "Nothing to save";
return 0;
}
BlocksMemoryAndCount total;
using ranges_t = std::unordered_map<profiler::thread_id_t, BlocksAndCSwitchesRange, estd::hash<profiler::thread_id_t> >;
ranges_t block_ranges;
// Calculate block ranges and used memory (for serialization)
profiler::timestamp_t beginTime = begin_time, endTime = end_time;
size_t i = 0;
for (const auto& kv : trees)
{
const auto id = kv.first;
const auto& tree = kv.second;
BlocksAndCSwitchesRange range;
range.blocks = findRange(tree.children, begin_time, end_time, block_getter);
range.cswitches = findRange(tree.sync, begin_time, end_time, block_getter);
range.blocksMemoryAndCount = calculateUsedMemoryAndBlocksCount(tree.children, range.blocks, block_getter,
descriptors, false);
total += range.blocksMemoryAndCount;
if (range.blocksMemoryAndCount.blocksCount != 0)
{
beginTime = std::min(beginTime, block_getter(tree.children[range.blocks.begin]).node->begin());
endTime = std::max(endTime, block_getter(tree.children[range.blocks.end - 1]).node->end());
}
range.cswitchesMemoryAndCount = calculateUsedMemoryAndBlocksCount(tree.sync, range.cswitches, block_getter,
descriptors, true);
total += range.cswitchesMemoryAndCount;
if (range.cswitchesMemoryAndCount.blocksCount != 0)
{
beginTime = std::min(beginTime, block_getter(tree.children[range.cswitches.begin]).cs->begin());
endTime = std::max(endTime, block_getter(tree.children[range.cswitches.end - 1]).cs->end());
}
block_ranges[id] = range;
if (!update_progress_write(progress, 15 / static_cast<int>(trees.size() - i), log))
return 0;
++i;
}
BlocksRange bookmarksRange;
uint16_t bookmarksCount = 0;
if (!bookmarks.empty())
{
bookmarksRange = findRange(bookmarks, begin_time, end_time);
bookmarksCount = static_cast<uint16_t>(bookmarksRange.end - bookmarksRange.begin);
if (bookmarksCount != 0)
{
beginTime = std::min(beginTime, bookmarks[bookmarksRange.begin].pos);
endTime = std::max(endTime, bookmarks[bookmarksRange.end - 1].pos);
}
}
if (total.blocksCount == 0)
{
log << "Nothing to save";
return 0;
}
const uint64_t usedMemorySizeDescriptors = serialized_descriptors.size() + descriptors_count * sizeof(uint16_t);
// Write data to stream
write(str, EASY_PROFILER_SIGNATURE);
write(str, EASY_PROFILER_VERSION);
write(str, pid);
// write 0 because we do not need to convert time from ticks to nanoseconds (it's already converted)
write<int64_t>(str, 0LL); // CPU frequency
write(str, beginTime);
write(str, endTime);
write(str, total.usedMemorySize);
write(str, usedMemorySizeDescriptors);
write(str, total.blocksCount);
write(str, descriptors_count);
write(str, static_cast<uint32_t>(trees.size()));
write(str, bookmarksCount);
write(str, static_cast<uint16_t>(0)); // padding
std::vector<char> buffer;
// Serialize all descriptors
serializeDescriptors(str, buffer, descriptors, descriptors_count);
// Serialize all blocks
i = 0;
for (const auto& kv : trees)
{
const auto id = kv.first;
const auto& tree = kv.second;
const auto& range = block_ranges.at(id);
const auto nameSize = static_cast<uint16_t>(tree.thread_name.size() + 1);
write(str, id);
write(str, nameSize);
write(str, tree.name(), nameSize);
// Serialize context switches
write(str, range.cswitchesMemoryAndCount.blocksCount);
if (range.cswitchesMemoryAndCount.blocksCount != 0)
serializeContextSwitches(str, buffer, tree.sync, range.cswitches, block_getter);
// Serialize blocks
write(str, range.blocksMemoryAndCount.blocksCount);
if (range.blocksMemoryAndCount.blocksCount != 0)
serializeBlocks(str, buffer, tree.children, range.blocks, block_getter, descriptors);
if (!update_progress_write(progress, 40 + 57 / static_cast<int>(trees.size() - i), log))
return 0;
}
write(str, EASY_PROFILER_SIGNATURE);
// Serialize bookmarks
if (bookmarksCount != 0)
{
serializeBookmarks(str, bookmarks, bookmarksRange);
write(str, EASY_PROFILER_SIGNATURE);
}
return total.blocksCount;
}
//////////////////////////////////////////////////////////////////////////

25
source/3rdparty/lua/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,25 @@
file(GLOB lua_src
"include/*.h"
"src/*.c"
)
if (MINGW)
#set_source_files_properties(${lua_src} PROPERTIES COMPILE_FLAGS "-DLUA_BUILD_AS_DLL")
endif()
if (MSVC)
#set_source_files_properties(${lua_src} PROPERTIES LANGUAGE CXX )
set_source_files_properties(${lua_src} PROPERTIES COMPILE_FLAGS "-D_CRT_SECURE_NO_WARNINGS")
endif()
configure_file(
luaconf_windows.h
${PROJECT_BINARY_DIR}/luaconf.h
COPYONLY
)
#add_library(lua STATIC ${lua_src})
add_library(lua_obj OBJECT ${lua_src})
add_library(lua STATIC $<TARGET_OBJECTS:lua_obj>)

24
source/3rdparty/lua/include/lapi.h vendored Normal file
View File

@ -0,0 +1,24 @@
/*
** $Id: lapi.h,v 2.7.1.1 2013/04/12 18:48:47 roberto Exp $
** Auxiliary functions from Lua API
** See Copyright Notice in lua.h
*/
#ifndef lapi_h
#define lapi_h
#include "llimits.h"
#include "lstate.h"
#define api_incr_top(L) {L->top++; api_check(L, L->top <= L->ci->top, \
"stack overflow");}
#define adjustresults(L,nres) \
{ if ((nres) == LUA_MULTRET && L->ci->top < L->top) L->ci->top = L->top; }
#define api_checknelems(L,n) api_check(L, (n) < (L->top - L->ci->func), \
"not enough elements in the stack")
#endif

212
source/3rdparty/lua/include/lauxlib.h vendored Normal file
View File

@ -0,0 +1,212 @@
/*
** $Id: lauxlib.h,v 1.120.1.1 2013/04/12 18:48:47 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
#ifndef lauxlib_h
#define lauxlib_h
#include <stddef.h>
#include <stdio.h>
#include "lua.h"
/* extra error code for `luaL_load' */
#define LUA_ERRFILE (LUA_ERRERR+1)
typedef struct luaL_Reg {
const char *name;
lua_CFunction func;
} luaL_Reg;
LUALIB_API void (luaL_checkversion_) (lua_State *L, lua_Number ver);
#define luaL_checkversion(L) luaL_checkversion_(L, LUA_VERSION_NUM)
LUALIB_API int (luaL_getmetafield) (lua_State *L, int obj, const char *e);
LUALIB_API int (luaL_callmeta) (lua_State *L, int obj, const char *e);
LUALIB_API const char *(luaL_tolstring) (lua_State *L, int idx, size_t *len);
LUALIB_API int (luaL_argerror) (lua_State *L, int numarg, const char *extramsg);
LUALIB_API const char *(luaL_checklstring) (lua_State *L, int numArg,
size_t *l);
LUALIB_API const char *(luaL_optlstring) (lua_State *L, int numArg,
const char *def, size_t *l);
LUALIB_API lua_Number (luaL_checknumber) (lua_State *L, int numArg);
LUALIB_API lua_Number (luaL_optnumber) (lua_State *L, int nArg, lua_Number def);
LUALIB_API lua_Integer (luaL_checkinteger) (lua_State *L, int numArg);
LUALIB_API lua_Integer (luaL_optinteger) (lua_State *L, int nArg,
lua_Integer def);
LUALIB_API lua_Unsigned (luaL_checkunsigned) (lua_State *L, int numArg);
LUALIB_API lua_Unsigned (luaL_optunsigned) (lua_State *L, int numArg,
lua_Unsigned def);
LUALIB_API void (luaL_checkstack) (lua_State *L, int sz, const char *msg);
LUALIB_API void (luaL_checktype) (lua_State *L, int narg, int t);
LUALIB_API void (luaL_checkany) (lua_State *L, int narg);
LUALIB_API int (luaL_newmetatable) (lua_State *L, const char *tname);
LUALIB_API void (luaL_setmetatable) (lua_State *L, const char *tname);
LUALIB_API void *(luaL_testudata) (lua_State *L, int ud, const char *tname);
LUALIB_API void *(luaL_checkudata) (lua_State *L, int ud, const char *tname);
LUALIB_API void (luaL_where) (lua_State *L, int lvl);
LUALIB_API int (luaL_error) (lua_State *L, const char *fmt, ...);
LUALIB_API int (luaL_checkoption) (lua_State *L, int narg, const char *def,
const char *const lst[]);
LUALIB_API int (luaL_fileresult) (lua_State *L, int stat, const char *fname);
LUALIB_API int (luaL_execresult) (lua_State *L, int stat);
/* pre-defined references */
#define LUA_NOREF (-2)
#define LUA_REFNIL (-1)
LUALIB_API int (luaL_ref) (lua_State *L, int t);
LUALIB_API void (luaL_unref) (lua_State *L, int t, int ref);
LUALIB_API int (luaL_loadfilex) (lua_State *L, const char *filename,
const char *mode);
#define luaL_loadfile(L,f) luaL_loadfilex(L,f,NULL)
LUALIB_API int (luaL_loadbufferx) (lua_State *L, const char *buff, size_t sz,
const char *name, const char *mode);
LUALIB_API int (luaL_loadstring) (lua_State *L, const char *s);
LUALIB_API lua_State *(luaL_newstate) (void);
LUALIB_API int (luaL_len) (lua_State *L, int idx);
LUALIB_API const char *(luaL_gsub) (lua_State *L, const char *s, const char *p,
const char *r);
LUALIB_API void (luaL_setfuncs) (lua_State *L, const luaL_Reg *l, int nup);
LUALIB_API int (luaL_getsubtable) (lua_State *L, int idx, const char *fname);
LUALIB_API void (luaL_traceback) (lua_State *L, lua_State *L1,
const char *msg, int level);
LUALIB_API void (luaL_requiref) (lua_State *L, const char *modname,
lua_CFunction openf, int glb);
/*
** ===============================================================
** some useful macros
** ===============================================================
*/
#define luaL_newlibtable(L,l) \
lua_createtable(L, 0, sizeof(l)/sizeof((l)[0]) - 1)
#define luaL_newlib(L,l) (luaL_newlibtable(L,l), luaL_setfuncs(L,l,0))
#define luaL_argcheck(L, cond,numarg,extramsg) \
((void)((cond) || luaL_argerror(L, (numarg), (extramsg))))
#define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL))
#define luaL_optstring(L,n,d) (luaL_optlstring(L, (n), (d), NULL))
#define luaL_checkint(L,n) ((int)luaL_checkinteger(L, (n)))
#define luaL_optint(L,n,d) ((int)luaL_optinteger(L, (n), (d)))
#define luaL_checklong(L,n) ((long)luaL_checkinteger(L, (n)))
#define luaL_optlong(L,n,d) ((long)luaL_optinteger(L, (n), (d)))
#define luaL_typename(L,i) lua_typename(L, lua_type(L,(i)))
#define luaL_dofile(L, fn) \
(luaL_loadfile(L, fn) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_dostring(L, s) \
(luaL_loadstring(L, s) || lua_pcall(L, 0, LUA_MULTRET, 0))
#define luaL_getmetatable(L,n) (lua_getfield(L, LUA_REGISTRYINDEX, (n)))
#define luaL_opt(L,f,n,d) (lua_isnoneornil(L,(n)) ? (d) : f(L,(n)))
#define luaL_loadbuffer(L,s,sz,n) luaL_loadbufferx(L,s,sz,n,NULL)
/*
** {======================================================
** Generic Buffer manipulation
** =======================================================
*/
typedef struct luaL_Buffer {
char *b; /* buffer address */
size_t size; /* buffer size */
size_t n; /* number of characters in buffer */
lua_State *L;
char initb[LUAL_BUFFERSIZE]; /* initial buffer */
} luaL_Buffer;
#define luaL_addchar(B,c) \
((void)((B)->n < (B)->size || luaL_prepbuffsize((B), 1)), \
((B)->b[(B)->n++] = (c)))
#define luaL_addsize(B,s) ((B)->n += (s))
LUALIB_API void (luaL_buffinit) (lua_State *L, luaL_Buffer *B);
LUALIB_API char *(luaL_prepbuffsize) (luaL_Buffer *B, size_t sz);
LUALIB_API void (luaL_addlstring) (luaL_Buffer *B, const char *s, size_t l);
LUALIB_API void (luaL_addstring) (luaL_Buffer *B, const char *s);
LUALIB_API void (luaL_addvalue) (luaL_Buffer *B);
LUALIB_API void (luaL_pushresult) (luaL_Buffer *B);
LUALIB_API void (luaL_pushresultsize) (luaL_Buffer *B, size_t sz);
LUALIB_API char *(luaL_buffinitsize) (lua_State *L, luaL_Buffer *B, size_t sz);
#define luaL_prepbuffer(B) luaL_prepbuffsize(B, LUAL_BUFFERSIZE)
/* }====================================================== */
/*
** {======================================================
** File handles for IO library
** =======================================================
*/
/*
** A file handle is a userdata with metatable 'LUA_FILEHANDLE' and
** initial structure 'luaL_Stream' (it may contain other fields
** after that initial structure).
*/
#define LUA_FILEHANDLE "FILE*"
typedef struct luaL_Stream {
FILE *f; /* stream (NULL for incompletely created streams) */
lua_CFunction closef; /* to close stream (NULL for closed streams) */
} luaL_Stream;
/* }====================================================== */
/* compatibility with old module system */
#if defined(LUA_COMPAT_MODULE)
LUALIB_API void (luaL_pushmodule) (lua_State *L, const char *modname,
int sizehint);
LUALIB_API void (luaL_openlib) (lua_State *L, const char *libname,
const luaL_Reg *l, int nup);
#define luaL_register(L,n,l) (luaL_openlib(L,(n),(l),0))
#endif
#endif

83
source/3rdparty/lua/include/lcode.h vendored Normal file
View File

@ -0,0 +1,83 @@
/*
** $Id: lcode.h,v 1.58.1.1 2013/04/12 18:48:47 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
#ifndef lcode_h
#define lcode_h
#include "llex.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lparser.h"
/*
** Marks the end of a patch list. It is an invalid value both as an absolute
** address, and as a list link (would link an element to itself).
*/
#define NO_JUMP (-1)
/*
** grep "ORDER OPR" if you change these enums (ORDER OP)
*/
typedef enum BinOpr {
OPR_ADD, OPR_SUB, OPR_MUL, OPR_DIV, OPR_MOD, OPR_POW,
OPR_CONCAT,
OPR_EQ, OPR_LT, OPR_LE,
OPR_NE, OPR_GT, OPR_GE,
OPR_AND, OPR_OR,
OPR_NOBINOPR
} BinOpr;
typedef enum UnOpr { OPR_MINUS, OPR_NOT, OPR_LEN, OPR_NOUNOPR } UnOpr;
#define getcode(fs,e) ((fs)->f->code[(e)->u.info])
#define luaK_codeAsBx(fs,o,A,sBx) luaK_codeABx(fs,o,A,(sBx)+MAXARG_sBx)
#define luaK_setmultret(fs,e) luaK_setreturns(fs, e, LUA_MULTRET)
#define luaK_jumpto(fs,t) luaK_patchlist(fs, luaK_jump(fs), t)
LUAI_FUNC int luaK_codeABx (FuncState *fs, OpCode o, int A, unsigned int Bx);
LUAI_FUNC int luaK_codeABC (FuncState *fs, OpCode o, int A, int B, int C);
LUAI_FUNC int luaK_codek (FuncState *fs, int reg, int k);
LUAI_FUNC void luaK_fixline (FuncState *fs, int line);
LUAI_FUNC void luaK_nil (FuncState *fs, int from, int n);
LUAI_FUNC void luaK_reserveregs (FuncState *fs, int n);
LUAI_FUNC void luaK_checkstack (FuncState *fs, int n);
LUAI_FUNC int luaK_stringK (FuncState *fs, TString *s);
LUAI_FUNC int luaK_numberK (FuncState *fs, lua_Number r);
LUAI_FUNC void luaK_dischargevars (FuncState *fs, expdesc *e);
LUAI_FUNC int luaK_exp2anyreg (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2anyregup (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2nextreg (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_exp2val (FuncState *fs, expdesc *e);
LUAI_FUNC int luaK_exp2RK (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_self (FuncState *fs, expdesc *e, expdesc *key);
LUAI_FUNC void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k);
LUAI_FUNC void luaK_goiftrue (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_goiffalse (FuncState *fs, expdesc *e);
LUAI_FUNC void luaK_storevar (FuncState *fs, expdesc *var, expdesc *e);
LUAI_FUNC void luaK_setreturns (FuncState *fs, expdesc *e, int nresults);
LUAI_FUNC void luaK_setoneret (FuncState *fs, expdesc *e);
LUAI_FUNC int luaK_jump (FuncState *fs);
LUAI_FUNC void luaK_ret (FuncState *fs, int first, int nret);
LUAI_FUNC void luaK_patchlist (FuncState *fs, int list, int target);
LUAI_FUNC void luaK_patchtohere (FuncState *fs, int list);
LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level);
LUAI_FUNC void luaK_concat (FuncState *fs, int *l1, int l2);
LUAI_FUNC int luaK_getlabel (FuncState *fs);
LUAI_FUNC void luaK_prefix (FuncState *fs, UnOpr op, expdesc *v, int line);
LUAI_FUNC void luaK_infix (FuncState *fs, BinOpr op, expdesc *v);
LUAI_FUNC void luaK_posfix (FuncState *fs, BinOpr op, expdesc *v1,
expdesc *v2, int line);
LUAI_FUNC void luaK_setlist (FuncState *fs, int base, int nelems, int tostore);
#endif

95
source/3rdparty/lua/include/lctype.h vendored Normal file
View File

@ -0,0 +1,95 @@
/*
** $Id: lctype.h,v 1.12.1.1 2013/04/12 18:48:47 roberto Exp $
** 'ctype' functions for Lua
** See Copyright Notice in lua.h
*/
#ifndef lctype_h
#define lctype_h
#include "lua.h"
/*
** WARNING: the functions defined here do not necessarily correspond
** to the similar functions in the standard C ctype.h. They are
** optimized for the specific needs of Lua
*/
#if !defined(LUA_USE_CTYPE)
#if 'A' == 65 && '0' == 48
/* ASCII case: can use its own tables; faster and fixed */
#define LUA_USE_CTYPE 0
#else
/* must use standard C ctype */
#define LUA_USE_CTYPE 1
#endif
#endif
#if !LUA_USE_CTYPE /* { */
#include <limits.h>
#include "llimits.h"
#define ALPHABIT 0
#define DIGITBIT 1
#define PRINTBIT 2
#define SPACEBIT 3
#define XDIGITBIT 4
#define MASK(B) (1 << (B))
/*
** add 1 to char to allow index -1 (EOZ)
*/
#define testprop(c,p) (luai_ctype_[(c)+1] & (p))
/*
** 'lalpha' (Lua alphabetic) and 'lalnum' (Lua alphanumeric) both include '_'
*/
#define lislalpha(c) testprop(c, MASK(ALPHABIT))
#define lislalnum(c) testprop(c, (MASK(ALPHABIT) | MASK(DIGITBIT)))
#define lisdigit(c) testprop(c, MASK(DIGITBIT))
#define lisspace(c) testprop(c, MASK(SPACEBIT))
#define lisprint(c) testprop(c, MASK(PRINTBIT))
#define lisxdigit(c) testprop(c, MASK(XDIGITBIT))
/*
** this 'ltolower' only works for alphabetic characters
*/
#define ltolower(c) ((c) | ('A' ^ 'a'))
/* two more entries for 0 and -1 (EOZ) */
LUAI_DDEC const lu_byte luai_ctype_[UCHAR_MAX + 2];
#else /* }{ */
/*
** use standard C ctypes
*/
#include <ctype.h>
#define lislalpha(c) (isalpha(c) || (c) == '_')
#define lislalnum(c) (isalnum(c) || (c) == '_')
#define lisdigit(c) (isdigit(c))
#define lisspace(c) (isspace(c))
#define lisprint(c) (isprint(c))
#define lisxdigit(c) (isxdigit(c))
#define ltolower(c) (tolower(c))
#endif /* } */
#endif

34
source/3rdparty/lua/include/ldebug.h vendored Normal file
View File

@ -0,0 +1,34 @@
/*
** $Id: ldebug.h,v 2.7.1.1 2013/04/12 18:48:47 roberto Exp $
** Auxiliary functions from Debug Interface module
** See Copyright Notice in lua.h
*/
#ifndef ldebug_h
#define ldebug_h
#include "lstate.h"
#define pcRel(pc, p) (cast(int, (pc) - (p)->code) - 1)
#define getfuncline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0)
#define resethookcount(L) (L->hookcount = L->basehookcount)
/* Active Lua function (given call info) */
#define ci_func(ci) (clLvalue((ci)->func))
LUAI_FUNC l_noret luaG_typeerror (lua_State *L, const TValue *o,
const char *opname);
LUAI_FUNC l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2);
LUAI_FUNC l_noret luaG_aritherror (lua_State *L, const TValue *p1,
const TValue *p2);
LUAI_FUNC l_noret luaG_ordererror (lua_State *L, const TValue *p1,
const TValue *p2);
LUAI_FUNC l_noret luaG_runerror (lua_State *L, const char *fmt, ...);
LUAI_FUNC l_noret luaG_errormsg (lua_State *L);
#endif

46
source/3rdparty/lua/include/ldo.h vendored Normal file
View File

@ -0,0 +1,46 @@
/*
** $Id: ldo.h,v 2.20.1.1 2013/04/12 18:48:47 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
#ifndef ldo_h
#define ldo_h
#include "lobject.h"
#include "lstate.h"
#include "lzio.h"
#define luaD_checkstack(L,n) if (L->stack_last - L->top <= (n)) \
luaD_growstack(L, n); else condmovestack(L);
#define incr_top(L) {L->top++; luaD_checkstack(L,0);}
#define savestack(L,p) ((char *)(p) - (char *)L->stack)
#define restorestack(L,n) ((TValue *)((char *)L->stack + (n)))
/* type of protected functions, to be ran by `runprotected' */
typedef void (*Pfunc) (lua_State *L, void *ud);
LUAI_FUNC int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
const char *mode);
LUAI_FUNC void luaD_hook (lua_State *L, int event, int line);
LUAI_FUNC int luaD_precall (lua_State *L, StkId func, int nresults);
LUAI_FUNC void luaD_call (lua_State *L, StkId func, int nResults,
int allowyield);
LUAI_FUNC int luaD_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t oldtop, ptrdiff_t ef);
LUAI_FUNC int luaD_poscall (lua_State *L, StkId firstResult);
LUAI_FUNC void luaD_reallocstack (lua_State *L, int newsize);
LUAI_FUNC void luaD_growstack (lua_State *L, int n);
LUAI_FUNC void luaD_shrinkstack (lua_State *L);
LUAI_FUNC l_noret luaD_throw (lua_State *L, int errcode);
LUAI_FUNC int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud);
#endif

33
source/3rdparty/lua/include/lfunc.h vendored Normal file
View File

@ -0,0 +1,33 @@
/*
** $Id: lfunc.h,v 2.8.1.1 2013/04/12 18:48:47 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
#ifndef lfunc_h
#define lfunc_h
#include "lobject.h"
#define sizeCclosure(n) (cast(int, sizeof(CClosure)) + \
cast(int, sizeof(TValue)*((n)-1)))
#define sizeLclosure(n) (cast(int, sizeof(LClosure)) + \
cast(int, sizeof(TValue *)*((n)-1)))
LUAI_FUNC Proto *luaF_newproto (lua_State *L);
LUAI_FUNC Closure *luaF_newCclosure (lua_State *L, int nelems);
LUAI_FUNC Closure *luaF_newLclosure (lua_State *L, int nelems);
LUAI_FUNC UpVal *luaF_newupval (lua_State *L);
LUAI_FUNC UpVal *luaF_findupval (lua_State *L, StkId level);
LUAI_FUNC void luaF_close (lua_State *L, StkId level);
LUAI_FUNC void luaF_freeproto (lua_State *L, Proto *f);
LUAI_FUNC void luaF_freeupval (lua_State *L, UpVal *uv);
LUAI_FUNC const char *luaF_getlocalname (const Proto *func, int local_number,
int pc);
#endif

157
source/3rdparty/lua/include/lgc.h vendored Normal file
View File

@ -0,0 +1,157 @@
/*
** $Id: lgc.h,v 2.58.1.1 2013/04/12 18:48:47 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
#ifndef lgc_h
#define lgc_h
#include "lobject.h"
#include "lstate.h"
/*
** Collectable objects may have one of three colors: white, which
** means the object is not marked; gray, which means the
** object is marked, but its references may be not marked; and
** black, which means that the object and all its references are marked.
** The main invariant of the garbage collector, while marking objects,
** is that a black object can never point to a white one. Moreover,
** any gray object must be in a "gray list" (gray, grayagain, weak,
** allweak, ephemeron) so that it can be visited again before finishing
** the collection cycle. These lists have no meaning when the invariant
** is not being enforced (e.g., sweep phase).
*/
/* how much to allocate before next GC step */
#if !defined(GCSTEPSIZE)
/* ~100 small strings */
#define GCSTEPSIZE (cast_int(100 * sizeof(TString)))
#endif
/*
** Possible states of the Garbage Collector
*/
#define GCSpropagate 0
#define GCSatomic 1
#define GCSsweepstring 2
#define GCSsweepudata 3
#define GCSsweep 4
#define GCSpause 5
#define issweepphase(g) \
(GCSsweepstring <= (g)->gcstate && (g)->gcstate <= GCSsweep)
#define isgenerational(g) ((g)->gckind == KGC_GEN)
/*
** macros to tell when main invariant (white objects cannot point to black
** ones) must be kept. During a non-generational collection, the sweep
** phase may break the invariant, as objects turned white may point to
** still-black objects. The invariant is restored when sweep ends and
** all objects are white again. During a generational collection, the
** invariant must be kept all times.
*/
#define keepinvariant(g) (isgenerational(g) || g->gcstate <= GCSatomic)
/*
** Outside the collector, the state in generational mode is kept in
** 'propagate', so 'keepinvariant' is always true.
*/
#define keepinvariantout(g) \
check_exp(g->gcstate == GCSpropagate || !isgenerational(g), \
g->gcstate <= GCSatomic)
/*
** some useful bit tricks
*/
#define resetbits(x,m) ((x) &= cast(lu_byte, ~(m)))
#define setbits(x,m) ((x) |= (m))
#define testbits(x,m) ((x) & (m))
#define bitmask(b) (1<<(b))
#define bit2mask(b1,b2) (bitmask(b1) | bitmask(b2))
#define l_setbit(x,b) setbits(x, bitmask(b))
#define resetbit(x,b) resetbits(x, bitmask(b))
#define testbit(x,b) testbits(x, bitmask(b))
/* Layout for bit use in `marked' field: */
#define WHITE0BIT 0 /* object is white (type 0) */
#define WHITE1BIT 1 /* object is white (type 1) */
#define BLACKBIT 2 /* object is black */
#define FINALIZEDBIT 3 /* object has been separated for finalization */
#define SEPARATED 4 /* object is in 'finobj' list or in 'tobefnz' */
#define FIXEDBIT 5 /* object is fixed (should not be collected) */
#define OLDBIT 6 /* object is old (only in generational mode) */
/* bit 7 is currently used by tests (luaL_checkmemory) */
#define WHITEBITS bit2mask(WHITE0BIT, WHITE1BIT)
#define iswhite(x) testbits((x)->gch.marked, WHITEBITS)
#define isblack(x) testbit((x)->gch.marked, BLACKBIT)
#define isgray(x) /* neither white nor black */ \
(!testbits((x)->gch.marked, WHITEBITS | bitmask(BLACKBIT)))
#define isold(x) testbit((x)->gch.marked, OLDBIT)
/* MOVE OLD rule: whenever an object is moved to the beginning of
a GC list, its old bit must be cleared */
#define resetoldbit(o) resetbit((o)->gch.marked, OLDBIT)
#define otherwhite(g) (g->currentwhite ^ WHITEBITS)
#define isdeadm(ow,m) (!(((m) ^ WHITEBITS) & (ow)))
#define isdead(g,v) isdeadm(otherwhite(g), (v)->gch.marked)
#define changewhite(x) ((x)->gch.marked ^= WHITEBITS)
#define gray2black(x) l_setbit((x)->gch.marked, BLACKBIT)
#define valiswhite(x) (iscollectable(x) && iswhite(gcvalue(x)))
#define luaC_white(g) cast(lu_byte, (g)->currentwhite & WHITEBITS)
#define luaC_condGC(L,c) \
{if (G(L)->GCdebt > 0) {c;}; condchangemem(L);}
#define luaC_checkGC(L) luaC_condGC(L, luaC_step(L);)
#define luaC_barrier(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \
luaC_barrier_(L,obj2gco(p),gcvalue(v)); }
#define luaC_barrierback(L,p,v) { if (valiswhite(v) && isblack(obj2gco(p))) \
luaC_barrierback_(L,p); }
#define luaC_objbarrier(L,p,o) \
{ if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) \
luaC_barrier_(L,obj2gco(p),obj2gco(o)); }
#define luaC_objbarrierback(L,p,o) \
{ if (iswhite(obj2gco(o)) && isblack(obj2gco(p))) luaC_barrierback_(L,p); }
#define luaC_barrierproto(L,p,c) \
{ if (isblack(obj2gco(p))) luaC_barrierproto_(L,p,c); }
LUAI_FUNC void luaC_freeallobjects (lua_State *L);
LUAI_FUNC void luaC_step (lua_State *L);
LUAI_FUNC void luaC_forcestep (lua_State *L);
LUAI_FUNC void luaC_runtilstate (lua_State *L, int statesmask);
LUAI_FUNC void luaC_fullgc (lua_State *L, int isemergency);
LUAI_FUNC GCObject *luaC_newobj (lua_State *L, int tt, size_t sz,
GCObject **list, int offset);
LUAI_FUNC void luaC_barrier_ (lua_State *L, GCObject *o, GCObject *v);
LUAI_FUNC void luaC_barrierback_ (lua_State *L, GCObject *o);
LUAI_FUNC void luaC_barrierproto_ (lua_State *L, Proto *p, Closure *c);
LUAI_FUNC void luaC_checkfinalizer (lua_State *L, GCObject *o, Table *mt);
LUAI_FUNC void luaC_checkupvalcolor (global_State *g, UpVal *uv);
LUAI_FUNC void luaC_changemode (lua_State *L, int mode);
#endif

78
source/3rdparty/lua/include/llex.h vendored Normal file
View File

@ -0,0 +1,78 @@
/*
** $Id: llex.h,v 1.72.1.1 2013/04/12 18:48:47 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
#ifndef llex_h
#define llex_h
#include "lobject.h"
#include "lzio.h"
#define FIRST_RESERVED 257
/*
* WARNING: if you change the order of this enumeration,
* grep "ORDER RESERVED"
*/
enum RESERVED {
/* terminal symbols denoted by reserved words */
TK_AND = FIRST_RESERVED, TK_BREAK,
TK_DO, TK_ELSE, TK_ELSEIF, TK_END, TK_FALSE, TK_FOR, TK_FUNCTION,
TK_GOTO, TK_IF, TK_IN, TK_LOCAL, TK_NIL, TK_NOT, TK_OR, TK_REPEAT,
TK_RETURN, TK_THEN, TK_TRUE, TK_UNTIL, TK_WHILE,
/* other terminal symbols */
TK_CONCAT, TK_DOTS, TK_EQ, TK_GE, TK_LE, TK_NE, TK_DBCOLON, TK_EOS,
TK_NUMBER, TK_NAME, TK_STRING
};
/* number of reserved words */
#define NUM_RESERVED (cast(int, TK_WHILE-FIRST_RESERVED+1))
typedef union {
lua_Number r;
TString *ts;
} SemInfo; /* semantics information */
typedef struct Token {
int token;
SemInfo seminfo;
} Token;
/* state of the lexer plus state of the parser when shared by all
functions */
typedef struct LexState {
int current; /* current character (charint) */
int linenumber; /* input line counter */
int lastline; /* line of last token `consumed' */
Token t; /* current token */
Token lookahead; /* look ahead token */
struct FuncState *fs; /* current function (parser) */
struct lua_State *L;
ZIO *z; /* input stream */
Mbuffer *buff; /* buffer for tokens */
struct Dyndata *dyd; /* dynamic structures used by the parser */
TString *source; /* current source name */
TString *envn; /* environment variable name */
char decpoint; /* locale decimal point */
} LexState;
LUAI_FUNC void luaX_init (lua_State *L);
LUAI_FUNC void luaX_setinput (lua_State *L, LexState *ls, ZIO *z,
TString *source, int firstchar);
LUAI_FUNC TString *luaX_newstring (LexState *ls, const char *str, size_t l);
LUAI_FUNC void luaX_next (LexState *ls);
LUAI_FUNC int luaX_lookahead (LexState *ls);
LUAI_FUNC l_noret luaX_syntaxerror (LexState *ls, const char *s);
LUAI_FUNC const char *luaX_token2str (LexState *ls, int token);
#endif

309
source/3rdparty/lua/include/llimits.h vendored Normal file
View File

@ -0,0 +1,309 @@
/*
** $Id: llimits.h,v 1.103.1.1 2013/04/12 18:48:47 roberto Exp $
** Limits, basic types, and some other `installation-dependent' definitions
** See Copyright Notice in lua.h
*/
#ifndef llimits_h
#define llimits_h
#include <limits.h>
#include <stddef.h>
#include "lua.h"
typedef unsigned LUA_INT32 lu_int32;
typedef LUAI_UMEM lu_mem;
typedef LUAI_MEM l_mem;
/* chars used as small naturals (so that `char' is reserved for characters) */
typedef unsigned char lu_byte;
#define MAX_SIZET ((size_t)(~(size_t)0)-2)
#define MAX_LUMEM ((lu_mem)(~(lu_mem)0)-2)
#define MAX_LMEM ((l_mem) ((MAX_LUMEM >> 1) - 2))
#define MAX_INT (INT_MAX-2) /* maximum value of an int (-2 for safety) */
/*
** conversion of pointer to integer
** this is for hashing only; there is no problem if the integer
** cannot hold the whole pointer value
*/
#define IntPoint(p) ((unsigned int)(lu_mem)(p))
/* type to ensure maximum alignment */
#if !defined(LUAI_USER_ALIGNMENT_T)
#define LUAI_USER_ALIGNMENT_T union { double u; void *s; long l; }
#endif
typedef LUAI_USER_ALIGNMENT_T L_Umaxalign;
/* result of a `usual argument conversion' over lua_Number */
typedef LUAI_UACNUMBER l_uacNumber;
/* internal assertions for in-house debugging */
#if defined(lua_assert)
#define check_exp(c,e) (lua_assert(c), (e))
/* to avoid problems with conditions too long */
#define lua_longassert(c) { if (!(c)) lua_assert(0); }
#else
#define lua_assert(c) ((void)0)
#define check_exp(c,e) (e)
#define lua_longassert(c) ((void)0)
#endif
/*
** assertion for checking API calls
*/
#if !defined(luai_apicheck)
#if defined(LUA_USE_APICHECK)
#include <assert.h>
#define luai_apicheck(L,e) assert(e)
#else
#define luai_apicheck(L,e) lua_assert(e)
#endif
#endif
#define api_check(l,e,msg) luai_apicheck(l,(e) && msg)
#if !defined(UNUSED)
#define UNUSED(x) ((void)(x)) /* to avoid warnings */
#endif
#define cast(t, exp) ((t)(exp))
#define cast_byte(i) cast(lu_byte, (i))
#define cast_num(i) cast(lua_Number, (i))
#define cast_int(i) cast(int, (i))
#define cast_uchar(i) cast(unsigned char, (i))
/*
** non-return type
*/
#if defined(__GNUC__)
#define l_noret void __attribute__((noreturn))
#elif defined(_MSC_VER)
#define l_noret void __declspec(noreturn)
#else
#define l_noret void
#endif
/*
** maximum depth for nested C calls and syntactical nested non-terminals
** in a program. (Value must fit in an unsigned short int.)
*/
#if !defined(LUAI_MAXCCALLS)
#define LUAI_MAXCCALLS 200
#endif
/*
** maximum number of upvalues in a closure (both C and Lua). (Value
** must fit in an unsigned char.)
*/
#define MAXUPVAL UCHAR_MAX
/*
** type for virtual-machine instructions
** must be an unsigned with (at least) 4 bytes (see details in lopcodes.h)
*/
typedef lu_int32 Instruction;
/* maximum stack for a Lua function */
#define MAXSTACK 250
/* minimum size for the string table (must be power of 2) */
#if !defined(MINSTRTABSIZE)
#define MINSTRTABSIZE 32
#endif
/* minimum size for string buffer */
#if !defined(LUA_MINBUFFER)
#define LUA_MINBUFFER 32
#endif
#if !defined(lua_lock)
#define lua_lock(L) ((void) 0)
#define lua_unlock(L) ((void) 0)
#endif
#if !defined(luai_threadyield)
#define luai_threadyield(L) {lua_unlock(L); lua_lock(L);}
#endif
/*
** these macros allow user-specific actions on threads when you defined
** LUAI_EXTRASPACE and need to do something extra when a thread is
** created/deleted/resumed/yielded.
*/
#if !defined(luai_userstateopen)
#define luai_userstateopen(L) ((void)L)
#endif
#if !defined(luai_userstateclose)
#define luai_userstateclose(L) ((void)L)
#endif
#if !defined(luai_userstatethread)
#define luai_userstatethread(L,L1) ((void)L)
#endif
#if !defined(luai_userstatefree)
#define luai_userstatefree(L,L1) ((void)L)
#endif
#if !defined(luai_userstateresume)
#define luai_userstateresume(L,n) ((void)L)
#endif
#if !defined(luai_userstateyield)
#define luai_userstateyield(L,n) ((void)L)
#endif
/*
** lua_number2int is a macro to convert lua_Number to int.
** lua_number2integer is a macro to convert lua_Number to lua_Integer.
** lua_number2unsigned is a macro to convert a lua_Number to a lua_Unsigned.
** lua_unsigned2number is a macro to convert a lua_Unsigned to a lua_Number.
** luai_hashnum is a macro to hash a lua_Number value into an integer.
** The hash must be deterministic and give reasonable values for
** both small and large values (outside the range of integers).
*/
#if defined(MS_ASMTRICK) || defined(LUA_MSASMTRICK) /* { */
/* trick with Microsoft assembler for X86 */
#define lua_number2int(i,n) __asm {__asm fld n __asm fistp i}
#define lua_number2integer(i,n) lua_number2int(i, n)
#define lua_number2unsigned(i,n) \
{__int64 l; __asm {__asm fld n __asm fistp l} i = (unsigned int)l;}
#elif defined(LUA_IEEE754TRICK) /* }{ */
/* the next trick should work on any machine using IEEE754 with
a 32-bit int type */
union luai_Cast { double l_d; LUA_INT32 l_p[2]; };
#if !defined(LUA_IEEEENDIAN) /* { */
#define LUAI_EXTRAIEEE \
static const union luai_Cast ieeeendian = {-(33.0 + 6755399441055744.0)};
#define LUA_IEEEENDIANLOC (ieeeendian.l_p[1] == 33)
#else
#define LUA_IEEEENDIANLOC LUA_IEEEENDIAN
#define LUAI_EXTRAIEEE /* empty */
#endif /* } */
#define lua_number2int32(i,n,t) \
{ LUAI_EXTRAIEEE \
volatile union luai_Cast u; u.l_d = (n) + 6755399441055744.0; \
(i) = (t)u.l_p[LUA_IEEEENDIANLOC]; }
#define luai_hashnum(i,n) \
{ volatile union luai_Cast u; u.l_d = (n) + 1.0; /* avoid -0 */ \
(i) = u.l_p[0]; (i) += u.l_p[1]; } /* add double bits for his hash */
#define lua_number2int(i,n) lua_number2int32(i, n, int)
#define lua_number2unsigned(i,n) lua_number2int32(i, n, lua_Unsigned)
/* the trick can be expanded to lua_Integer when it is a 32-bit value */
#if defined(LUA_IEEELL)
#define lua_number2integer(i,n) lua_number2int32(i, n, lua_Integer)
#endif
#endif /* } */
/* the following definitions always work, but may be slow */
#if !defined(lua_number2int)
#define lua_number2int(i,n) ((i)=(int)(n))
#endif
#if !defined(lua_number2integer)
#define lua_number2integer(i,n) ((i)=(lua_Integer)(n))
#endif
#if !defined(lua_number2unsigned) /* { */
/* the following definition assures proper modulo behavior */
#if defined(LUA_NUMBER_DOUBLE) || defined(LUA_NUMBER_FLOAT)
#include <math.h>
#define SUPUNSIGNED ((lua_Number)(~(lua_Unsigned)0) + 1)
#define lua_number2unsigned(i,n) \
((i)=(lua_Unsigned)((n) - floor((n)/SUPUNSIGNED)*SUPUNSIGNED))
#else
#define lua_number2unsigned(i,n) ((i)=(lua_Unsigned)(n))
#endif
#endif /* } */
#if !defined(lua_unsigned2number)
/* on several machines, coercion from unsigned to double is slow,
so it may be worth to avoid */
#define lua_unsigned2number(u) \
(((u) <= (lua_Unsigned)INT_MAX) ? (lua_Number)(int)(u) : (lua_Number)(u))
#endif
#if defined(ltable_c) && !defined(luai_hashnum)
#include <float.h>
#include <math.h>
#define luai_hashnum(i,n) { int e; \
n = l_mathop(frexp)(n, &e) * (lua_Number)(INT_MAX - DBL_MAX_EXP); \
lua_number2int(i, n); i += e; }
#endif
/*
** macro to control inclusion of some hard tests on stack reallocation
*/
#if !defined(HARDSTACKTESTS)
#define condmovestack(L) ((void)0)
#else
/* realloc stack keeping its size */
#define condmovestack(L) luaD_reallocstack((L), (L)->stacksize)
#endif
#if !defined(HARDMEMTESTS)
#define condchangemem(L) condmovestack(L)
#else
#define condchangemem(L) \
((void)(!(G(L)->gcrunning) || (luaC_fullgc(L, 0), 1)))
#endif
#endif

57
source/3rdparty/lua/include/lmem.h vendored Normal file
View File

@ -0,0 +1,57 @@
/*
** $Id: lmem.h,v 1.40.1.1 2013/04/12 18:48:47 roberto Exp $
** Interface to Memory Manager
** See Copyright Notice in lua.h
*/
#ifndef lmem_h
#define lmem_h
#include <stddef.h>
#include "llimits.h"
#include "lua.h"
/*
** This macro avoids the runtime division MAX_SIZET/(e), as 'e' is
** always constant.
** The macro is somewhat complex to avoid warnings:
** +1 avoids warnings of "comparison has constant result";
** cast to 'void' avoids warnings of "value unused".
*/
#define luaM_reallocv(L,b,on,n,e) \
(cast(void, \
(cast(size_t, (n)+1) > MAX_SIZET/(e)) ? (luaM_toobig(L), 0) : 0), \
luaM_realloc_(L, (b), (on)*(e), (n)*(e)))
#define luaM_freemem(L, b, s) luaM_realloc_(L, (b), (s), 0)
#define luaM_free(L, b) luaM_realloc_(L, (b), sizeof(*(b)), 0)
#define luaM_freearray(L, b, n) luaM_reallocv(L, (b), n, 0, sizeof((b)[0]))
#define luaM_malloc(L,s) luaM_realloc_(L, NULL, 0, (s))
#define luaM_new(L,t) cast(t *, luaM_malloc(L, sizeof(t)))
#define luaM_newvector(L,n,t) \
cast(t *, luaM_reallocv(L, NULL, 0, n, sizeof(t)))
#define luaM_newobject(L,tag,s) luaM_realloc_(L, NULL, tag, (s))
#define luaM_growvector(L,v,nelems,size,t,limit,e) \
if ((nelems)+1 > (size)) \
((v)=cast(t *, luaM_growaux_(L,v,&(size),sizeof(t),limit,e)))
#define luaM_reallocvector(L, v,oldn,n,t) \
((v)=cast(t *, luaM_reallocv(L, v, oldn, n, sizeof(t))))
LUAI_FUNC l_noret luaM_toobig (lua_State *L);
/* not to be called directly */
LUAI_FUNC void *luaM_realloc_ (lua_State *L, void *block, size_t oldsize,
size_t size);
LUAI_FUNC void *luaM_growaux_ (lua_State *L, void *block, int *size,
size_t size_elem, int limit,
const char *what);
#endif

607
source/3rdparty/lua/include/lobject.h vendored Normal file
View File

@ -0,0 +1,607 @@
/*
** $Id: lobject.h,v 2.71.1.2 2014/05/07 14:14:58 roberto Exp $
** Type definitions for Lua objects
** See Copyright Notice in lua.h
*/
#ifndef lobject_h
#define lobject_h
#include <stdarg.h>
#include "llimits.h"
#include "lua.h"
/*
** Extra tags for non-values
*/
#define LUA_TPROTO LUA_NUMTAGS
#define LUA_TUPVAL (LUA_NUMTAGS+1)
#define LUA_TDEADKEY (LUA_NUMTAGS+2)
/*
** number of all possible tags (including LUA_TNONE but excluding DEADKEY)
*/
#define LUA_TOTALTAGS (LUA_TUPVAL+2)
/*
** tags for Tagged Values have the following use of bits:
** bits 0-3: actual tag (a LUA_T* value)
** bits 4-5: variant bits
** bit 6: whether value is collectable
*/
#define VARBITS (3 << 4)
/*
** LUA_TFUNCTION variants:
** 0 - Lua function
** 1 - light C function
** 2 - regular C function (closure)
*/
/* Variant tags for functions */
#define LUA_TLCL (LUA_TFUNCTION | (0 << 4)) /* Lua closure */
#define LUA_TLCF (LUA_TFUNCTION | (1 << 4)) /* light C function */
#define LUA_TCCL (LUA_TFUNCTION | (2 << 4)) /* C closure */
/* Variant tags for strings */
#define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) /* short strings */
#define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */
/* Bit mark for collectable types */
#define BIT_ISCOLLECTABLE (1 << 6)
/* mark a tag as collectable */
#define ctb(t) ((t) | BIT_ISCOLLECTABLE)
/*
** Union of all collectable objects
*/
typedef union GCObject GCObject;
/*
** Common Header for all collectable objects (in macro form, to be
** included in other objects)
*/
#define CommonHeader GCObject *next; lu_byte tt; lu_byte marked
/*
** Common header in struct form
*/
typedef struct GCheader {
CommonHeader;
} GCheader;
/*
** Union of all Lua values
*/
typedef union Value Value;
#define numfield lua_Number n; /* numbers */
/*
** Tagged Values. This is the basic representation of values in Lua,
** an actual value plus a tag with its type.
*/
#define TValuefields Value value_; int tt_
typedef struct lua_TValue TValue;
/* macro defining a nil value */
#define NILCONSTANT {NULL}, LUA_TNIL
#define val_(o) ((o)->value_)
#define num_(o) (val_(o).n)
/* raw type tag of a TValue */
#define rttype(o) ((o)->tt_)
/* tag with no variants (bits 0-3) */
#define novariant(x) ((x) & 0x0F)
/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */
#define ttype(o) (rttype(o) & 0x3F)
/* type tag of a TValue with no variants (bits 0-3) */
#define ttypenv(o) (novariant(rttype(o)))
/* Macros to test type */
#define checktag(o,t) (rttype(o) == (t))
#define checktype(o,t) (ttypenv(o) == (t))
#define ttisnumber(o) checktag((o), LUA_TNUMBER)
#define ttisnil(o) checktag((o), LUA_TNIL)
#define ttisboolean(o) checktag((o), LUA_TBOOLEAN)
#define ttislightuserdata(o) checktag((o), LUA_TLIGHTUSERDATA)
#define ttisstring(o) checktype((o), LUA_TSTRING)
#define ttisshrstring(o) checktag((o), ctb(LUA_TSHRSTR))
#define ttislngstring(o) checktag((o), ctb(LUA_TLNGSTR))
#define ttistable(o) checktag((o), ctb(LUA_TTABLE))
#define ttisfunction(o) checktype(o, LUA_TFUNCTION)
#define ttisclosure(o) ((rttype(o) & 0x1F) == LUA_TFUNCTION)
#define ttisCclosure(o) checktag((o), ctb(LUA_TCCL))
#define ttisLclosure(o) checktag((o), ctb(LUA_TLCL))
#define ttislcf(o) checktag((o), LUA_TLCF)
#define ttisuserdata(o) checktag((o), ctb(LUA_TUSERDATA))
#define ttisthread(o) checktag((o), ctb(LUA_TTHREAD))
#define ttisdeadkey(o) checktag((o), LUA_TDEADKEY)
#define ttisequal(o1,o2) (rttype(o1) == rttype(o2))
/* Macros to access values */
#define nvalue(o) check_exp(ttisnumber(o), num_(o))
#define gcvalue(o) check_exp(iscollectable(o), val_(o).gc)
#define pvalue(o) check_exp(ttislightuserdata(o), val_(o).p)
#define rawtsvalue(o) check_exp(ttisstring(o), &val_(o).gc->ts)
#define tsvalue(o) (&rawtsvalue(o)->tsv)
#define rawuvalue(o) check_exp(ttisuserdata(o), &val_(o).gc->u)
#define uvalue(o) (&rawuvalue(o)->uv)
#define clvalue(o) check_exp(ttisclosure(o), &val_(o).gc->cl)
#define clLvalue(o) check_exp(ttisLclosure(o), &val_(o).gc->cl.l)
#define clCvalue(o) check_exp(ttisCclosure(o), &val_(o).gc->cl.c)
#define fvalue(o) check_exp(ttislcf(o), val_(o).f)
#define hvalue(o) check_exp(ttistable(o), &val_(o).gc->h)
#define bvalue(o) check_exp(ttisboolean(o), val_(o).b)
#define thvalue(o) check_exp(ttisthread(o), &val_(o).gc->th)
/* a dead value may get the 'gc' field, but cannot access its contents */
#define deadvalue(o) check_exp(ttisdeadkey(o), cast(void *, val_(o).gc))
#define l_isfalse(o) (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))
#define iscollectable(o) (rttype(o) & BIT_ISCOLLECTABLE)
/* Macros for internal tests */
#define righttt(obj) (ttype(obj) == gcvalue(obj)->gch.tt)
#define checkliveness(g,obj) \
lua_longassert(!iscollectable(obj) || \
(righttt(obj) && !isdead(g,gcvalue(obj))))
/* Macros to set values */
#define settt_(o,t) ((o)->tt_=(t))
#define setnvalue(obj,x) \
{ TValue *io=(obj); num_(io)=(x); settt_(io, LUA_TNUMBER); }
#define setnilvalue(obj) settt_(obj, LUA_TNIL)
#define setfvalue(obj,x) \
{ TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_TLCF); }
#define setpvalue(obj,x) \
{ TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_TLIGHTUSERDATA); }
#define setbvalue(obj,x) \
{ TValue *io=(obj); val_(io).b=(x); settt_(io, LUA_TBOOLEAN); }
#define setgcovalue(L,obj,x) \
{ TValue *io=(obj); GCObject *i_g=(x); \
val_(io).gc=i_g; settt_(io, ctb(gch(i_g)->tt)); }
#define setsvalue(L,obj,x) \
{ TValue *io=(obj); \
TString *x_ = (x); \
val_(io).gc=cast(GCObject *, x_); settt_(io, ctb(x_->tsv.tt)); \
checkliveness(G(L),io); }
#define setuvalue(L,obj,x) \
{ TValue *io=(obj); \
val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TUSERDATA)); \
checkliveness(G(L),io); }
#define setthvalue(L,obj,x) \
{ TValue *io=(obj); \
val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTHREAD)); \
checkliveness(G(L),io); }
#define setclLvalue(L,obj,x) \
{ TValue *io=(obj); \
val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TLCL)); \
checkliveness(G(L),io); }
#define setclCvalue(L,obj,x) \
{ TValue *io=(obj); \
val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TCCL)); \
checkliveness(G(L),io); }
#define sethvalue(L,obj,x) \
{ TValue *io=(obj); \
val_(io).gc=cast(GCObject *, (x)); settt_(io, ctb(LUA_TTABLE)); \
checkliveness(G(L),io); }
#define setdeadvalue(obj) settt_(obj, LUA_TDEADKEY)
#define setobj(L,obj1,obj2) \
{ const TValue *io2=(obj2); TValue *io1=(obj1); \
io1->value_ = io2->value_; io1->tt_ = io2->tt_; \
checkliveness(G(L),io1); }
/*
** different types of assignments, according to destination
*/
/* from stack to (same) stack */
#define setobjs2s setobj
/* to stack (not from same stack) */
#define setobj2s setobj
#define setsvalue2s setsvalue
#define sethvalue2s sethvalue
#define setptvalue2s setptvalue
/* from table to same table */
#define setobjt2t setobj
/* to table */
#define setobj2t setobj
/* to new object */
#define setobj2n setobj
#define setsvalue2n setsvalue
/* check whether a number is valid (useful only for NaN trick) */
#define luai_checknum(L,o,c) { /* empty */ }
/*
** {======================================================
** NaN Trick
** =======================================================
*/
#if defined(LUA_NANTRICK)
/*
** numbers are represented in the 'd_' field. All other values have the
** value (NNMARK | tag) in 'tt__'. A number with such pattern would be
** a "signaled NaN", which is never generated by regular operations by
** the CPU (nor by 'strtod')
*/
/* allows for external implementation for part of the trick */
#if !defined(NNMARK) /* { */
#if !defined(LUA_IEEEENDIAN)
#error option 'LUA_NANTRICK' needs 'LUA_IEEEENDIAN'
#endif
#define NNMARK 0x7FF7A500
#define NNMASK 0x7FFFFF00
#undef TValuefields
#undef NILCONSTANT
#if (LUA_IEEEENDIAN == 0) /* { */
/* little endian */
#define TValuefields \
union { struct { Value v__; int tt__; } i; double d__; } u
#define NILCONSTANT {{{NULL}, tag2tt(LUA_TNIL)}}
/* field-access macros */
#define v_(o) ((o)->u.i.v__)
#define d_(o) ((o)->u.d__)
#define tt_(o) ((o)->u.i.tt__)
#else /* }{ */
/* big endian */
#define TValuefields \
union { struct { int tt__; Value v__; } i; double d__; } u
#define NILCONSTANT {{tag2tt(LUA_TNIL), {NULL}}}
/* field-access macros */
#define v_(o) ((o)->u.i.v__)
#define d_(o) ((o)->u.d__)
#define tt_(o) ((o)->u.i.tt__)
#endif /* } */
#endif /* } */
/* correspondence with standard representation */
#undef val_
#define val_(o) v_(o)
#undef num_
#define num_(o) d_(o)
#undef numfield
#define numfield /* no such field; numbers are the entire struct */
/* basic check to distinguish numbers from non-numbers */
#undef ttisnumber
#define ttisnumber(o) ((tt_(o) & NNMASK) != NNMARK)
#define tag2tt(t) (NNMARK | (t))
#undef rttype
#define rttype(o) (ttisnumber(o) ? LUA_TNUMBER : tt_(o) & 0xff)
#undef settt_
#define settt_(o,t) (tt_(o) = tag2tt(t))
#undef setnvalue
#define setnvalue(obj,x) \
{ TValue *io_=(obj); num_(io_)=(x); lua_assert(ttisnumber(io_)); }
#undef setobj
#define setobj(L,obj1,obj2) \
{ const TValue *o2_=(obj2); TValue *o1_=(obj1); \
o1_->u = o2_->u; \
checkliveness(G(L),o1_); }
/*
** these redefinitions are not mandatory, but these forms are more efficient
*/
#undef checktag
#undef checktype
#define checktag(o,t) (tt_(o) == tag2tt(t))
#define checktype(o,t) (ctb(tt_(o) | VARBITS) == ctb(tag2tt(t) | VARBITS))
#undef ttisequal
#define ttisequal(o1,o2) \
(ttisnumber(o1) ? ttisnumber(o2) : (tt_(o1) == tt_(o2)))
#undef luai_checknum
#define luai_checknum(L,o,c) { if (!ttisnumber(o)) c; }
#endif
/* }====================================================== */
/*
** {======================================================
** types and prototypes
** =======================================================
*/
union Value {
GCObject *gc; /* collectable objects */
void *p; /* light userdata */
int b; /* booleans */
lua_CFunction f; /* light C functions */
numfield /* numbers */
};
struct lua_TValue {
TValuefields;
};
typedef TValue *StkId; /* index to stack elements */
/*
** Header for string value; string bytes follow the end of this structure
*/
typedef union TString {
L_Umaxalign dummy; /* ensures maximum alignment for strings */
struct {
CommonHeader;
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
unsigned int hash;
size_t len; /* number of characters in string */
} tsv;
} TString;
/* get the actual string (array of bytes) from a TString */
#define getstr(ts) cast(const char *, (ts) + 1)
/* get the actual string (array of bytes) from a Lua value */
#define svalue(o) getstr(rawtsvalue(o))
/*
** Header for userdata; memory area follows the end of this structure
*/
typedef union Udata {
L_Umaxalign dummy; /* ensures maximum alignment for `local' udata */
struct {
CommonHeader;
struct Table *metatable;
struct Table *env;
size_t len; /* number of bytes */
} uv;
} Udata;
/*
** Description of an upvalue for function prototypes
*/
typedef struct Upvaldesc {
TString *name; /* upvalue name (for debug information) */
lu_byte instack; /* whether it is in stack */
lu_byte idx; /* index of upvalue (in stack or in outer function's list) */
} Upvaldesc;
/*
** Description of a local variable for function prototypes
** (used for debug information)
*/
typedef struct LocVar {
TString *varname;
int startpc; /* first point where variable is active */
int endpc; /* first point where variable is dead */
} LocVar;
/*
** Function Prototypes
*/
typedef struct Proto {
CommonHeader;
TValue *k; /* constants used by the function */
Instruction *code;
struct Proto **p; /* functions defined inside the function */
int *lineinfo; /* map from opcodes to source lines (debug information) */
LocVar *locvars; /* information about local variables (debug information) */
Upvaldesc *upvalues; /* upvalue information */
union Closure *cache; /* last created closure with this prototype */
TString *source; /* used for debug information */
int sizeupvalues; /* size of 'upvalues' */
int sizek; /* size of `k' */
int sizecode;
int sizelineinfo;
int sizep; /* size of `p' */
int sizelocvars;
int linedefined;
int lastlinedefined;
GCObject *gclist;
lu_byte numparams; /* number of fixed parameters */
lu_byte is_vararg;
lu_byte maxstacksize; /* maximum stack used by this function */
} Proto;
/*
** Lua Upvalues
*/
typedef struct UpVal {
CommonHeader;
TValue *v; /* points to stack or to its own value */
union {
TValue value; /* the value (when closed) */
struct { /* double linked list (when open) */
struct UpVal *prev;
struct UpVal *next;
} l;
} u;
} UpVal;
/*
** Closures
*/
#define ClosureHeader \
CommonHeader; lu_byte nupvalues; GCObject *gclist
typedef struct CClosure {
ClosureHeader;
lua_CFunction f;
TValue upvalue[1]; /* list of upvalues */
} CClosure;
typedef struct LClosure {
ClosureHeader;
struct Proto *p;
UpVal *upvals[1]; /* list of upvalues */
} LClosure;
typedef union Closure {
CClosure c;
LClosure l;
} Closure;
#define isLfunction(o) ttisLclosure(o)
#define getproto(o) (clLvalue(o)->p)
/*
** Tables
*/
typedef union TKey {
struct {
TValuefields;
struct Node *next; /* for chaining */
} nk;
TValue tvk;
} TKey;
typedef struct Node {
TValue i_val;
TKey i_key;
} Node;
typedef struct Table {
CommonHeader;
lu_byte flags; /* 1<<p means tagmethod(p) is not present */
lu_byte lsizenode; /* log2 of size of `node' array */
int sizearray; /* size of `array' array */
TValue *array; /* array part */
Node *node;
Node *lastfree; /* any free position is before this position */
struct Table *metatable;
GCObject *gclist;
} Table;
/*
** `module' operation for hashing (size is always a power of 2)
*/
#define lmod(s,size) \
(check_exp((size&(size-1))==0, (cast(int, (s) & ((size)-1)))))
#define twoto(x) (1<<(x))
#define sizenode(t) (twoto((t)->lsizenode))
/*
** (address of) a fixed nil value
*/
#define luaO_nilobject (&luaO_nilobject_)
LUAI_DDEC const TValue luaO_nilobject_;
LUAI_FUNC int luaO_int2fb (unsigned int x);
LUAI_FUNC int luaO_fb2int (int x);
LUAI_FUNC int luaO_ceillog2 (unsigned int x);
LUAI_FUNC lua_Number luaO_arith (int op, lua_Number v1, lua_Number v2);
LUAI_FUNC int luaO_str2d (const char *s, size_t len, lua_Number *result);
LUAI_FUNC int luaO_hexavalue (int c);
LUAI_FUNC const char *luaO_pushvfstring (lua_State *L, const char *fmt,
va_list argp);
LUAI_FUNC const char *luaO_pushfstring (lua_State *L, const char *fmt, ...);
LUAI_FUNC void luaO_chunkid (char *out, const char *source, size_t len);
#endif

288
source/3rdparty/lua/include/lopcodes.h vendored Normal file
View File

@ -0,0 +1,288 @@
/*
** $Id: lopcodes.h,v 1.142.1.2 2014/10/20 18:32:09 roberto Exp $
** Opcodes for Lua virtual machine
** See Copyright Notice in lua.h
*/
#ifndef lopcodes_h
#define lopcodes_h
#include "llimits.h"
/*===========================================================================
We assume that instructions are unsigned numbers.
All instructions have an opcode in the first 6 bits.
Instructions can have the following fields:
`A' : 8 bits
`B' : 9 bits
`C' : 9 bits
'Ax' : 26 bits ('A', 'B', and 'C' together)
`Bx' : 18 bits (`B' and `C' together)
`sBx' : signed Bx
A signed argument is represented in excess K; that is, the number
value is the unsigned value minus K. K is exactly the maximum value
for that argument (so that -max is represented by 0, and +max is
represented by 2*max), which is half the maximum for the corresponding
unsigned argument.
===========================================================================*/
enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */
/*
** size and position of opcode arguments.
*/
#define SIZE_C 9
#define SIZE_B 9
#define SIZE_Bx (SIZE_C + SIZE_B)
#define SIZE_A 8
#define SIZE_Ax (SIZE_C + SIZE_B + SIZE_A)
#define SIZE_OP 6
#define POS_OP 0
#define POS_A (POS_OP + SIZE_OP)
#define POS_C (POS_A + SIZE_A)
#define POS_B (POS_C + SIZE_C)
#define POS_Bx POS_C
#define POS_Ax POS_A
/*
** limits for opcode arguments.
** we use (signed) int to manipulate most arguments,
** so they must fit in LUAI_BITSINT-1 bits (-1 for sign)
*/
#if SIZE_Bx < LUAI_BITSINT-1
#define MAXARG_Bx ((1<<SIZE_Bx)-1)
#define MAXARG_sBx (MAXARG_Bx>>1) /* `sBx' is signed */
#else
#define MAXARG_Bx MAX_INT
#define MAXARG_sBx MAX_INT
#endif
#if SIZE_Ax < LUAI_BITSINT-1
#define MAXARG_Ax ((1<<SIZE_Ax)-1)
#else
#define MAXARG_Ax MAX_INT
#endif
#define MAXARG_A ((1<<SIZE_A)-1)
#define MAXARG_B ((1<<SIZE_B)-1)
#define MAXARG_C ((1<<SIZE_C)-1)
/* creates a mask with `n' 1 bits at position `p' */
#define MASK1(n,p) ((~((~(Instruction)0)<<(n)))<<(p))
/* creates a mask with `n' 0 bits at position `p' */
#define MASK0(n,p) (~MASK1(n,p))
/*
** the following macros help to manipulate instructions
*/
#define GET_OPCODE(i) (cast(OpCode, ((i)>>POS_OP) & MASK1(SIZE_OP,0)))
#define SET_OPCODE(i,o) ((i) = (((i)&MASK0(SIZE_OP,POS_OP)) | \
((cast(Instruction, o)<<POS_OP)&MASK1(SIZE_OP,POS_OP))))
#define getarg(i,pos,size) (cast(int, ((i)>>pos) & MASK1(size,0)))
#define setarg(i,v,pos,size) ((i) = (((i)&MASK0(size,pos)) | \
((cast(Instruction, v)<<pos)&MASK1(size,pos))))
#define GETARG_A(i) getarg(i, POS_A, SIZE_A)
#define SETARG_A(i,v) setarg(i, v, POS_A, SIZE_A)
#define GETARG_B(i) getarg(i, POS_B, SIZE_B)
#define SETARG_B(i,v) setarg(i, v, POS_B, SIZE_B)
#define GETARG_C(i) getarg(i, POS_C, SIZE_C)
#define SETARG_C(i,v) setarg(i, v, POS_C, SIZE_C)
#define GETARG_Bx(i) getarg(i, POS_Bx, SIZE_Bx)
#define SETARG_Bx(i,v) setarg(i, v, POS_Bx, SIZE_Bx)
#define GETARG_Ax(i) getarg(i, POS_Ax, SIZE_Ax)
#define SETARG_Ax(i,v) setarg(i, v, POS_Ax, SIZE_Ax)
#define GETARG_sBx(i) (GETARG_Bx(i)-MAXARG_sBx)
#define SETARG_sBx(i,b) SETARG_Bx((i),cast(unsigned int, (b)+MAXARG_sBx))
#define CREATE_ABC(o,a,b,c) ((cast(Instruction, o)<<POS_OP) \
| (cast(Instruction, a)<<POS_A) \
| (cast(Instruction, b)<<POS_B) \
| (cast(Instruction, c)<<POS_C))
#define CREATE_ABx(o,a,bc) ((cast(Instruction, o)<<POS_OP) \
| (cast(Instruction, a)<<POS_A) \
| (cast(Instruction, bc)<<POS_Bx))
#define CREATE_Ax(o,a) ((cast(Instruction, o)<<POS_OP) \
| (cast(Instruction, a)<<POS_Ax))
/*
** Macros to operate RK indices
*/
/* this bit 1 means constant (0 means register) */
#define BITRK (1 << (SIZE_B - 1))
/* test whether value is a constant */
#define ISK(x) ((x) & BITRK)
/* gets the index of the constant */
#define INDEXK(r) ((int)(r) & ~BITRK)
#define MAXINDEXRK (BITRK - 1)
/* code a constant index as a RK value */
#define RKASK(x) ((x) | BITRK)
/*
** invalid register that fits in 8 bits
*/
#define NO_REG MAXARG_A
/*
** R(x) - register
** Kst(x) - constant (in constant table)
** RK(x) == if ISK(x) then Kst(INDEXK(x)) else R(x)
*/
/*
** grep "ORDER OP" if you change these enums
*/
typedef enum {
/*----------------------------------------------------------------------
name args description
------------------------------------------------------------------------*/
OP_MOVE,/* A B R(A) := R(B) */
OP_LOADK,/* A Bx R(A) := Kst(Bx) */
OP_LOADKX,/* A R(A) := Kst(extra arg) */
OP_LOADBOOL,/* A B C R(A) := (Bool)B; if (C) pc++ */
OP_LOADNIL,/* A B R(A), R(A+1), ..., R(A+B) := nil */
OP_GETUPVAL,/* A B R(A) := UpValue[B] */
OP_GETTABUP,/* A B C R(A) := UpValue[B][RK(C)] */
OP_GETTABLE,/* A B C R(A) := R(B)[RK(C)] */
OP_SETTABUP,/* A B C UpValue[A][RK(B)] := RK(C) */
OP_SETUPVAL,/* A B UpValue[B] := R(A) */
OP_SETTABLE,/* A B C R(A)[RK(B)] := RK(C) */
OP_NEWTABLE,/* A B C R(A) := {} (size = B,C) */
OP_SELF,/* A B C R(A+1) := R(B); R(A) := R(B)[RK(C)] */
OP_ADD,/* A B C R(A) := RK(B) + RK(C) */
OP_SUB,/* A B C R(A) := RK(B) - RK(C) */
OP_MUL,/* A B C R(A) := RK(B) * RK(C) */
OP_DIV,/* A B C R(A) := RK(B) / RK(C) */
OP_MOD,/* A B C R(A) := RK(B) % RK(C) */
OP_POW,/* A B C R(A) := RK(B) ^ RK(C) */
OP_UNM,/* A B R(A) := -R(B) */
OP_NOT,/* A B R(A) := not R(B) */
OP_LEN,/* A B R(A) := length of R(B) */
OP_CONCAT,/* A B C R(A) := R(B).. ... ..R(C) */
OP_JMP,/* A sBx pc+=sBx; if (A) close all upvalues >= R(A - 1) */
OP_EQ,/* A B C if ((RK(B) == RK(C)) ~= A) then pc++ */
OP_LT,/* A B C if ((RK(B) < RK(C)) ~= A) then pc++ */
OP_LE,/* A B C if ((RK(B) <= RK(C)) ~= A) then pc++ */
OP_TEST,/* A C if not (R(A) <=> C) then pc++ */
OP_TESTSET,/* A B C if (R(B) <=> C) then R(A) := R(B) else pc++ */
OP_CALL,/* A B C R(A), ... ,R(A+C-2) := R(A)(R(A+1), ... ,R(A+B-1)) */
OP_TAILCALL,/* A B C return R(A)(R(A+1), ... ,R(A+B-1)) */
OP_RETURN,/* A B return R(A), ... ,R(A+B-2) (see note) */
OP_FORLOOP,/* A sBx R(A)+=R(A+2);
if R(A) <?= R(A+1) then { pc+=sBx; R(A+3)=R(A) }*/
OP_FORPREP,/* A sBx R(A)-=R(A+2); pc+=sBx */
OP_TFORCALL,/* A C R(A+3), ... ,R(A+2+C) := R(A)(R(A+1), R(A+2)); */
OP_TFORLOOP,/* A sBx if R(A+1) ~= nil then { R(A)=R(A+1); pc += sBx }*/
OP_SETLIST,/* A B C R(A)[(C-1)*FPF+i] := R(A+i), 1 <= i <= B */
OP_CLOSURE,/* A Bx R(A) := closure(KPROTO[Bx]) */
OP_VARARG,/* A B R(A), R(A+1), ..., R(A+B-2) = vararg */
OP_EXTRAARG/* Ax extra (larger) argument for previous opcode */
} OpCode;
#define NUM_OPCODES (cast(int, OP_EXTRAARG) + 1)
/*===========================================================================
Notes:
(*) In OP_CALL, if (B == 0) then B = top. If (C == 0), then `top' is
set to last_result+1, so next open instruction (OP_CALL, OP_RETURN,
OP_SETLIST) may use `top'.
(*) In OP_VARARG, if (B == 0) then use actual number of varargs and
set top (like in OP_CALL with C == 0).
(*) In OP_RETURN, if (B == 0) then return up to `top'.
(*) In OP_SETLIST, if (B == 0) then B = `top'; if (C == 0) then next
'instruction' is EXTRAARG(real C).
(*) In OP_LOADKX, the next 'instruction' is always EXTRAARG.
(*) For comparisons, A specifies what condition the test should accept
(true or false).
(*) All `skips' (pc++) assume that next instruction is a jump.
===========================================================================*/
/*
** masks for instruction properties. The format is:
** bits 0-1: op mode
** bits 2-3: C arg mode
** bits 4-5: B arg mode
** bit 6: instruction set register A
** bit 7: operator is a test (next instruction must be a jump)
*/
enum OpArgMask {
OpArgN, /* argument is not used */
OpArgU, /* argument is used */
OpArgR, /* argument is a register or a jump offset */
OpArgK /* argument is a constant or register/constant */
};
LUAI_DDEC const lu_byte luaP_opmodes[NUM_OPCODES];
#define getOpMode(m) (cast(enum OpMode, luaP_opmodes[m] & 3))
#define getBMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 4) & 3))
#define getCMode(m) (cast(enum OpArgMask, (luaP_opmodes[m] >> 2) & 3))
#define testAMode(m) (luaP_opmodes[m] & (1 << 6))
#define testTMode(m) (luaP_opmodes[m] & (1 << 7))
LUAI_DDEC const char *const luaP_opnames[NUM_OPCODES+1]; /* opcode names */
/* number of list items to accumulate before a SETLIST instruction */
#define LFIELDS_PER_FLUSH 50
#endif

119
source/3rdparty/lua/include/lparser.h vendored Normal file
View File

@ -0,0 +1,119 @@
/*
** $Id: lparser.h,v 1.70.1.1 2013/04/12 18:48:47 roberto Exp $
** Lua Parser
** See Copyright Notice in lua.h
*/
#ifndef lparser_h
#define lparser_h
#include "llimits.h"
#include "lobject.h"
#include "lzio.h"
/*
** Expression descriptor
*/
typedef enum {
VVOID, /* no value */
VNIL,
VTRUE,
VFALSE,
VK, /* info = index of constant in `k' */
VKNUM, /* nval = numerical value */
VNONRELOC, /* info = result register */
VLOCAL, /* info = local register */
VUPVAL, /* info = index of upvalue in 'upvalues' */
VINDEXED, /* t = table register/upvalue; idx = index R/K */
VJMP, /* info = instruction pc */
VRELOCABLE, /* info = instruction pc */
VCALL, /* info = instruction pc */
VVARARG /* info = instruction pc */
} expkind;
#define vkisvar(k) (VLOCAL <= (k) && (k) <= VINDEXED)
#define vkisinreg(k) ((k) == VNONRELOC || (k) == VLOCAL)
typedef struct expdesc {
expkind k;
union {
struct { /* for indexed variables (VINDEXED) */
short idx; /* index (R/K) */
lu_byte t; /* table (register or upvalue) */
lu_byte vt; /* whether 't' is register (VLOCAL) or upvalue (VUPVAL) */
} ind;
int info; /* for generic use */
lua_Number nval; /* for VKNUM */
} u;
int t; /* patch list of `exit when true' */
int f; /* patch list of `exit when false' */
} expdesc;
/* description of active local variable */
typedef struct Vardesc {
short idx; /* variable index in stack */
} Vardesc;
/* description of pending goto statements and label statements */
typedef struct Labeldesc {
TString *name; /* label identifier */
int pc; /* position in code */
int line; /* line where it appeared */
lu_byte nactvar; /* local level where it appears in current block */
} Labeldesc;
/* list of labels or gotos */
typedef struct Labellist {
Labeldesc *arr; /* array */
int n; /* number of entries in use */
int size; /* array size */
} Labellist;
/* dynamic structures used by the parser */
typedef struct Dyndata {
struct { /* list of active local variables */
Vardesc *arr;
int n;
int size;
} actvar;
Labellist gt; /* list of pending gotos */
Labellist label; /* list of active labels */
} Dyndata;
/* control of blocks */
struct BlockCnt; /* defined in lparser.c */
/* state needed to generate code for a given function */
typedef struct FuncState {
Proto *f; /* current function header */
Table *h; /* table to find (and reuse) elements in `k' */
struct FuncState *prev; /* enclosing function */
struct LexState *ls; /* lexical state */
struct BlockCnt *bl; /* chain of current blocks */
int pc; /* next position to code (equivalent to `ncode') */
int lasttarget; /* 'label' of last 'jump label' */
int jpc; /* list of pending jumps to `pc' */
int nk; /* number of elements in `k' */
int np; /* number of elements in `p' */
int firstlocal; /* index of first local var (in Dyndata array) */
short nlocvars; /* number of elements in 'f->locvars' */
lu_byte nactvar; /* number of active local variables */
lu_byte nups; /* number of upvalues */
lu_byte freereg; /* first free register */
} FuncState;
LUAI_FUNC Closure *luaY_parser (lua_State *L, ZIO *z, Mbuffer *buff,
Dyndata *dyd, const char *name, int firstchar);
#endif

228
source/3rdparty/lua/include/lstate.h vendored Normal file
View File

@ -0,0 +1,228 @@
/*
** $Id: lstate.h,v 2.82.1.1 2013/04/12 18:48:47 roberto Exp $
** Global State
** See Copyright Notice in lua.h
*/
#ifndef lstate_h
#define lstate_h
#include "lua.h"
#include "lobject.h"
#include "ltm.h"
#include "lzio.h"
/*
** Some notes about garbage-collected objects: All objects in Lua must
** be kept somehow accessible until being freed.
**
** Lua keeps most objects linked in list g->allgc. The link uses field
** 'next' of the CommonHeader.
**
** Strings are kept in several lists headed by the array g->strt.hash.
**
** Open upvalues are not subject to independent garbage collection. They
** are collected together with their respective threads. Lua keeps a
** double-linked list with all open upvalues (g->uvhead) so that it can
** mark objects referred by them. (They are always gray, so they must
** be remarked in the atomic step. Usually their contents would be marked
** when traversing the respective threads, but the thread may already be
** dead, while the upvalue is still accessible through closures.)
**
** Objects with finalizers are kept in the list g->finobj.
**
** The list g->tobefnz links all objects being finalized.
*/
struct lua_longjmp; /* defined in ldo.c */
/* extra stack space to handle TM calls and some other extras */
#define EXTRA_STACK 5
#define BASIC_STACK_SIZE (2*LUA_MINSTACK)
/* kinds of Garbage Collection */
#define KGC_NORMAL 0
#define KGC_EMERGENCY 1 /* gc was forced by an allocation failure */
#define KGC_GEN 2 /* generational collection */
typedef struct stringtable {
GCObject **hash;
lu_int32 nuse; /* number of elements */
int size;
} stringtable;
/*
** information about a call
*/
typedef struct CallInfo {
StkId func; /* function index in the stack */
StkId top; /* top for this function */
struct CallInfo *previous, *next; /* dynamic call link */
short nresults; /* expected number of results from this function */
lu_byte callstatus;
ptrdiff_t extra;
union {
struct { /* only for Lua functions */
StkId base; /* base for this function */
const Instruction *savedpc;
} l;
struct { /* only for C functions */
int ctx; /* context info. in case of yields */
lua_CFunction k; /* continuation in case of yields */
ptrdiff_t old_errfunc;
lu_byte old_allowhook;
lu_byte status;
} c;
} u;
} CallInfo;
/*
** Bits in CallInfo status
*/
#define CIST_LUA (1<<0) /* call is running a Lua function */
#define CIST_HOOKED (1<<1) /* call is running a debug hook */
#define CIST_REENTRY (1<<2) /* call is running on same invocation of
luaV_execute of previous call */
#define CIST_YIELDED (1<<3) /* call reentered after suspension */
#define CIST_YPCALL (1<<4) /* call is a yieldable protected call */
#define CIST_STAT (1<<5) /* call has an error status (pcall) */
#define CIST_TAIL (1<<6) /* call was tail called */
#define CIST_HOOKYIELD (1<<7) /* last hook called yielded */
#define isLua(ci) ((ci)->callstatus & CIST_LUA)
/*
** `global state', shared by all threads of this state
*/
typedef struct global_State {
lua_Alloc frealloc; /* function to reallocate memory */
void *ud; /* auxiliary data to `frealloc' */
lu_mem totalbytes; /* number of bytes currently allocated - GCdebt */
l_mem GCdebt; /* bytes allocated not yet compensated by the collector */
lu_mem GCmemtrav; /* memory traversed by the GC */
lu_mem GCestimate; /* an estimate of the non-garbage memory in use */
stringtable strt; /* hash table for strings */
TValue l_registry;
unsigned int seed; /* randomized seed for hashes */
lu_byte currentwhite;
lu_byte gcstate; /* state of garbage collector */
lu_byte gckind; /* kind of GC running */
lu_byte gcrunning; /* true if GC is running */
int sweepstrgc; /* position of sweep in `strt' */
GCObject *allgc; /* list of all collectable objects */
GCObject *finobj; /* list of collectable objects with finalizers */
GCObject **sweepgc; /* current position of sweep in list 'allgc' */
GCObject **sweepfin; /* current position of sweep in list 'finobj' */
GCObject *gray; /* list of gray objects */
GCObject *grayagain; /* list of objects to be traversed atomically */
GCObject *weak; /* list of tables with weak values */
GCObject *ephemeron; /* list of ephemeron tables (weak keys) */
GCObject *allweak; /* list of all-weak tables */
GCObject *tobefnz; /* list of userdata to be GC */
UpVal uvhead; /* head of double-linked list of all open upvalues */
Mbuffer buff; /* temporary buffer for string concatenation */
int gcpause; /* size of pause between successive GCs */
int gcmajorinc; /* pause between major collections (only in gen. mode) */
int gcstepmul; /* GC `granularity' */
lua_CFunction panic; /* to be called in unprotected errors */
struct lua_State *mainthread;
const lua_Number *version; /* pointer to version number */
TString *memerrmsg; /* memory-error message */
TString *tmname[TM_N]; /* array with tag-method names */
struct Table *mt[LUA_NUMTAGS]; /* metatables for basic types */
} global_State;
/*
** `per thread' state
*/
struct lua_State {
CommonHeader;
lu_byte status;
StkId top; /* first free slot in the stack */
global_State *l_G;
CallInfo *ci; /* call info for current function */
const Instruction *oldpc; /* last pc traced */
StkId stack_last; /* last free slot in the stack */
StkId stack; /* stack base */
int stacksize;
unsigned short nny; /* number of non-yieldable calls in stack */
unsigned short nCcalls; /* number of nested C calls */
lu_byte hookmask;
lu_byte allowhook;
int basehookcount;
int hookcount;
lua_Hook hook;
GCObject *openupval; /* list of open upvalues in this stack */
GCObject *gclist;
struct lua_longjmp *errorJmp; /* current error recover point */
ptrdiff_t errfunc; /* current error handling function (stack index) */
CallInfo base_ci; /* CallInfo for first level (C calling Lua) */
};
#define G(L) (L->l_G)
/*
** Union of all collectable objects
*/
union GCObject {
GCheader gch; /* common header */
union TString ts;
union Udata u;
union Closure cl;
struct Table h;
struct Proto p;
struct UpVal uv;
struct lua_State th; /* thread */
};
#define gch(o) (&(o)->gch)
/* macros to convert a GCObject into a specific value */
#define rawgco2ts(o) \
check_exp(novariant((o)->gch.tt) == LUA_TSTRING, &((o)->ts))
#define gco2ts(o) (&rawgco2ts(o)->tsv)
#define rawgco2u(o) check_exp((o)->gch.tt == LUA_TUSERDATA, &((o)->u))
#define gco2u(o) (&rawgco2u(o)->uv)
#define gco2lcl(o) check_exp((o)->gch.tt == LUA_TLCL, &((o)->cl.l))
#define gco2ccl(o) check_exp((o)->gch.tt == LUA_TCCL, &((o)->cl.c))
#define gco2cl(o) \
check_exp(novariant((o)->gch.tt) == LUA_TFUNCTION, &((o)->cl))
#define gco2t(o) check_exp((o)->gch.tt == LUA_TTABLE, &((o)->h))
#define gco2p(o) check_exp((o)->gch.tt == LUA_TPROTO, &((o)->p))
#define gco2uv(o) check_exp((o)->gch.tt == LUA_TUPVAL, &((o)->uv))
#define gco2th(o) check_exp((o)->gch.tt == LUA_TTHREAD, &((o)->th))
/* macro to convert any Lua object into a GCObject */
#define obj2gco(v) (cast(GCObject *, (v)))
/* actual number of total bytes allocated */
#define gettotalbytes(g) ((g)->totalbytes + (g)->GCdebt)
LUAI_FUNC void luaE_setdebt (global_State *g, l_mem debt);
LUAI_FUNC void luaE_freethread (lua_State *L, lua_State *L1);
LUAI_FUNC CallInfo *luaE_extendCI (lua_State *L);
LUAI_FUNC void luaE_freeCI (lua_State *L);
#endif

46
source/3rdparty/lua/include/lstring.h vendored Normal file
View File

@ -0,0 +1,46 @@
/*
** $Id: lstring.h,v 1.49.1.1 2013/04/12 18:48:47 roberto Exp $
** String table (keep all strings handled by Lua)
** See Copyright Notice in lua.h
*/
#ifndef lstring_h
#define lstring_h
#include "lgc.h"
#include "lobject.h"
#include "lstate.h"
#define sizestring(s) (sizeof(union TString)+((s)->len+1)*sizeof(char))
#define sizeudata(u) (sizeof(union Udata)+(u)->len)
#define luaS_newliteral(L, s) (luaS_newlstr(L, "" s, \
(sizeof(s)/sizeof(char))-1))
#define luaS_fix(s) l_setbit((s)->tsv.marked, FIXEDBIT)
/*
** test whether a string is a reserved word
*/
#define isreserved(s) ((s)->tsv.tt == LUA_TSHRSTR && (s)->tsv.extra > 0)
/*
** equality for short strings, which are always internalized
*/
#define eqshrstr(a,b) check_exp((a)->tsv.tt == LUA_TSHRSTR, (a) == (b))
LUAI_FUNC unsigned int luaS_hash (const char *str, size_t l, unsigned int seed);
LUAI_FUNC int luaS_eqlngstr (TString *a, TString *b);
LUAI_FUNC int luaS_eqstr (TString *a, TString *b);
LUAI_FUNC void luaS_resize (lua_State *L, int newsize);
LUAI_FUNC Udata *luaS_newudata (lua_State *L, size_t s, Table *e);
LUAI_FUNC TString *luaS_newlstr (lua_State *L, const char *str, size_t l);
LUAI_FUNC TString *luaS_new (lua_State *L, const char *str);
#endif

45
source/3rdparty/lua/include/ltable.h vendored Normal file
View File

@ -0,0 +1,45 @@
/*
** $Id: ltable.h,v 2.16.1.2 2013/08/30 15:49:41 roberto Exp $
** Lua tables (hash)
** See Copyright Notice in lua.h
*/
#ifndef ltable_h
#define ltable_h
#include "lobject.h"
#define gnode(t,i) (&(t)->node[i])
#define gkey(n) (&(n)->i_key.tvk)
#define gval(n) (&(n)->i_val)
#define gnext(n) ((n)->i_key.nk.next)
#define invalidateTMcache(t) ((t)->flags = 0)
/* returns the key, given the value of a table entry */
#define keyfromval(v) \
(gkey(cast(Node *, cast(char *, (v)) - offsetof(Node, i_val))))
LUAI_FUNC const TValue *luaH_getint (Table *t, int key);
LUAI_FUNC void luaH_setint (lua_State *L, Table *t, int key, TValue *value);
LUAI_FUNC const TValue *luaH_getstr (Table *t, TString *key);
LUAI_FUNC const TValue *luaH_get (Table *t, const TValue *key);
LUAI_FUNC TValue *luaH_newkey (lua_State *L, Table *t, const TValue *key);
LUAI_FUNC TValue *luaH_set (lua_State *L, Table *t, const TValue *key);
LUAI_FUNC Table *luaH_new (lua_State *L);
LUAI_FUNC void luaH_resize (lua_State *L, Table *t, int nasize, int nhsize);
LUAI_FUNC void luaH_resizearray (lua_State *L, Table *t, int nasize);
LUAI_FUNC void luaH_free (lua_State *L, Table *t);
LUAI_FUNC int luaH_next (lua_State *L, Table *t, StkId key);
LUAI_FUNC int luaH_getn (Table *t);
#if defined(LUA_DEBUG)
LUAI_FUNC Node *luaH_mainposition (const Table *t, const TValue *key);
LUAI_FUNC int luaH_isdummy (Node *n);
#endif
#endif

57
source/3rdparty/lua/include/ltm.h vendored Normal file
View File

@ -0,0 +1,57 @@
/*
** $Id: ltm.h,v 2.11.1.1 2013/04/12 18:48:47 roberto Exp $
** Tag methods
** See Copyright Notice in lua.h
*/
#ifndef ltm_h
#define ltm_h
#include "lobject.h"
/*
* WARNING: if you change the order of this enumeration,
* grep "ORDER TM"
*/
typedef enum {
TM_INDEX,
TM_NEWINDEX,
TM_GC,
TM_MODE,
TM_LEN,
TM_EQ, /* last tag method with `fast' access */
TM_ADD,
TM_SUB,
TM_MUL,
TM_DIV,
TM_MOD,
TM_POW,
TM_UNM,
TM_LT,
TM_LE,
TM_CONCAT,
TM_CALL,
TM_N /* number of elements in the enum */
} TMS;
#define gfasttm(g,et,e) ((et) == NULL ? NULL : \
((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e]))
#define fasttm(l,et,e) gfasttm(G(l), et, e)
#define ttypename(x) luaT_typenames_[(x) + 1]
#define objtypename(x) ttypename(ttypenv(x))
LUAI_DDEC const char *const luaT_typenames_[LUA_TOTALTAGS];
LUAI_FUNC const TValue *luaT_gettm (Table *events, TMS event, TString *ename);
LUAI_FUNC const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o,
TMS event);
LUAI_FUNC void luaT_init (lua_State *L);
#endif

444
source/3rdparty/lua/include/lua.h vendored Normal file
View File

@ -0,0 +1,444 @@
/*
** $Id: lua.h,v 1.285.1.4 2015/02/21 14:04:50 roberto Exp $
** Lua - A Scripting Language
** Lua.org, PUC-Rio, Brazil (http://www.lua.org)
** See Copyright Notice at the end of this file
*/
#ifndef lua_h
#define lua_h
#include <stdarg.h>
#include <stddef.h>
#include "luaconf.h"
#define LUA_VERSION_MAJOR "5"
#define LUA_VERSION_MINOR "2"
#define LUA_VERSION_NUM 502
#define LUA_VERSION_RELEASE "4"
#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR
#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE
#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2015 Lua.org, PUC-Rio"
#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes"
/* mark for precompiled code ('<esc>Lua') */
#define LUA_SIGNATURE "\033Lua"
/* option for multiple returns in 'lua_pcall' and 'lua_call' */
#define LUA_MULTRET (-1)
/*
** pseudo-indices
*/
#define LUA_REGISTRYINDEX LUAI_FIRSTPSEUDOIDX
#define lua_upvalueindex(i) (LUA_REGISTRYINDEX - (i))
/* thread status */
#define LUA_OK 0
#define LUA_YIELD 1
#define LUA_ERRRUN 2
#define LUA_ERRSYNTAX 3
#define LUA_ERRMEM 4
#define LUA_ERRGCMM 5
#define LUA_ERRERR 6
typedef struct lua_State lua_State;
typedef int (*lua_CFunction) (lua_State *L);
/*
** functions that read/write blocks when loading/dumping Lua chunks
*/
typedef const char * (*lua_Reader) (lua_State *L, void *ud, size_t *sz);
typedef int (*lua_Writer) (lua_State *L, const void* p, size_t sz, void* ud);
/*
** prototype for memory-allocation functions
*/
typedef void * (*lua_Alloc) (void *ud, void *ptr, size_t osize, size_t nsize);
/*
** basic types
*/
#define LUA_TNONE (-1)
#define LUA_TNIL 0
#define LUA_TBOOLEAN 1
#define LUA_TLIGHTUSERDATA 2
#define LUA_TNUMBER 3
#define LUA_TSTRING 4
#define LUA_TTABLE 5
#define LUA_TFUNCTION 6
#define LUA_TUSERDATA 7
#define LUA_TTHREAD 8
#define LUA_NUMTAGS 9
/* minimum Lua stack available to a C function */
#define LUA_MINSTACK 20
/* predefined values in the registry */
#define LUA_RIDX_MAINTHREAD 1
#define LUA_RIDX_GLOBALS 2
#define LUA_RIDX_LAST LUA_RIDX_GLOBALS
/* type of numbers in Lua */
typedef LUA_NUMBER lua_Number;
/* type for integer functions */
typedef LUA_INTEGER lua_Integer;
/* unsigned integer type */
typedef LUA_UNSIGNED lua_Unsigned;
/*
** generic extra include file
*/
#if defined(LUA_USER_H)
#include LUA_USER_H
#endif
/*
** RCS ident string
*/
extern const char lua_ident[];
/*
** state manipulation
*/
LUA_API lua_State *(lua_newstate) (lua_Alloc f, void *ud);
LUA_API void (lua_close) (lua_State *L);
LUA_API lua_State *(lua_newthread) (lua_State *L);
LUA_API lua_CFunction (lua_atpanic) (lua_State *L, lua_CFunction panicf);
LUA_API const lua_Number *(lua_version) (lua_State *L);
/*
** basic stack manipulation
*/
LUA_API int (lua_absindex) (lua_State *L, int idx);
LUA_API int (lua_gettop) (lua_State *L);
LUA_API void (lua_settop) (lua_State *L, int idx);
LUA_API void (lua_pushvalue) (lua_State *L, int idx);
LUA_API void (lua_remove) (lua_State *L, int idx);
LUA_API void (lua_insert) (lua_State *L, int idx);
LUA_API void (lua_replace) (lua_State *L, int idx);
LUA_API void (lua_copy) (lua_State *L, int fromidx, int toidx);
LUA_API int (lua_checkstack) (lua_State *L, int sz);
LUA_API void (lua_xmove) (lua_State *from, lua_State *to, int n);
/*
** access functions (stack -> C)
*/
LUA_API int (lua_isnumber) (lua_State *L, int idx);
LUA_API int (lua_isstring) (lua_State *L, int idx);
LUA_API int (lua_iscfunction) (lua_State *L, int idx);
LUA_API int (lua_isuserdata) (lua_State *L, int idx);
LUA_API int (lua_type) (lua_State *L, int idx);
LUA_API const char *(lua_typename) (lua_State *L, int tp);
LUA_API lua_Number (lua_tonumberx) (lua_State *L, int idx, int *isnum);
LUA_API lua_Integer (lua_tointegerx) (lua_State *L, int idx, int *isnum);
LUA_API lua_Unsigned (lua_tounsignedx) (lua_State *L, int idx, int *isnum);
LUA_API int (lua_toboolean) (lua_State *L, int idx);
LUA_API const char *(lua_tolstring) (lua_State *L, int idx, size_t *len);
LUA_API size_t (lua_rawlen) (lua_State *L, int idx);
LUA_API lua_CFunction (lua_tocfunction) (lua_State *L, int idx);
LUA_API void *(lua_touserdata) (lua_State *L, int idx);
LUA_API lua_State *(lua_tothread) (lua_State *L, int idx);
LUA_API const void *(lua_topointer) (lua_State *L, int idx);
/*
** Comparison and arithmetic functions
*/
#define LUA_OPADD 0 /* ORDER TM */
#define LUA_OPSUB 1
#define LUA_OPMUL 2
#define LUA_OPDIV 3
#define LUA_OPMOD 4
#define LUA_OPPOW 5
#define LUA_OPUNM 6
LUA_API void (lua_arith) (lua_State *L, int op);
#define LUA_OPEQ 0
#define LUA_OPLT 1
#define LUA_OPLE 2
LUA_API int (lua_rawequal) (lua_State *L, int idx1, int idx2);
LUA_API int (lua_compare) (lua_State *L, int idx1, int idx2, int op);
/*
** push functions (C -> stack)
*/
LUA_API void (lua_pushnil) (lua_State *L);
LUA_API void (lua_pushnumber) (lua_State *L, lua_Number n);
LUA_API void (lua_pushinteger) (lua_State *L, lua_Integer n);
LUA_API void (lua_pushunsigned) (lua_State *L, lua_Unsigned n);
LUA_API const char *(lua_pushlstring) (lua_State *L, const char *s, size_t l);
LUA_API const char *(lua_pushstring) (lua_State *L, const char *s);
LUA_API const char *(lua_pushvfstring) (lua_State *L, const char *fmt,
va_list argp);
LUA_API const char *(lua_pushfstring) (lua_State *L, const char *fmt, ...);
LUA_API void (lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
LUA_API void (lua_pushboolean) (lua_State *L, int b);
LUA_API void (lua_pushlightuserdata) (lua_State *L, void *p);
LUA_API int (lua_pushthread) (lua_State *L);
/*
** get functions (Lua -> stack)
*/
LUA_API void (lua_getglobal) (lua_State *L, const char *var);
LUA_API void (lua_gettable) (lua_State *L, int idx);
LUA_API void (lua_getfield) (lua_State *L, int idx, const char *k);
LUA_API void (lua_rawget) (lua_State *L, int idx);
LUA_API void (lua_rawgeti) (lua_State *L, int idx, int n);
LUA_API void (lua_rawgetp) (lua_State *L, int idx, const void *p);
LUA_API void (lua_createtable) (lua_State *L, int narr, int nrec);
LUA_API void *(lua_newuserdata) (lua_State *L, size_t sz);
LUA_API int (lua_getmetatable) (lua_State *L, int objindex);
LUA_API void (lua_getuservalue) (lua_State *L, int idx);
/*
** set functions (stack -> Lua)
*/
LUA_API void (lua_setglobal) (lua_State *L, const char *var);
LUA_API void (lua_settable) (lua_State *L, int idx);
LUA_API void (lua_setfield) (lua_State *L, int idx, const char *k);
LUA_API void (lua_rawset) (lua_State *L, int idx);
LUA_API void (lua_rawseti) (lua_State *L, int idx, int n);
LUA_API void (lua_rawsetp) (lua_State *L, int idx, const void *p);
LUA_API int (lua_setmetatable) (lua_State *L, int objindex);
LUA_API void (lua_setuservalue) (lua_State *L, int idx);
/*
** 'load' and 'call' functions (load and run Lua code)
*/
LUA_API void (lua_callk) (lua_State *L, int nargs, int nresults, int ctx,
lua_CFunction k);
#define lua_call(L,n,r) lua_callk(L, (n), (r), 0, NULL)
LUA_API int (lua_getctx) (lua_State *L, int *ctx);
LUA_API int (lua_pcallk) (lua_State *L, int nargs, int nresults, int errfunc,
int ctx, lua_CFunction k);
#define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL)
LUA_API int (lua_load) (lua_State *L, lua_Reader reader, void *dt,
const char *chunkname,
const char *mode);
LUA_API int (lua_dump) (lua_State *L, lua_Writer writer, void *data);
/*
** coroutine functions
*/
LUA_API int (lua_yieldk) (lua_State *L, int nresults, int ctx,
lua_CFunction k);
#define lua_yield(L,n) lua_yieldk(L, (n), 0, NULL)
LUA_API int (lua_resume) (lua_State *L, lua_State *from, int narg);
LUA_API int (lua_status) (lua_State *L);
/*
** garbage-collection function and options
*/
#define LUA_GCSTOP 0
#define LUA_GCRESTART 1
#define LUA_GCCOLLECT 2
#define LUA_GCCOUNT 3
#define LUA_GCCOUNTB 4
#define LUA_GCSTEP 5
#define LUA_GCSETPAUSE 6
#define LUA_GCSETSTEPMUL 7
#define LUA_GCSETMAJORINC 8
#define LUA_GCISRUNNING 9
#define LUA_GCGEN 10
#define LUA_GCINC 11
LUA_API int (lua_gc) (lua_State *L, int what, int data);
/*
** miscellaneous functions
*/
LUA_API int (lua_error) (lua_State *L);
LUA_API int (lua_next) (lua_State *L, int idx);
LUA_API void (lua_concat) (lua_State *L, int n);
LUA_API void (lua_len) (lua_State *L, int idx);
LUA_API lua_Alloc (lua_getallocf) (lua_State *L, void **ud);
LUA_API void (lua_setallocf) (lua_State *L, lua_Alloc f, void *ud);
/*
** ===============================================================
** some useful macros
** ===============================================================
*/
#define lua_tonumber(L,i) lua_tonumberx(L,i,NULL)
#define lua_tointeger(L,i) lua_tointegerx(L,i,NULL)
#define lua_tounsigned(L,i) lua_tounsignedx(L,i,NULL)
#define lua_pop(L,n) lua_settop(L, -(n)-1)
#define lua_newtable(L) lua_createtable(L, 0, 0)
#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
#define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION)
#define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE)
#define lua_islightuserdata(L,n) (lua_type(L, (n)) == LUA_TLIGHTUSERDATA)
#define lua_isnil(L,n) (lua_type(L, (n)) == LUA_TNIL)
#define lua_isboolean(L,n) (lua_type(L, (n)) == LUA_TBOOLEAN)
#define lua_isthread(L,n) (lua_type(L, (n)) == LUA_TTHREAD)
#define lua_isnone(L,n) (lua_type(L, (n)) == LUA_TNONE)
#define lua_isnoneornil(L, n) (lua_type(L, (n)) <= 0)
#define lua_pushliteral(L, s) \
lua_pushlstring(L, "" s, (sizeof(s)/sizeof(char))-1)
#define lua_pushglobaltable(L) \
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS)
#define lua_tostring(L,i) lua_tolstring(L, (i), NULL)
/*
** {======================================================================
** Debug API
** =======================================================================
*/
/*
** Event codes
*/
#define LUA_HOOKCALL 0
#define LUA_HOOKRET 1
#define LUA_HOOKLINE 2
#define LUA_HOOKCOUNT 3
#define LUA_HOOKTAILCALL 4
/*
** Event masks
*/
#define LUA_MASKCALL (1 << LUA_HOOKCALL)
#define LUA_MASKRET (1 << LUA_HOOKRET)
#define LUA_MASKLINE (1 << LUA_HOOKLINE)
#define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT)
typedef struct lua_Debug lua_Debug; /* activation record */
/* Functions to be called by the debugger in specific events */
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
LUA_API int (lua_getstack) (lua_State *L, int level, lua_Debug *ar);
LUA_API int (lua_getinfo) (lua_State *L, const char *what, lua_Debug *ar);
LUA_API const char *(lua_getlocal) (lua_State *L, const lua_Debug *ar, int n);
LUA_API const char *(lua_setlocal) (lua_State *L, const lua_Debug *ar, int n);
LUA_API const char *(lua_getupvalue) (lua_State *L, int funcindex, int n);
LUA_API const char *(lua_setupvalue) (lua_State *L, int funcindex, int n);
LUA_API void *(lua_upvalueid) (lua_State *L, int fidx, int n);
LUA_API void (lua_upvaluejoin) (lua_State *L, int fidx1, int n1,
int fidx2, int n2);
LUA_API int (lua_sethook) (lua_State *L, lua_Hook func, int mask, int count);
LUA_API lua_Hook (lua_gethook) (lua_State *L);
LUA_API int (lua_gethookmask) (lua_State *L);
LUA_API int (lua_gethookcount) (lua_State *L);
struct lua_Debug {
int event;
const char *name; /* (n) */
const char *namewhat; /* (n) 'global', 'local', 'field', 'method' */
const char *what; /* (S) 'Lua', 'C', 'main', 'tail' */
const char *source; /* (S) */
int currentline; /* (l) */
int linedefined; /* (S) */
int lastlinedefined; /* (S) */
unsigned char nups; /* (u) number of upvalues */
unsigned char nparams;/* (u) number of parameters */
char isvararg; /* (u) */
char istailcall; /* (t) */
char short_src[LUA_IDSIZE]; /* (S) */
/* private part */
struct CallInfo *i_ci; /* active function */
};
/* }====================================================================== */
/******************************************************************************
* Copyright (C) 1994-2015 Lua.org, PUC-Rio.
*
* 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.
******************************************************************************/
#endif

55
source/3rdparty/lua/include/lualib.h vendored Normal file
View File

@ -0,0 +1,55 @@
/*
** $Id: lualib.h,v 1.43.1.1 2013/04/12 18:48:47 roberto Exp $
** Lua standard libraries
** See Copyright Notice in lua.h
*/
#ifndef lualib_h
#define lualib_h
#include "lua.h"
LUAMOD_API int (luaopen_base) (lua_State *L);
#define LUA_COLIBNAME "coroutine"
LUAMOD_API int (luaopen_coroutine) (lua_State *L);
#define LUA_TABLIBNAME "table"
LUAMOD_API int (luaopen_table) (lua_State *L);
#define LUA_IOLIBNAME "io"
LUAMOD_API int (luaopen_io) (lua_State *L);
#define LUA_OSLIBNAME "os"
LUAMOD_API int (luaopen_os) (lua_State *L);
#define LUA_STRLIBNAME "string"
LUAMOD_API int (luaopen_string) (lua_State *L);
#define LUA_BITLIBNAME "bit32"
LUAMOD_API int (luaopen_bit32) (lua_State *L);
#define LUA_MATHLIBNAME "math"
LUAMOD_API int (luaopen_math) (lua_State *L);
#define LUA_DBLIBNAME "debug"
LUAMOD_API int (luaopen_debug) (lua_State *L);
#define LUA_LOADLIBNAME "package"
LUAMOD_API int (luaopen_package) (lua_State *L);
/* open all previous libraries */
LUALIB_API void (luaL_openlibs) (lua_State *L);
#if !defined(lua_assert)
#define lua_assert(x) ((void)0)
#endif
#endif

28
source/3rdparty/lua/include/lundump.h vendored Normal file
View File

@ -0,0 +1,28 @@
/*
** $Id: lundump.h,v 1.39.1.1 2013/04/12 18:48:47 roberto Exp $
** load precompiled Lua chunks
** See Copyright Notice in lua.h
*/
#ifndef lundump_h
#define lundump_h
#include "lobject.h"
#include "lzio.h"
/* load one chunk; from lundump.c */
LUAI_FUNC Closure* luaU_undump (lua_State* L, ZIO* Z, Mbuffer* buff, const char* name);
/* make header; from lundump.c */
LUAI_FUNC void luaU_header (lu_byte* h);
/* dump one chunk; from ldump.c */
LUAI_FUNC int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip);
/* data to catch conversion errors */
#define LUAC_TAIL "\x19\x93\r\n\x1a\n"
/* size in bytes of header of binary files */
#define LUAC_HEADERSIZE (sizeof(LUA_SIGNATURE)-sizeof(char)+2+6+sizeof(LUAC_TAIL)-sizeof(char))
#endif

44
source/3rdparty/lua/include/lvm.h vendored Normal file
View File

@ -0,0 +1,44 @@
/*
** $Id: lvm.h,v 2.18.1.1 2013/04/12 18:48:47 roberto Exp $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
#ifndef lvm_h
#define lvm_h
#include "ldo.h"
#include "lobject.h"
#include "ltm.h"
#define tostring(L,o) (ttisstring(o) || (luaV_tostring(L, o)))
#define tonumber(o,n) (ttisnumber(o) || (((o) = luaV_tonumber(o,n)) != NULL))
#define equalobj(L,o1,o2) (ttisequal(o1, o2) && luaV_equalobj_(L, o1, o2))
#define luaV_rawequalobj(o1,o2) equalobj(NULL,o1,o2)
/* not to called directly */
LUAI_FUNC int luaV_equalobj_ (lua_State *L, const TValue *t1, const TValue *t2);
LUAI_FUNC int luaV_lessthan (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC int luaV_lessequal (lua_State *L, const TValue *l, const TValue *r);
LUAI_FUNC const TValue *luaV_tonumber (const TValue *obj, TValue *n);
LUAI_FUNC int luaV_tostring (lua_State *L, StkId obj);
LUAI_FUNC void luaV_gettable (lua_State *L, const TValue *t, TValue *key,
StkId val);
LUAI_FUNC void luaV_settable (lua_State *L, const TValue *t, TValue *key,
StkId val);
LUAI_FUNC void luaV_finishOp (lua_State *L);
LUAI_FUNC void luaV_execute (lua_State *L);
LUAI_FUNC void luaV_concat (lua_State *L, int total);
LUAI_FUNC void luaV_arith (lua_State *L, StkId ra, const TValue *rb,
const TValue *rc, TMS op);
LUAI_FUNC void luaV_objlen (lua_State *L, StkId ra, const TValue *rb);
#endif

65
source/3rdparty/lua/include/lzio.h vendored Normal file
View File

@ -0,0 +1,65 @@
/*
** $Id: lzio.h,v 1.26.1.1 2013/04/12 18:48:47 roberto Exp $
** Buffered streams
** See Copyright Notice in lua.h
*/
#ifndef lzio_h
#define lzio_h
#include "lua.h"
#include "lmem.h"
#define EOZ (-1) /* end of stream */
typedef struct Zio ZIO;
#define zgetc(z) (((z)->n--)>0 ? cast_uchar(*(z)->p++) : luaZ_fill(z))
typedef struct Mbuffer {
char *buffer;
size_t n;
size_t buffsize;
} Mbuffer;
#define luaZ_initbuffer(L, buff) ((buff)->buffer = NULL, (buff)->buffsize = 0)
#define luaZ_buffer(buff) ((buff)->buffer)
#define luaZ_sizebuffer(buff) ((buff)->buffsize)
#define luaZ_bufflen(buff) ((buff)->n)
#define luaZ_resetbuffer(buff) ((buff)->n = 0)
#define luaZ_resizebuffer(L, buff, size) \
(luaM_reallocvector(L, (buff)->buffer, (buff)->buffsize, size, char), \
(buff)->buffsize = size)
#define luaZ_freebuffer(L, buff) luaZ_resizebuffer(L, buff, 0)
LUAI_FUNC char *luaZ_openspace (lua_State *L, Mbuffer *buff, size_t n);
LUAI_FUNC void luaZ_init (lua_State *L, ZIO *z, lua_Reader reader,
void *data);
LUAI_FUNC size_t luaZ_read (ZIO* z, void* b, size_t n); /* read next n bytes */
/* --------- Private Part ------------------ */
struct Zio {
size_t n; /* bytes still unread */
const char *p; /* current position in buffer */
lua_Reader reader; /* reader function */
void* data; /* additional data */
lua_State *L; /* Lua state (for reader) */
};
LUAI_FUNC int luaZ_fill (ZIO *z);
#endif

6
source/3rdparty/lua/license vendored Normal file
View File

@ -0,0 +1,6 @@
Copyright © 19942016 Lua.org, PUC-Rio.
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.

551
source/3rdparty/lua/luaconf_windows.h vendored Normal file
View File

@ -0,0 +1,551 @@
/*
** $Id: luaconf.h,v 1.176.1.2 2013/11/21 17:26:16 roberto Exp $
** Configuration file for Lua
** See Copyright Notice in lua.h
*/
#ifndef lconfig_h
#define lconfig_h
#include <limits.h>
#include <stddef.h>
/*
** ==================================================================
** Search for "@@" to find all configurable definitions.
** ===================================================================
*/
/*
@@ LUA_ANSI controls the use of non-ansi features.
** CHANGE it (define it) if you want Lua to avoid the use of any
** non-ansi feature or library.
*/
#if !defined(LUA_ANSI) && defined(__STRICT_ANSI__)
#define LUA_ANSI
#endif
#if !defined(LUA_ANSI) && defined(_WIN32) && !defined(_WIN32_WCE)
#define LUA_WIN /* enable goodies for regular Windows platforms */
#endif
#if defined(LUA_WIN)
#define LUA_DL_DLL
#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */
#endif
#if defined(LUA_USE_LINUX)
#define LUA_USE_POSIX
#define LUA_USE_DLOPEN /* needs an extra library: -ldl */
#define LUA_USE_READLINE /* needs some extra libraries */
#define LUA_USE_STRTODHEX /* assume 'strtod' handles hex formats */
#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */
#define LUA_USE_LONGLONG /* assume support for long long */
#endif
#if defined(LUA_USE_MACOSX)
#define LUA_USE_POSIX
#define LUA_USE_DLOPEN /* does not need -ldl */
#define LUA_USE_READLINE /* needs an extra library: -lreadline */
#define LUA_USE_STRTODHEX /* assume 'strtod' handles hex formats */
#define LUA_USE_AFORMAT /* assume 'printf' handles 'aA' specifiers */
#define LUA_USE_LONGLONG /* assume support for long long */
#endif
/*
@@ LUA_USE_POSIX includes all functionality listed as X/Open System
@* Interfaces Extension (XSI).
** CHANGE it (define it) if your system is XSI compatible.
*/
#if defined(LUA_USE_POSIX)
#define LUA_USE_MKSTEMP
#define LUA_USE_ISATTY
#define LUA_USE_POPEN
#define LUA_USE_ULONGJMP
#define LUA_USE_GMTIME_R
#endif
/*
@@ LUA_PATH_DEFAULT is the default path that Lua uses to look for
@* Lua libraries.
@@ LUA_CPATH_DEFAULT is the default path that Lua uses to look for
@* C libraries.
** CHANGE them if your machine has a non-conventional directory
** hierarchy or if you want to install your libraries in
** non-conventional directories.
*/
#if defined(_WIN32) /* { */
/*
** In Windows, any exclamation mark ('!') in the path is replaced by the
** path of the directory of the executable file of the current process.
*/
#define LUA_LDIR "!\\lua\\"
#define LUA_CDIR "!\\"
#define LUA_PATH_DEFAULT \
LUA_LDIR"?.lua;" LUA_LDIR"?\\init.lua;" \
LUA_CDIR"?.lua;" LUA_CDIR"?\\init.lua;" ".\\?.lua"
#define LUA_CPATH_DEFAULT \
LUA_CDIR"?.dll;" LUA_CDIR"loadall.dll;" ".\\?.dll"
#else /* }{ */
#define LUA_VDIR LUA_VERSION_MAJOR "." LUA_VERSION_MINOR "/"
#define LUA_ROOT "/usr/local/"
#define LUA_LDIR LUA_ROOT "share/lua/" LUA_VDIR
#define LUA_CDIR LUA_ROOT "lib/lua/" LUA_VDIR
#define LUA_PATH_DEFAULT \
LUA_LDIR"?.lua;" LUA_LDIR"?/init.lua;" \
LUA_CDIR"?.lua;" LUA_CDIR"?/init.lua;" "./?.lua"
#define LUA_CPATH_DEFAULT \
LUA_CDIR"?.so;" LUA_CDIR"loadall.so;" "./?.so"
#endif /* } */
/*
@@ LUA_DIRSEP is the directory separator (for submodules).
** CHANGE it if your machine does not use "/" as the directory separator
** and is not Windows. (On Windows Lua automatically uses "\".)
*/
#if defined(_WIN32)
#define LUA_DIRSEP "\\"
#else
#define LUA_DIRSEP "/"
#endif
/*
@@ LUA_ENV is the name of the variable that holds the current
@@ environment, used to access global names.
** CHANGE it if you do not like this name.
*/
#define LUA_ENV "_ENV"
/*
@@ LUA_API is a mark for all core API functions.
@@ LUALIB_API is a mark for all auxiliary library functions.
@@ LUAMOD_API is a mark for all standard library opening functions.
** CHANGE them if you need to define those functions in some special way.
** For instance, if you want to create one Windows DLL with the core and
** the libraries, you may want to use the following definition (define
** LUA_BUILD_AS_DLL to get it).
*/
#if defined(LUA_BUILD_AS_DLL) /* { */
#if defined(LUA_CORE) || defined(LUA_LIB) /* { */
#define LUA_API __declspec(dllexport)
#else /* }{ */
#define LUA_API __declspec(dllimport)
#endif /* } */
#else /* }{ */
#define LUA_API extern
#endif /* } */
/* more often than not the libs go together with the core */
#define LUALIB_API LUA_API
#define LUAMOD_API LUALIB_API
/*
@@ LUAI_FUNC is a mark for all extern functions that are not to be
@* exported to outside modules.
@@ LUAI_DDEF and LUAI_DDEC are marks for all extern (const) variables
@* that are not to be exported to outside modules (LUAI_DDEF for
@* definitions and LUAI_DDEC for declarations).
** CHANGE them if you need to mark them in some special way. Elf/gcc
** (versions 3.2 and later) mark them as "hidden" to optimize access
** when Lua is compiled as a shared library. Not all elf targets support
** this attribute. Unfortunately, gcc does not offer a way to check
** whether the target offers that support, and those without support
** give a warning about it. To avoid these warnings, change to the
** default definition.
*/
#if defined(__GNUC__) && ((__GNUC__*100 + __GNUC_MINOR__) >= 302) && \
defined(__ELF__) /* { */
#define LUAI_FUNC __attribute__((visibility("hidden"))) extern
#define LUAI_DDEC LUAI_FUNC
#define LUAI_DDEF /* empty */
#else /* }{ */
#define LUAI_FUNC extern
#define LUAI_DDEC extern
#define LUAI_DDEF /* empty */
#endif /* } */
/*
@@ LUA_QL describes how error messages quote program elements.
** CHANGE it if you want a different appearance.
*/
#define LUA_QL(x) "'" x "'"
#define LUA_QS LUA_QL("%s")
/*
@@ LUA_IDSIZE gives the maximum size for the description of the source
@* of a function in debug information.
** CHANGE it if you want a different size.
*/
#define LUA_IDSIZE 60
/*
@@ luai_writestring/luai_writeline define how 'print' prints its results.
** They are only used in libraries and the stand-alone program. (The #if
** avoids including 'stdio.h' everywhere.)
*/
#if defined(LUA_LIB) || defined(lua_c)
#include <stdio.h>
#define luai_writestring(s,l) fwrite((s), sizeof(char), (l), stdout)
#define luai_writeline() (luai_writestring("\n", 1), fflush(stdout))
#endif
/*
@@ luai_writestringerror defines how to print error messages.
** (A format string with one argument is enough for Lua...)
*/
#define luai_writestringerror(s,p) \
(fprintf(stderr, (s), (p)), fflush(stderr))
/*
@@ LUAI_MAXSHORTLEN is the maximum length for short strings, that is,
** strings that are internalized. (Cannot be smaller than reserved words
** or tags for metamethods, as these strings must be internalized;
** #("function") = 8, #("__newindex") = 10.)
*/
#define LUAI_MAXSHORTLEN 40
/*
** {==================================================================
** Compatibility with previous versions
** ===================================================================
*/
/*
@@ LUA_COMPAT_ALL controls all compatibility options.
** You can define it to get all options, or change specific options
** to fit your specific needs.
*/
#if defined(LUA_COMPAT_ALL) /* { */
/*
@@ LUA_COMPAT_UNPACK controls the presence of global 'unpack'.
** You can replace it with 'table.unpack'.
*/
#define LUA_COMPAT_UNPACK
/*
@@ LUA_COMPAT_LOADERS controls the presence of table 'package.loaders'.
** You can replace it with 'package.searchers'.
*/
#define LUA_COMPAT_LOADERS
/*
@@ macro 'lua_cpcall' emulates deprecated function lua_cpcall.
** You can call your C function directly (with light C functions).
*/
#define lua_cpcall(L,f,u) \
(lua_pushcfunction(L, (f)), \
lua_pushlightuserdata(L,(u)), \
lua_pcall(L,1,0,0))
/*
@@ LUA_COMPAT_LOG10 defines the function 'log10' in the math library.
** You can rewrite 'log10(x)' as 'log(x, 10)'.
*/
#define LUA_COMPAT_LOG10
/*
@@ LUA_COMPAT_LOADSTRING defines the function 'loadstring' in the base
** library. You can rewrite 'loadstring(s)' as 'load(s)'.
*/
#define LUA_COMPAT_LOADSTRING
/*
@@ LUA_COMPAT_MAXN defines the function 'maxn' in the table library.
*/
#define LUA_COMPAT_MAXN
/*
@@ The following macros supply trivial compatibility for some
** changes in the API. The macros themselves document how to
** change your code to avoid using them.
*/
#define lua_strlen(L,i) lua_rawlen(L, (i))
#define lua_objlen(L,i) lua_rawlen(L, (i))
#define lua_equal(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPEQ)
#define lua_lessthan(L,idx1,idx2) lua_compare(L,(idx1),(idx2),LUA_OPLT)
/*
@@ LUA_COMPAT_MODULE controls compatibility with previous
** module functions 'module' (Lua) and 'luaL_register' (C).
*/
#define LUA_COMPAT_MODULE
#endif /* } */
/* }================================================================== */
/*
@@ LUAI_BITSINT defines the number of bits in an int.
** CHANGE here if Lua cannot automatically detect the number of bits of
** your machine. Probably you do not need to change this.
*/
/* avoid overflows in comparison */
#if INT_MAX-20 < 32760 /* { */
#define LUAI_BITSINT 16
#elif INT_MAX > 2147483640L /* }{ */
/* int has at least 32 bits */
#define LUAI_BITSINT 32
#else /* }{ */
#error "you must define LUA_BITSINT with number of bits in an integer"
#endif /* } */
/*
@@ LUA_INT32 is a signed integer with exactly 32 bits.
@@ LUAI_UMEM is an unsigned integer big enough to count the total
@* memory used by Lua.
@@ LUAI_MEM is a signed integer big enough to count the total memory
@* used by Lua.
** CHANGE here if for some weird reason the default definitions are not
** good enough for your machine. Probably you do not need to change
** this.
*/
#if LUAI_BITSINT >= 32 /* { */
#define LUA_INT32 int
#define LUAI_UMEM size_t
#define LUAI_MEM ptrdiff_t
#else /* }{ */
/* 16-bit ints */
#define LUA_INT32 long
#define LUAI_UMEM unsigned long
#define LUAI_MEM long
#endif /* } */
/*
@@ LUAI_MAXSTACK limits the size of the Lua stack.
** CHANGE it if you need a different limit. This limit is arbitrary;
** its only purpose is to stop Lua from consuming unlimited stack
** space (and to reserve some numbers for pseudo-indices).
*/
#if LUAI_BITSINT >= 32
#define LUAI_MAXSTACK 1000000
#else
#define LUAI_MAXSTACK 15000
#endif
/* reserve some space for error handling */
#define LUAI_FIRSTPSEUDOIDX (-LUAI_MAXSTACK - 1000)
/*
@@ LUAL_BUFFERSIZE is the buffer size used by the lauxlib buffer system.
** CHANGE it if it uses too much C-stack space.
*/
#define LUAL_BUFFERSIZE BUFSIZ
/*
** {==================================================================
@@ LUA_NUMBER is the type of numbers in Lua.
** CHANGE the following definitions only if you want to build Lua
** with a number type different from double. You may also need to
** change lua_number2int & lua_number2integer.
** ===================================================================
*/
#define LUA_NUMBER_DOUBLE
#define LUA_NUMBER double
/*
@@ LUAI_UACNUMBER is the result of an 'usual argument conversion'
@* over a number.
*/
#define LUAI_UACNUMBER double
/*
@@ LUA_NUMBER_SCAN is the format for reading numbers.
@@ LUA_NUMBER_FMT is the format for writing numbers.
@@ lua_number2str converts a number to a string.
@@ LUAI_MAXNUMBER2STR is maximum size of previous conversion.
*/
#define LUA_NUMBER_SCAN "%lf"
#define LUA_NUMBER_FMT "%.14g"
#define lua_number2str(s,n) sprintf((s), LUA_NUMBER_FMT, (n))
#define LUAI_MAXNUMBER2STR 32 /* 16 digits, sign, point, and \0 */
/*
@@ l_mathop allows the addition of an 'l' or 'f' to all math operations
*/
#define l_mathop(x) (x)
/*
@@ lua_str2number converts a decimal numeric string to a number.
@@ lua_strx2number converts an hexadecimal numeric string to a number.
** In C99, 'strtod' does both conversions. C89, however, has no function
** to convert floating hexadecimal strings to numbers. For these
** systems, you can leave 'lua_strx2number' undefined and Lua will
** provide its own implementation.
*/
#define lua_str2number(s,p) strtod((s), (p))
#if defined(LUA_USE_STRTODHEX)
#define lua_strx2number(s,p) strtod((s), (p))
#endif
/*
@@ The luai_num* macros define the primitive operations over numbers.
*/
/* the following operations need the math library */
#if defined(lobject_c) || defined(lvm_c)
#include <math.h>
#define luai_nummod(L,a,b) ((a) - l_mathop(floor)((a)/(b))*(b))
#define luai_numpow(L,a,b) (l_mathop(pow)(a,b))
#endif
/* these are quite standard operations */
#if defined(LUA_CORE)
#define luai_numadd(L,a,b) ((a)+(b))
#define luai_numsub(L,a,b) ((a)-(b))
#define luai_nummul(L,a,b) ((a)*(b))
#define luai_numdiv(L,a,b) ((a)/(b))
#define luai_numunm(L,a) (-(a))
#define luai_numeq(a,b) ((a)==(b))
#define luai_numlt(L,a,b) ((a)<(b))
#define luai_numle(L,a,b) ((a)<=(b))
#define luai_numisnan(L,a) (!luai_numeq((a), (a)))
#endif
/*
@@ LUA_INTEGER is the integral type used by lua_pushinteger/lua_tointeger.
** CHANGE that if ptrdiff_t is not adequate on your machine. (On most
** machines, ptrdiff_t gives a good choice between int or long.)
*/
#define LUA_INTEGER ptrdiff_t
/*
@@ LUA_UNSIGNED is the integral type used by lua_pushunsigned/lua_tounsigned.
** It must have at least 32 bits.
*/
#define LUA_UNSIGNED unsigned LUA_INT32
/*
** Some tricks with doubles
*/
#if defined(LUA_NUMBER_DOUBLE) && !defined(LUA_ANSI) /* { */
/*
** The next definitions activate some tricks to speed up the
** conversion from doubles to integer types, mainly to LUA_UNSIGNED.
**
@@ LUA_MSASMTRICK uses Microsoft assembler to avoid clashes with a
** DirectX idiosyncrasy.
**
@@ LUA_IEEE754TRICK uses a trick that should work on any machine
** using IEEE754 with a 32-bit integer type.
**
@@ LUA_IEEELL extends the trick to LUA_INTEGER; should only be
** defined when LUA_INTEGER is a 32-bit integer.
**
@@ LUA_IEEEENDIAN is the endianness of doubles in your machine
** (0 for little endian, 1 for big endian); if not defined, Lua will
** check it dynamically for LUA_IEEE754TRICK (but not for LUA_NANTRICK).
**
@@ LUA_NANTRICK controls the use of a trick to pack all types into
** a single double value, using NaN values to represent non-number
** values. The trick only works on 32-bit machines (ints and pointers
** are 32-bit values) with numbers represented as IEEE 754-2008 doubles
** with conventional endianess (12345678 or 87654321), in CPUs that do
** not produce signaling NaN values (all NaNs are quiet).
*/
/* Microsoft compiler on a Pentium (32 bit) ? */
#if defined(LUA_WIN) && defined(_MSC_VER) && defined(_M_IX86) /* { */
#define LUA_MSASMTRICK
#define LUA_IEEEENDIAN 0
#define LUA_NANTRICK
/* pentium 32 bits? */
#elif defined(__i386__) || defined(__i386) || defined(__X86__) /* }{ */
#define LUA_IEEE754TRICK
#define LUA_IEEELL
#define LUA_IEEEENDIAN 0
#define LUA_NANTRICK
/* pentium 64 bits? */
#elif defined(__x86_64) /* }{ */
#define LUA_IEEE754TRICK
#define LUA_IEEEENDIAN 0
#elif defined(__POWERPC__) || defined(__ppc__) /* }{ */
#define LUA_IEEE754TRICK
#define LUA_IEEEENDIAN 1
#else /* }{ */
/* assume IEEE754 and a 32-bit integer type */
#define LUA_IEEE754TRICK
#endif /* } */
#endif /* } */
/* }================================================================== */
/* =================================================================== */
/*
** Local configuration. You can use this space to add your redefinitions
** without modifying the main part of the file.
*/
#endif

1284
source/3rdparty/lua/src/lapi.c vendored Normal file

File diff suppressed because it is too large Load Diff

959
source/3rdparty/lua/src/lauxlib.c vendored Normal file
View File

@ -0,0 +1,959 @@
/*
** $Id: lauxlib.c,v 1.248.1.1 2013/04/12 18:48:47 roberto Exp $
** Auxiliary functions for building Lua libraries
** See Copyright Notice in lua.h
*/
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* This file uses only the official API of Lua.
** Any function declared here could be written as an application function.
*/
#define lauxlib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
/*
** {======================================================
** Traceback
** =======================================================
*/
#define LEVELS1 12 /* size of the first part of the stack */
#define LEVELS2 10 /* size of the second part of the stack */
/*
** search for 'objidx' in table at index -1.
** return 1 + string at top if find a good name.
*/
static int findfield (lua_State *L, int objidx, int level) {
if (level == 0 || !lua_istable(L, -1))
return 0; /* not found */
lua_pushnil(L); /* start 'next' loop */
while (lua_next(L, -2)) { /* for each pair in table */
if (lua_type(L, -2) == LUA_TSTRING) { /* ignore non-string keys */
if (lua_rawequal(L, objidx, -1)) { /* found object? */
lua_pop(L, 1); /* remove value (but keep name) */
return 1;
}
else if (findfield(L, objidx, level - 1)) { /* try recursively */
lua_remove(L, -2); /* remove table (but keep name) */
lua_pushliteral(L, ".");
lua_insert(L, -2); /* place '.' between the two names */
lua_concat(L, 3);
return 1;
}
}
lua_pop(L, 1); /* remove value */
}
return 0; /* not found */
}
static int pushglobalfuncname (lua_State *L, lua_Debug *ar) {
int top = lua_gettop(L);
lua_getinfo(L, "f", ar); /* push function */
lua_pushglobaltable(L);
if (findfield(L, top + 1, 2)) {
lua_copy(L, -1, top + 1); /* move name to proper place */
lua_pop(L, 2); /* remove pushed values */
return 1;
}
else {
lua_settop(L, top); /* remove function and global table */
return 0;
}
}
static void pushfuncname (lua_State *L, lua_Debug *ar) {
if (*ar->namewhat != '\0') /* is there a name? */
lua_pushfstring(L, "function " LUA_QS, ar->name);
else if (*ar->what == 'm') /* main? */
lua_pushliteral(L, "main chunk");
else if (*ar->what == 'C') {
if (pushglobalfuncname(L, ar)) {
lua_pushfstring(L, "function " LUA_QS, lua_tostring(L, -1));
lua_remove(L, -2); /* remove name */
}
else
lua_pushliteral(L, "?");
}
else
lua_pushfstring(L, "function <%s:%d>", ar->short_src, ar->linedefined);
}
static int countlevels (lua_State *L) {
lua_Debug ar;
int li = 1, le = 1;
/* find an upper bound */
while (lua_getstack(L, le, &ar)) { li = le; le *= 2; }
/* do a binary search */
while (li < le) {
int m = (li + le)/2;
if (lua_getstack(L, m, &ar)) li = m + 1;
else le = m;
}
return le - 1;
}
LUALIB_API void luaL_traceback (lua_State *L, lua_State *L1,
const char *msg, int level) {
lua_Debug ar;
int top = lua_gettop(L);
int numlevels = countlevels(L1);
int mark = (numlevels > LEVELS1 + LEVELS2) ? LEVELS1 : 0;
if (msg) lua_pushfstring(L, "%s\n", msg);
lua_pushliteral(L, "stack traceback:");
while (lua_getstack(L1, level++, &ar)) {
if (level == mark) { /* too many levels? */
lua_pushliteral(L, "\n\t..."); /* add a '...' */
level = numlevels - LEVELS2; /* and skip to last ones */
}
else {
lua_getinfo(L1, "Slnt", &ar);
lua_pushfstring(L, "\n\t%s:", ar.short_src);
if (ar.currentline > 0)
lua_pushfstring(L, "%d:", ar.currentline);
lua_pushliteral(L, " in ");
pushfuncname(L, &ar);
if (ar.istailcall)
lua_pushliteral(L, "\n\t(...tail calls...)");
lua_concat(L, lua_gettop(L) - top);
}
}
lua_concat(L, lua_gettop(L) - top);
}
/* }====================================================== */
/*
** {======================================================
** Error-report functions
** =======================================================
*/
LUALIB_API int luaL_argerror (lua_State *L, int narg, const char *extramsg) {
lua_Debug ar;
if (!lua_getstack(L, 0, &ar)) /* no stack frame? */
return luaL_error(L, "bad argument #%d (%s)", narg, extramsg);
lua_getinfo(L, "n", &ar);
if (strcmp(ar.namewhat, "method") == 0) {
narg--; /* do not count `self' */
if (narg == 0) /* error is in the self argument itself? */
return luaL_error(L, "calling " LUA_QS " on bad self (%s)",
ar.name, extramsg);
}
if (ar.name == NULL)
ar.name = (pushglobalfuncname(L, &ar)) ? lua_tostring(L, -1) : "?";
return luaL_error(L, "bad argument #%d to " LUA_QS " (%s)",
narg, ar.name, extramsg);
}
static int typeerror (lua_State *L, int narg, const char *tname) {
const char *msg = lua_pushfstring(L, "%s expected, got %s",
tname, luaL_typename(L, narg));
return luaL_argerror(L, narg, msg);
}
static void tag_error (lua_State *L, int narg, int tag) {
typeerror(L, narg, lua_typename(L, tag));
}
LUALIB_API void luaL_where (lua_State *L, int level) {
lua_Debug ar;
if (lua_getstack(L, level, &ar)) { /* check function at level */
lua_getinfo(L, "Sl", &ar); /* get info about it */
if (ar.currentline > 0) { /* is there info? */
lua_pushfstring(L, "%s:%d: ", ar.short_src, ar.currentline);
return;
}
}
lua_pushliteral(L, ""); /* else, no information available... */
}
LUALIB_API int luaL_error (lua_State *L, const char *fmt, ...) {
va_list argp;
va_start(argp, fmt);
luaL_where(L, 1);
lua_pushvfstring(L, fmt, argp);
va_end(argp);
lua_concat(L, 2);
return lua_error(L);
}
LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) {
int en = errno; /* calls to Lua API may change this value */
if (stat) {
lua_pushboolean(L, 1);
return 1;
}
else {
lua_pushnil(L);
if (fname)
lua_pushfstring(L, "%s: %s", fname, strerror(en));
else
lua_pushstring(L, strerror(en));
lua_pushinteger(L, en);
return 3;
}
}
#if !defined(inspectstat) /* { */
#if defined(LUA_USE_POSIX)
#include <sys/wait.h>
/*
** use appropriate macros to interpret 'pclose' return status
*/
#define inspectstat(stat,what) \
if (WIFEXITED(stat)) { stat = WEXITSTATUS(stat); } \
else if (WIFSIGNALED(stat)) { stat = WTERMSIG(stat); what = "signal"; }
#else
#define inspectstat(stat,what) /* no op */
#endif
#endif /* } */
LUALIB_API int luaL_execresult (lua_State *L, int stat) {
const char *what = "exit"; /* type of termination */
if (stat == -1) /* error? */
return luaL_fileresult(L, 0, NULL);
else {
inspectstat(stat, what); /* interpret result */
if (*what == 'e' && stat == 0) /* successful termination? */
lua_pushboolean(L, 1);
else
lua_pushnil(L);
lua_pushstring(L, what);
lua_pushinteger(L, stat);
return 3; /* return true/nil,what,code */
}
}
/* }====================================================== */
/*
** {======================================================
** Userdata's metatable manipulation
** =======================================================
*/
LUALIB_API int luaL_newmetatable (lua_State *L, const char *tname) {
luaL_getmetatable(L, tname); /* try to get metatable */
if (!lua_isnil(L, -1)) /* name already in use? */
return 0; /* leave previous value on top, but return 0 */
lua_pop(L, 1);
lua_newtable(L); /* create metatable */
lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, tname); /* registry.name = metatable */
return 1;
}
LUALIB_API void luaL_setmetatable (lua_State *L, const char *tname) {
luaL_getmetatable(L, tname);
lua_setmetatable(L, -2);
}
LUALIB_API void *luaL_testudata (lua_State *L, int ud, const char *tname) {
void *p = lua_touserdata(L, ud);
if (p != NULL) { /* value is a userdata? */
if (lua_getmetatable(L, ud)) { /* does it have a metatable? */
luaL_getmetatable(L, tname); /* get correct metatable */
if (!lua_rawequal(L, -1, -2)) /* not the same? */
p = NULL; /* value is a userdata with wrong metatable */
lua_pop(L, 2); /* remove both metatables */
return p;
}
}
return NULL; /* value is not a userdata with a metatable */
}
LUALIB_API void *luaL_checkudata (lua_State *L, int ud, const char *tname) {
void *p = luaL_testudata(L, ud, tname);
if (p == NULL) typeerror(L, ud, tname);
return p;
}
/* }====================================================== */
/*
** {======================================================
** Argument check functions
** =======================================================
*/
LUALIB_API int luaL_checkoption (lua_State *L, int narg, const char *def,
const char *const lst[]) {
const char *name = (def) ? luaL_optstring(L, narg, def) :
luaL_checkstring(L, narg);
int i;
for (i=0; lst[i]; i++)
if (strcmp(lst[i], name) == 0)
return i;
return luaL_argerror(L, narg,
lua_pushfstring(L, "invalid option " LUA_QS, name));
}
LUALIB_API void luaL_checkstack (lua_State *L, int space, const char *msg) {
/* keep some extra space to run error routines, if needed */
const int extra = LUA_MINSTACK;
if (!lua_checkstack(L, space + extra)) {
if (msg)
luaL_error(L, "stack overflow (%s)", msg);
else
luaL_error(L, "stack overflow");
}
}
LUALIB_API void luaL_checktype (lua_State *L, int narg, int t) {
if (lua_type(L, narg) != t)
tag_error(L, narg, t);
}
LUALIB_API void luaL_checkany (lua_State *L, int narg) {
if (lua_type(L, narg) == LUA_TNONE)
luaL_argerror(L, narg, "value expected");
}
LUALIB_API const char *luaL_checklstring (lua_State *L, int narg, size_t *len) {
const char *s = lua_tolstring(L, narg, len);
if (!s) tag_error(L, narg, LUA_TSTRING);
return s;
}
LUALIB_API const char *luaL_optlstring (lua_State *L, int narg,
const char *def, size_t *len) {
if (lua_isnoneornil(L, narg)) {
if (len)
*len = (def ? strlen(def) : 0);
return def;
}
else return luaL_checklstring(L, narg, len);
}
LUALIB_API lua_Number luaL_checknumber (lua_State *L, int narg) {
int isnum;
lua_Number d = lua_tonumberx(L, narg, &isnum);
if (!isnum)
tag_error(L, narg, LUA_TNUMBER);
return d;
}
LUALIB_API lua_Number luaL_optnumber (lua_State *L, int narg, lua_Number def) {
return luaL_opt(L, luaL_checknumber, narg, def);
}
LUALIB_API lua_Integer luaL_checkinteger (lua_State *L, int narg) {
int isnum;
lua_Integer d = lua_tointegerx(L, narg, &isnum);
if (!isnum)
tag_error(L, narg, LUA_TNUMBER);
return d;
}
LUALIB_API lua_Unsigned luaL_checkunsigned (lua_State *L, int narg) {
int isnum;
lua_Unsigned d = lua_tounsignedx(L, narg, &isnum);
if (!isnum)
tag_error(L, narg, LUA_TNUMBER);
return d;
}
LUALIB_API lua_Integer luaL_optinteger (lua_State *L, int narg,
lua_Integer def) {
return luaL_opt(L, luaL_checkinteger, narg, def);
}
LUALIB_API lua_Unsigned luaL_optunsigned (lua_State *L, int narg,
lua_Unsigned def) {
return luaL_opt(L, luaL_checkunsigned, narg, def);
}
/* }====================================================== */
/*
** {======================================================
** Generic Buffer manipulation
** =======================================================
*/
/*
** check whether buffer is using a userdata on the stack as a temporary
** buffer
*/
#define buffonstack(B) ((B)->b != (B)->initb)
/*
** returns a pointer to a free area with at least 'sz' bytes
*/
LUALIB_API char *luaL_prepbuffsize (luaL_Buffer *B, size_t sz) {
lua_State *L = B->L;
if (B->size - B->n < sz) { /* not enough space? */
char *newbuff;
size_t newsize = B->size * 2; /* double buffer size */
if (newsize - B->n < sz) /* not big enough? */
newsize = B->n + sz;
if (newsize < B->n || newsize - B->n < sz)
luaL_error(L, "buffer too large");
/* create larger buffer */
newbuff = (char *)lua_newuserdata(L, newsize * sizeof(char));
/* move content to new buffer */
memcpy(newbuff, B->b, B->n * sizeof(char));
if (buffonstack(B))
lua_remove(L, -2); /* remove old buffer */
B->b = newbuff;
B->size = newsize;
}
return &B->b[B->n];
}
LUALIB_API void luaL_addlstring (luaL_Buffer *B, const char *s, size_t l) {
char *b = luaL_prepbuffsize(B, l);
memcpy(b, s, l * sizeof(char));
luaL_addsize(B, l);
}
LUALIB_API void luaL_addstring (luaL_Buffer *B, const char *s) {
luaL_addlstring(B, s, strlen(s));
}
LUALIB_API void luaL_pushresult (luaL_Buffer *B) {
lua_State *L = B->L;
lua_pushlstring(L, B->b, B->n);
if (buffonstack(B))
lua_remove(L, -2); /* remove old buffer */
}
LUALIB_API void luaL_pushresultsize (luaL_Buffer *B, size_t sz) {
luaL_addsize(B, sz);
luaL_pushresult(B);
}
LUALIB_API void luaL_addvalue (luaL_Buffer *B) {
lua_State *L = B->L;
size_t l;
const char *s = lua_tolstring(L, -1, &l);
if (buffonstack(B))
lua_insert(L, -2); /* put value below buffer */
luaL_addlstring(B, s, l);
lua_remove(L, (buffonstack(B)) ? -2 : -1); /* remove value */
}
LUALIB_API void luaL_buffinit (lua_State *L, luaL_Buffer *B) {
B->L = L;
B->b = B->initb;
B->n = 0;
B->size = LUAL_BUFFERSIZE;
}
LUALIB_API char *luaL_buffinitsize (lua_State *L, luaL_Buffer *B, size_t sz) {
luaL_buffinit(L, B);
return luaL_prepbuffsize(B, sz);
}
/* }====================================================== */
/*
** {======================================================
** Reference system
** =======================================================
*/
/* index of free-list header */
#define freelist 0
LUALIB_API int luaL_ref (lua_State *L, int t) {
int ref;
if (lua_isnil(L, -1)) {
lua_pop(L, 1); /* remove from stack */
return LUA_REFNIL; /* `nil' has a unique fixed reference */
}
t = lua_absindex(L, t);
lua_rawgeti(L, t, freelist); /* get first free element */
ref = (int)lua_tointeger(L, -1); /* ref = t[freelist] */
lua_pop(L, 1); /* remove it from stack */
if (ref != 0) { /* any free element? */
lua_rawgeti(L, t, ref); /* remove it from list */
lua_rawseti(L, t, freelist); /* (t[freelist] = t[ref]) */
}
else /* no free elements */
ref = (int)lua_rawlen(L, t) + 1; /* get a new reference */
lua_rawseti(L, t, ref);
return ref;
}
LUALIB_API void luaL_unref (lua_State *L, int t, int ref) {
if (ref >= 0) {
t = lua_absindex(L, t);
lua_rawgeti(L, t, freelist);
lua_rawseti(L, t, ref); /* t[ref] = t[freelist] */
lua_pushinteger(L, ref);
lua_rawseti(L, t, freelist); /* t[freelist] = ref */
}
}
/* }====================================================== */
/*
** {======================================================
** Load functions
** =======================================================
*/
typedef struct LoadF {
int n; /* number of pre-read characters */
FILE *f; /* file being read */
char buff[LUAL_BUFFERSIZE]; /* area for reading file */
} LoadF;
static const char *getF (lua_State *L, void *ud, size_t *size) {
LoadF *lf = (LoadF *)ud;
(void)L; /* not used */
if (lf->n > 0) { /* are there pre-read characters to be read? */
*size = lf->n; /* return them (chars already in buffer) */
lf->n = 0; /* no more pre-read characters */
}
else { /* read a block from file */
/* 'fread' can return > 0 *and* set the EOF flag. If next call to
'getF' called 'fread', it might still wait for user input.
The next check avoids this problem. */
if (feof(lf->f)) return NULL;
*size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */
}
return lf->buff;
}
static int errfile (lua_State *L, const char *what, int fnameindex) {
const char *serr = strerror(errno);
const char *filename = lua_tostring(L, fnameindex) + 1;
lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
lua_remove(L, fnameindex);
return LUA_ERRFILE;
}
static int skipBOM (LoadF *lf) {
const char *p = "\xEF\xBB\xBF"; /* Utf8 BOM mark */
int c;
lf->n = 0;
do {
c = getc(lf->f);
if (c == EOF || c != *(const unsigned char *)p++) return c;
lf->buff[lf->n++] = c; /* to be read by the parser */
} while (*p != '\0');
lf->n = 0; /* prefix matched; discard it */
return getc(lf->f); /* return next character */
}
/*
** reads the first character of file 'f' and skips an optional BOM mark
** in its beginning plus its first line if it starts with '#'. Returns
** true if it skipped the first line. In any case, '*cp' has the
** first "valid" character of the file (after the optional BOM and
** a first-line comment).
*/
static int skipcomment (LoadF *lf, int *cp) {
int c = *cp = skipBOM(lf);
if (c == '#') { /* first line is a comment (Unix exec. file)? */
do { /* skip first line */
c = getc(lf->f);
} while (c != EOF && c != '\n') ;
*cp = getc(lf->f); /* skip end-of-line, if present */
return 1; /* there was a comment */
}
else return 0; /* no comment */
}
LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename,
const char *mode) {
LoadF lf;
int status, readstatus;
int c;
int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */
if (filename == NULL) {
lua_pushliteral(L, "=stdin");
lf.f = stdin;
}
else {
lua_pushfstring(L, "@%s", filename);
lf.f = fopen(filename, "r");
if (lf.f == NULL) return errfile(L, "open", fnameindex);
}
if (skipcomment(&lf, &c)) /* read initial portion */
lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */
if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */
if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
skipcomment(&lf, &c); /* re-read initial portion */
}
if (c != EOF)
lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */
status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode);
readstatus = ferror(lf.f);
if (filename) fclose(lf.f); /* close file (even in case of errors) */
if (readstatus) {
lua_settop(L, fnameindex); /* ignore results from `lua_load' */
return errfile(L, "read", fnameindex);
}
lua_remove(L, fnameindex);
return status;
}
typedef struct LoadS {
const char *s;
size_t size;
} LoadS;
static const char *getS (lua_State *L, void *ud, size_t *size) {
LoadS *ls = (LoadS *)ud;
(void)L; /* not used */
if (ls->size == 0) return NULL;
*size = ls->size;
ls->size = 0;
return ls->s;
}
LUALIB_API int luaL_loadbufferx (lua_State *L, const char *buff, size_t size,
const char *name, const char *mode) {
LoadS ls;
ls.s = buff;
ls.size = size;
return lua_load(L, getS, &ls, name, mode);
}
LUALIB_API int luaL_loadstring (lua_State *L, const char *s) {
return luaL_loadbuffer(L, s, strlen(s), s);
}
/* }====================================================== */
LUALIB_API int luaL_getmetafield (lua_State *L, int obj, const char *event) {
if (!lua_getmetatable(L, obj)) /* no metatable? */
return 0;
lua_pushstring(L, event);
lua_rawget(L, -2);
if (lua_isnil(L, -1)) {
lua_pop(L, 2); /* remove metatable and metafield */
return 0;
}
else {
lua_remove(L, -2); /* remove only metatable */
return 1;
}
}
LUALIB_API int luaL_callmeta (lua_State *L, int obj, const char *event) {
obj = lua_absindex(L, obj);
if (!luaL_getmetafield(L, obj, event)) /* no metafield? */
return 0;
lua_pushvalue(L, obj);
lua_call(L, 1, 1);
return 1;
}
LUALIB_API int luaL_len (lua_State *L, int idx) {
int l;
int isnum;
lua_len(L, idx);
l = (int)lua_tointegerx(L, -1, &isnum);
if (!isnum)
luaL_error(L, "object length is not a number");
lua_pop(L, 1); /* remove object */
return l;
}
LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) {
if (!luaL_callmeta(L, idx, "__tostring")) { /* no metafield? */
switch (lua_type(L, idx)) {
case LUA_TNUMBER:
case LUA_TSTRING:
lua_pushvalue(L, idx);
break;
case LUA_TBOOLEAN:
lua_pushstring(L, (lua_toboolean(L, idx) ? "true" : "false"));
break;
case LUA_TNIL:
lua_pushliteral(L, "nil");
break;
default:
lua_pushfstring(L, "%s: %p", luaL_typename(L, idx),
lua_topointer(L, idx));
break;
}
}
return lua_tolstring(L, -1, len);
}
/*
** {======================================================
** Compatibility with 5.1 module functions
** =======================================================
*/
#if defined(LUA_COMPAT_MODULE)
static const char *luaL_findtable (lua_State *L, int idx,
const char *fname, int szhint) {
const char *e;
if (idx) lua_pushvalue(L, idx);
do {
e = strchr(fname, '.');
if (e == NULL) e = fname + strlen(fname);
lua_pushlstring(L, fname, e - fname);
lua_rawget(L, -2);
if (lua_isnil(L, -1)) { /* no such field? */
lua_pop(L, 1); /* remove this nil */
lua_createtable(L, 0, (*e == '.' ? 1 : szhint)); /* new table for field */
lua_pushlstring(L, fname, e - fname);
lua_pushvalue(L, -2);
lua_settable(L, -4); /* set new table into field */
}
else if (!lua_istable(L, -1)) { /* field has a non-table value? */
lua_pop(L, 2); /* remove table and value */
return fname; /* return problematic part of the name */
}
lua_remove(L, -2); /* remove previous table */
fname = e + 1;
} while (*e == '.');
return NULL;
}
/*
** Count number of elements in a luaL_Reg list.
*/
static int libsize (const luaL_Reg *l) {
int size = 0;
for (; l && l->name; l++) size++;
return size;
}
/*
** Find or create a module table with a given name. The function
** first looks at the _LOADED table and, if that fails, try a
** global variable with that name. In any case, leaves on the stack
** the module table.
*/
LUALIB_API void luaL_pushmodule (lua_State *L, const char *modname,
int sizehint) {
luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 1); /* get _LOADED table */
lua_getfield(L, -1, modname); /* get _LOADED[modname] */
if (!lua_istable(L, -1)) { /* not found? */
lua_pop(L, 1); /* remove previous result */
/* try global variable (and create one if it does not exist) */
lua_pushglobaltable(L);
if (luaL_findtable(L, 0, modname, sizehint) != NULL)
luaL_error(L, "name conflict for module " LUA_QS, modname);
lua_pushvalue(L, -1);
lua_setfield(L, -3, modname); /* _LOADED[modname] = new table */
}
lua_remove(L, -2); /* remove _LOADED table */
}
LUALIB_API void luaL_openlib (lua_State *L, const char *libname,
const luaL_Reg *l, int nup) {
luaL_checkversion(L);
if (libname) {
luaL_pushmodule(L, libname, libsize(l)); /* get/create library table */
lua_insert(L, -(nup + 1)); /* move library table to below upvalues */
}
if (l)
luaL_setfuncs(L, l, nup);
else
lua_pop(L, nup); /* remove upvalues */
}
#endif
/* }====================================================== */
/*
** set functions from list 'l' into table at top - 'nup'; each
** function gets the 'nup' elements at the top as upvalues.
** Returns with only the table at the stack.
*/
LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
luaL_checkversion(L);
luaL_checkstack(L, nup, "too many upvalues");
for (; l->name != NULL; l++) { /* fill the table with given functions */
int i;
for (i = 0; i < nup; i++) /* copy upvalues to the top */
lua_pushvalue(L, -nup);
lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */
lua_setfield(L, -(nup + 2), l->name);
}
lua_pop(L, nup); /* remove upvalues */
}
/*
** ensure that stack[idx][fname] has a table and push that table
** into the stack
*/
LUALIB_API int luaL_getsubtable (lua_State *L, int idx, const char *fname) {
lua_getfield(L, idx, fname);
if (lua_istable(L, -1)) return 1; /* table already there */
else {
lua_pop(L, 1); /* remove previous result */
idx = lua_absindex(L, idx);
lua_newtable(L);
lua_pushvalue(L, -1); /* copy to be left at top */
lua_setfield(L, idx, fname); /* assign new table to field */
return 0; /* false, because did not find table there */
}
}
/*
** stripped-down 'require'. Calls 'openf' to open a module,
** registers the result in 'package.loaded' table and, if 'glb'
** is true, also registers the result in the global table.
** Leaves resulting module on the top.
*/
LUALIB_API void luaL_requiref (lua_State *L, const char *modname,
lua_CFunction openf, int glb) {
lua_pushcfunction(L, openf);
lua_pushstring(L, modname); /* argument to open function */
lua_call(L, 1, 1); /* open module */
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED");
lua_pushvalue(L, -2); /* make copy of module (call result) */
lua_setfield(L, -2, modname); /* _LOADED[modname] = module */
lua_pop(L, 1); /* remove _LOADED table */
if (glb) {
lua_pushvalue(L, -1); /* copy of 'mod' */
lua_setglobal(L, modname); /* _G[modname] = module */
}
}
LUALIB_API const char *luaL_gsub (lua_State *L, const char *s, const char *p,
const char *r) {
const char *wild;
size_t l = strlen(p);
luaL_Buffer b;
luaL_buffinit(L, &b);
while ((wild = strstr(s, p)) != NULL) {
luaL_addlstring(&b, s, wild - s); /* push prefix */
luaL_addstring(&b, r); /* push replacement in place of pattern */
s = wild + l; /* continue after `p' */
}
luaL_addstring(&b, s); /* push last suffix */
luaL_pushresult(&b);
return lua_tostring(L, -1);
}
static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) {
(void)ud; (void)osize; /* not used */
if (nsize == 0) {
free(ptr);
return NULL;
}
else
return realloc(ptr, nsize);
}
static int panic (lua_State *L) {
luai_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n",
lua_tostring(L, -1));
return 0; /* return to Lua to abort */
}
LUALIB_API lua_State *luaL_newstate (void) {
lua_State *L = lua_newstate(l_alloc, NULL);
if (L) lua_atpanic(L, &panic);
return L;
}
LUALIB_API void luaL_checkversion_ (lua_State *L, lua_Number ver) {
const lua_Number *v = lua_version(L);
if (v != lua_version(NULL))
luaL_error(L, "multiple Lua VMs detected");
else if (*v != ver)
luaL_error(L, "version mismatch: app. needs %f, Lua core provides %f",
ver, *v);
/* check conversions number -> integer types */
lua_pushnumber(L, -(lua_Number)0x1234);
if (lua_tointeger(L, -1) != -0x1234 ||
lua_tounsigned(L, -1) != (lua_Unsigned)-0x1234)
luaL_error(L, "bad conversion number->int;"
" must recompile Lua with proper settings");
lua_pop(L, 1);
}

458
source/3rdparty/lua/src/lbaselib.c vendored Normal file
View File

@ -0,0 +1,458 @@
/*
** $Id: lbaselib.c,v 1.276.1.1 2013/04/12 18:48:47 roberto Exp $
** Basic library
** See Copyright Notice in lua.h
*/
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define lbaselib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
static int luaB_print (lua_State *L) {
int n = lua_gettop(L); /* number of arguments */
int i;
lua_getglobal(L, "tostring");
for (i=1; i<=n; i++) {
const char *s;
size_t l;
lua_pushvalue(L, -1); /* function to be called */
lua_pushvalue(L, i); /* value to print */
lua_call(L, 1, 1);
s = lua_tolstring(L, -1, &l); /* get result */
if (s == NULL)
return luaL_error(L,
LUA_QL("tostring") " must return a string to " LUA_QL("print"));
if (i>1) luai_writestring("\t", 1);
luai_writestring(s, l);
lua_pop(L, 1); /* pop result */
}
luai_writeline();
return 0;
}
#define SPACECHARS " \f\n\r\t\v"
static int luaB_tonumber (lua_State *L) {
if (lua_isnoneornil(L, 2)) { /* standard conversion */
int isnum;
lua_Number n = lua_tonumberx(L, 1, &isnum);
if (isnum) {
lua_pushnumber(L, n);
return 1;
} /* else not a number; must be something */
luaL_checkany(L, 1);
}
else {
size_t l;
const char *s = luaL_checklstring(L, 1, &l);
const char *e = s + l; /* end point for 's' */
int base = luaL_checkint(L, 2);
int neg = 0;
luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
s += strspn(s, SPACECHARS); /* skip initial spaces */
if (*s == '-') { s++; neg = 1; } /* handle signal */
else if (*s == '+') s++;
if (isalnum((unsigned char)*s)) {
lua_Number n = 0;
do {
int digit = (isdigit((unsigned char)*s)) ? *s - '0'
: toupper((unsigned char)*s) - 'A' + 10;
if (digit >= base) break; /* invalid numeral; force a fail */
n = n * (lua_Number)base + (lua_Number)digit;
s++;
} while (isalnum((unsigned char)*s));
s += strspn(s, SPACECHARS); /* skip trailing spaces */
if (s == e) { /* no invalid trailing characters? */
lua_pushnumber(L, (neg) ? -n : n);
return 1;
} /* else not a number */
} /* else not a number */
}
lua_pushnil(L); /* not a number */
return 1;
}
static int luaB_error (lua_State *L) {
int level = luaL_optint(L, 2, 1);
lua_settop(L, 1);
if (lua_isstring(L, 1) && level > 0) { /* add extra information? */
luaL_where(L, level);
lua_pushvalue(L, 1);
lua_concat(L, 2);
}
return lua_error(L);
}
static int luaB_getmetatable (lua_State *L) {
luaL_checkany(L, 1);
if (!lua_getmetatable(L, 1)) {
lua_pushnil(L);
return 1; /* no metatable */
}
luaL_getmetafield(L, 1, "__metatable");
return 1; /* returns either __metatable field (if present) or metatable */
}
static int luaB_setmetatable (lua_State *L) {
int t = lua_type(L, 2);
luaL_checktype(L, 1, LUA_TTABLE);
luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
"nil or table expected");
if (luaL_getmetafield(L, 1, "__metatable"))
return luaL_error(L, "cannot change a protected metatable");
lua_settop(L, 2);
lua_setmetatable(L, 1);
return 1;
}
static int luaB_rawequal (lua_State *L) {
luaL_checkany(L, 1);
luaL_checkany(L, 2);
lua_pushboolean(L, lua_rawequal(L, 1, 2));
return 1;
}
static int luaB_rawlen (lua_State *L) {
int t = lua_type(L, 1);
luaL_argcheck(L, t == LUA_TTABLE || t == LUA_TSTRING, 1,
"table or string expected");
lua_pushinteger(L, lua_rawlen(L, 1));
return 1;
}
static int luaB_rawget (lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
luaL_checkany(L, 2);
lua_settop(L, 2);
lua_rawget(L, 1);
return 1;
}
static int luaB_rawset (lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
luaL_checkany(L, 2);
luaL_checkany(L, 3);
lua_settop(L, 3);
lua_rawset(L, 1);
return 1;
}
static int luaB_collectgarbage (lua_State *L) {
static const char *const opts[] = {"stop", "restart", "collect",
"count", "step", "setpause", "setstepmul",
"setmajorinc", "isrunning", "generational", "incremental", NULL};
static const int optsnum[] = {LUA_GCSTOP, LUA_GCRESTART, LUA_GCCOLLECT,
LUA_GCCOUNT, LUA_GCSTEP, LUA_GCSETPAUSE, LUA_GCSETSTEPMUL,
LUA_GCSETMAJORINC, LUA_GCISRUNNING, LUA_GCGEN, LUA_GCINC};
int o = optsnum[luaL_checkoption(L, 1, "collect", opts)];
int ex = luaL_optint(L, 2, 0);
int res = lua_gc(L, o, ex);
switch (o) {
case LUA_GCCOUNT: {
int b = lua_gc(L, LUA_GCCOUNTB, 0);
lua_pushnumber(L, res + ((lua_Number)b/1024));
lua_pushinteger(L, b);
return 2;
}
case LUA_GCSTEP: case LUA_GCISRUNNING: {
lua_pushboolean(L, res);
return 1;
}
default: {
lua_pushinteger(L, res);
return 1;
}
}
}
static int luaB_type (lua_State *L) {
luaL_checkany(L, 1);
lua_pushstring(L, luaL_typename(L, 1));
return 1;
}
static int pairsmeta (lua_State *L, const char *method, int iszero,
lua_CFunction iter) {
if (!luaL_getmetafield(L, 1, method)) { /* no metamethod? */
luaL_checktype(L, 1, LUA_TTABLE); /* argument must be a table */
lua_pushcfunction(L, iter); /* will return generator, */
lua_pushvalue(L, 1); /* state, */
if (iszero) lua_pushinteger(L, 0); /* and initial value */
else lua_pushnil(L);
}
else {
lua_pushvalue(L, 1); /* argument 'self' to metamethod */
lua_call(L, 1, 3); /* get 3 values from metamethod */
}
return 3;
}
static int luaB_next (lua_State *L) {
luaL_checktype(L, 1, LUA_TTABLE);
lua_settop(L, 2); /* create a 2nd argument if there isn't one */
if (lua_next(L, 1))
return 2;
else {
lua_pushnil(L);
return 1;
}
}
static int luaB_pairs (lua_State *L) {
return pairsmeta(L, "__pairs", 0, luaB_next);
}
static int ipairsaux (lua_State *L) {
int i = luaL_checkint(L, 2);
luaL_checktype(L, 1, LUA_TTABLE);
i++; /* next value */
lua_pushinteger(L, i);
lua_rawgeti(L, 1, i);
return (lua_isnil(L, -1)) ? 1 : 2;
}
static int luaB_ipairs (lua_State *L) {
return pairsmeta(L, "__ipairs", 1, ipairsaux);
}
static int load_aux (lua_State *L, int status, int envidx) {
if (status == LUA_OK) {
if (envidx != 0) { /* 'env' parameter? */
lua_pushvalue(L, envidx); /* environment for loaded function */
if (!lua_setupvalue(L, -2, 1)) /* set it as 1st upvalue */
lua_pop(L, 1); /* remove 'env' if not used by previous call */
}
return 1;
}
else { /* error (message is on top of the stack) */
lua_pushnil(L);
lua_insert(L, -2); /* put before error message */
return 2; /* return nil plus error message */
}
}
static int luaB_loadfile (lua_State *L) {
const char *fname = luaL_optstring(L, 1, NULL);
const char *mode = luaL_optstring(L, 2, NULL);
int env = (!lua_isnone(L, 3) ? 3 : 0); /* 'env' index or 0 if no 'env' */
int status = luaL_loadfilex(L, fname, mode);
return load_aux(L, status, env);
}
/*
** {======================================================
** Generic Read function
** =======================================================
*/
/*
** reserved slot, above all arguments, to hold a copy of the returned
** string to avoid it being collected while parsed. 'load' has four
** optional arguments (chunk, source name, mode, and environment).
*/
#define RESERVEDSLOT 5
/*
** Reader for generic `load' function: `lua_load' uses the
** stack for internal stuff, so the reader cannot change the
** stack top. Instead, it keeps its resulting string in a
** reserved slot inside the stack.
*/
static const char *generic_reader (lua_State *L, void *ud, size_t *size) {
(void)(ud); /* not used */
luaL_checkstack(L, 2, "too many nested functions");
lua_pushvalue(L, 1); /* get function */
lua_call(L, 0, 1); /* call it */
if (lua_isnil(L, -1)) {
lua_pop(L, 1); /* pop result */
*size = 0;
return NULL;
}
else if (!lua_isstring(L, -1))
luaL_error(L, "reader function must return a string");
lua_replace(L, RESERVEDSLOT); /* save string in reserved slot */
return lua_tolstring(L, RESERVEDSLOT, size);
}
static int luaB_load (lua_State *L) {
int status;
size_t l;
const char *s = lua_tolstring(L, 1, &l);
const char *mode = luaL_optstring(L, 3, "bt");
int env = (!lua_isnone(L, 4) ? 4 : 0); /* 'env' index or 0 if no 'env' */
if (s != NULL) { /* loading a string? */
const char *chunkname = luaL_optstring(L, 2, s);
status = luaL_loadbufferx(L, s, l, chunkname, mode);
}
else { /* loading from a reader function */
const char *chunkname = luaL_optstring(L, 2, "=(load)");
luaL_checktype(L, 1, LUA_TFUNCTION);
lua_settop(L, RESERVEDSLOT); /* create reserved slot */
status = lua_load(L, generic_reader, NULL, chunkname, mode);
}
return load_aux(L, status, env);
}
/* }====================================================== */
static int dofilecont (lua_State *L) {
return lua_gettop(L) - 1;
}
static int luaB_dofile (lua_State *L) {
const char *fname = luaL_optstring(L, 1, NULL);
lua_settop(L, 1);
if (luaL_loadfile(L, fname) != LUA_OK)
return lua_error(L);
lua_callk(L, 0, LUA_MULTRET, 0, dofilecont);
return dofilecont(L);
}
static int luaB_assert (lua_State *L) {
if (!lua_toboolean(L, 1))
return luaL_error(L, "%s", luaL_optstring(L, 2, "assertion failed!"));
return lua_gettop(L);
}
static int luaB_select (lua_State *L) {
int n = lua_gettop(L);
if (lua_type(L, 1) == LUA_TSTRING && *lua_tostring(L, 1) == '#') {
lua_pushinteger(L, n-1);
return 1;
}
else {
int i = luaL_checkint(L, 1);
if (i < 0) i = n + i;
else if (i > n) i = n;
luaL_argcheck(L, 1 <= i, 1, "index out of range");
return n - i;
}
}
static int finishpcall (lua_State *L, int status) {
if (!lua_checkstack(L, 1)) { /* no space for extra boolean? */
lua_settop(L, 0); /* create space for return values */
lua_pushboolean(L, 0);
lua_pushstring(L, "stack overflow");
return 2; /* return false, msg */
}
lua_pushboolean(L, status); /* first result (status) */
lua_replace(L, 1); /* put first result in first slot */
return lua_gettop(L);
}
static int pcallcont (lua_State *L) {
int status = lua_getctx(L, NULL);
return finishpcall(L, (status == LUA_YIELD));
}
static int luaB_pcall (lua_State *L) {
int status;
luaL_checkany(L, 1);
lua_pushnil(L);
lua_insert(L, 1); /* create space for status result */
status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0, 0, pcallcont);
return finishpcall(L, (status == LUA_OK));
}
static int luaB_xpcall (lua_State *L) {
int status;
int n = lua_gettop(L);
luaL_argcheck(L, n >= 2, 2, "value expected");
lua_pushvalue(L, 1); /* exchange function... */
lua_copy(L, 2, 1); /* ...and error handler */
lua_replace(L, 2);
status = lua_pcallk(L, n - 2, LUA_MULTRET, 1, 0, pcallcont);
return finishpcall(L, (status == LUA_OK));
}
static int luaB_tostring (lua_State *L) {
luaL_checkany(L, 1);
luaL_tolstring(L, 1, NULL);
return 1;
}
static const luaL_Reg base_funcs[] = {
{"assert", luaB_assert},
{"collectgarbage", luaB_collectgarbage},
{"dofile", luaB_dofile},
{"error", luaB_error},
{"getmetatable", luaB_getmetatable},
{"ipairs", luaB_ipairs},
{"loadfile", luaB_loadfile},
{"load", luaB_load},
#if defined(LUA_COMPAT_LOADSTRING)
{"loadstring", luaB_load},
#endif
{"next", luaB_next},
{"pairs", luaB_pairs},
{"pcall", luaB_pcall},
{"print", luaB_print},
{"rawequal", luaB_rawequal},
{"rawlen", luaB_rawlen},
{"rawget", luaB_rawget},
{"rawset", luaB_rawset},
{"select", luaB_select},
{"setmetatable", luaB_setmetatable},
{"tonumber", luaB_tonumber},
{"tostring", luaB_tostring},
{"type", luaB_type},
{"xpcall", luaB_xpcall},
{NULL, NULL}
};
LUAMOD_API int luaopen_base (lua_State *L) {
/* set global _G */
lua_pushglobaltable(L);
lua_pushglobaltable(L);
lua_setfield(L, -2, "_G");
/* open lib into global table */
luaL_setfuncs(L, base_funcs, 0);
lua_pushliteral(L, LUA_VERSION);
lua_setfield(L, -2, "_VERSION"); /* set global _VERSION */
return 1;
}

212
source/3rdparty/lua/src/lbitlib.c vendored Normal file
View File

@ -0,0 +1,212 @@
/*
** $Id: lbitlib.c,v 1.18.1.2 2013/07/09 18:01:41 roberto Exp $
** Standard library for bitwise operations
** See Copyright Notice in lua.h
*/
#define lbitlib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
/* number of bits to consider in a number */
#if !defined(LUA_NBITS)
#define LUA_NBITS 32
#endif
#define ALLONES (~(((~(lua_Unsigned)0) << (LUA_NBITS - 1)) << 1))
/* macro to trim extra bits */
#define trim(x) ((x) & ALLONES)
/* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */
#define mask(n) (~((ALLONES << 1) << ((n) - 1)))
typedef lua_Unsigned b_uint;
static b_uint andaux (lua_State *L) {
int i, n = lua_gettop(L);
b_uint r = ~(b_uint)0;
for (i = 1; i <= n; i++)
r &= luaL_checkunsigned(L, i);
return trim(r);
}
static int b_and (lua_State *L) {
b_uint r = andaux(L);
lua_pushunsigned(L, r);
return 1;
}
static int b_test (lua_State *L) {
b_uint r = andaux(L);
lua_pushboolean(L, r != 0);
return 1;
}
static int b_or (lua_State *L) {
int i, n = lua_gettop(L);
b_uint r = 0;
for (i = 1; i <= n; i++)
r |= luaL_checkunsigned(L, i);
lua_pushunsigned(L, trim(r));
return 1;
}
static int b_xor (lua_State *L) {
int i, n = lua_gettop(L);
b_uint r = 0;
for (i = 1; i <= n; i++)
r ^= luaL_checkunsigned(L, i);
lua_pushunsigned(L, trim(r));
return 1;
}
static int b_not (lua_State *L) {
b_uint r = ~luaL_checkunsigned(L, 1);
lua_pushunsigned(L, trim(r));
return 1;
}
static int b_shift (lua_State *L, b_uint r, int i) {
if (i < 0) { /* shift right? */
i = -i;
r = trim(r);
if (i >= LUA_NBITS) r = 0;
else r >>= i;
}
else { /* shift left */
if (i >= LUA_NBITS) r = 0;
else r <<= i;
r = trim(r);
}
lua_pushunsigned(L, r);
return 1;
}
static int b_lshift (lua_State *L) {
return b_shift(L, luaL_checkunsigned(L, 1), luaL_checkint(L, 2));
}
static int b_rshift (lua_State *L) {
return b_shift(L, luaL_checkunsigned(L, 1), -luaL_checkint(L, 2));
}
static int b_arshift (lua_State *L) {
b_uint r = luaL_checkunsigned(L, 1);
int i = luaL_checkint(L, 2);
if (i < 0 || !(r & ((b_uint)1 << (LUA_NBITS - 1))))
return b_shift(L, r, -i);
else { /* arithmetic shift for 'negative' number */
if (i >= LUA_NBITS) r = ALLONES;
else
r = trim((r >> i) | ~(~(b_uint)0 >> i)); /* add signal bit */
lua_pushunsigned(L, r);
return 1;
}
}
static int b_rot (lua_State *L, int i) {
b_uint r = luaL_checkunsigned(L, 1);
i &= (LUA_NBITS - 1); /* i = i % NBITS */
r = trim(r);
if (i != 0) /* avoid undefined shift of LUA_NBITS when i == 0 */
r = (r << i) | (r >> (LUA_NBITS - i));
lua_pushunsigned(L, trim(r));
return 1;
}
static int b_lrot (lua_State *L) {
return b_rot(L, luaL_checkint(L, 2));
}
static int b_rrot (lua_State *L) {
return b_rot(L, -luaL_checkint(L, 2));
}
/*
** get field and width arguments for field-manipulation functions,
** checking whether they are valid.
** ('luaL_error' called without 'return' to avoid later warnings about
** 'width' being used uninitialized.)
*/
static int fieldargs (lua_State *L, int farg, int *width) {
int f = luaL_checkint(L, farg);
int w = luaL_optint(L, farg + 1, 1);
luaL_argcheck(L, 0 <= f, farg, "field cannot be negative");
luaL_argcheck(L, 0 < w, farg + 1, "width must be positive");
if (f + w > LUA_NBITS)
luaL_error(L, "trying to access non-existent bits");
*width = w;
return f;
}
static int b_extract (lua_State *L) {
int w;
b_uint r = luaL_checkunsigned(L, 1);
int f = fieldargs(L, 2, &w);
r = (r >> f) & mask(w);
lua_pushunsigned(L, r);
return 1;
}
static int b_replace (lua_State *L) {
int w;
b_uint r = luaL_checkunsigned(L, 1);
b_uint v = luaL_checkunsigned(L, 2);
int f = fieldargs(L, 3, &w);
int m = mask(w);
v &= m; /* erase bits outside given width */
r = (r & ~(m << f)) | (v << f);
lua_pushunsigned(L, r);
return 1;
}
static const luaL_Reg bitlib[] = {
{"arshift", b_arshift},
{"band", b_and},
{"bnot", b_not},
{"bor", b_or},
{"bxor", b_xor},
{"btest", b_test},
{"extract", b_extract},
{"lrotate", b_lrot},
{"lshift", b_lshift},
{"replace", b_replace},
{"rrotate", b_rrot},
{"rshift", b_rshift},
{NULL, NULL}
};
LUAMOD_API int luaopen_bit32 (lua_State *L) {
luaL_newlib(L, bitlib);
return 1;
}

881
source/3rdparty/lua/src/lcode.c vendored Normal file
View File

@ -0,0 +1,881 @@
/*
** $Id: lcode.c,v 2.62.1.1 2013/04/12 18:48:47 roberto Exp $
** Code generator for Lua
** See Copyright Notice in lua.h
*/
#include <stdlib.h>
#define lcode_c
#define LUA_CORE
#include "lua.h"
#include "lcode.h"
#include "ldebug.h"
#include "ldo.h"
#include "lgc.h"
#include "llex.h"
#include "lmem.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lparser.h"
#include "lstring.h"
#include "ltable.h"
#include "lvm.h"
#define hasjumps(e) ((e)->t != (e)->f)
static int isnumeral(expdesc *e) {
return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP);
}
void luaK_nil (FuncState *fs, int from, int n) {
Instruction *previous;
int l = from + n - 1; /* last register to set nil */
if (fs->pc > fs->lasttarget) { /* no jumps to current position? */
previous = &fs->f->code[fs->pc-1];
if (GET_OPCODE(*previous) == OP_LOADNIL) {
int pfrom = GETARG_A(*previous);
int pl = pfrom + GETARG_B(*previous);
if ((pfrom <= from && from <= pl + 1) ||
(from <= pfrom && pfrom <= l + 1)) { /* can connect both? */
if (pfrom < from) from = pfrom; /* from = min(from, pfrom) */
if (pl > l) l = pl; /* l = max(l, pl) */
SETARG_A(*previous, from);
SETARG_B(*previous, l - from);
return;
}
} /* else go through */
}
luaK_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */
}
int luaK_jump (FuncState *fs) {
int jpc = fs->jpc; /* save list of jumps to here */
int j;
fs->jpc = NO_JUMP;
j = luaK_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
luaK_concat(fs, &j, jpc); /* keep them on hold */
return j;
}
void luaK_ret (FuncState *fs, int first, int nret) {
luaK_codeABC(fs, OP_RETURN, first, nret+1, 0);
}
static int condjump (FuncState *fs, OpCode op, int A, int B, int C) {
luaK_codeABC(fs, op, A, B, C);
return luaK_jump(fs);
}
static void fixjump (FuncState *fs, int pc, int dest) {
Instruction *jmp = &fs->f->code[pc];
int offset = dest-(pc+1);
lua_assert(dest != NO_JUMP);
if (abs(offset) > MAXARG_sBx)
luaX_syntaxerror(fs->ls, "control structure too long");
SETARG_sBx(*jmp, offset);
}
/*
** returns current `pc' and marks it as a jump target (to avoid wrong
** optimizations with consecutive instructions not in the same basic block).
*/
int luaK_getlabel (FuncState *fs) {
fs->lasttarget = fs->pc;
return fs->pc;
}
static int getjump (FuncState *fs, int pc) {
int offset = GETARG_sBx(fs->f->code[pc]);
if (offset == NO_JUMP) /* point to itself represents end of list */
return NO_JUMP; /* end of list */
else
return (pc+1)+offset; /* turn offset into absolute position */
}
static Instruction *getjumpcontrol (FuncState *fs, int pc) {
Instruction *pi = &fs->f->code[pc];
if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
return pi-1;
else
return pi;
}
/*
** check whether list has any jump that do not produce a value
** (or produce an inverted value)
*/
static int need_value (FuncState *fs, int list) {
for (; list != NO_JUMP; list = getjump(fs, list)) {
Instruction i = *getjumpcontrol(fs, list);
if (GET_OPCODE(i) != OP_TESTSET) return 1;
}
return 0; /* not found */
}
static int patchtestreg (FuncState *fs, int node, int reg) {
Instruction *i = getjumpcontrol(fs, node);
if (GET_OPCODE(*i) != OP_TESTSET)
return 0; /* cannot patch other instructions */
if (reg != NO_REG && reg != GETARG_B(*i))
SETARG_A(*i, reg);
else /* no register to put value or register already has the value */
*i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
return 1;
}
static void removevalues (FuncState *fs, int list) {
for (; list != NO_JUMP; list = getjump(fs, list))
patchtestreg(fs, list, NO_REG);
}
static void patchlistaux (FuncState *fs, int list, int vtarget, int reg,
int dtarget) {
while (list != NO_JUMP) {
int next = getjump(fs, list);
if (patchtestreg(fs, list, reg))
fixjump(fs, list, vtarget);
else
fixjump(fs, list, dtarget); /* jump to default target */
list = next;
}
}
static void dischargejpc (FuncState *fs) {
patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
fs->jpc = NO_JUMP;
}
void luaK_patchlist (FuncState *fs, int list, int target) {
if (target == fs->pc)
luaK_patchtohere(fs, list);
else {
lua_assert(target < fs->pc);
patchlistaux(fs, list, target, NO_REG, target);
}
}
LUAI_FUNC void luaK_patchclose (FuncState *fs, int list, int level) {
level++; /* argument is +1 to reserve 0 as non-op */
while (list != NO_JUMP) {
int next = getjump(fs, list);
lua_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP &&
(GETARG_A(fs->f->code[list]) == 0 ||
GETARG_A(fs->f->code[list]) >= level));
SETARG_A(fs->f->code[list], level);
list = next;
}
}
void luaK_patchtohere (FuncState *fs, int list) {
luaK_getlabel(fs);
luaK_concat(fs, &fs->jpc, list);
}
void luaK_concat (FuncState *fs, int *l1, int l2) {
if (l2 == NO_JUMP) return;
else if (*l1 == NO_JUMP)
*l1 = l2;
else {
int list = *l1;
int next;
while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */
list = next;
fixjump(fs, list, l2);
}
}
static int luaK_code (FuncState *fs, Instruction i) {
Proto *f = fs->f;
dischargejpc(fs); /* `pc' will change */
/* put new instruction in code array */
luaM_growvector(fs->ls->L, f->code, fs->pc, f->sizecode, Instruction,
MAX_INT, "opcodes");
f->code[fs->pc] = i;
/* save corresponding line information */
luaM_growvector(fs->ls->L, f->lineinfo, fs->pc, f->sizelineinfo, int,
MAX_INT, "opcodes");
f->lineinfo[fs->pc] = fs->ls->lastline;
return fs->pc++;
}
int luaK_codeABC (FuncState *fs, OpCode o, int a, int b, int c) {
lua_assert(getOpMode(o) == iABC);
lua_assert(getBMode(o) != OpArgN || b == 0);
lua_assert(getCMode(o) != OpArgN || c == 0);
lua_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C);
return luaK_code(fs, CREATE_ABC(o, a, b, c));
}
int luaK_codeABx (FuncState *fs, OpCode o, int a, unsigned int bc) {
lua_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
lua_assert(getCMode(o) == OpArgN);
lua_assert(a <= MAXARG_A && bc <= MAXARG_Bx);
return luaK_code(fs, CREATE_ABx(o, a, bc));
}
static int codeextraarg (FuncState *fs, int a) {
lua_assert(a <= MAXARG_Ax);
return luaK_code(fs, CREATE_Ax(OP_EXTRAARG, a));
}
int luaK_codek (FuncState *fs, int reg, int k) {
if (k <= MAXARG_Bx)
return luaK_codeABx(fs, OP_LOADK, reg, k);
else {
int p = luaK_codeABx(fs, OP_LOADKX, reg, 0);
codeextraarg(fs, k);
return p;
}
}
void luaK_checkstack (FuncState *fs, int n) {
int newstack = fs->freereg + n;
if (newstack > fs->f->maxstacksize) {
if (newstack >= MAXSTACK)
luaX_syntaxerror(fs->ls, "function or expression too complex");
fs->f->maxstacksize = cast_byte(newstack);
}
}
void luaK_reserveregs (FuncState *fs, int n) {
luaK_checkstack(fs, n);
fs->freereg += n;
}
static void freereg (FuncState *fs, int reg) {
if (!ISK(reg) && reg >= fs->nactvar) {
fs->freereg--;
lua_assert(reg == fs->freereg);
}
}
static void freeexp (FuncState *fs, expdesc *e) {
if (e->k == VNONRELOC)
freereg(fs, e->u.info);
}
static int addk (FuncState *fs, TValue *key, TValue *v) {
lua_State *L = fs->ls->L;
TValue *idx = luaH_set(L, fs->h, key);
Proto *f = fs->f;
int k, oldsize;
if (ttisnumber(idx)) {
lua_Number n = nvalue(idx);
lua_number2int(k, n);
if (luaV_rawequalobj(&f->k[k], v))
return k;
/* else may be a collision (e.g., between 0.0 and "\0\0\0\0\0\0\0\0");
go through and create a new entry for this value */
}
/* constant not found; create a new entry */
oldsize = f->sizek;
k = fs->nk;
/* numerical value does not need GC barrier;
table has no metatable, so it does not need to invalidate cache */
setnvalue(idx, cast_num(k));
luaM_growvector(L, f->k, k, f->sizek, TValue, MAXARG_Ax, "constants");
while (oldsize < f->sizek) setnilvalue(&f->k[oldsize++]);
setobj(L, &f->k[k], v);
fs->nk++;
luaC_barrier(L, f, v);
return k;
}
int luaK_stringK (FuncState *fs, TString *s) {
TValue o;
setsvalue(fs->ls->L, &o, s);
return addk(fs, &o, &o);
}
int luaK_numberK (FuncState *fs, lua_Number r) {
int n;
lua_State *L = fs->ls->L;
TValue o;
setnvalue(&o, r);
if (r == 0 || luai_numisnan(NULL, r)) { /* handle -0 and NaN */
/* use raw representation as key to avoid numeric problems */
setsvalue(L, L->top++, luaS_newlstr(L, (char *)&r, sizeof(r)));
n = addk(fs, L->top - 1, &o);
L->top--;
}
else
n = addk(fs, &o, &o); /* regular case */
return n;
}
static int boolK (FuncState *fs, int b) {
TValue o;
setbvalue(&o, b);
return addk(fs, &o, &o);
}
static int nilK (FuncState *fs) {
TValue k, v;
setnilvalue(&v);
/* cannot use nil as key; instead use table itself to represent nil */
sethvalue(fs->ls->L, &k, fs->h);
return addk(fs, &k, &v);
}
void luaK_setreturns (FuncState *fs, expdesc *e, int nresults) {
if (e->k == VCALL) { /* expression is an open function call? */
SETARG_C(getcode(fs, e), nresults+1);
}
else if (e->k == VVARARG) {
SETARG_B(getcode(fs, e), nresults+1);
SETARG_A(getcode(fs, e), fs->freereg);
luaK_reserveregs(fs, 1);
}
}
void luaK_setoneret (FuncState *fs, expdesc *e) {
if (e->k == VCALL) { /* expression is an open function call? */
e->k = VNONRELOC;
e->u.info = GETARG_A(getcode(fs, e));
}
else if (e->k == VVARARG) {
SETARG_B(getcode(fs, e), 2);
e->k = VRELOCABLE; /* can relocate its simple result */
}
}
void luaK_dischargevars (FuncState *fs, expdesc *e) {
switch (e->k) {
case VLOCAL: {
e->k = VNONRELOC;
break;
}
case VUPVAL: {
e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
e->k = VRELOCABLE;
break;
}
case VINDEXED: {
OpCode op = OP_GETTABUP; /* assume 't' is in an upvalue */
freereg(fs, e->u.ind.idx);
if (e->u.ind.vt == VLOCAL) { /* 't' is in a register? */
freereg(fs, e->u.ind.t);
op = OP_GETTABLE;
}
e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx);
e->k = VRELOCABLE;
break;
}
case VVARARG:
case VCALL: {
luaK_setoneret(fs, e);
break;
}
default: break; /* there is one value available (somewhere) */
}
}
static int code_label (FuncState *fs, int A, int b, int jump) {
luaK_getlabel(fs); /* those instructions may be jump targets */
return luaK_codeABC(fs, OP_LOADBOOL, A, b, jump);
}
static void discharge2reg (FuncState *fs, expdesc *e, int reg) {
luaK_dischargevars(fs, e);
switch (e->k) {
case VNIL: {
luaK_nil(fs, reg, 1);
break;
}
case VFALSE: case VTRUE: {
luaK_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
break;
}
case VK: {
luaK_codek(fs, reg, e->u.info);
break;
}
case VKNUM: {
luaK_codek(fs, reg, luaK_numberK(fs, e->u.nval));
break;
}
case VRELOCABLE: {
Instruction *pc = &getcode(fs, e);
SETARG_A(*pc, reg);
break;
}
case VNONRELOC: {
if (reg != e->u.info)
luaK_codeABC(fs, OP_MOVE, reg, e->u.info, 0);
break;
}
default: {
lua_assert(e->k == VVOID || e->k == VJMP);
return; /* nothing to do... */
}
}
e->u.info = reg;
e->k = VNONRELOC;
}
static void discharge2anyreg (FuncState *fs, expdesc *e) {
if (e->k != VNONRELOC) {
luaK_reserveregs(fs, 1);
discharge2reg(fs, e, fs->freereg-1);
}
}
static void exp2reg (FuncState *fs, expdesc *e, int reg) {
discharge2reg(fs, e, reg);
if (e->k == VJMP)
luaK_concat(fs, &e->t, e->u.info); /* put this jump in `t' list */
if (hasjumps(e)) {
int final; /* position after whole expression */
int p_f = NO_JUMP; /* position of an eventual LOAD false */
int p_t = NO_JUMP; /* position of an eventual LOAD true */
if (need_value(fs, e->t) || need_value(fs, e->f)) {
int fj = (e->k == VJMP) ? NO_JUMP : luaK_jump(fs);
p_f = code_label(fs, reg, 0, 1);
p_t = code_label(fs, reg, 1, 0);
luaK_patchtohere(fs, fj);
}
final = luaK_getlabel(fs);
patchlistaux(fs, e->f, final, reg, p_f);
patchlistaux(fs, e->t, final, reg, p_t);
}
e->f = e->t = NO_JUMP;
e->u.info = reg;
e->k = VNONRELOC;
}
void luaK_exp2nextreg (FuncState *fs, expdesc *e) {
luaK_dischargevars(fs, e);
freeexp(fs, e);
luaK_reserveregs(fs, 1);
exp2reg(fs, e, fs->freereg - 1);
}
int luaK_exp2anyreg (FuncState *fs, expdesc *e) {
luaK_dischargevars(fs, e);
if (e->k == VNONRELOC) {
if (!hasjumps(e)) return e->u.info; /* exp is already in a register */
if (e->u.info >= fs->nactvar) { /* reg. is not a local? */
exp2reg(fs, e, e->u.info); /* put value on it */
return e->u.info;
}
}
luaK_exp2nextreg(fs, e); /* default */
return e->u.info;
}
void luaK_exp2anyregup (FuncState *fs, expdesc *e) {
if (e->k != VUPVAL || hasjumps(e))
luaK_exp2anyreg(fs, e);
}
void luaK_exp2val (FuncState *fs, expdesc *e) {
if (hasjumps(e))
luaK_exp2anyreg(fs, e);
else
luaK_dischargevars(fs, e);
}
int luaK_exp2RK (FuncState *fs, expdesc *e) {
luaK_exp2val(fs, e);
switch (e->k) {
case VTRUE:
case VFALSE:
case VNIL: {
if (fs->nk <= MAXINDEXRK) { /* constant fits in RK operand? */
e->u.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE));
e->k = VK;
return RKASK(e->u.info);
}
else break;
}
case VKNUM: {
e->u.info = luaK_numberK(fs, e->u.nval);
e->k = VK;
/* go through */
}
case VK: {
if (e->u.info <= MAXINDEXRK) /* constant fits in argC? */
return RKASK(e->u.info);
else break;
}
default: break;
}
/* not a constant in the right range: put it in a register */
return luaK_exp2anyreg(fs, e);
}
void luaK_storevar (FuncState *fs, expdesc *var, expdesc *ex) {
switch (var->k) {
case VLOCAL: {
freeexp(fs, ex);
exp2reg(fs, ex, var->u.info);
return;
}
case VUPVAL: {
int e = luaK_exp2anyreg(fs, ex);
luaK_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);
break;
}
case VINDEXED: {
OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP;
int e = luaK_exp2RK(fs, ex);
luaK_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e);
break;
}
default: {
lua_assert(0); /* invalid var kind to store */
break;
}
}
freeexp(fs, ex);
}
void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
int ereg;
luaK_exp2anyreg(fs, e);
ereg = e->u.info; /* register where 'e' was placed */
freeexp(fs, e);
e->u.info = fs->freereg; /* base register for op_self */
e->k = VNONRELOC;
luaK_reserveregs(fs, 2); /* function and 'self' produced by op_self */
luaK_codeABC(fs, OP_SELF, e->u.info, ereg, luaK_exp2RK(fs, key));
freeexp(fs, key);
}
static void invertjump (FuncState *fs, expdesc *e) {
Instruction *pc = getjumpcontrol(fs, e->u.info);
lua_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
GET_OPCODE(*pc) != OP_TEST);
SETARG_A(*pc, !(GETARG_A(*pc)));
}
static int jumponcond (FuncState *fs, expdesc *e, int cond) {
if (e->k == VRELOCABLE) {
Instruction ie = getcode(fs, e);
if (GET_OPCODE(ie) == OP_NOT) {
fs->pc--; /* remove previous OP_NOT */
return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
}
/* else go through */
}
discharge2anyreg(fs, e);
freeexp(fs, e);
return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond);
}
void luaK_goiftrue (FuncState *fs, expdesc *e) {
int pc; /* pc of last jump */
luaK_dischargevars(fs, e);
switch (e->k) {
case VJMP: {
invertjump(fs, e);
pc = e->u.info;
break;
}
case VK: case VKNUM: case VTRUE: {
pc = NO_JUMP; /* always true; do nothing */
break;
}
default: {
pc = jumponcond(fs, e, 0);
break;
}
}
luaK_concat(fs, &e->f, pc); /* insert last jump in `f' list */
luaK_patchtohere(fs, e->t);
e->t = NO_JUMP;
}
void luaK_goiffalse (FuncState *fs, expdesc *e) {
int pc; /* pc of last jump */
luaK_dischargevars(fs, e);
switch (e->k) {
case VJMP: {
pc = e->u.info;
break;
}
case VNIL: case VFALSE: {
pc = NO_JUMP; /* always false; do nothing */
break;
}
default: {
pc = jumponcond(fs, e, 1);
break;
}
}
luaK_concat(fs, &e->t, pc); /* insert last jump in `t' list */
luaK_patchtohere(fs, e->f);
e->f = NO_JUMP;
}
static void codenot (FuncState *fs, expdesc *e) {
luaK_dischargevars(fs, e);
switch (e->k) {
case VNIL: case VFALSE: {
e->k = VTRUE;
break;
}
case VK: case VKNUM: case VTRUE: {
e->k = VFALSE;
break;
}
case VJMP: {
invertjump(fs, e);
break;
}
case VRELOCABLE:
case VNONRELOC: {
discharge2anyreg(fs, e);
freeexp(fs, e);
e->u.info = luaK_codeABC(fs, OP_NOT, 0, e->u.info, 0);
e->k = VRELOCABLE;
break;
}
default: {
lua_assert(0); /* cannot happen */
break;
}
}
/* interchange true and false lists */
{ int temp = e->f; e->f = e->t; e->t = temp; }
removevalues(fs, e->f);
removevalues(fs, e->t);
}
void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) {
lua_assert(!hasjumps(t));
t->u.ind.t = t->u.info;
t->u.ind.idx = luaK_exp2RK(fs, k);
t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL
: check_exp(vkisinreg(t->k), VLOCAL);
t->k = VINDEXED;
}
static int constfolding (OpCode op, expdesc *e1, expdesc *e2) {
lua_Number r;
if (!isnumeral(e1) || !isnumeral(e2)) return 0;
if ((op == OP_DIV || op == OP_MOD) && e2->u.nval == 0)
return 0; /* do not attempt to divide by 0 */
r = luaO_arith(op - OP_ADD + LUA_OPADD, e1->u.nval, e2->u.nval);
e1->u.nval = r;
return 1;
}
static void codearith (FuncState *fs, OpCode op,
expdesc *e1, expdesc *e2, int line) {
if (constfolding(op, e1, e2))
return;
else {
int o2 = (op != OP_UNM && op != OP_LEN) ? luaK_exp2RK(fs, e2) : 0;
int o1 = luaK_exp2RK(fs, e1);
if (o1 > o2) {
freeexp(fs, e1);
freeexp(fs, e2);
}
else {
freeexp(fs, e2);
freeexp(fs, e1);
}
e1->u.info = luaK_codeABC(fs, op, 0, o1, o2);
e1->k = VRELOCABLE;
luaK_fixline(fs, line);
}
}
static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1,
expdesc *e2) {
int o1 = luaK_exp2RK(fs, e1);
int o2 = luaK_exp2RK(fs, e2);
freeexp(fs, e2);
freeexp(fs, e1);
if (cond == 0 && op != OP_EQ) {
int temp; /* exchange args to replace by `<' or `<=' */
temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */
cond = 1;
}
e1->u.info = condjump(fs, op, cond, o1, o2);
e1->k = VJMP;
}
void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) {
expdesc e2;
e2.t = e2.f = NO_JUMP; e2.k = VKNUM; e2.u.nval = 0;
switch (op) {
case OPR_MINUS: {
if (isnumeral(e)) /* minus constant? */
e->u.nval = luai_numunm(NULL, e->u.nval); /* fold it */
else {
luaK_exp2anyreg(fs, e);
codearith(fs, OP_UNM, e, &e2, line);
}
break;
}
case OPR_NOT: codenot(fs, e); break;
case OPR_LEN: {
luaK_exp2anyreg(fs, e); /* cannot operate on constants */
codearith(fs, OP_LEN, e, &e2, line);
break;
}
default: lua_assert(0);
}
}
void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
switch (op) {
case OPR_AND: {
luaK_goiftrue(fs, v);
break;
}
case OPR_OR: {
luaK_goiffalse(fs, v);
break;
}
case OPR_CONCAT: {
luaK_exp2nextreg(fs, v); /* operand must be on the `stack' */
break;
}
case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
case OPR_MOD: case OPR_POW: {
if (!isnumeral(v)) luaK_exp2RK(fs, v);
break;
}
default: {
luaK_exp2RK(fs, v);
break;
}
}
}
void luaK_posfix (FuncState *fs, BinOpr op,
expdesc *e1, expdesc *e2, int line) {
switch (op) {
case OPR_AND: {
lua_assert(e1->t == NO_JUMP); /* list must be closed */
luaK_dischargevars(fs, e2);
luaK_concat(fs, &e2->f, e1->f);
*e1 = *e2;
break;
}
case OPR_OR: {
lua_assert(e1->f == NO_JUMP); /* list must be closed */
luaK_dischargevars(fs, e2);
luaK_concat(fs, &e2->t, e1->t);
*e1 = *e2;
break;
}
case OPR_CONCAT: {
luaK_exp2val(fs, e2);
if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
lua_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1);
freeexp(fs, e1);
SETARG_B(getcode(fs, e2), e1->u.info);
e1->k = VRELOCABLE; e1->u.info = e2->u.info;
}
else {
luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */
codearith(fs, OP_CONCAT, e1, e2, line);
}
break;
}
case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
case OPR_MOD: case OPR_POW: {
codearith(fs, cast(OpCode, op - OPR_ADD + OP_ADD), e1, e2, line);
break;
}
case OPR_EQ: case OPR_LT: case OPR_LE: {
codecomp(fs, cast(OpCode, op - OPR_EQ + OP_EQ), 1, e1, e2);
break;
}
case OPR_NE: case OPR_GT: case OPR_GE: {
codecomp(fs, cast(OpCode, op - OPR_NE + OP_EQ), 0, e1, e2);
break;
}
default: lua_assert(0);
}
}
void luaK_fixline (FuncState *fs, int line) {
fs->f->lineinfo[fs->pc - 1] = line;
}
void luaK_setlist (FuncState *fs, int base, int nelems, int tostore) {
int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1;
int b = (tostore == LUA_MULTRET) ? 0 : tostore;
lua_assert(tostore != 0);
if (c <= MAXARG_C)
luaK_codeABC(fs, OP_SETLIST, base, b, c);
else if (c <= MAXARG_Ax) {
luaK_codeABC(fs, OP_SETLIST, base, b, 0);
codeextraarg(fs, c);
}
else
luaX_syntaxerror(fs->ls, "constructor too long");
fs->freereg = base + 1; /* free registers with list values */
}

155
source/3rdparty/lua/src/lcorolib.c vendored Normal file
View File

@ -0,0 +1,155 @@
/*
** $Id: lcorolib.c,v 1.5.1.1 2013/04/12 18:48:47 roberto Exp $
** Coroutine Library
** See Copyright Notice in lua.h
*/
#include <stdlib.h>
#define lcorolib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
static int auxresume (lua_State *L, lua_State *co, int narg) {
int status;
if (!lua_checkstack(co, narg)) {
lua_pushliteral(L, "too many arguments to resume");
return -1; /* error flag */
}
if (lua_status(co) == LUA_OK && lua_gettop(co) == 0) {
lua_pushliteral(L, "cannot resume dead coroutine");
return -1; /* error flag */
}
lua_xmove(L, co, narg);
status = lua_resume(co, L, narg);
if (status == LUA_OK || status == LUA_YIELD) {
int nres = lua_gettop(co);
if (!lua_checkstack(L, nres + 1)) {
lua_pop(co, nres); /* remove results anyway */
lua_pushliteral(L, "too many results to resume");
return -1; /* error flag */
}
lua_xmove(co, L, nres); /* move yielded values */
return nres;
}
else {
lua_xmove(co, L, 1); /* move error message */
return -1; /* error flag */
}
}
static int luaB_coresume (lua_State *L) {
lua_State *co = lua_tothread(L, 1);
int r;
luaL_argcheck(L, co, 1, "coroutine expected");
r = auxresume(L, co, lua_gettop(L) - 1);
if (r < 0) {
lua_pushboolean(L, 0);
lua_insert(L, -2);
return 2; /* return false + error message */
}
else {
lua_pushboolean(L, 1);
lua_insert(L, -(r + 1));
return r + 1; /* return true + `resume' returns */
}
}
static int luaB_auxwrap (lua_State *L) {
lua_State *co = lua_tothread(L, lua_upvalueindex(1));
int r = auxresume(L, co, lua_gettop(L));
if (r < 0) {
if (lua_isstring(L, -1)) { /* error object is a string? */
luaL_where(L, 1); /* add extra info */
lua_insert(L, -2);
lua_concat(L, 2);
}
return lua_error(L); /* propagate error */
}
return r;
}
static int luaB_cocreate (lua_State *L) {
lua_State *NL;
luaL_checktype(L, 1, LUA_TFUNCTION);
NL = lua_newthread(L);
lua_pushvalue(L, 1); /* move function to top */
lua_xmove(L, NL, 1); /* move function from L to NL */
return 1;
}
static int luaB_cowrap (lua_State *L) {
luaB_cocreate(L);
lua_pushcclosure(L, luaB_auxwrap, 1);
return 1;
}
static int luaB_yield (lua_State *L) {
return lua_yield(L, lua_gettop(L));
}
static int luaB_costatus (lua_State *L) {
lua_State *co = lua_tothread(L, 1);
luaL_argcheck(L, co, 1, "coroutine expected");
if (L == co) lua_pushliteral(L, "running");
else {
switch (lua_status(co)) {
case LUA_YIELD:
lua_pushliteral(L, "suspended");
break;
case LUA_OK: {
lua_Debug ar;
if (lua_getstack(co, 0, &ar) > 0) /* does it have frames? */
lua_pushliteral(L, "normal"); /* it is running */
else if (lua_gettop(co) == 0)
lua_pushliteral(L, "dead");
else
lua_pushliteral(L, "suspended"); /* initial state */
break;
}
default: /* some error occurred */
lua_pushliteral(L, "dead");
break;
}
}
return 1;
}
static int luaB_corunning (lua_State *L) {
int ismain = lua_pushthread(L);
lua_pushboolean(L, ismain);
return 2;
}
static const luaL_Reg co_funcs[] = {
{"create", luaB_cocreate},
{"resume", luaB_coresume},
{"running", luaB_corunning},
{"status", luaB_costatus},
{"wrap", luaB_cowrap},
{"yield", luaB_yield},
{NULL, NULL}
};
LUAMOD_API int luaopen_coroutine (lua_State *L) {
luaL_newlib(L, co_funcs);
return 1;
}

52
source/3rdparty/lua/src/lctype.c vendored Normal file
View File

@ -0,0 +1,52 @@
/*
** $Id: lctype.c,v 1.11.1.1 2013/04/12 18:48:47 roberto Exp $
** 'ctype' functions for Lua
** See Copyright Notice in lua.h
*/
#define lctype_c
#define LUA_CORE
#include "lctype.h"
#if !LUA_USE_CTYPE /* { */
#include <limits.h>
LUAI_DDEF const lu_byte luai_ctype_[UCHAR_MAX + 2] = {
0x00, /* EOZ */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0. */
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 1. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0c, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, /* 2. */
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, /* 3. */
0x16, 0x16, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 4. */
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 5. */
0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x05,
0x04, 0x15, 0x15, 0x15, 0x15, 0x15, 0x15, 0x05, /* 6. */
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05,
0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, /* 7. */
0x05, 0x05, 0x05, 0x04, 0x04, 0x04, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 8. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 9. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* a. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* b. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* c. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* d. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* e. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* f. */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
#endif /* } */

408
source/3rdparty/lua/src/ldblib.c vendored Normal file
View File

@ -0,0 +1,408 @@
/*
** $Id: ldblib.c,v 1.132.1.2 2015/02/19 17:16:55 roberto Exp $
** Interface from Lua to its debug API
** See Copyright Notice in lua.h
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ldblib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#define HOOKKEY "_HKEY"
static void checkstack (lua_State *L, lua_State *L1, int n) {
if (L != L1 && !lua_checkstack(L1, n))
luaL_error(L, "stack overflow");
}
static int db_getregistry (lua_State *L) {
lua_pushvalue(L, LUA_REGISTRYINDEX);
return 1;
}
static int db_getmetatable (lua_State *L) {
luaL_checkany(L, 1);
if (!lua_getmetatable(L, 1)) {
lua_pushnil(L); /* no metatable */
}
return 1;
}
static int db_setmetatable (lua_State *L) {
int t = lua_type(L, 2);
luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2,
"nil or table expected");
lua_settop(L, 2);
lua_setmetatable(L, 1);
return 1; /* return 1st argument */
}
static int db_getuservalue (lua_State *L) {
if (lua_type(L, 1) != LUA_TUSERDATA)
lua_pushnil(L);
else
lua_getuservalue(L, 1);
return 1;
}
static int db_setuservalue (lua_State *L) {
if (lua_type(L, 1) == LUA_TLIGHTUSERDATA)
luaL_argerror(L, 1, "full userdata expected, got light userdata");
luaL_checktype(L, 1, LUA_TUSERDATA);
if (!lua_isnoneornil(L, 2))
luaL_checktype(L, 2, LUA_TTABLE);
lua_settop(L, 2);
lua_setuservalue(L, 1);
return 1;
}
static void settabss (lua_State *L, const char *i, const char *v) {
lua_pushstring(L, v);
lua_setfield(L, -2, i);
}
static void settabsi (lua_State *L, const char *i, int v) {
lua_pushinteger(L, v);
lua_setfield(L, -2, i);
}
static void settabsb (lua_State *L, const char *i, int v) {
lua_pushboolean(L, v);
lua_setfield(L, -2, i);
}
static lua_State *getthread (lua_State *L, int *arg) {
if (lua_isthread(L, 1)) {
*arg = 1;
return lua_tothread(L, 1);
}
else {
*arg = 0;
return L;
}
}
static void treatstackoption (lua_State *L, lua_State *L1, const char *fname) {
if (L == L1) {
lua_pushvalue(L, -2);
lua_remove(L, -3);
}
else
lua_xmove(L1, L, 1);
lua_setfield(L, -2, fname);
}
static int db_getinfo (lua_State *L) {
lua_Debug ar;
int arg;
lua_State *L1 = getthread(L, &arg);
const char *options = luaL_optstring(L, arg+2, "flnStu");
checkstack(L, L1, 3);
if (lua_isnumber(L, arg+1)) {
if (!lua_getstack(L1, (int)lua_tointeger(L, arg+1), &ar)) {
lua_pushnil(L); /* level out of range */
return 1;
}
}
else if (lua_isfunction(L, arg+1)) {
lua_pushfstring(L, ">%s", options);
options = lua_tostring(L, -1);
lua_pushvalue(L, arg+1);
lua_xmove(L, L1, 1);
}
else
return luaL_argerror(L, arg+1, "function or level expected");
if (!lua_getinfo(L1, options, &ar))
return luaL_argerror(L, arg+2, "invalid option");
lua_createtable(L, 0, 2);
if (strchr(options, 'S')) {
settabss(L, "source", ar.source);
settabss(L, "short_src", ar.short_src);
settabsi(L, "linedefined", ar.linedefined);
settabsi(L, "lastlinedefined", ar.lastlinedefined);
settabss(L, "what", ar.what);
}
if (strchr(options, 'l'))
settabsi(L, "currentline", ar.currentline);
if (strchr(options, 'u')) {
settabsi(L, "nups", ar.nups);
settabsi(L, "nparams", ar.nparams);
settabsb(L, "isvararg", ar.isvararg);
}
if (strchr(options, 'n')) {
settabss(L, "name", ar.name);
settabss(L, "namewhat", ar.namewhat);
}
if (strchr(options, 't'))
settabsb(L, "istailcall", ar.istailcall);
if (strchr(options, 'L'))
treatstackoption(L, L1, "activelines");
if (strchr(options, 'f'))
treatstackoption(L, L1, "func");
return 1; /* return table */
}
static int db_getlocal (lua_State *L) {
int arg;
lua_State *L1 = getthread(L, &arg);
lua_Debug ar;
const char *name;
int nvar = luaL_checkint(L, arg+2); /* local-variable index */
if (lua_isfunction(L, arg + 1)) { /* function argument? */
lua_pushvalue(L, arg + 1); /* push function */
lua_pushstring(L, lua_getlocal(L, NULL, nvar)); /* push local name */
return 1;
}
else { /* stack-level argument */
if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */
return luaL_argerror(L, arg+1, "level out of range");
checkstack(L, L1, 1);
name = lua_getlocal(L1, &ar, nvar);
if (name) {
lua_xmove(L1, L, 1); /* push local value */
lua_pushstring(L, name); /* push name */
lua_pushvalue(L, -2); /* re-order */
return 2;
}
else {
lua_pushnil(L); /* no name (nor value) */
return 1;
}
}
}
static int db_setlocal (lua_State *L) {
int arg;
lua_State *L1 = getthread(L, &arg);
lua_Debug ar;
if (!lua_getstack(L1, luaL_checkint(L, arg+1), &ar)) /* out of range? */
return luaL_argerror(L, arg+1, "level out of range");
luaL_checkany(L, arg+3);
lua_settop(L, arg+3);
checkstack(L, L1, 1);
lua_xmove(L, L1, 1);
lua_pushstring(L, lua_setlocal(L1, &ar, luaL_checkint(L, arg+2)));
return 1;
}
static int auxupvalue (lua_State *L, int get) {
const char *name;
int n = luaL_checkint(L, 2);
luaL_checktype(L, 1, LUA_TFUNCTION);
name = get ? lua_getupvalue(L, 1, n) : lua_setupvalue(L, 1, n);
if (name == NULL) return 0;
lua_pushstring(L, name);
lua_insert(L, -(get+1));
return get + 1;
}
static int db_getupvalue (lua_State *L) {
return auxupvalue(L, 1);
}
static int db_setupvalue (lua_State *L) {
luaL_checkany(L, 3);
return auxupvalue(L, 0);
}
static int checkupval (lua_State *L, int argf, int argnup) {
lua_Debug ar;
int nup = luaL_checkint(L, argnup);
luaL_checktype(L, argf, LUA_TFUNCTION);
lua_pushvalue(L, argf);
lua_getinfo(L, ">u", &ar);
luaL_argcheck(L, 1 <= nup && nup <= ar.nups, argnup, "invalid upvalue index");
return nup;
}
static int db_upvalueid (lua_State *L) {
int n = checkupval(L, 1, 2);
lua_pushlightuserdata(L, lua_upvalueid(L, 1, n));
return 1;
}
static int db_upvaluejoin (lua_State *L) {
int n1 = checkupval(L, 1, 2);
int n2 = checkupval(L, 3, 4);
luaL_argcheck(L, !lua_iscfunction(L, 1), 1, "Lua function expected");
luaL_argcheck(L, !lua_iscfunction(L, 3), 3, "Lua function expected");
lua_upvaluejoin(L, 1, n1, 3, n2);
return 0;
}
#define gethooktable(L) luaL_getsubtable(L, LUA_REGISTRYINDEX, HOOKKEY)
static void hookf (lua_State *L, lua_Debug *ar) {
static const char *const hooknames[] =
{"call", "return", "line", "count", "tail call"};
gethooktable(L);
lua_pushthread(L);
lua_rawget(L, -2);
if (lua_isfunction(L, -1)) {
lua_pushstring(L, hooknames[(int)ar->event]);
if (ar->currentline >= 0)
lua_pushinteger(L, ar->currentline);
else lua_pushnil(L);
lua_assert(lua_getinfo(L, "lS", ar));
lua_call(L, 2, 0);
}
}
static int makemask (const char *smask, int count) {
int mask = 0;
if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
if (strchr(smask, 'r')) mask |= LUA_MASKRET;
if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
if (count > 0) mask |= LUA_MASKCOUNT;
return mask;
}
static char *unmakemask (int mask, char *smask) {
int i = 0;
if (mask & LUA_MASKCALL) smask[i++] = 'c';
if (mask & LUA_MASKRET) smask[i++] = 'r';
if (mask & LUA_MASKLINE) smask[i++] = 'l';
smask[i] = '\0';
return smask;
}
static int db_sethook (lua_State *L) {
int arg, mask, count;
lua_Hook func;
lua_State *L1 = getthread(L, &arg);
if (lua_isnoneornil(L, arg+1)) {
lua_settop(L, arg+1);
func = NULL; mask = 0; count = 0; /* turn off hooks */
}
else {
const char *smask = luaL_checkstring(L, arg+2);
luaL_checktype(L, arg+1, LUA_TFUNCTION);
count = luaL_optint(L, arg+3, 0);
func = hookf; mask = makemask(smask, count);
}
if (gethooktable(L) == 0) { /* creating hook table? */
lua_pushstring(L, "k");
lua_setfield(L, -2, "__mode"); /** hooktable.__mode = "k" */
lua_pushvalue(L, -1);
lua_setmetatable(L, -2); /* setmetatable(hooktable) = hooktable */
}
checkstack(L, L1, 1);
lua_pushthread(L1); lua_xmove(L1, L, 1);
lua_pushvalue(L, arg+1);
lua_rawset(L, -3); /* set new hook */
lua_sethook(L1, func, mask, count); /* set hooks */
return 0;
}
static int db_gethook (lua_State *L) {
int arg;
lua_State *L1 = getthread(L, &arg);
char buff[5];
int mask = lua_gethookmask(L1);
lua_Hook hook = lua_gethook(L1);
if (hook != NULL && hook != hookf) /* external hook? */
lua_pushliteral(L, "external hook");
else {
gethooktable(L);
checkstack(L, L1, 1);
lua_pushthread(L1); lua_xmove(L1, L, 1);
lua_rawget(L, -2); /* get hook */
lua_remove(L, -2); /* remove hook table */
}
lua_pushstring(L, unmakemask(mask, buff));
lua_pushinteger(L, lua_gethookcount(L1));
return 3;
}
static int db_debug (lua_State *L) {
for (;;) {
char buffer[250];
luai_writestringerror("%s", "lua_debug> ");
if (fgets(buffer, sizeof(buffer), stdin) == 0 ||
strcmp(buffer, "cont\n") == 0)
return 0;
if (luaL_loadbuffer(L, buffer, strlen(buffer), "=(debug command)") ||
lua_pcall(L, 0, 0, 0))
luai_writestringerror("%s\n", lua_tostring(L, -1));
lua_settop(L, 0); /* remove eventual returns */
}
}
static int db_traceback (lua_State *L) {
int arg;
lua_State *L1 = getthread(L, &arg);
const char *msg = lua_tostring(L, arg + 1);
if (msg == NULL && !lua_isnoneornil(L, arg + 1)) /* non-string 'msg'? */
lua_pushvalue(L, arg + 1); /* return it untouched */
else {
int level = luaL_optint(L, arg + 2, (L == L1) ? 1 : 0);
luaL_traceback(L, L1, msg, level);
}
return 1;
}
static const luaL_Reg dblib[] = {
{"debug", db_debug},
{"getuservalue", db_getuservalue},
{"gethook", db_gethook},
{"getinfo", db_getinfo},
{"getlocal", db_getlocal},
{"getregistry", db_getregistry},
{"getmetatable", db_getmetatable},
{"getupvalue", db_getupvalue},
{"upvaluejoin", db_upvaluejoin},
{"upvalueid", db_upvalueid},
{"setuservalue", db_setuservalue},
{"sethook", db_sethook},
{"setlocal", db_setlocal},
{"setmetatable", db_setmetatable},
{"setupvalue", db_setupvalue},
{"traceback", db_traceback},
{NULL, NULL}
};
LUAMOD_API int luaopen_debug (lua_State *L) {
luaL_newlib(L, dblib);
return 1;
}

610
source/3rdparty/lua/src/ldebug.c vendored Normal file
View File

@ -0,0 +1,610 @@
/*
** $Id: ldebug.c,v 2.90.1.4 2015/02/19 17:05:13 roberto Exp $
** Debug Interface
** See Copyright Notice in lua.h
*/
#include <stdarg.h>
#include <stddef.h>
#include <string.h>
#define ldebug_c
#define LUA_CORE
#include "lua.h"
#include "lapi.h"
#include "lcode.h"
#include "ldebug.h"
#include "ldo.h"
#include "lfunc.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
#include "ltm.h"
#include "lvm.h"
#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_TCCL)
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name);
static int currentpc (CallInfo *ci) {
lua_assert(isLua(ci));
return pcRel(ci->u.l.savedpc, ci_func(ci)->p);
}
static int currentline (CallInfo *ci) {
return getfuncline(ci_func(ci)->p, currentpc(ci));
}
static void swapextra (lua_State *L) {
if (L->status == LUA_YIELD) {
CallInfo *ci = L->ci; /* get function that yielded */
StkId temp = ci->func; /* exchange its 'func' and 'extra' values */
ci->func = restorestack(L, ci->extra);
ci->extra = savestack(L, temp);
}
}
/*
** this function can be called asynchronous (e.g. during a signal)
*/
LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask, int count) {
if (func == NULL || mask == 0) { /* turn off hooks? */
mask = 0;
func = NULL;
}
if (isLua(L->ci))
L->oldpc = L->ci->u.l.savedpc;
L->hook = func;
L->basehookcount = count;
resethookcount(L);
L->hookmask = cast_byte(mask);
return 1;
}
LUA_API lua_Hook lua_gethook (lua_State *L) {
return L->hook;
}
LUA_API int lua_gethookmask (lua_State *L) {
return L->hookmask;
}
LUA_API int lua_gethookcount (lua_State *L) {
return L->basehookcount;
}
LUA_API int lua_getstack (lua_State *L, int level, lua_Debug *ar) {
int status;
CallInfo *ci;
if (level < 0) return 0; /* invalid (negative) level */
lua_lock(L);
for (ci = L->ci; level > 0 && ci != &L->base_ci; ci = ci->previous)
level--;
if (level == 0 && ci != &L->base_ci) { /* level found? */
status = 1;
ar->i_ci = ci;
}
else status = 0; /* no such level */
lua_unlock(L);
return status;
}
static const char *upvalname (Proto *p, int uv) {
TString *s = check_exp(uv < p->sizeupvalues, p->upvalues[uv].name);
if (s == NULL) return "?";
else return getstr(s);
}
static const char *findvararg (CallInfo *ci, int n, StkId *pos) {
int nparams = clLvalue(ci->func)->p->numparams;
if (n >= ci->u.l.base - ci->func - nparams)
return NULL; /* no such vararg */
else {
*pos = ci->func + nparams + n;
return "(*vararg)"; /* generic name for any vararg */
}
}
static const char *findlocal (lua_State *L, CallInfo *ci, int n,
StkId *pos) {
const char *name = NULL;
StkId base;
if (isLua(ci)) {
if (n < 0) /* access to vararg values? */
return findvararg(ci, -n, pos);
else {
base = ci->u.l.base;
name = luaF_getlocalname(ci_func(ci)->p, n, currentpc(ci));
}
}
else
base = ci->func + 1;
if (name == NULL) { /* no 'standard' name? */
StkId limit = (ci == L->ci) ? L->top : ci->next->func;
if (limit - base >= n && n > 0) /* is 'n' inside 'ci' stack? */
name = "(*temporary)"; /* generic name for any valid slot */
else
return NULL; /* no name */
}
*pos = base + (n - 1);
return name;
}
LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n) {
const char *name;
lua_lock(L);
swapextra(L);
if (ar == NULL) { /* information about non-active function? */
if (!isLfunction(L->top - 1)) /* not a Lua function? */
name = NULL;
else /* consider live variables at function start (parameters) */
name = luaF_getlocalname(clLvalue(L->top - 1)->p, n, 0);
}
else { /* active function; get information through 'ar' */
StkId pos = 0; /* to avoid warnings */
name = findlocal(L, ar->i_ci, n, &pos);
if (name) {
setobj2s(L, L->top, pos);
api_incr_top(L);
}
}
swapextra(L);
lua_unlock(L);
return name;
}
LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) {
StkId pos = 0; /* to avoid warnings */
const char *name;
lua_lock(L);
swapextra(L);
name = findlocal(L, ar->i_ci, n, &pos);
if (name)
setobjs2s(L, pos, L->top - 1);
L->top--; /* pop value */
swapextra(L);
lua_unlock(L);
return name;
}
static void funcinfo (lua_Debug *ar, Closure *cl) {
if (noLuaClosure(cl)) {
ar->source = "=[C]";
ar->linedefined = -1;
ar->lastlinedefined = -1;
ar->what = "C";
}
else {
Proto *p = cl->l.p;
ar->source = p->source ? getstr(p->source) : "=?";
ar->linedefined = p->linedefined;
ar->lastlinedefined = p->lastlinedefined;
ar->what = (ar->linedefined == 0) ? "main" : "Lua";
}
luaO_chunkid(ar->short_src, ar->source, LUA_IDSIZE);
}
static void collectvalidlines (lua_State *L, Closure *f) {
if (noLuaClosure(f)) {
setnilvalue(L->top);
api_incr_top(L);
}
else {
int i;
TValue v;
int *lineinfo = f->l.p->lineinfo;
Table *t = luaH_new(L); /* new table to store active lines */
sethvalue(L, L->top, t); /* push it on stack */
api_incr_top(L);
setbvalue(&v, 1); /* boolean 'true' to be the value of all indices */
for (i = 0; i < f->l.p->sizelineinfo; i++) /* for all lines with code */
luaH_setint(L, t, lineinfo[i], &v); /* table[line] = true */
}
}
static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar,
Closure *f, CallInfo *ci) {
int status = 1;
for (; *what; what++) {
switch (*what) {
case 'S': {
funcinfo(ar, f);
break;
}
case 'l': {
ar->currentline = (ci && isLua(ci)) ? currentline(ci) : -1;
break;
}
case 'u': {
ar->nups = (f == NULL) ? 0 : f->c.nupvalues;
if (noLuaClosure(f)) {
ar->isvararg = 1;
ar->nparams = 0;
}
else {
ar->isvararg = f->l.p->is_vararg;
ar->nparams = f->l.p->numparams;
}
break;
}
case 't': {
ar->istailcall = (ci) ? ci->callstatus & CIST_TAIL : 0;
break;
}
case 'n': {
/* calling function is a known Lua function? */
if (ci && !(ci->callstatus & CIST_TAIL) && isLua(ci->previous))
ar->namewhat = getfuncname(L, ci->previous, &ar->name);
else
ar->namewhat = NULL;
if (ar->namewhat == NULL) {
ar->namewhat = ""; /* not found */
ar->name = NULL;
}
break;
}
case 'L':
case 'f': /* handled by lua_getinfo */
break;
default: status = 0; /* invalid option */
}
}
return status;
}
LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar) {
int status;
Closure *cl;
CallInfo *ci;
StkId func;
lua_lock(L);
swapextra(L);
if (*what == '>') {
ci = NULL;
func = L->top - 1;
api_check(L, ttisfunction(func), "function expected");
what++; /* skip the '>' */
L->top--; /* pop function */
}
else {
ci = ar->i_ci;
func = ci->func;
lua_assert(ttisfunction(ci->func));
}
cl = ttisclosure(func) ? clvalue(func) : NULL;
status = auxgetinfo(L, what, ar, cl, ci);
if (strchr(what, 'f')) {
setobjs2s(L, L->top, func);
api_incr_top(L);
}
swapextra(L);
if (strchr(what, 'L'))
collectvalidlines(L, cl);
lua_unlock(L);
return status;
}
/*
** {======================================================
** Symbolic Execution
** =======================================================
*/
static const char *getobjname (Proto *p, int lastpc, int reg,
const char **name);
/*
** find a "name" for the RK value 'c'
*/
static void kname (Proto *p, int pc, int c, const char **name) {
if (ISK(c)) { /* is 'c' a constant? */
TValue *kvalue = &p->k[INDEXK(c)];
if (ttisstring(kvalue)) { /* literal constant? */
*name = svalue(kvalue); /* it is its own name */
return;
}
/* else no reasonable name found */
}
else { /* 'c' is a register */
const char *what = getobjname(p, pc, c, name); /* search for 'c' */
if (what && *what == 'c') { /* found a constant name? */
return; /* 'name' already filled */
}
/* else no reasonable name found */
}
*name = "?"; /* no reasonable name found */
}
static int filterpc (int pc, int jmptarget) {
if (pc < jmptarget) /* is code conditional (inside a jump)? */
return -1; /* cannot know who sets that register */
else return pc; /* current position sets that register */
}
/*
** try to find last instruction before 'lastpc' that modified register 'reg'
*/
static int findsetreg (Proto *p, int lastpc, int reg) {
int pc;
int setreg = -1; /* keep last instruction that changed 'reg' */
int jmptarget = 0; /* any code before this address is conditional */
for (pc = 0; pc < lastpc; pc++) {
Instruction i = p->code[pc];
OpCode op = GET_OPCODE(i);
int a = GETARG_A(i);
switch (op) {
case OP_LOADNIL: {
int b = GETARG_B(i);
if (a <= reg && reg <= a + b) /* set registers from 'a' to 'a+b' */
setreg = filterpc(pc, jmptarget);
break;
}
case OP_TFORCALL: {
if (reg >= a + 2) /* affect all regs above its base */
setreg = filterpc(pc, jmptarget);
break;
}
case OP_CALL:
case OP_TAILCALL: {
if (reg >= a) /* affect all registers above base */
setreg = filterpc(pc, jmptarget);
break;
}
case OP_JMP: {
int b = GETARG_sBx(i);
int dest = pc + 1 + b;
/* jump is forward and do not skip `lastpc'? */
if (pc < dest && dest <= lastpc) {
if (dest > jmptarget)
jmptarget = dest; /* update 'jmptarget' */
}
break;
}
case OP_TEST: {
if (reg == a) /* jumped code can change 'a' */
setreg = filterpc(pc, jmptarget);
break;
}
default:
if (testAMode(op) && reg == a) /* any instruction that set A */
setreg = filterpc(pc, jmptarget);
break;
}
}
return setreg;
}
static const char *getobjname (Proto *p, int lastpc, int reg,
const char **name) {
int pc;
*name = luaF_getlocalname(p, reg + 1, lastpc);
if (*name) /* is a local? */
return "local";
/* else try symbolic execution */
pc = findsetreg(p, lastpc, reg);
if (pc != -1) { /* could find instruction? */
Instruction i = p->code[pc];
OpCode op = GET_OPCODE(i);
switch (op) {
case OP_MOVE: {
int b = GETARG_B(i); /* move from 'b' to 'a' */
if (b < GETARG_A(i))
return getobjname(p, pc, b, name); /* get name for 'b' */
break;
}
case OP_GETTABUP:
case OP_GETTABLE: {
int k = GETARG_C(i); /* key index */
int t = GETARG_B(i); /* table index */
const char *vn = (op == OP_GETTABLE) /* name of indexed variable */
? luaF_getlocalname(p, t + 1, pc)
: upvalname(p, t);
kname(p, pc, k, name);
return (vn && strcmp(vn, LUA_ENV) == 0) ? "global" : "field";
}
case OP_GETUPVAL: {
*name = upvalname(p, GETARG_B(i));
return "upvalue";
}
case OP_LOADK:
case OP_LOADKX: {
int b = (op == OP_LOADK) ? GETARG_Bx(i)
: GETARG_Ax(p->code[pc + 1]);
if (ttisstring(&p->k[b])) {
*name = svalue(&p->k[b]);
return "constant";
}
break;
}
case OP_SELF: {
int k = GETARG_C(i); /* key index */
kname(p, pc, k, name);
return "method";
}
default: break; /* go through to return NULL */
}
}
return NULL; /* could not find reasonable name */
}
static const char *getfuncname (lua_State *L, CallInfo *ci, const char **name) {
TMS tm;
Proto *p = ci_func(ci)->p; /* calling function */
int pc = currentpc(ci); /* calling instruction index */
Instruction i = p->code[pc]; /* calling instruction */
switch (GET_OPCODE(i)) {
case OP_CALL:
case OP_TAILCALL: /* get function name */
return getobjname(p, pc, GETARG_A(i), name);
case OP_TFORCALL: { /* for iterator */
*name = "for iterator";
return "for iterator";
}
/* all other instructions can call only through metamethods */
case OP_SELF:
case OP_GETTABUP:
case OP_GETTABLE: tm = TM_INDEX; break;
case OP_SETTABUP:
case OP_SETTABLE: tm = TM_NEWINDEX; break;
case OP_EQ: tm = TM_EQ; break;
case OP_ADD: tm = TM_ADD; break;
case OP_SUB: tm = TM_SUB; break;
case OP_MUL: tm = TM_MUL; break;
case OP_DIV: tm = TM_DIV; break;
case OP_MOD: tm = TM_MOD; break;
case OP_POW: tm = TM_POW; break;
case OP_UNM: tm = TM_UNM; break;
case OP_LEN: tm = TM_LEN; break;
case OP_LT: tm = TM_LT; break;
case OP_LE: tm = TM_LE; break;
case OP_CONCAT: tm = TM_CONCAT; break;
default:
return NULL; /* else no useful name can be found */
}
*name = getstr(G(L)->tmname[tm]);
return "metamethod";
}
/* }====================================================== */
/*
** only ANSI way to check whether a pointer points to an array
** (used only for error messages, so efficiency is not a big concern)
*/
static int isinstack (CallInfo *ci, const TValue *o) {
StkId p;
for (p = ci->u.l.base; p < ci->top; p++)
if (o == p) return 1;
return 0;
}
static const char *getupvalname (CallInfo *ci, const TValue *o,
const char **name) {
LClosure *c = ci_func(ci);
int i;
for (i = 0; i < c->nupvalues; i++) {
if (c->upvals[i]->v == o) {
*name = upvalname(c->p, i);
return "upvalue";
}
}
return NULL;
}
l_noret luaG_typeerror (lua_State *L, const TValue *o, const char *op) {
CallInfo *ci = L->ci;
const char *name = NULL;
const char *t = objtypename(o);
const char *kind = NULL;
if (isLua(ci)) {
kind = getupvalname(ci, o, &name); /* check whether 'o' is an upvalue */
if (!kind && isinstack(ci, o)) /* no? try a register */
kind = getobjname(ci_func(ci)->p, currentpc(ci),
cast_int(o - ci->u.l.base), &name);
}
if (kind)
luaG_runerror(L, "attempt to %s %s " LUA_QS " (a %s value)",
op, kind, name, t);
else
luaG_runerror(L, "attempt to %s a %s value", op, t);
}
l_noret luaG_concaterror (lua_State *L, StkId p1, StkId p2) {
if (ttisstring(p1) || ttisnumber(p1)) p1 = p2;
lua_assert(!ttisstring(p1) && !ttisnumber(p1));
luaG_typeerror(L, p1, "concatenate");
}
l_noret luaG_aritherror (lua_State *L, const TValue *p1, const TValue *p2) {
TValue temp;
if (luaV_tonumber(p1, &temp) == NULL)
p2 = p1; /* first operand is wrong */
luaG_typeerror(L, p2, "perform arithmetic on");
}
l_noret luaG_ordererror (lua_State *L, const TValue *p1, const TValue *p2) {
const char *t1 = objtypename(p1);
const char *t2 = objtypename(p2);
if (t1 == t2)
luaG_runerror(L, "attempt to compare two %s values", t1);
else
luaG_runerror(L, "attempt to compare %s with %s", t1, t2);
}
static void addinfo (lua_State *L, const char *msg) {
CallInfo *ci = L->ci;
if (isLua(ci)) { /* is Lua code? */
char buff[LUA_IDSIZE]; /* add file:line information */
int line = currentline(ci);
TString *src = ci_func(ci)->p->source;
if (src)
luaO_chunkid(buff, getstr(src), LUA_IDSIZE);
else { /* no source available; use "?" instead */
buff[0] = '?'; buff[1] = '\0';
}
luaO_pushfstring(L, "%s:%d: %s", buff, line, msg);
}
}
l_noret luaG_errormsg (lua_State *L) {
if (L->errfunc != 0) { /* is there an error handling function? */
StkId errfunc = restorestack(L, L->errfunc);
if (!ttisfunction(errfunc)) luaD_throw(L, LUA_ERRERR);
setobjs2s(L, L->top, L->top - 1); /* move argument */
setobjs2s(L, L->top - 1, errfunc); /* push function */
L->top++;
luaD_call(L, L->top - 2, 1, 0); /* call it */
}
luaD_throw(L, LUA_ERRRUN);
}
l_noret luaG_runerror (lua_State *L, const char *fmt, ...) {
va_list argp;
va_start(argp, fmt);
addinfo(L, luaO_pushvfstring(L, fmt, argp));
va_end(argp);
luaG_errormsg(L);
}

681
source/3rdparty/lua/src/ldo.c vendored Normal file
View File

@ -0,0 +1,681 @@
/*
** $Id: ldo.c,v 2.108.1.3 2013/11/08 18:22:50 roberto Exp $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
#include <setjmp.h>
#include <stdlib.h>
#include <string.h>
#define ldo_c
#define LUA_CORE
#include "lua.h"
#include "lapi.h"
#include "ldebug.h"
#include "ldo.h"
#include "lfunc.h"
#include "lgc.h"
#include "lmem.h"
#include "lobject.h"
#include "lopcodes.h"
#include "lparser.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
#include "ltm.h"
#include "lundump.h"
#include "lvm.h"
#include "lzio.h"
/*
** {======================================================
** Error-recovery functions
** =======================================================
*/
/*
** LUAI_THROW/LUAI_TRY define how Lua does exception handling. By
** default, Lua handles errors with exceptions when compiling as
** C++ code, with _longjmp/_setjmp when asked to use them, and with
** longjmp/setjmp otherwise.
*/
#if !defined(LUAI_THROW)
#if defined(__cplusplus) && !defined(LUA_USE_LONGJMP)
/* C++ exceptions */
#define LUAI_THROW(L,c) throw(c)
#define LUAI_TRY(L,c,a) \
try { a } catch(...) { if ((c)->status == 0) (c)->status = -1; }
#define luai_jmpbuf int /* dummy variable */
#elif defined(LUA_USE_ULONGJMP)
/* in Unix, try _longjmp/_setjmp (more efficient) */
#define LUAI_THROW(L,c) _longjmp((c)->b, 1)
#define LUAI_TRY(L,c,a) if (_setjmp((c)->b) == 0) { a }
#define luai_jmpbuf jmp_buf
#else
/* default handling with long jumps */
#define LUAI_THROW(L,c) longjmp((c)->b, 1)
#define LUAI_TRY(L,c,a) if (setjmp((c)->b) == 0) { a }
#define luai_jmpbuf jmp_buf
#endif
#endif
/* chain list of long jump buffers */
struct lua_longjmp {
struct lua_longjmp *previous;
luai_jmpbuf b;
volatile int status; /* error code */
};
static void seterrorobj (lua_State *L, int errcode, StkId oldtop) {
switch (errcode) {
case LUA_ERRMEM: { /* memory error? */
setsvalue2s(L, oldtop, G(L)->memerrmsg); /* reuse preregistered msg. */
break;
}
case LUA_ERRERR: {
setsvalue2s(L, oldtop, luaS_newliteral(L, "error in error handling"));
break;
}
default: {
setobjs2s(L, oldtop, L->top - 1); /* error message on current top */
break;
}
}
L->top = oldtop + 1;
}
l_noret luaD_throw (lua_State *L, int errcode) {
if (L->errorJmp) { /* thread has an error handler? */
L->errorJmp->status = errcode; /* set status */
LUAI_THROW(L, L->errorJmp); /* jump to it */
}
else { /* thread has no error handler */
L->status = cast_byte(errcode); /* mark it as dead */
if (G(L)->mainthread->errorJmp) { /* main thread has a handler? */
setobjs2s(L, G(L)->mainthread->top++, L->top - 1); /* copy error obj. */
luaD_throw(G(L)->mainthread, errcode); /* re-throw in main thread */
}
else { /* no handler at all; abort */
if (G(L)->panic) { /* panic function? */
lua_unlock(L);
G(L)->panic(L); /* call it (last chance to jump out) */
}
abort();
}
}
}
int luaD_rawrunprotected (lua_State *L, Pfunc f, void *ud) {
unsigned short oldnCcalls = L->nCcalls;
struct lua_longjmp lj;
lj.status = LUA_OK;
lj.previous = L->errorJmp; /* chain new error handler */
L->errorJmp = &lj;
LUAI_TRY(L, &lj,
(*f)(L, ud);
);
L->errorJmp = lj.previous; /* restore old error handler */
L->nCcalls = oldnCcalls;
return lj.status;
}
/* }====================================================== */
static void correctstack (lua_State *L, TValue *oldstack) {
CallInfo *ci;
GCObject *up;
L->top = (L->top - oldstack) + L->stack;
for (up = L->openupval; up != NULL; up = up->gch.next)
gco2uv(up)->v = (gco2uv(up)->v - oldstack) + L->stack;
for (ci = L->ci; ci != NULL; ci = ci->previous) {
ci->top = (ci->top - oldstack) + L->stack;
ci->func = (ci->func - oldstack) + L->stack;
if (isLua(ci))
ci->u.l.base = (ci->u.l.base - oldstack) + L->stack;
}
}
/* some space for error handling */
#define ERRORSTACKSIZE (LUAI_MAXSTACK + 200)
void luaD_reallocstack (lua_State *L, int newsize) {
TValue *oldstack = L->stack;
int lim = L->stacksize;
lua_assert(newsize <= LUAI_MAXSTACK || newsize == ERRORSTACKSIZE);
lua_assert(L->stack_last - L->stack == L->stacksize - EXTRA_STACK);
luaM_reallocvector(L, L->stack, L->stacksize, newsize, TValue);
for (; lim < newsize; lim++)
setnilvalue(L->stack + lim); /* erase new segment */
L->stacksize = newsize;
L->stack_last = L->stack + newsize - EXTRA_STACK;
correctstack(L, oldstack);
}
void luaD_growstack (lua_State *L, int n) {
int size = L->stacksize;
if (size > LUAI_MAXSTACK) /* error after extra size? */
luaD_throw(L, LUA_ERRERR);
else {
int needed = cast_int(L->top - L->stack) + n + EXTRA_STACK;
int newsize = 2 * size;
if (newsize > LUAI_MAXSTACK) newsize = LUAI_MAXSTACK;
if (newsize < needed) newsize = needed;
if (newsize > LUAI_MAXSTACK) { /* stack overflow? */
luaD_reallocstack(L, ERRORSTACKSIZE);
luaG_runerror(L, "stack overflow");
}
else
luaD_reallocstack(L, newsize);
}
}
static int stackinuse (lua_State *L) {
CallInfo *ci;
StkId lim = L->top;
for (ci = L->ci; ci != NULL; ci = ci->previous) {
lua_assert(ci->top <= L->stack_last);
if (lim < ci->top) lim = ci->top;
}
return cast_int(lim - L->stack) + 1; /* part of stack in use */
}
void luaD_shrinkstack (lua_State *L) {
int inuse = stackinuse(L);
int goodsize = inuse + (inuse / 8) + 2*EXTRA_STACK;
if (goodsize > LUAI_MAXSTACK) goodsize = LUAI_MAXSTACK;
if (inuse > LUAI_MAXSTACK || /* handling stack overflow? */
goodsize >= L->stacksize) /* would grow instead of shrink? */
condmovestack(L); /* don't change stack (change only for debugging) */
else
luaD_reallocstack(L, goodsize); /* shrink it */
}
void luaD_hook (lua_State *L, int event, int line) {
lua_Hook hook = L->hook;
if (hook && L->allowhook) {
CallInfo *ci = L->ci;
ptrdiff_t top = savestack(L, L->top);
ptrdiff_t ci_top = savestack(L, ci->top);
lua_Debug ar;
ar.event = event;
ar.currentline = line;
ar.i_ci = ci;
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
ci->top = L->top + LUA_MINSTACK;
lua_assert(ci->top <= L->stack_last);
L->allowhook = 0; /* cannot call hooks inside a hook */
ci->callstatus |= CIST_HOOKED;
lua_unlock(L);
(*hook)(L, &ar);
lua_lock(L);
lua_assert(!L->allowhook);
L->allowhook = 1;
ci->top = restorestack(L, ci_top);
L->top = restorestack(L, top);
ci->callstatus &= ~CIST_HOOKED;
}
}
static void callhook (lua_State *L, CallInfo *ci) {
int hook = LUA_HOOKCALL;
ci->u.l.savedpc++; /* hooks assume 'pc' is already incremented */
if (isLua(ci->previous) &&
GET_OPCODE(*(ci->previous->u.l.savedpc - 1)) == OP_TAILCALL) {
ci->callstatus |= CIST_TAIL;
hook = LUA_HOOKTAILCALL;
}
luaD_hook(L, hook, -1);
ci->u.l.savedpc--; /* correct 'pc' */
}
static StkId adjust_varargs (lua_State *L, Proto *p, int actual) {
int i;
int nfixargs = p->numparams;
StkId base, fixed;
lua_assert(actual >= nfixargs);
/* move fixed parameters to final position */
luaD_checkstack(L, p->maxstacksize); /* check again for new 'base' */
fixed = L->top - actual; /* first fixed argument */
base = L->top; /* final position of first argument */
for (i=0; i<nfixargs; i++) {
setobjs2s(L, L->top++, fixed + i);
setnilvalue(fixed + i);
}
return base;
}
static StkId tryfuncTM (lua_State *L, StkId func) {
const TValue *tm = luaT_gettmbyobj(L, func, TM_CALL);
StkId p;
ptrdiff_t funcr = savestack(L, func);
if (!ttisfunction(tm))
luaG_typeerror(L, func, "call");
/* Open a hole inside the stack at `func' */
for (p = L->top; p > func; p--) setobjs2s(L, p, p-1);
incr_top(L);
func = restorestack(L, funcr); /* previous call may change stack */
setobj2s(L, func, tm); /* tag method is the new function to be called */
return func;
}
#define next_ci(L) (L->ci = (L->ci->next ? L->ci->next : luaE_extendCI(L)))
/*
** returns true if function has been executed (C function)
*/
int luaD_precall (lua_State *L, StkId func, int nresults) {
lua_CFunction f;
CallInfo *ci;
int n; /* number of arguments (Lua) or returns (C) */
ptrdiff_t funcr = savestack(L, func);
switch (ttype(func)) {
case LUA_TLCF: /* light C function */
f = fvalue(func);
goto Cfunc;
case LUA_TCCL: { /* C closure */
f = clCvalue(func)->f;
Cfunc:
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
ci = next_ci(L); /* now 'enter' new function */
ci->nresults = nresults;
ci->func = restorestack(L, funcr);
ci->top = L->top + LUA_MINSTACK;
lua_assert(ci->top <= L->stack_last);
ci->callstatus = 0;
luaC_checkGC(L); /* stack grow uses memory */
if (L->hookmask & LUA_MASKCALL)
luaD_hook(L, LUA_HOOKCALL, -1);
lua_unlock(L);
n = (*f)(L); /* do the actual call */
lua_lock(L);
api_checknelems(L, n);
luaD_poscall(L, L->top - n);
return 1;
}
case LUA_TLCL: { /* Lua function: prepare its call */
StkId base;
Proto *p = clLvalue(func)->p;
n = cast_int(L->top - func) - 1; /* number of real arguments */
luaD_checkstack(L, p->maxstacksize);
for (; n < p->numparams; n++)
setnilvalue(L->top++); /* complete missing arguments */
if (!p->is_vararg) {
func = restorestack(L, funcr);
base = func + 1;
}
else {
base = adjust_varargs(L, p, n);
func = restorestack(L, funcr); /* previous call can change stack */
}
ci = next_ci(L); /* now 'enter' new function */
ci->nresults = nresults;
ci->func = func;
ci->u.l.base = base;
ci->top = base + p->maxstacksize;
lua_assert(ci->top <= L->stack_last);
ci->u.l.savedpc = p->code; /* starting point */
ci->callstatus = CIST_LUA;
L->top = ci->top;
luaC_checkGC(L); /* stack grow uses memory */
if (L->hookmask & LUA_MASKCALL)
callhook(L, ci);
return 0;
}
default: { /* not a function */
func = tryfuncTM(L, func); /* retry with 'function' tag method */
return luaD_precall(L, func, nresults); /* now it must be a function */
}
}
}
int luaD_poscall (lua_State *L, StkId firstResult) {
StkId res;
int wanted, i;
CallInfo *ci = L->ci;
if (L->hookmask & (LUA_MASKRET | LUA_MASKLINE)) {
if (L->hookmask & LUA_MASKRET) {
ptrdiff_t fr = savestack(L, firstResult); /* hook may change stack */
luaD_hook(L, LUA_HOOKRET, -1);
firstResult = restorestack(L, fr);
}
L->oldpc = ci->previous->u.l.savedpc; /* 'oldpc' for caller function */
}
res = ci->func; /* res == final position of 1st result */
wanted = ci->nresults;
L->ci = ci = ci->previous; /* back to caller */
/* move results to correct place */
for (i = wanted; i != 0 && firstResult < L->top; i--)
setobjs2s(L, res++, firstResult++);
while (i-- > 0)
setnilvalue(res++);
L->top = res;
return (wanted - LUA_MULTRET); /* 0 iff wanted == LUA_MULTRET */
}
/*
** Call a function (C or Lua). The function to be called is at *func.
** The arguments are on the stack, right after the function.
** When returns, all the results are on the stack, starting at the original
** function position.
*/
void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) {
if (++L->nCcalls >= LUAI_MAXCCALLS) {
if (L->nCcalls == LUAI_MAXCCALLS)
luaG_runerror(L, "C stack overflow");
else if (L->nCcalls >= (LUAI_MAXCCALLS + (LUAI_MAXCCALLS>>3)))
luaD_throw(L, LUA_ERRERR); /* error while handing stack error */
}
if (!allowyield) L->nny++;
if (!luaD_precall(L, func, nResults)) /* is a Lua function? */
luaV_execute(L); /* call it */
if (!allowyield) L->nny--;
L->nCcalls--;
}
static void finishCcall (lua_State *L) {
CallInfo *ci = L->ci;
int n;
lua_assert(ci->u.c.k != NULL); /* must have a continuation */
lua_assert(L->nny == 0);
if (ci->callstatus & CIST_YPCALL) { /* was inside a pcall? */
ci->callstatus &= ~CIST_YPCALL; /* finish 'lua_pcall' */
L->errfunc = ci->u.c.old_errfunc;
}
/* finish 'lua_callk'/'lua_pcall' */
adjustresults(L, ci->nresults);
/* call continuation function */
if (!(ci->callstatus & CIST_STAT)) /* no call status? */
ci->u.c.status = LUA_YIELD; /* 'default' status */
lua_assert(ci->u.c.status != LUA_OK);
ci->callstatus = (ci->callstatus & ~(CIST_YPCALL | CIST_STAT)) | CIST_YIELDED;
lua_unlock(L);
n = (*ci->u.c.k)(L);
lua_lock(L);
api_checknelems(L, n);
/* finish 'luaD_precall' */
luaD_poscall(L, L->top - n);
}
static void unroll (lua_State *L, void *ud) {
UNUSED(ud);
for (;;) {
if (L->ci == &L->base_ci) /* stack is empty? */
return; /* coroutine finished normally */
if (!isLua(L->ci)) /* C function? */
finishCcall(L);
else { /* Lua function */
luaV_finishOp(L); /* finish interrupted instruction */
luaV_execute(L); /* execute down to higher C 'boundary' */
}
}
}
/*
** check whether thread has a suspended protected call
*/
static CallInfo *findpcall (lua_State *L) {
CallInfo *ci;
for (ci = L->ci; ci != NULL; ci = ci->previous) { /* search for a pcall */
if (ci->callstatus & CIST_YPCALL)
return ci;
}
return NULL; /* no pending pcall */
}
static int recover (lua_State *L, int status) {
StkId oldtop;
CallInfo *ci = findpcall(L);
if (ci == NULL) return 0; /* no recovery point */
/* "finish" luaD_pcall */
oldtop = restorestack(L, ci->extra);
luaF_close(L, oldtop);
seterrorobj(L, status, oldtop);
L->ci = ci;
L->allowhook = ci->u.c.old_allowhook;
L->nny = 0; /* should be zero to be yieldable */
luaD_shrinkstack(L);
L->errfunc = ci->u.c.old_errfunc;
ci->callstatus |= CIST_STAT; /* call has error status */
ci->u.c.status = status; /* (here it is) */
return 1; /* continue running the coroutine */
}
/*
** signal an error in the call to 'resume', not in the execution of the
** coroutine itself. (Such errors should not be handled by any coroutine
** error handler and should not kill the coroutine.)
*/
static l_noret resume_error (lua_State *L, const char *msg, StkId firstArg) {
L->top = firstArg; /* remove args from the stack */
setsvalue2s(L, L->top, luaS_new(L, msg)); /* push error message */
api_incr_top(L);
luaD_throw(L, -1); /* jump back to 'lua_resume' */
}
/*
** do the work for 'lua_resume' in protected mode
*/
static void resume (lua_State *L, void *ud) {
int nCcalls = L->nCcalls;
StkId firstArg = cast(StkId, ud);
CallInfo *ci = L->ci;
if (nCcalls >= LUAI_MAXCCALLS)
resume_error(L, "C stack overflow", firstArg);
if (L->status == LUA_OK) { /* may be starting a coroutine */
if (ci != &L->base_ci) /* not in base level? */
resume_error(L, "cannot resume non-suspended coroutine", firstArg);
/* coroutine is in base level; start running it */
if (!luaD_precall(L, firstArg - 1, LUA_MULTRET)) /* Lua function? */
luaV_execute(L); /* call it */
}
else if (L->status != LUA_YIELD)
resume_error(L, "cannot resume dead coroutine", firstArg);
else { /* resuming from previous yield */
L->status = LUA_OK;
ci->func = restorestack(L, ci->extra);
if (isLua(ci)) /* yielded inside a hook? */
luaV_execute(L); /* just continue running Lua code */
else { /* 'common' yield */
if (ci->u.c.k != NULL) { /* does it have a continuation? */
int n;
ci->u.c.status = LUA_YIELD; /* 'default' status */
ci->callstatus |= CIST_YIELDED;
lua_unlock(L);
n = (*ci->u.c.k)(L); /* call continuation */
lua_lock(L);
api_checknelems(L, n);
firstArg = L->top - n; /* yield results come from continuation */
}
luaD_poscall(L, firstArg); /* finish 'luaD_precall' */
}
unroll(L, NULL);
}
lua_assert(nCcalls == L->nCcalls);
}
LUA_API int lua_resume (lua_State *L, lua_State *from, int nargs) {
int status;
int oldnny = L->nny; /* save 'nny' */
lua_lock(L);
luai_userstateresume(L, nargs);
L->nCcalls = (from) ? from->nCcalls + 1 : 1;
L->nny = 0; /* allow yields */
api_checknelems(L, (L->status == LUA_OK) ? nargs + 1 : nargs);
status = luaD_rawrunprotected(L, resume, L->top - nargs);
if (status == -1) /* error calling 'lua_resume'? */
status = LUA_ERRRUN;
else { /* yield or regular error */
while (status != LUA_OK && status != LUA_YIELD) { /* error? */
if (recover(L, status)) /* recover point? */
status = luaD_rawrunprotected(L, unroll, NULL); /* run continuation */
else { /* unrecoverable error */
L->status = cast_byte(status); /* mark thread as `dead' */
seterrorobj(L, status, L->top);
L->ci->top = L->top;
break;
}
}
lua_assert(status == L->status);
}
L->nny = oldnny; /* restore 'nny' */
L->nCcalls--;
lua_assert(L->nCcalls == ((from) ? from->nCcalls : 0));
lua_unlock(L);
return status;
}
LUA_API int lua_yieldk (lua_State *L, int nresults, int ctx, lua_CFunction k) {
CallInfo *ci = L->ci;
luai_userstateyield(L, nresults);
lua_lock(L);
api_checknelems(L, nresults);
if (L->nny > 0) {
if (L != G(L)->mainthread)
luaG_runerror(L, "attempt to yield across a C-call boundary");
else
luaG_runerror(L, "attempt to yield from outside a coroutine");
}
L->status = LUA_YIELD;
ci->extra = savestack(L, ci->func); /* save current 'func' */
if (isLua(ci)) { /* inside a hook? */
api_check(L, k == NULL, "hooks cannot continue after yielding");
}
else {
if ((ci->u.c.k = k) != NULL) /* is there a continuation? */
ci->u.c.ctx = ctx; /* save context */
ci->func = L->top - nresults - 1; /* protect stack below results */
luaD_throw(L, LUA_YIELD);
}
lua_assert(ci->callstatus & CIST_HOOKED); /* must be inside a hook */
lua_unlock(L);
return 0; /* return to 'luaD_hook' */
}
int luaD_pcall (lua_State *L, Pfunc func, void *u,
ptrdiff_t old_top, ptrdiff_t ef) {
int status;
CallInfo *old_ci = L->ci;
lu_byte old_allowhooks = L->allowhook;
unsigned short old_nny = L->nny;
ptrdiff_t old_errfunc = L->errfunc;
L->errfunc = ef;
status = luaD_rawrunprotected(L, func, u);
if (status != LUA_OK) { /* an error occurred? */
StkId oldtop = restorestack(L, old_top);
luaF_close(L, oldtop); /* close possible pending closures */
seterrorobj(L, status, oldtop);
L->ci = old_ci;
L->allowhook = old_allowhooks;
L->nny = old_nny;
luaD_shrinkstack(L);
}
L->errfunc = old_errfunc;
return status;
}
/*
** Execute a protected parser.
*/
struct SParser { /* data to `f_parser' */
ZIO *z;
Mbuffer buff; /* dynamic structure used by the scanner */
Dyndata dyd; /* dynamic structures used by the parser */
const char *mode;
const char *name;
};
static void checkmode (lua_State *L, const char *mode, const char *x) {
if (mode && strchr(mode, x[0]) == NULL) {
luaO_pushfstring(L,
"attempt to load a %s chunk (mode is " LUA_QS ")", x, mode);
luaD_throw(L, LUA_ERRSYNTAX);
}
}
static void f_parser (lua_State *L, void *ud) {
int i;
Closure *cl;
struct SParser *p = cast(struct SParser *, ud);
int c = zgetc(p->z); /* read first character */
if (c == LUA_SIGNATURE[0]) {
checkmode(L, p->mode, "binary");
cl = luaU_undump(L, p->z, &p->buff, p->name);
}
else {
checkmode(L, p->mode, "text");
cl = luaY_parser(L, p->z, &p->buff, &p->dyd, p->name, c);
}
lua_assert(cl->l.nupvalues == cl->l.p->sizeupvalues);
for (i = 0; i < cl->l.nupvalues; i++) { /* initialize upvalues */
UpVal *up = luaF_newupval(L);
cl->l.upvals[i] = up;
luaC_objbarrier(L, cl, up);
}
}
int luaD_protectedparser (lua_State *L, ZIO *z, const char *name,
const char *mode) {
struct SParser p;
int status;
L->nny++; /* cannot yield during parsing */
p.z = z; p.name = name; p.mode = mode;
p.dyd.actvar.arr = NULL; p.dyd.actvar.size = 0;
p.dyd.gt.arr = NULL; p.dyd.gt.size = 0;
p.dyd.label.arr = NULL; p.dyd.label.size = 0;
luaZ_initbuffer(L, &p.buff);
status = luaD_pcall(L, f_parser, &p, savestack(L, L->top), L->errfunc);
luaZ_freebuffer(L, &p.buff);
luaM_freearray(L, p.dyd.actvar.arr, p.dyd.actvar.size);
luaM_freearray(L, p.dyd.gt.arr, p.dyd.gt.size);
luaM_freearray(L, p.dyd.label.arr, p.dyd.label.size);
L->nny--;
return status;
}

173
source/3rdparty/lua/src/ldump.c vendored Normal file
View File

@ -0,0 +1,173 @@
/*
** $Id: ldump.c,v 2.17.1.1 2013/04/12 18:48:47 roberto Exp $
** save precompiled Lua chunks
** See Copyright Notice in lua.h
*/
#include <stddef.h>
#define ldump_c
#define LUA_CORE
#include "lua.h"
#include "lobject.h"
#include "lstate.h"
#include "lundump.h"
typedef struct {
lua_State* L;
lua_Writer writer;
void* data;
int strip;
int status;
} DumpState;
#define DumpMem(b,n,size,D) DumpBlock(b,(n)*(size),D)
#define DumpVar(x,D) DumpMem(&x,1,sizeof(x),D)
static void DumpBlock(const void* b, size_t size, DumpState* D)
{
if (D->status==0)
{
lua_unlock(D->L);
D->status=(*D->writer)(D->L,b,size,D->data);
lua_lock(D->L);
}
}
static void DumpChar(int y, DumpState* D)
{
char x=(char)y;
DumpVar(x,D);
}
static void DumpInt(int x, DumpState* D)
{
DumpVar(x,D);
}
static void DumpNumber(lua_Number x, DumpState* D)
{
DumpVar(x,D);
}
static void DumpVector(const void* b, int n, size_t size, DumpState* D)
{
DumpInt(n,D);
DumpMem(b,n,size,D);
}
static void DumpString(const TString* s, DumpState* D)
{
if (s==NULL)
{
size_t size=0;
DumpVar(size,D);
}
else
{
size_t size=s->tsv.len+1; /* include trailing '\0' */
DumpVar(size,D);
DumpBlock(getstr(s),size*sizeof(char),D);
}
}
#define DumpCode(f,D) DumpVector(f->code,f->sizecode,sizeof(Instruction),D)
static void DumpFunction(const Proto* f, DumpState* D);
static void DumpConstants(const Proto* f, DumpState* D)
{
int i,n=f->sizek;
DumpInt(n,D);
for (i=0; i<n; i++)
{
const TValue* o=&f->k[i];
DumpChar(ttypenv(o),D);
switch (ttypenv(o))
{
case LUA_TNIL:
break;
case LUA_TBOOLEAN:
DumpChar(bvalue(o),D);
break;
case LUA_TNUMBER:
DumpNumber(nvalue(o),D);
break;
case LUA_TSTRING:
DumpString(rawtsvalue(o),D);
break;
default: lua_assert(0);
}
}
n=f->sizep;
DumpInt(n,D);
for (i=0; i<n; i++) DumpFunction(f->p[i],D);
}
static void DumpUpvalues(const Proto* f, DumpState* D)
{
int i,n=f->sizeupvalues;
DumpInt(n,D);
for (i=0; i<n; i++)
{
DumpChar(f->upvalues[i].instack,D);
DumpChar(f->upvalues[i].idx,D);
}
}
static void DumpDebug(const Proto* f, DumpState* D)
{
int i,n;
DumpString((D->strip) ? NULL : f->source,D);
n= (D->strip) ? 0 : f->sizelineinfo;
DumpVector(f->lineinfo,n,sizeof(int),D);
n= (D->strip) ? 0 : f->sizelocvars;
DumpInt(n,D);
for (i=0; i<n; i++)
{
DumpString(f->locvars[i].varname,D);
DumpInt(f->locvars[i].startpc,D);
DumpInt(f->locvars[i].endpc,D);
}
n= (D->strip) ? 0 : f->sizeupvalues;
DumpInt(n,D);
for (i=0; i<n; i++) DumpString(f->upvalues[i].name,D);
}
static void DumpFunction(const Proto* f, DumpState* D)
{
DumpInt(f->linedefined,D);
DumpInt(f->lastlinedefined,D);
DumpChar(f->numparams,D);
DumpChar(f->is_vararg,D);
DumpChar(f->maxstacksize,D);
DumpCode(f,D);
DumpConstants(f,D);
DumpUpvalues(f,D);
DumpDebug(f,D);
}
static void DumpHeader(DumpState* D)
{
lu_byte h[LUAC_HEADERSIZE];
luaU_header(h);
DumpBlock(h,LUAC_HEADERSIZE,D);
}
/*
** dump Lua function as precompiled chunk
*/
int luaU_dump (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip)
{
DumpState D;
D.L=L;
D.writer=w;
D.data=data;
D.strip=strip;
D.status=0;
DumpHeader(&D);
DumpFunction(f,&D);
return D.status;
}

161
source/3rdparty/lua/src/lfunc.c vendored Normal file
View File

@ -0,0 +1,161 @@
/*
** $Id: lfunc.c,v 2.30.1.1 2013/04/12 18:48:47 roberto Exp $
** Auxiliary functions to manipulate prototypes and closures
** See Copyright Notice in lua.h
*/
#include <stddef.h>
#define lfunc_c
#define LUA_CORE
#include "lua.h"
#include "lfunc.h"
#include "lgc.h"
#include "lmem.h"
#include "lobject.h"
#include "lstate.h"
Closure *luaF_newCclosure (lua_State *L, int n) {
Closure *c = &luaC_newobj(L, LUA_TCCL, sizeCclosure(n), NULL, 0)->cl;
c->c.nupvalues = cast_byte(n);
return c;
}
Closure *luaF_newLclosure (lua_State *L, int n) {
Closure *c = &luaC_newobj(L, LUA_TLCL, sizeLclosure(n), NULL, 0)->cl;
c->l.p = NULL;
c->l.nupvalues = cast_byte(n);
while (n--) c->l.upvals[n] = NULL;
return c;
}
UpVal *luaF_newupval (lua_State *L) {
UpVal *uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), NULL, 0)->uv;
uv->v = &uv->u.value;
setnilvalue(uv->v);
return uv;
}
UpVal *luaF_findupval (lua_State *L, StkId level) {
global_State *g = G(L);
GCObject **pp = &L->openupval;
UpVal *p;
UpVal *uv;
while (*pp != NULL && (p = gco2uv(*pp))->v >= level) {
GCObject *o = obj2gco(p);
lua_assert(p->v != &p->u.value);
lua_assert(!isold(o) || isold(obj2gco(L)));
if (p->v == level) { /* found a corresponding upvalue? */
if (isdead(g, o)) /* is it dead? */
changewhite(o); /* resurrect it */
return p;
}
pp = &p->next;
}
/* not found: create a new one */
uv = &luaC_newobj(L, LUA_TUPVAL, sizeof(UpVal), pp, 0)->uv;
uv->v = level; /* current value lives in the stack */
uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */
uv->u.l.next = g->uvhead.u.l.next;
uv->u.l.next->u.l.prev = uv;
g->uvhead.u.l.next = uv;
lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
return uv;
}
static void unlinkupval (UpVal *uv) {
lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
uv->u.l.next->u.l.prev = uv->u.l.prev; /* remove from `uvhead' list */
uv->u.l.prev->u.l.next = uv->u.l.next;
}
void luaF_freeupval (lua_State *L, UpVal *uv) {
if (uv->v != &uv->u.value) /* is it open? */
unlinkupval(uv); /* remove from open list */
luaM_free(L, uv); /* free upvalue */
}
void luaF_close (lua_State *L, StkId level) {
UpVal *uv;
global_State *g = G(L);
while (L->openupval != NULL && (uv = gco2uv(L->openupval))->v >= level) {
GCObject *o = obj2gco(uv);
lua_assert(!isblack(o) && uv->v != &uv->u.value);
L->openupval = uv->next; /* remove from `open' list */
if (isdead(g, o))
luaF_freeupval(L, uv); /* free upvalue */
else {
unlinkupval(uv); /* remove upvalue from 'uvhead' list */
setobj(L, &uv->u.value, uv->v); /* move value to upvalue slot */
uv->v = &uv->u.value; /* now current value lives here */
gch(o)->next = g->allgc; /* link upvalue into 'allgc' list */
g->allgc = o;
luaC_checkupvalcolor(g, uv);
}
}
}
Proto *luaF_newproto (lua_State *L) {
Proto *f = &luaC_newobj(L, LUA_TPROTO, sizeof(Proto), NULL, 0)->p;
f->k = NULL;
f->sizek = 0;
f->p = NULL;
f->sizep = 0;
f->code = NULL;
f->cache = NULL;
f->sizecode = 0;
f->lineinfo = NULL;
f->sizelineinfo = 0;
f->upvalues = NULL;
f->sizeupvalues = 0;
f->numparams = 0;
f->is_vararg = 0;
f->maxstacksize = 0;
f->locvars = NULL;
f->sizelocvars = 0;
f->linedefined = 0;
f->lastlinedefined = 0;
f->source = NULL;
return f;
}
void luaF_freeproto (lua_State *L, Proto *f) {
luaM_freearray(L, f->code, f->sizecode);
luaM_freearray(L, f->p, f->sizep);
luaM_freearray(L, f->k, f->sizek);
luaM_freearray(L, f->lineinfo, f->sizelineinfo);
luaM_freearray(L, f->locvars, f->sizelocvars);
luaM_freearray(L, f->upvalues, f->sizeupvalues);
luaM_free(L, f);
}
/*
** Look for n-th local variable at line `line' in function `func'.
** Returns NULL if not found.
*/
const char *luaF_getlocalname (const Proto *f, int local_number, int pc) {
int i;
for (i = 0; i<f->sizelocvars && f->locvars[i].startpc <= pc; i++) {
if (pc < f->locvars[i].endpc) { /* is variable active? */
local_number--;
if (local_number == 0)
return getstr(f->locvars[i].varname);
}
}
return NULL; /* not found */
}

1220
source/3rdparty/lua/src/lgc.c vendored Normal file

File diff suppressed because it is too large Load Diff

67
source/3rdparty/lua/src/linit.c vendored Normal file
View File

@ -0,0 +1,67 @@
/*
** $Id: linit.c,v 1.32.1.1 2013/04/12 18:48:47 roberto Exp $
** Initialization of libraries for lua.c and other clients
** See Copyright Notice in lua.h
*/
/*
** If you embed Lua in your program and need to open the standard
** libraries, call luaL_openlibs in your program. If you need a
** different set of libraries, copy this file to your project and edit
** it to suit your needs.
*/
#define linit_c
#define LUA_LIB
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
/*
** these libs are loaded by lua.c and are readily available to any Lua
** program
*/
static const luaL_Reg loadedlibs[] = {
{"_G", luaopen_base},
{LUA_LOADLIBNAME, luaopen_package},
{LUA_COLIBNAME, luaopen_coroutine},
{LUA_TABLIBNAME, luaopen_table},
{LUA_IOLIBNAME, luaopen_io},
{LUA_OSLIBNAME, luaopen_os},
{LUA_STRLIBNAME, luaopen_string},
{LUA_BITLIBNAME, luaopen_bit32},
{LUA_MATHLIBNAME, luaopen_math},
{LUA_DBLIBNAME, luaopen_debug},
{NULL, NULL}
};
/*
** these libs are preloaded and must be required before used
*/
static const luaL_Reg preloadedlibs[] = {
{NULL, NULL}
};
LUALIB_API void luaL_openlibs (lua_State *L) {
const luaL_Reg *lib;
/* call open functions from 'loadedlibs' and set results to global table */
for (lib = loadedlibs; lib->func; lib++) {
luaL_requiref(L, lib->name, lib->func, 1);
lua_pop(L, 1); /* remove lib */
}
/* add open functions from 'preloadedlibs' into 'package.preload' table */
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD");
for (lib = preloadedlibs; lib->func; lib++) {
lua_pushcfunction(L, lib->func);
lua_setfield(L, -2, lib->name);
}
lua_pop(L, 1); /* remove _PRELOAD table */
}

666
source/3rdparty/lua/src/liolib.c vendored Normal file
View File

@ -0,0 +1,666 @@
/*
** $Id: liolib.c,v 2.112.1.1 2013/04/12 18:48:47 roberto Exp $
** Standard I/O (and system) library
** See Copyright Notice in lua.h
*/
/*
** This definition must come before the inclusion of 'stdio.h'; it
** should not affect non-POSIX systems
*/
#if !defined(_FILE_OFFSET_BITS)
#define _LARGEFILE_SOURCE 1
#define _FILE_OFFSET_BITS 64
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define liolib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#if !defined(lua_checkmode)
/*
** Check whether 'mode' matches '[rwa]%+?b?'.
** Change this macro to accept other modes for 'fopen' besides
** the standard ones.
*/
#define lua_checkmode(mode) \
(*mode != '\0' && strchr("rwa", *(mode++)) != NULL && \
(*mode != '+' || ++mode) && /* skip if char is '+' */ \
(*mode != 'b' || ++mode) && /* skip if char is 'b' */ \
(*mode == '\0'))
#endif
/*
** {======================================================
** lua_popen spawns a new process connected to the current
** one through the file streams.
** =======================================================
*/
#if !defined(lua_popen) /* { */
#if defined(LUA_USE_POPEN) /* { */
#define lua_popen(L,c,m) ((void)L, fflush(NULL), popen(c,m))
#define lua_pclose(L,file) ((void)L, pclose(file))
#elif defined(LUA_WIN) /* }{ */
#define lua_popen(L,c,m) ((void)L, _popen(c,m))
#define lua_pclose(L,file) ((void)L, _pclose(file))
#else /* }{ */
#define lua_popen(L,c,m) ((void)((void)c, m), \
luaL_error(L, LUA_QL("popen") " not supported"), (FILE*)0)
#define lua_pclose(L,file) ((void)((void)L, file), -1)
#endif /* } */
#endif /* } */
/* }====================================================== */
/*
** {======================================================
** lua_fseek: configuration for longer offsets
** =======================================================
*/
#if !defined(lua_fseek) && !defined(LUA_ANSI) /* { */
#if defined(LUA_USE_POSIX) /* { */
#define l_fseek(f,o,w) fseeko(f,o,w)
#define l_ftell(f) ftello(f)
#define l_seeknum off_t
#elif defined(LUA_WIN) && !defined(_CRTIMP_TYPEINFO) \
&& defined(_MSC_VER) && (_MSC_VER >= 1400) /* }{ */
/* Windows (but not DDK) and Visual C++ 2005 or higher */
#define l_fseek(f,o,w) _fseeki64(f,o,w)
#define l_ftell(f) _ftelli64(f)
#define l_seeknum __int64
#endif /* } */
#endif /* } */
#if !defined(l_fseek) /* default definitions */
#define l_fseek(f,o,w) fseek(f,o,w)
#define l_ftell(f) ftell(f)
#define l_seeknum long
#endif
/* }====================================================== */
#define IO_PREFIX "_IO_"
#define IO_INPUT (IO_PREFIX "input")
#define IO_OUTPUT (IO_PREFIX "output")
typedef luaL_Stream LStream;
#define tolstream(L) ((LStream *)luaL_checkudata(L, 1, LUA_FILEHANDLE))
#define isclosed(p) ((p)->closef == NULL)
static int io_type (lua_State *L) {
LStream *p;
luaL_checkany(L, 1);
p = (LStream *)luaL_testudata(L, 1, LUA_FILEHANDLE);
if (p == NULL)
lua_pushnil(L); /* not a file */
else if (isclosed(p))
lua_pushliteral(L, "closed file");
else
lua_pushliteral(L, "file");
return 1;
}
static int f_tostring (lua_State *L) {
LStream *p = tolstream(L);
if (isclosed(p))
lua_pushliteral(L, "file (closed)");
else
lua_pushfstring(L, "file (%p)", p->f);
return 1;
}
static FILE *tofile (lua_State *L) {
LStream *p = tolstream(L);
if (isclosed(p))
luaL_error(L, "attempt to use a closed file");
lua_assert(p->f);
return p->f;
}
/*
** When creating file handles, always creates a `closed' file handle
** before opening the actual file; so, if there is a memory error, the
** file is not left opened.
*/
static LStream *newprefile (lua_State *L) {
LStream *p = (LStream *)lua_newuserdata(L, sizeof(LStream));
p->closef = NULL; /* mark file handle as 'closed' */
luaL_setmetatable(L, LUA_FILEHANDLE);
return p;
}
static int aux_close (lua_State *L) {
LStream *p = tolstream(L);
lua_CFunction cf = p->closef;
p->closef = NULL; /* mark stream as closed */
return (*cf)(L); /* close it */
}
static int io_close (lua_State *L) {
if (lua_isnone(L, 1)) /* no argument? */
lua_getfield(L, LUA_REGISTRYINDEX, IO_OUTPUT); /* use standard output */
tofile(L); /* make sure argument is an open stream */
return aux_close(L);
}
static int f_gc (lua_State *L) {
LStream *p = tolstream(L);
if (!isclosed(p) && p->f != NULL)
aux_close(L); /* ignore closed and incompletely open files */
return 0;
}
/*
** function to close regular files
*/
static int io_fclose (lua_State *L) {
LStream *p = tolstream(L);
int res = fclose(p->f);
return luaL_fileresult(L, (res == 0), NULL);
}
static LStream *newfile (lua_State *L) {
LStream *p = newprefile(L);
p->f = NULL;
p->closef = &io_fclose;
return p;
}
static void opencheck (lua_State *L, const char *fname, const char *mode) {
LStream *p = newfile(L);
p->f = fopen(fname, mode);
if (p->f == NULL)
luaL_error(L, "cannot open file " LUA_QS " (%s)", fname, strerror(errno));
}
static int io_open (lua_State *L) {
const char *filename = luaL_checkstring(L, 1);
const char *mode = luaL_optstring(L, 2, "r");
LStream *p = newfile(L);
const char *md = mode; /* to traverse/check mode */
luaL_argcheck(L, lua_checkmode(md), 2, "invalid mode");
p->f = fopen(filename, mode);
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
}
/*
** function to close 'popen' files
*/
static int io_pclose (lua_State *L) {
LStream *p = tolstream(L);
return luaL_execresult(L, lua_pclose(L, p->f));
}
static int io_popen (lua_State *L) {
const char *filename = luaL_checkstring(L, 1);
const char *mode = luaL_optstring(L, 2, "r");
LStream *p = newprefile(L);
p->f = lua_popen(L, filename, mode);
p->closef = &io_pclose;
return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1;
}
static int io_tmpfile (lua_State *L) {
LStream *p = newfile(L);
p->f = tmpfile();
return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1;
}
static FILE *getiofile (lua_State *L, const char *findex) {
LStream *p;
lua_getfield(L, LUA_REGISTRYINDEX, findex);
p = (LStream *)lua_touserdata(L, -1);
if (isclosed(p))
luaL_error(L, "standard %s file is closed", findex + strlen(IO_PREFIX));
return p->f;
}
static int g_iofile (lua_State *L, const char *f, const char *mode) {
if (!lua_isnoneornil(L, 1)) {
const char *filename = lua_tostring(L, 1);
if (filename)
opencheck(L, filename, mode);
else {
tofile(L); /* check that it's a valid file handle */
lua_pushvalue(L, 1);
}
lua_setfield(L, LUA_REGISTRYINDEX, f);
}
/* return current value */
lua_getfield(L, LUA_REGISTRYINDEX, f);
return 1;
}
static int io_input (lua_State *L) {
return g_iofile(L, IO_INPUT, "r");
}
static int io_output (lua_State *L) {
return g_iofile(L, IO_OUTPUT, "w");
}
static int io_readline (lua_State *L);
static void aux_lines (lua_State *L, int toclose) {
int i;
int n = lua_gettop(L) - 1; /* number of arguments to read */
/* ensure that arguments will fit here and into 'io_readline' stack */
luaL_argcheck(L, n <= LUA_MINSTACK - 3, LUA_MINSTACK - 3, "too many options");
lua_pushvalue(L, 1); /* file handle */
lua_pushinteger(L, n); /* number of arguments to read */
lua_pushboolean(L, toclose); /* close/not close file when finished */
for (i = 1; i <= n; i++) lua_pushvalue(L, i + 1); /* copy arguments */
lua_pushcclosure(L, io_readline, 3 + n);
}
static int f_lines (lua_State *L) {
tofile(L); /* check that it's a valid file handle */
aux_lines(L, 0);
return 1;
}
static int io_lines (lua_State *L) {
int toclose;
if (lua_isnone(L, 1)) lua_pushnil(L); /* at least one argument */
if (lua_isnil(L, 1)) { /* no file name? */
lua_getfield(L, LUA_REGISTRYINDEX, IO_INPUT); /* get default input */
lua_replace(L, 1); /* put it at index 1 */
tofile(L); /* check that it's a valid file handle */
toclose = 0; /* do not close it after iteration */
}
else { /* open a new file */
const char *filename = luaL_checkstring(L, 1);
opencheck(L, filename, "r");
lua_replace(L, 1); /* put file at index 1 */
toclose = 1; /* close it after iteration */
}
aux_lines(L, toclose);
return 1;
}
/*
** {======================================================
** READ
** =======================================================
*/
static int read_number (lua_State *L, FILE *f) {
lua_Number d;
if (fscanf(f, LUA_NUMBER_SCAN, &d) == 1) {
lua_pushnumber(L, d);
return 1;
}
else {
lua_pushnil(L); /* "result" to be removed */
return 0; /* read fails */
}
}
static int test_eof (lua_State *L, FILE *f) {
int c = getc(f);
ungetc(c, f);
lua_pushlstring(L, NULL, 0);
return (c != EOF);
}
static int read_line (lua_State *L, FILE *f, int chop) {
luaL_Buffer b;
luaL_buffinit(L, &b);
for (;;) {
size_t l;
char *p = luaL_prepbuffer(&b);
if (fgets(p, LUAL_BUFFERSIZE, f) == NULL) { /* eof? */
luaL_pushresult(&b); /* close buffer */
return (lua_rawlen(L, -1) > 0); /* check whether read something */
}
l = strlen(p);
if (l == 0 || p[l-1] != '\n')
luaL_addsize(&b, l);
else {
luaL_addsize(&b, l - chop); /* chop 'eol' if needed */
luaL_pushresult(&b); /* close buffer */
return 1; /* read at least an `eol' */
}
}
}
#define MAX_SIZE_T (~(size_t)0)
static void read_all (lua_State *L, FILE *f) {
size_t rlen = LUAL_BUFFERSIZE; /* how much to read in each cycle */
luaL_Buffer b;
luaL_buffinit(L, &b);
for (;;) {
char *p = luaL_prepbuffsize(&b, rlen);
size_t nr = fread(p, sizeof(char), rlen, f);
luaL_addsize(&b, nr);
if (nr < rlen) break; /* eof? */
else if (rlen <= (MAX_SIZE_T / 4)) /* avoid buffers too large */
rlen *= 2; /* double buffer size at each iteration */
}
luaL_pushresult(&b); /* close buffer */
}
static int read_chars (lua_State *L, FILE *f, size_t n) {
size_t nr; /* number of chars actually read */
char *p;
luaL_Buffer b;
luaL_buffinit(L, &b);
p = luaL_prepbuffsize(&b, n); /* prepare buffer to read whole block */
nr = fread(p, sizeof(char), n, f); /* try to read 'n' chars */
luaL_addsize(&b, nr);
luaL_pushresult(&b); /* close buffer */
return (nr > 0); /* true iff read something */
}
static int g_read (lua_State *L, FILE *f, int first) {
int nargs = lua_gettop(L) - 1;
int success;
int n;
clearerr(f);
if (nargs == 0) { /* no arguments? */
success = read_line(L, f, 1);
n = first+1; /* to return 1 result */
}
else { /* ensure stack space for all results and for auxlib's buffer */
luaL_checkstack(L, nargs+LUA_MINSTACK, "too many arguments");
success = 1;
for (n = first; nargs-- && success; n++) {
if (lua_type(L, n) == LUA_TNUMBER) {
size_t l = (size_t)lua_tointeger(L, n);
success = (l == 0) ? test_eof(L, f) : read_chars(L, f, l);
}
else {
const char *p = lua_tostring(L, n);
luaL_argcheck(L, p && p[0] == '*', n, "invalid option");
switch (p[1]) {
case 'n': /* number */
success = read_number(L, f);
break;
case 'l': /* line */
success = read_line(L, f, 1);
break;
case 'L': /* line with end-of-line */
success = read_line(L, f, 0);
break;
case 'a': /* file */
read_all(L, f); /* read entire file */
success = 1; /* always success */
break;
default:
return luaL_argerror(L, n, "invalid format");
}
}
}
}
if (ferror(f))
return luaL_fileresult(L, 0, NULL);
if (!success) {
lua_pop(L, 1); /* remove last result */
lua_pushnil(L); /* push nil instead */
}
return n - first;
}
static int io_read (lua_State *L) {
return g_read(L, getiofile(L, IO_INPUT), 1);
}
static int f_read (lua_State *L) {
return g_read(L, tofile(L), 2);
}
static int io_readline (lua_State *L) {
LStream *p = (LStream *)lua_touserdata(L, lua_upvalueindex(1));
int i;
int n = (int)lua_tointeger(L, lua_upvalueindex(2));
if (isclosed(p)) /* file is already closed? */
return luaL_error(L, "file is already closed");
lua_settop(L , 1);
for (i = 1; i <= n; i++) /* push arguments to 'g_read' */
lua_pushvalue(L, lua_upvalueindex(3 + i));
n = g_read(L, p->f, 2); /* 'n' is number of results */
lua_assert(n > 0); /* should return at least a nil */
if (!lua_isnil(L, -n)) /* read at least one value? */
return n; /* return them */
else { /* first result is nil: EOF or error */
if (n > 1) { /* is there error information? */
/* 2nd result is error message */
return luaL_error(L, "%s", lua_tostring(L, -n + 1));
}
if (lua_toboolean(L, lua_upvalueindex(3))) { /* generator created file? */
lua_settop(L, 0);
lua_pushvalue(L, lua_upvalueindex(1));
aux_close(L); /* close it */
}
return 0;
}
}
/* }====================================================== */
static int g_write (lua_State *L, FILE *f, int arg) {
int nargs = lua_gettop(L) - arg;
int status = 1;
for (; nargs--; arg++) {
if (lua_type(L, arg) == LUA_TNUMBER) {
/* optimization: could be done exactly as for strings */
status = status &&
fprintf(f, LUA_NUMBER_FMT, lua_tonumber(L, arg)) > 0;
}
else {
size_t l;
const char *s = luaL_checklstring(L, arg, &l);
status = status && (fwrite(s, sizeof(char), l, f) == l);
}
}
if (status) return 1; /* file handle already on stack top */
else return luaL_fileresult(L, status, NULL);
}
static int io_write (lua_State *L) {
return g_write(L, getiofile(L, IO_OUTPUT), 1);
}
static int f_write (lua_State *L) {
FILE *f = tofile(L);
lua_pushvalue(L, 1); /* push file at the stack top (to be returned) */
return g_write(L, f, 2);
}
static int f_seek (lua_State *L) {
static const int mode[] = {SEEK_SET, SEEK_CUR, SEEK_END};
static const char *const modenames[] = {"set", "cur", "end", NULL};
FILE *f = tofile(L);
int op = luaL_checkoption(L, 2, "cur", modenames);
lua_Number p3 = luaL_optnumber(L, 3, 0);
l_seeknum offset = (l_seeknum)p3;
luaL_argcheck(L, (lua_Number)offset == p3, 3,
"not an integer in proper range");
op = l_fseek(f, offset, mode[op]);
if (op)
return luaL_fileresult(L, 0, NULL); /* error */
else {
lua_pushnumber(L, (lua_Number)l_ftell(f));
return 1;
}
}
static int f_setvbuf (lua_State *L) {
static const int mode[] = {_IONBF, _IOFBF, _IOLBF};
static const char *const modenames[] = {"no", "full", "line", NULL};
FILE *f = tofile(L);
int op = luaL_checkoption(L, 2, NULL, modenames);
lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE);
int res = setvbuf(f, NULL, mode[op], sz);
return luaL_fileresult(L, res == 0, NULL);
}
static int io_flush (lua_State *L) {
return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL);
}
static int f_flush (lua_State *L) {
return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL);
}
/*
** functions for 'io' library
*/
static const luaL_Reg iolib[] = {
{"close", io_close},
{"flush", io_flush},
{"input", io_input},
{"lines", io_lines},
{"open", io_open},
{"output", io_output},
{"popen", io_popen},
{"read", io_read},
{"tmpfile", io_tmpfile},
{"type", io_type},
{"write", io_write},
{NULL, NULL}
};
/*
** methods for file handles
*/
static const luaL_Reg flib[] = {
{"close", io_close},
{"flush", f_flush},
{"lines", f_lines},
{"read", f_read},
{"seek", f_seek},
{"setvbuf", f_setvbuf},
{"write", f_write},
{"__gc", f_gc},
{"__tostring", f_tostring},
{NULL, NULL}
};
static void createmeta (lua_State *L) {
luaL_newmetatable(L, LUA_FILEHANDLE); /* create metatable for file handles */
lua_pushvalue(L, -1); /* push metatable */
lua_setfield(L, -2, "__index"); /* metatable.__index = metatable */
luaL_setfuncs(L, flib, 0); /* add file methods to new metatable */
lua_pop(L, 1); /* pop new metatable */
}
/*
** function to (not) close the standard files stdin, stdout, and stderr
*/
static int io_noclose (lua_State *L) {
LStream *p = tolstream(L);
p->closef = &io_noclose; /* keep file opened */
lua_pushnil(L);
lua_pushliteral(L, "cannot close standard file");
return 2;
}
static void createstdfile (lua_State *L, FILE *f, const char *k,
const char *fname) {
LStream *p = newprefile(L);
p->f = f;
p->closef = &io_noclose;
if (k != NULL) {
lua_pushvalue(L, -1);
lua_setfield(L, LUA_REGISTRYINDEX, k); /* add file to registry */
}
lua_setfield(L, -2, fname); /* add file to module */
}
LUAMOD_API int luaopen_io (lua_State *L) {
luaL_newlib(L, iolib); /* new module */
createmeta(L);
/* create (and set) default files */
createstdfile(L, stdin, IO_INPUT, "stdin");
createstdfile(L, stdout, IO_OUTPUT, "stdout");
createstdfile(L, stderr, NULL, "stderr");
return 1;
}

530
source/3rdparty/lua/src/llex.c vendored Normal file
View File

@ -0,0 +1,530 @@
/*
** $Id: llex.c,v 2.63.1.3 2015/02/09 17:56:34 roberto Exp $
** Lexical Analyzer
** See Copyright Notice in lua.h
*/
#include <locale.h>
#include <string.h>
#define llex_c
#define LUA_CORE
#include "lua.h"
#include "lctype.h"
#include "ldo.h"
#include "llex.h"
#include "lobject.h"
#include "lparser.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
#include "lzio.h"
#define next(ls) (ls->current = zgetc(ls->z))
#define currIsNewline(ls) (ls->current == '\n' || ls->current == '\r')
/* ORDER RESERVED */
static const char *const luaX_tokens [] = {
"and", "break", "do", "else", "elseif",
"end", "false", "for", "function", "goto", "if",
"in", "local", "nil", "not", "or", "repeat",
"return", "then", "true", "until", "while",
"..", "...", "==", ">=", "<=", "~=", "::", "<eof>",
"<number>", "<name>", "<string>"
};
#define save_and_next(ls) (save(ls, ls->current), next(ls))
static l_noret lexerror (LexState *ls, const char *msg, int token);
static void save (LexState *ls, int c) {
Mbuffer *b = ls->buff;
if (luaZ_bufflen(b) + 1 > luaZ_sizebuffer(b)) {
size_t newsize;
if (luaZ_sizebuffer(b) >= MAX_SIZET/2)
lexerror(ls, "lexical element too long", 0);
newsize = luaZ_sizebuffer(b) * 2;
luaZ_resizebuffer(ls->L, b, newsize);
}
b->buffer[luaZ_bufflen(b)++] = cast(char, c);
}
void luaX_init (lua_State *L) {
int i;
for (i=0; i<NUM_RESERVED; i++) {
TString *ts = luaS_new(L, luaX_tokens[i]);
luaS_fix(ts); /* reserved words are never collected */
ts->tsv.extra = cast_byte(i+1); /* reserved word */
}
}
const char *luaX_token2str (LexState *ls, int token) {
if (token < FIRST_RESERVED) { /* single-byte symbols? */
lua_assert(token == cast(unsigned char, token));
return (lisprint(token)) ? luaO_pushfstring(ls->L, LUA_QL("%c"), token) :
luaO_pushfstring(ls->L, "char(%d)", token);
}
else {
const char *s = luaX_tokens[token - FIRST_RESERVED];
if (token < TK_EOS) /* fixed format (symbols and reserved words)? */
return luaO_pushfstring(ls->L, LUA_QS, s);
else /* names, strings, and numerals */
return s;
}
}
static const char *txtToken (LexState *ls, int token) {
switch (token) {
case TK_NAME:
case TK_STRING:
case TK_NUMBER:
save(ls, '\0');
return luaO_pushfstring(ls->L, LUA_QS, luaZ_buffer(ls->buff));
default:
return luaX_token2str(ls, token);
}
}
static l_noret lexerror (LexState *ls, const char *msg, int token) {
char buff[LUA_IDSIZE];
luaO_chunkid(buff, getstr(ls->source), LUA_IDSIZE);
msg = luaO_pushfstring(ls->L, "%s:%d: %s", buff, ls->linenumber, msg);
if (token)
luaO_pushfstring(ls->L, "%s near %s", msg, txtToken(ls, token));
luaD_throw(ls->L, LUA_ERRSYNTAX);
}
l_noret luaX_syntaxerror (LexState *ls, const char *msg) {
lexerror(ls, msg, ls->t.token);
}
/*
** creates a new string and anchors it in function's table so that
** it will not be collected until the end of the function's compilation
** (by that time it should be anchored in function's prototype)
*/
TString *luaX_newstring (LexState *ls, const char *str, size_t l) {
lua_State *L = ls->L;
TValue *o; /* entry for `str' */
TString *ts = luaS_newlstr(L, str, l); /* create new string */
setsvalue2s(L, L->top++, ts); /* temporarily anchor it in stack */
o = luaH_set(L, ls->fs->h, L->top - 1);
if (ttisnil(o)) { /* not in use yet? (see 'addK') */
/* boolean value does not need GC barrier;
table has no metatable, so it does not need to invalidate cache */
setbvalue(o, 1); /* t[string] = true */
luaC_checkGC(L);
}
else { /* string already present */
ts = rawtsvalue(keyfromval(o)); /* re-use value previously stored */
}
L->top--; /* remove string from stack */
return ts;
}
/*
** increment line number and skips newline sequence (any of
** \n, \r, \n\r, or \r\n)
*/
static void inclinenumber (LexState *ls) {
int old = ls->current;
lua_assert(currIsNewline(ls));
next(ls); /* skip `\n' or `\r' */
if (currIsNewline(ls) && ls->current != old)
next(ls); /* skip `\n\r' or `\r\n' */
if (++ls->linenumber >= MAX_INT)
lexerror(ls, "chunk has too many lines", 0);
}
void luaX_setinput (lua_State *L, LexState *ls, ZIO *z, TString *source,
int firstchar) {
ls->decpoint = '.';
ls->L = L;
ls->current = firstchar;
ls->lookahead.token = TK_EOS; /* no look-ahead token */
ls->z = z;
ls->fs = NULL;
ls->linenumber = 1;
ls->lastline = 1;
ls->source = source;
ls->envn = luaS_new(L, LUA_ENV); /* create env name */
luaS_fix(ls->envn); /* never collect this name */
luaZ_resizebuffer(ls->L, ls->buff, LUA_MINBUFFER); /* initialize buffer */
}
/*
** =======================================================
** LEXICAL ANALYZER
** =======================================================
*/
static int check_next (LexState *ls, const char *set) {
if (ls->current == '\0' || !strchr(set, ls->current))
return 0;
save_and_next(ls);
return 1;
}
/*
** change all characters 'from' in buffer to 'to'
*/
static void buffreplace (LexState *ls, char from, char to) {
size_t n = luaZ_bufflen(ls->buff);
char *p = luaZ_buffer(ls->buff);
while (n--)
if (p[n] == from) p[n] = to;
}
#if !defined(getlocaledecpoint)
#define getlocaledecpoint() (localeconv()->decimal_point[0])
#endif
#define buff2d(b,e) luaO_str2d(luaZ_buffer(b), luaZ_bufflen(b) - 1, e)
/*
** in case of format error, try to change decimal point separator to
** the one defined in the current locale and check again
*/
static void trydecpoint (LexState *ls, SemInfo *seminfo) {
char old = ls->decpoint;
ls->decpoint = getlocaledecpoint();
buffreplace(ls, old, ls->decpoint); /* try new decimal separator */
if (!buff2d(ls->buff, &seminfo->r)) {
/* format error with correct decimal point: no more options */
buffreplace(ls, ls->decpoint, '.'); /* undo change (for error message) */
lexerror(ls, "malformed number", TK_NUMBER);
}
}
/* LUA_NUMBER */
/*
** this function is quite liberal in what it accepts, as 'luaO_str2d'
** will reject ill-formed numerals.
*/
static void read_numeral (LexState *ls, SemInfo *seminfo) {
const char *expo = "Ee";
int first = ls->current;
lua_assert(lisdigit(ls->current));
save_and_next(ls);
if (first == '0' && check_next(ls, "Xx")) /* hexadecimal? */
expo = "Pp";
for (;;) {
if (check_next(ls, expo)) /* exponent part? */
check_next(ls, "+-"); /* optional exponent sign */
if (lisxdigit(ls->current) || ls->current == '.')
save_and_next(ls);
else break;
}
save(ls, '\0');
buffreplace(ls, '.', ls->decpoint); /* follow locale for decimal point */
if (!buff2d(ls->buff, &seminfo->r)) /* format error? */
trydecpoint(ls, seminfo); /* try to update decimal point separator */
}
/*
** skip a sequence '[=*[' or ']=*]' and return its number of '='s or
** -1 if sequence is malformed
*/
static int skip_sep (LexState *ls) {
int count = 0;
int s = ls->current;
lua_assert(s == '[' || s == ']');
save_and_next(ls);
while (ls->current == '=') {
save_and_next(ls);
count++;
}
return (ls->current == s) ? count : (-count) - 1;
}
static void read_long_string (LexState *ls, SemInfo *seminfo, int sep) {
save_and_next(ls); /* skip 2nd `[' */
if (currIsNewline(ls)) /* string starts with a newline? */
inclinenumber(ls); /* skip it */
for (;;) {
switch (ls->current) {
case EOZ:
lexerror(ls, (seminfo) ? "unfinished long string" :
"unfinished long comment", TK_EOS);
break; /* to avoid warnings */
case ']': {
if (skip_sep(ls) == sep) {
save_and_next(ls); /* skip 2nd `]' */
goto endloop;
}
break;
}
case '\n': case '\r': {
save(ls, '\n');
inclinenumber(ls);
if (!seminfo) luaZ_resetbuffer(ls->buff); /* avoid wasting space */
break;
}
default: {
if (seminfo) save_and_next(ls);
else next(ls);
}
}
} endloop:
if (seminfo)
seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + (2 + sep),
luaZ_bufflen(ls->buff) - 2*(2 + sep));
}
static void escerror (LexState *ls, int *c, int n, const char *msg) {
int i;
luaZ_resetbuffer(ls->buff); /* prepare error message */
save(ls, '\\');
for (i = 0; i < n && c[i] != EOZ; i++)
save(ls, c[i]);
lexerror(ls, msg, TK_STRING);
}
static int readhexaesc (LexState *ls) {
int c[3], i; /* keep input for error message */
int r = 0; /* result accumulator */
c[0] = 'x'; /* for error message */
for (i = 1; i < 3; i++) { /* read two hexadecimal digits */
c[i] = next(ls);
if (!lisxdigit(c[i]))
escerror(ls, c, i + 1, "hexadecimal digit expected");
r = (r << 4) + luaO_hexavalue(c[i]);
}
return r;
}
static int readdecesc (LexState *ls) {
int c[3], i;
int r = 0; /* result accumulator */
for (i = 0; i < 3 && lisdigit(ls->current); i++) { /* read up to 3 digits */
c[i] = ls->current;
r = 10*r + c[i] - '0';
next(ls);
}
if (r > UCHAR_MAX)
escerror(ls, c, i, "decimal escape too large");
return r;
}
static void read_string (LexState *ls, int del, SemInfo *seminfo) {
save_and_next(ls); /* keep delimiter (for error messages) */
while (ls->current != del) {
switch (ls->current) {
case EOZ:
lexerror(ls, "unfinished string", TK_EOS);
break; /* to avoid warnings */
case '\n':
case '\r':
lexerror(ls, "unfinished string", TK_STRING);
break; /* to avoid warnings */
case '\\': { /* escape sequences */
int c; /* final character to be saved */
next(ls); /* do not save the `\' */
switch (ls->current) {
case 'a': c = '\a'; goto read_save;
case 'b': c = '\b'; goto read_save;
case 'f': c = '\f'; goto read_save;
case 'n': c = '\n'; goto read_save;
case 'r': c = '\r'; goto read_save;
case 't': c = '\t'; goto read_save;
case 'v': c = '\v'; goto read_save;
case 'x': c = readhexaesc(ls); goto read_save;
case '\n': case '\r':
inclinenumber(ls); c = '\n'; goto only_save;
case '\\': case '\"': case '\'':
c = ls->current; goto read_save;
case EOZ: goto no_save; /* will raise an error next loop */
case 'z': { /* zap following span of spaces */
next(ls); /* skip the 'z' */
while (lisspace(ls->current)) {
if (currIsNewline(ls)) inclinenumber(ls);
else next(ls);
}
goto no_save;
}
default: {
if (!lisdigit(ls->current))
escerror(ls, &ls->current, 1, "invalid escape sequence");
/* digital escape \ddd */
c = readdecesc(ls);
goto only_save;
}
}
read_save: next(ls); /* read next character */
only_save: save(ls, c); /* save 'c' */
no_save: break;
}
default:
save_and_next(ls);
}
}
save_and_next(ls); /* skip delimiter */
seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff) + 1,
luaZ_bufflen(ls->buff) - 2);
}
static int llex (LexState *ls, SemInfo *seminfo) {
luaZ_resetbuffer(ls->buff);
for (;;) {
switch (ls->current) {
case '\n': case '\r': { /* line breaks */
inclinenumber(ls);
break;
}
case ' ': case '\f': case '\t': case '\v': { /* spaces */
next(ls);
break;
}
case '-': { /* '-' or '--' (comment) */
next(ls);
if (ls->current != '-') return '-';
/* else is a comment */
next(ls);
if (ls->current == '[') { /* long comment? */
int sep = skip_sep(ls);
luaZ_resetbuffer(ls->buff); /* `skip_sep' may dirty the buffer */
if (sep >= 0) {
read_long_string(ls, NULL, sep); /* skip long comment */
luaZ_resetbuffer(ls->buff); /* previous call may dirty the buff. */
break;
}
}
/* else short comment */
while (!currIsNewline(ls) && ls->current != EOZ)
next(ls); /* skip until end of line (or end of file) */
break;
}
case '[': { /* long string or simply '[' */
int sep = skip_sep(ls);
if (sep >= 0) {
read_long_string(ls, seminfo, sep);
return TK_STRING;
}
else if (sep == -1) return '[';
else lexerror(ls, "invalid long string delimiter", TK_STRING);
}
case '=': {
next(ls);
if (ls->current != '=') return '=';
else { next(ls); return TK_EQ; }
}
case '<': {
next(ls);
if (ls->current != '=') return '<';
else { next(ls); return TK_LE; }
}
case '>': {
next(ls);
if (ls->current != '=') return '>';
else { next(ls); return TK_GE; }
}
case '~': {
next(ls);
if (ls->current != '=') return '~';
else { next(ls); return TK_NE; }
}
case ':': {
next(ls);
if (ls->current != ':') return ':';
else { next(ls); return TK_DBCOLON; }
}
case '"': case '\'': { /* short literal strings */
read_string(ls, ls->current, seminfo);
return TK_STRING;
}
case '.': { /* '.', '..', '...', or number */
save_and_next(ls);
if (check_next(ls, ".")) {
if (check_next(ls, "."))
return TK_DOTS; /* '...' */
else return TK_CONCAT; /* '..' */
}
else if (!lisdigit(ls->current)) return '.';
/* else go through */
}
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': {
read_numeral(ls, seminfo);
return TK_NUMBER;
}
case EOZ: {
return TK_EOS;
}
default: {
if (lislalpha(ls->current)) { /* identifier or reserved word? */
TString *ts;
do {
save_and_next(ls);
} while (lislalnum(ls->current));
ts = luaX_newstring(ls, luaZ_buffer(ls->buff),
luaZ_bufflen(ls->buff));
seminfo->ts = ts;
if (isreserved(ts)) /* reserved word? */
return ts->tsv.extra - 1 + FIRST_RESERVED;
else {
return TK_NAME;
}
}
else { /* single-char tokens (+ - / ...) */
int c = ls->current;
next(ls);
return c;
}
}
}
}
}
void luaX_next (LexState *ls) {
ls->lastline = ls->linenumber;
if (ls->lookahead.token != TK_EOS) { /* is there a look-ahead token? */
ls->t = ls->lookahead; /* use this one */
ls->lookahead.token = TK_EOS; /* and discharge it */
}
else
ls->t.token = llex(ls, &ls->t.seminfo); /* read next token */
}
int luaX_lookahead (LexState *ls) {
lua_assert(ls->lookahead.token == TK_EOS);
ls->lookahead.token = llex(ls, &ls->lookahead.seminfo);
return ls->lookahead.token;
}

279
source/3rdparty/lua/src/lmathlib.c vendored Normal file
View File

@ -0,0 +1,279 @@
/*
** $Id: lmathlib.c,v 1.83.1.1 2013/04/12 18:48:47 roberto Exp $
** Standard mathematical library
** See Copyright Notice in lua.h
*/
#include <stdlib.h>
#include <math.h>
#define lmathlib_c
#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"
#include "lualib.h"
#undef PI
#define PI ((lua_Number)(3.1415926535897932384626433832795))
#define RADIANS_PER_DEGREE ((lua_Number)(PI/180.0))
static int math_abs (lua_State *L) {
lua_pushnumber(L, l_mathop(fabs)(luaL_checknumber(L, 1)));
return 1;
}
static int math_sin (lua_State *L) {
lua_pushnumber(L, l_mathop(sin)(luaL_checknumber(L, 1)));
return 1;
}
static int math_sinh (lua_State *L) {
lua_pushnumber(L, l_mathop(sinh)(luaL_checknumber(L, 1)));
return 1;
}
static int math_cos (lua_State *L) {
lua_pushnumber(L, l_mathop(cos)(luaL_checknumber(L, 1)));
return 1;
}
static int math_cosh (lua_State *L) {
lua_pushnumber(L, l_mathop(cosh)(luaL_checknumber(L, 1)));
return 1;
}
static int math_tan (lua_State *L) {
lua_pushnumber(L, l_mathop(tan)(luaL_checknumber(L, 1)));
return 1;
}
static int math_tanh (lua_State *L) {
lua_pushnumber(L, l_mathop(tanh)(luaL_checknumber(L, 1)));
return 1;
}
static int math_asin (lua_State *L) {
lua_pushnumber(L, l_mathop(asin)(luaL_checknumber(L, 1)));
return 1;
}
static int math_acos (lua_State *L) {
lua_pushnumber(L, l_mathop(acos)(luaL_checknumber(L, 1)));
return 1;
}
static int math_atan (lua_State *L) {
lua_pushnumber(L, l_mathop(atan)(luaL_checknumber(L, 1)));
return 1;
}
static int math_atan2 (lua_State *L) {
lua_pushnumber(L, l_mathop(atan2)(luaL_checknumber(L, 1),
luaL_checknumber(L, 2)));
return 1;
}
static int math_ceil (lua_State *L) {
lua_pushnumber(L, l_mathop(ceil)(luaL_checknumber(L, 1)));
return 1;
}
static int math_floor (lua_State *L) {
lua_pushnumber(L, l_mathop(floor)(luaL_checknumber(L, 1)));
return 1;
}
static int math_fmod (lua_State *L) {
lua_pushnumber(L, l_mathop(fmod)(luaL_checknumber(L, 1),
luaL_checknumber(L, 2)));
return 1;
}
static int math_modf (lua_State *L) {
lua_Number ip;
lua_Number fp = l_mathop(modf)(luaL_checknumber(L, 1), &ip);
lua_pushnumber(L, ip);
lua_pushnumber(L, fp);
return 2;
}
static int math_sqrt (lua_State *L) {
lua_pushnumber(L, l_mathop(sqrt)(luaL_checknumber(L, 1)));
return 1;
}
static int math_pow (lua_State *L) {
lua_Number x = luaL_checknumber(L, 1);
lua_Number y = luaL_checknumber(L, 2);
lua_pushnumber(L, l_mathop(pow)(x, y));
return 1;
}
static int math_log (lua_State *L) {
lua_Number x = luaL_checknumber(L, 1);
lua_Number res;
if (lua_isnoneornil(L, 2))
res = l_mathop(log)(x);
else {
lua_Number base = luaL_checknumber(L, 2);
if (base == (lua_Number)10.0) res = l_mathop(log10)(x);
else res = l_mathop(log)(x)/l_mathop(log)(base);
}
lua_pushnumber(L, res);
return 1;
}
#if defined(LUA_COMPAT_LOG10)
static int math_log10 (lua_State *L) {
lua_pushnumber(L, l_mathop(log10)(luaL_checknumber(L, 1)));
return 1;
}
#endif
static int math_exp (lua_State *L) {
lua_pushnumber(L, l_mathop(exp)(luaL_checknumber(L, 1)));
return 1;
}
static int math_deg (lua_State *L) {
lua_pushnumber(L, luaL_checknumber(L, 1)/RADIANS_PER_DEGREE);
return 1;
}
static int math_rad (lua_State *L) {
lua_pushnumber(L, luaL_checknumber(L, 1)*RADIANS_PER_DEGREE);
return 1;
}
static int math_frexp (lua_State *L) {
int e;
lua_pushnumber(L, l_mathop(frexp)(luaL_checknumber(L, 1), &e));
lua_pushinteger(L, e);
return 2;
}
static int math_ldexp (lua_State *L) {
lua_Number x = luaL_checknumber(L, 1);
int ep = luaL_checkint(L, 2);
lua_pushnumber(L, l_mathop(ldexp)(x, ep));
return 1;
}
static int math_min (lua_State *L) {
int n = lua_gettop(L); /* number of arguments */
lua_Number dmin = luaL_checknumber(L, 1);
int i;
for (i=2; i<=n; i++) {
lua_Number d = luaL_checknumber(L, i);
if (d < dmin)
dmin = d;
}
lua_pushnumber(L, dmin);
return 1;
}
static int math_max (lua_State *L) {
int n = lua_gettop(L); /* number of arguments */
lua_Number dmax = luaL_checknumber(L, 1);
int i;
for (i=2; i<=n; i++) {
lua_Number d = luaL_checknumber(L, i);
if (d > dmax)
dmax = d;
}
lua_pushnumber(L, dmax);
return 1;
}
static int math_random (lua_State *L) {
/* the `%' avoids the (rare) case of r==1, and is needed also because on
some systems (SunOS!) `rand()' may return a value larger than RAND_MAX */
lua_Number r = (lua_Number)(rand()%RAND_MAX) / (lua_Number)RAND_MAX;
switch (lua_gettop(L)) { /* check number of arguments */
case 0: { /* no arguments */
lua_pushnumber(L, r); /* Number between 0 and 1 */
break;
}
case 1: { /* only upper limit */
lua_Number u = luaL_checknumber(L, 1);
luaL_argcheck(L, (lua_Number)1.0 <= u, 1, "interval is empty");
lua_pushnumber(L, l_mathop(floor)(r*u) + (lua_Number)(1.0)); /* [1, u] */
break;
}
case 2: { /* lower and upper limits */
lua_Number l = luaL_checknumber(L, 1);
lua_Number u = luaL_checknumber(L, 2);
luaL_argcheck(L, l <= u, 2, "interval is empty");
lua_pushnumber(L, l_mathop(floor)(r*(u-l+1)) + l); /* [l, u] */
break;
}
default: return luaL_error(L, "wrong number of arguments");
}
return 1;
}
static int math_randomseed (lua_State *L) {
srand(luaL_checkunsigned(L, 1));
(void)rand(); /* discard first value to avoid undesirable correlations */
return 0;
}
static const luaL_Reg mathlib[] = {
{"abs", math_abs},
{"acos", math_acos},
{"asin", math_asin},
{"atan2", math_atan2},
{"atan", math_atan},
{"ceil", math_ceil},
{"cosh", math_cosh},
{"cos", math_cos},
{"deg", math_deg},
{"exp", math_exp},
{"floor", math_floor},
{"fmod", math_fmod},
{"frexp", math_frexp},
{"ldexp", math_ldexp},
#if defined(LUA_COMPAT_LOG10)
{"log10", math_log10},
#endif
{"log", math_log},
{"max", math_max},
{"min", math_min},
{"modf", math_modf},
{"pow", math_pow},
{"rad", math_rad},
{"random", math_random},
{"randomseed", math_randomseed},
{"sinh", math_sinh},
{"sin", math_sin},
{"sqrt", math_sqrt},
{"tanh", math_tanh},
{"tan", math_tan},
{NULL, NULL}
};
/*
** Open math library
*/
LUAMOD_API int luaopen_math (lua_State *L) {
luaL_newlib(L, mathlib);
lua_pushnumber(L, PI);
lua_setfield(L, -2, "pi");
lua_pushnumber(L, HUGE_VAL);
lua_setfield(L, -2, "huge");
return 1;
}

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