First
This commit is contained in:
@@ -0,0 +1,102 @@
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Copyright (C) Electronic Arts Inc. All rights reserved.
|
||||
#-------------------------------------------------------------------------------------------
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# CMake info
|
||||
#-------------------------------------------------------------------------------------------
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
project(EASTLTest CXX)
|
||||
include(CTest)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Defines
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
|
||||
add_definitions(-DEASTL_OPENSOURCE=1)
|
||||
add_definitions(-D_CHAR16T)
|
||||
add_definitions(-DEASTL_THREAD_SUPPORT_AVAILABLE=0)
|
||||
if (EASTL_STD_ITERATOR_CATEGORY_ENABLED)
|
||||
add_definitions(-DEASTL_STD_ITERATOR_CATEGORY_ENABLED=1)
|
||||
endif()
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Compiler Flags
|
||||
#-------------------------------------------------------------------------------------------
|
||||
set (CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/../scripts/CMake")
|
||||
include(CommonCppFlags)
|
||||
|
||||
if (MSVC)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP")
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-pointer-bool-conversion -Wno-unknown-warning-option")
|
||||
endif()
|
||||
|
||||
# Parts of the test suite fail to compile if char8_t is enabled, so we
|
||||
# disable it and only enable for specific source files later on.
|
||||
if (EASTL_NO_CHAR8T_FLAG)
|
||||
add_compile_options(${EASTL_NO_CHAR8T_FLAG})
|
||||
endif()
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Source files
|
||||
#-------------------------------------------------------------------------------------------
|
||||
file(GLOB EASTLTEST_SOURCES "source/*.cpp" "source/*.inl" "source/*.h")
|
||||
set(SOURCES ${EASTLTEST_SOURCES})
|
||||
|
||||
# Compile a subset of tests with explicit char8_t support if available.
|
||||
if (EASTL_CHAR8T_FLAG)
|
||||
message(STATUS "Building with char8_t support in tests.")
|
||||
set(EASTLTEST_CHAR8T_SOURCES "source/TestString.cpp" "source/TestStringView.cpp")
|
||||
|
||||
set_source_files_properties(${EASTLTEST_CHAR8T_SOURCES} PROPERTIES
|
||||
COMPILE_FLAGS ${EASTL_CHAR8T_FLAG}
|
||||
COMPILE_DEFINITIONS "EASTL_EXPECT_CHAR8T_SUPPORT")
|
||||
endif()
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Executable definition
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_executable(EASTLTest ${SOURCES})
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Include directories
|
||||
#-------------------------------------------------------------------------------------------
|
||||
target_include_directories(EASTLTest PUBLIC include)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Dependencies
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_subdirectory(packages/EABase)
|
||||
add_subdirectory(packages/EAAssert)
|
||||
add_subdirectory(packages/EAStdC)
|
||||
add_subdirectory(packages/EAMain)
|
||||
add_subdirectory(packages/EATest)
|
||||
add_subdirectory(packages/EAThread)
|
||||
|
||||
target_link_libraries(EASTLTest EABase)
|
||||
target_link_libraries(EASTLTest EAAssert)
|
||||
target_link_libraries(EASTLTest EAMain)
|
||||
target_link_libraries(EASTLTest EASTL)
|
||||
target_link_libraries(EASTLTest EAStdC)
|
||||
target_link_libraries(EASTLTest EATest)
|
||||
target_link_libraries(EASTLTest EAThread)
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if((NOT APPLE) AND (NOT WIN32))
|
||||
target_link_libraries(EASTLTest ${EASTLTest_Libraries} Threads::Threads rt)
|
||||
else()
|
||||
target_link_libraries(EASTLTest ${EASTLTest_Libraries} Threads::Threads)
|
||||
endif()
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Run Unit tests and verify the results.
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_test(EASTLTestRuns EASTLTest)
|
||||
set_tests_properties (EASTLTestRuns PROPERTIES PASS_REGULAR_EXPRESSION "RETURNCODE=0")
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
tags
|
||||
.p4config
|
||||
build.bat
|
||||
/build/
|
||||
@@ -0,0 +1,18 @@
|
||||
[submodule "test/packages/EAMain"]
|
||||
path = test/packages/EAMain
|
||||
url = git@github.com:electronicarts/EAMain.git
|
||||
[submodule "test/packages/EATest"]
|
||||
path = test/packages/EATest
|
||||
url = git@github.com:electronicarts/EATest.git
|
||||
[submodule "test/packages/EAStdC"]
|
||||
path = test/packages/EAStdC
|
||||
url = git@github.com:electronicarts/EAStdC.git
|
||||
[submodule "test/packages/EAThread"]
|
||||
path = test/packages/EAThread
|
||||
url = git@github.com:electronicarts/EAThread.git
|
||||
[submodule "test/packages/EASTL"]
|
||||
path = test/packages/EASTL
|
||||
url = git@github.com:electronicarts/EASTL.git
|
||||
[submodule "test/packages/EABase"]
|
||||
path = test/packages/EABase
|
||||
url = git@github.com:electronicarts/EABase.git
|
||||
@@ -0,0 +1,71 @@
|
||||
language: cpp
|
||||
|
||||
cache:
|
||||
- ccache: true
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
- windows
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
- msvc
|
||||
|
||||
env:
|
||||
- EA_CONFIG=Debug
|
||||
- EA_CONFIG=Release
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- george-edison55-precise-backports
|
||||
- llvm-toolchain-trusty-7
|
||||
packages:
|
||||
- cmake
|
||||
- cmake-data
|
||||
- g++-7
|
||||
- clang-7
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- os: osx
|
||||
compiler: gcc
|
||||
- os: osx
|
||||
compiler: msvc
|
||||
- os: linux
|
||||
compiler: msvc
|
||||
- os: windows
|
||||
compiler: clang
|
||||
- os: windows
|
||||
compiler: gcc
|
||||
|
||||
# Handle git submodules yourself
|
||||
git:
|
||||
submodules: false
|
||||
|
||||
# Use sed to replace the SSH URL with the public URL, then initialize submodules
|
||||
before_install:
|
||||
- sed --version >/dev/null 2>&1 && sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules || sed -i "" 's/git@github.com:/https:\/\/github.com\//' .gitmodules
|
||||
- git submodule update --init
|
||||
|
||||
install:
|
||||
- if [[ "$CXX" == "g++" ]]; then export CC="gcc-7" ;fi
|
||||
- if [[ "$CXX" == "g++" ]]; then export CXX="g++-7" ;fi
|
||||
- if [[ "$CXX" == "clang++" && "${TRAVIS_OS_NAME}" != "osx" ]]; then export CC="clang-7" ;fi
|
||||
- if [[ "$CXX" == "clang++" && "${TRAVIS_OS_NAME}" != "osx" ]]; then export CXX="clang++-7" ;fi
|
||||
|
||||
# Universal Setup
|
||||
before_script:
|
||||
- mkdir build_$EA_CONFIG
|
||||
- cd build_$EA_CONFIG
|
||||
- cmake .. -DEAASSERT_BUILD_TESTS:BOOL=ON
|
||||
- cmake --build . --config $EA_CONFIG
|
||||
|
||||
script:
|
||||
# Run Tests
|
||||
- cd $TRAVIS_BUILD_DIR/build_$EA_CONFIG/test
|
||||
- ctest -C $EA_CONFIG -V || exit 1
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Copyright (C) Electronic Arts Inc. All rights reserved.
|
||||
#-------------------------------------------------------------------------------------------
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
project(EAAssert CXX)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Options
|
||||
#-------------------------------------------------------------------------------------------
|
||||
option(EAASSERT_BUILD_TESTS "Enable generation of build files for tests" OFF)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Compiler Flags
|
||||
#-------------------------------------------------------------------------------------------
|
||||
set (CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/test/packages/EASTL/scripts/CMake")
|
||||
include(CommonCppFlags)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Library definition
|
||||
#-------------------------------------------------------------------------------------------
|
||||
file(GLOB EAASSERT_SOURCES "source/*.cpp")
|
||||
add_library(EAAssert ${EAASSERT_SOURCES})
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Package Tests
|
||||
#-------------------------------------------------------------------------------------------
|
||||
if(EAASSERT_BUILD_TESTS)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Defines
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_definitions(-D_CHAR16T)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Export Include Directories
|
||||
#-------------------------------------------------------------------------------------------
|
||||
target_include_directories(EAAssert PUBLIC include)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Package Dependencies
|
||||
#-------------------------------------------------------------------------------------------
|
||||
target_link_libraries(EAAssert EABase)
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
## Contributing
|
||||
|
||||
Before you can contribute, EA must have a Contributor License Agreement (CLA) on file that has been signed by each contributor.
|
||||
You can sign here: [Go to CLA](https://electronicarts.na1.echosign.com/public/esignWidget?wid=CBFCIBAA3AAABLblqZhByHRvZqmltGtliuExmuV-WNzlaJGPhbSRg2ufuPsM3P0QmILZjLpkGslg24-UJtek*)
|
||||
|
||||
### Pull Request Policy
|
||||
|
||||
All code contributions are submitted as [Github pull requests](https://help.github.com/articles/using-pull-requests/). All pull requests will be reviewed by a maintainer according to the guidelines found in the next section.
|
||||
|
||||
Your pull request should:
|
||||
|
||||
* merge cleanly
|
||||
* come with tests
|
||||
* tests should be minimal and stable
|
||||
* fail before your fix is applied
|
||||
* pass the test suite
|
||||
* code formatting is encoded in clang format
|
||||
* limit using clang format on new code
|
||||
* do not deviate from style already established in the files
|
||||
|
||||
|
||||
### Running the Unit Tests
|
||||
|
||||
EAAssert uses CMake as its build system.
|
||||
|
||||
* Create and navigate to "your_build_folder":
|
||||
* mkdir your_build_folder && cd your_build_folder
|
||||
* Generate build scripts:
|
||||
* cmake source_folder -DEAASSERT_BUILD_TESTS:BOOL=ON
|
||||
* Build unit tests for "your_config":
|
||||
* cmake --build . --config your_config
|
||||
* Run the unit tests for "your_config" from the test folder:
|
||||
* cd test && ctest -C your_config
|
||||
|
||||
|
||||
Here is an example batch file.
|
||||
```batch
|
||||
set build_folder=out
|
||||
mkdir %build_folder%
|
||||
pushd %build_folder%
|
||||
call cmake .. -DEAASSERT_BUILD_TESTS:BOOL=ON
|
||||
call cmake --build . --config Release
|
||||
call cmake --build . --config Debug
|
||||
call cmake --build . --config RelWithDebInfo
|
||||
call cmake --build . --config MinSizeRel
|
||||
pushd test
|
||||
call ctest -C Release
|
||||
call ctest -C Debug
|
||||
call ctest -C RelWithDebInfo
|
||||
call ctest -C MinSizeRel
|
||||
popd
|
||||
popd
|
||||
```
|
||||
|
||||
Here is an example bash file
|
||||
```bash
|
||||
build_folder=out
|
||||
mkdir $build_folder
|
||||
pushd $build_folder
|
||||
cmake .. -DEAASSERT_BUILD_TESTS:BOOL=ON
|
||||
cmake --build . --config Release
|
||||
cmake --build . --config Debug
|
||||
cmake --build . --config RelWithDebInfo
|
||||
cmake --build . --config MinSizeRel
|
||||
pushd test
|
||||
ctest -C Release
|
||||
ctest -C Debug
|
||||
ctest -C RelWithDebInfo
|
||||
ctest -C MinSizeRel
|
||||
popd
|
||||
popd
|
||||
```
|
||||
@@ -0,0 +1,2 @@
|
||||
(C) Electronic Arts. All rights reserved.
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright (C) 2017 Electronic Arts Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of
|
||||
its contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
@@ -0,0 +1,25 @@
|
||||
# EAAssert
|
||||
|
||||
[](https://travis-ci.org/electronicarts/EAAssert)
|
||||
|
||||
EAAssert is a simple and lightweight assert technology.
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
Please see [Introduction](https://rawgit.com/electronicarts/EAAssert/master/doc/eaassert.html).
|
||||
|
||||
|
||||
## Compiling sources
|
||||
|
||||
Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on compiling and testing the source.
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
Roberto Parolin is the current EAAssert owner within EA and is responsible for the open source repository.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Modified BSD License (3-Clause BSD license) see the file LICENSE in the project root.
|
||||
@@ -0,0 +1,217 @@
|
||||
<html>
|
||||
<title>EA Assert</title>
|
||||
<body>
|
||||
<font face="tahoma">
|
||||
<h1>EA Assert</h1>
|
||||
<hr>
|
||||
A simple lightweight package. Use...
|
||||
<font color="#0000FF"><pre>
|
||||
#include "EAAssert/eaassert.h"
|
||||
</pre></font>
|
||||
And get the following macros...
|
||||
<ul>
|
||||
<li>
|
||||
<code><font color="#FF00EE">EA_ASSERT(expr)</font></code> where <code><font color="#000099">
|
||||
expr</font></code> is an expression that evaluates to a boolean. For
|
||||
example... <font color="#000099">
|
||||
<pre> EA_ASSERT(3 != 5);</pre>
|
||||
</font>
|
||||
<li>
|
||||
<code><font color="#FF00EE">EA_ASSERT_MSG(expr, msg)</font></code> where <code><font color="#000099">
|
||||
msg</font></code> is an string (i.e., a <code><font color="#000099">char*</font></code>).
|
||||
For example... <font color="#000099">
|
||||
<pre> EA_ASSERT_MSG(3 != 5, "mathematics is flawed");</pre>
|
||||
</font>
|
||||
<li>
|
||||
<code><font color="#FF00EE">EA_ASSERT_FORMATTED(expr, fmt)</font></code> where <code>
|
||||
<font color="#000099">fmt</font></code> is a parentheses wrapped tuple of
|
||||
which the first parameter is a string (i.e., a <code><font color="#000099">char*</font></code>)
|
||||
and the rest are <code><font color="#000099">printf</font></code> style
|
||||
parameters. For example... <font color="#000099">
|
||||
<pre> EA_ASSERT_FORMATTED(3 != 5, ("The answer is: %d", 42));</pre>
|
||||
</font>
|
||||
<li>
|
||||
<code><font color="#FF00EE">EA_FAIL()</font></code> similar to <code><font color="#000099">
|
||||
EA_ASSERT(false)</font></code>
|
||||
but avoids warning of constant conditional expression.
|
||||
<li>
|
||||
<code><font color="#FF00EE">EA_FAIL_MSG(msg)</font></code> similar to <code><font color="#000099">
|
||||
EA_ASSERT_MSG(false, msg);</font></code>
|
||||
<li>
|
||||
<code><font color="#FF00EE">EA_FAIL_FORMATTED(fmt)</font></code> similar to <code><font color="#000099">
|
||||
EA_ASSERT_FORMATTED(false, fmt);</font></code></li>
|
||||
</ul>
|
||||
For compatibility reasons (with existing EATrace practice), there are synonyms for <font color="#FF00EE">EA_ASSERT_MSG</font>, defined as <font color="#FF00EE">EA_ASSERT_MESSAGE</font> and <font color="#FF00EE">EA_ASSERT_M</font>.
|
||||
<hr>
|
||||
<h2>Enabling and Disabling</h2>
|
||||
Whether or not <code><font color="#000099">EA_ASSERT</font></code> is enabled hinges on the following logic...
|
||||
<font color="#000099">
|
||||
<pre>
|
||||
#ifdef EA_DEBUG
|
||||
#define EA_ASSERT_ENABLED
|
||||
#endif
|
||||
|
||||
#ifndef EA_ASSERT
|
||||
#if EA_ASSERT_ENABLED
|
||||
#define EA_ASSERT(expr) ...definition of EA_ASSERT...
|
||||
#else
|
||||
#define EA_ASSERT(expr) ((void)0)
|
||||
#endif
|
||||
#endif
|
||||
</pre>
|
||||
</font>
|
||||
<hr />
|
||||
<h2>Design Considerations</h2>
|
||||
Below are some thoughts that went into the creation of this package...
|
||||
<ul>
|
||||
<li>Aim to be lightweight and simple.</li>
|
||||
<li>Become the single most used ubiquitous assert technology, along EA Base lines.</li>
|
||||
<li>Have minimal dependencies; e.g. EA Base only.</li>
|
||||
<li>Ability for users to override functionality.</li>
|
||||
<li>Ability for users to redirect assertions to their application's given system.</li>
|
||||
<li>Ability for users to extend the system.</li>
|
||||
<li>Enable users to rebuild other technology but have it use their assert system.</li>
|
||||
<li>Make it easy to supply your own assert-failure callback function, but...
|
||||
<ul>
|
||||
<li>...don't enforce a link-time definition (i.e., provide a default)</li>
|
||||
<li>...don't require a global #define.</li>
|
||||
</ul>
|
||||
The result is that we require a CPP file (and resulting library) where we can declare and store a function pointer that points to the current assert handler.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2>Integration</h2>
|
||||
<p>To use <code><font color="#000099">EA_ASSERT</font></code> in your own code you just include the header and use it.</p>
|
||||
<p>To overwrite the default handler for assert failure, you need to implement the following function <font color="#000099">
|
||||
<pre>
|
||||
bool EAAssertFailure(
|
||||
|
||||
const char* expr, <font color=#009900>// Stringized version of the assert expression.</font>
|
||||
const char* filename, <font color=#009900>// Name of the file in which the assert occured.</font>
|
||||
int line, <font color=#009900>// Line number on which the assert occured.</font>
|
||||
const char* function, <font color=#009900>// Name of the function the assert occured in.</font>
|
||||
const char* msg, <font color=#009900>// Optional descriptive message.</font>
|
||||
va_list args <font color=#009900>// Variable argument list (printf style) in case msg contains formatters.</font>
|
||||
|
||||
);
|
||||
</pre>
|
||||
</font>The return value of this function should be <code><font color="#000099">true</font></code>
|
||||
if you want the failed assert to break into the debugger and <code><font color="#000099">
|
||||
false</font></code>
|
||||
if you want to continue running past the assert.
|
||||
<p>To enable the use of this function, use:<font color="#000099">
|
||||
<pre>
|
||||
EA::Assert::SetFailureCallback(&yourCallback);
|
||||
</pre>
|
||||
</font>
|
||||
</p>
|
||||
<P>The simplest possible implementation of this function (which happens to be the default) just returns <code><font color="#000099">true</font></code> immediately, always triggering a debug break.</P>
|
||||
<p>
|
||||
For reference, here's an example implementation of <code><font color="#000099">EAAssertFailure</font></code>
|
||||
that you can copy paste into your own code. <font color="#000099">
|
||||
<pre>
|
||||
bool EAAssertFailure(const char* expr, const char* filename, int line, const char* function, const char* msg, va_list args)
|
||||
{
|
||||
const int size = 1024;
|
||||
char output[size + 1] = {};
|
||||
char fmtMsg[size + 1] = {};
|
||||
|
||||
_vsnprintf(fmtMsg, size, msg, args);
|
||||
_snprintf(output, size, "%s(%d) : assert failed: '%s' in function: %s\n, message: %s", filename, line, expr, function, fmtMsg);
|
||||
|
||||
printf(output);
|
||||
|
||||
return true;
|
||||
}
|
||||
</pre>
|
||||
</font>
|
||||
<P></P>
|
||||
<h3>If You already Have Your Own Asserts</h3>
|
||||
If you already have your own asserts and would like other technology to use
|
||||
yours, you can easily forward <code><font color="#000099">EA_ASSERT</font></code>
|
||||
to your own implementation. The trick is in the <code><font color="#000099">#EA_ASSERT_HAVE_OWN_HEADER</font></code>
|
||||
macro. Define this to the name of your own header file that has equivalents of
|
||||
the macros defined above (make sure you provide all of them). For example, you
|
||||
could put the following in a file called "game/my_own_awesome_assert.h"... <font color="#000099">
|
||||
<pre>
|
||||
#define EA_ASSERT(expr) MY_OWN_AWESOME_ASSERT(expr)
|
||||
#define EA_ASSERT_MSG(expr, msg) MY_OWN_AWESOME_ASSERT(expr)
|
||||
#define EA_ASSERT_FORMATTED(expr, fmt) MY_OWN_AWESOME_ASSERT(expr)
|
||||
#define EA_FAIL() MY_OWN_AWESOME_ASSERT(false)
|
||||
#define EA_FAIL_MSG(msg) MY_OWN_AWESOME_ASSERT(false)
|
||||
#define EA_FAIL_FORMATTED(fmt) MY_OWN_AWESOME_ASSERT(false)
|
||||
</pre>
|
||||
</font>Next, define <code><font color="#000099">#EA_ASSERT_HAVE_OWN_HEADER</font></code>
|
||||
to <code><font color="#000099">"game/my_own_awesome_assert.h"</font></code> (including
|
||||
the quotes) when you build <code><font color="#000099">EA_ASSERT</font></code> using
|
||||
technology and it will automatically use your assert instead.
|
||||
<hr>
|
||||
<h2>Frequently Asked Questions</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<b>Why don't you supply <code><font color="#000099">EA_WARNING</font></code> macros?</b><p>Because
|
||||
few people can use warnings properly. This often results in games spewing so
|
||||
much output to the console that nobody cares anymore. If the problem is serious
|
||||
enough, just assert. If it's not serious enough, put a bright pink texture on
|
||||
it in the game.</p>
|
||||
<li>
|
||||
<b>But I really need <code><font color="#000099">EA_WARNING</font></code>, can't
|
||||
you add it?</b><p>The truth is, the original author of this package didn't need
|
||||
them. Warning support would increase the complexity of this package of
|
||||
proportion (now you need warning levels, etc.) If you need warnings, write your
|
||||
own.</p>
|
||||
<li>
|
||||
<b>I already have my own definitions of the <code><font color="#000099">EA_ASSERT</font></code>
|
||||
macro and others, now what?</b><p>Use the <code><font color="#000099">EA_ASSERT_HAVE_OWN_HEADER</font></code>
|
||||
feature described above. Now any library that uses <code><font color="#000099">EA_ASSERT</font></code>
|
||||
automatically leverages your assert.</p>
|
||||
<li>
|
||||
<b>I need multilevel asserts, only enabling some when I really need to. Can you add
|
||||
it?</b><p>This often occurs when you have asserts in a tight inner loop that
|
||||
you only want enabled every now and then when you do very strict integrity
|
||||
checking. Unfortunately it would complicate this library too much. We don't
|
||||
feel enough technologies have a need for this. Fortunately you can implement
|
||||
this yourself fairly easily by doing... <font color="#000099">
|
||||
<pre>
|
||||
#if MY_TECH_DEBUG_LEVEL == 1
|
||||
#define MY_TECH_ASSERT(expr) EA_ASSERT(expr)
|
||||
#define MY_TECH_HARDCORE_ASSERT(expr) ((void)0)
|
||||
#else if MY_TECH_DEBUG_LEVEL == 1
|
||||
#define MY_TECH_ASSERT(expr) EA_ASSERT(expr)
|
||||
#define MY_TECH_HARDCORE_ASSERT(expr) EA_ASSERT(expr)
|
||||
#endif
|
||||
</pre>
|
||||
</font>That way you can still leverage <code><font color="#000099">EA_ASSERT</font></code>
|
||||
but have more fine grained control over assert subsets in your technology.
|
||||
<P></P>
|
||||
<li>
|
||||
<b>Why aren't your asserts ignorable?</b><p>Because it would make things more
|
||||
complicated than I'd like. Furthermore, ignorable asserts often flawed. People
|
||||
end up using them to signal user errors that should be handled differently
|
||||
(proper fallback mechanisms, bright pink textures, etc.). What happens is that
|
||||
everybody starts ignoring asserts when they happen rather than fixing them or
|
||||
reporting them. You get away with this for a while, until one day shit hits the
|
||||
fan. Asserts are for programmer error, exceptions and other mechanisms are for
|
||||
user error.</p>
|
||||
<p>That said if you desperately need ignorable asserts, all is not lost. Either use
|
||||
the <code><font color="#000099">#EA_ASSERT_HAVE_OWN_HEADER</font></code> feature,
|
||||
or simply catch the filename and line-number in the handler function. Stick
|
||||
them as a pair into a set. Whenever you find them in the set, return false from
|
||||
the assert handler to ignore the assert.</p>
|
||||
<li>
|
||||
<b>Why isn't platform X supported?</b><p>I don't know. Let me know what its
|
||||
break-into-debugger statement is and I'll gladly add it.</p>
|
||||
<li>
|
||||
<b>Why don't you have feature X?</b><p>Probably because I didn't need it.
|
||||
Alternatively, because it would make this package more complicated than I'd
|
||||
like. Perhaps feature X is best implemented in your own technology? Of course,
|
||||
you can always try sending us an email. Maybe we'll add feature X.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2>Acknowledgements</h2>
|
||||
|
||||
Input for this package came from Paul Pedriana, Ian Davids, James Fairweather, Max Burke, Bob Summerwill and others.
|
||||
</font>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,538 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
|
||||
#pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
|
||||
#endif
|
||||
|
||||
#ifndef EAASSERT_EAASSERT_H
|
||||
#define EAASSERT_EAASSERT_H
|
||||
|
||||
// Users can #define EA_ASSERT_HAVE_OWN_HEADER to their own header file and provide their
|
||||
// own definition of EA_ASSERT. Make sure to include quotes in your
|
||||
// definition, i.e. #define EA_ASSERT_HAVE_OWN_HEADER "my_game/my_game_assert.h"
|
||||
//
|
||||
// At minimum, this header needs to provide the following:
|
||||
//
|
||||
// EA_ASSERT(expr)
|
||||
// EA_ASSERT_MSG(expr, msg)
|
||||
// EA_ASSERT_FORMATTED(expr, fmt)
|
||||
// EA_FAIL()
|
||||
// EA_FAIL_MSG(msg)
|
||||
// EA_FAIL_FORMATTED(fmt)
|
||||
// EA_COMPILETIME_ASSERT(expr) Note: EABase (2.0.21 and later) has static_assert which should now be used in place of this.
|
||||
// EA_PANIC(expr)
|
||||
// EA_PANIC_MSG(expr, msg)
|
||||
// EA_PANIC_FORMATTED(expr, fmt)
|
||||
//
|
||||
// Where:
|
||||
//
|
||||
// expr is an expression that evaluates to a boolean
|
||||
// msg is a string (char*)
|
||||
// fmt is a tuple wrapped in parentheses where the first message is
|
||||
// a formatted string (char*) and the rest is printf style parameters
|
||||
//
|
||||
#ifdef EA_ASSERT_HAVE_OWN_HEADER
|
||||
#include EA_ASSERT_HAVE_OWN_HEADER
|
||||
|
||||
#else // The user did not supply their own assert definition, so we'll use ours instead
|
||||
|
||||
#include "EABase/eabase.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
// The default assert handling mechanism just breaks into the debugger on an assert failure. If you wish to overwrite this
|
||||
// functionality, simply implement the following callback:
|
||||
//
|
||||
// bool EAAssertFailure(
|
||||
// const char* expr,
|
||||
// const char* filename,
|
||||
// int line,
|
||||
// const char* function,
|
||||
// const char* msg,
|
||||
// va_list args)
|
||||
//
|
||||
// And then use:
|
||||
//
|
||||
// EA::Assert::SetCallback(&yourCallback);
|
||||
//
|
||||
|
||||
#if defined(EA_DLL) && defined(_MSC_VER)
|
||||
#ifndef EA_ASSERT_API
|
||||
#define EA_ASSERT_API __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
#define EA_ASSERT_API
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace EA {
|
||||
namespace Assert {
|
||||
|
||||
typedef bool (*FailureCallback)(const char*, const char*, int, const char*, const char*, va_list);
|
||||
|
||||
EA_ASSERT_API FailureCallback GetFailureCallback();
|
||||
EA_ASSERT_API void SetFailureCallback(FailureCallback failureCallback);
|
||||
|
||||
namespace Detail {
|
||||
EA_ASSERT_API bool VCall(const char *expr, const char *filename, int line, const char *function, const char *msg, ...);
|
||||
EA_ASSERT_API bool Call(const char *expr, const char *filename, int line, const char *function, const char *msg);
|
||||
EA_ASSERT_API bool Call(const char *expr, const char *filename, int line, const char *function);
|
||||
}}}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// EA_DEBUG_BREAK
|
||||
///
|
||||
/// This function causes an app to immediately stop under the debugger.
|
||||
/// It is implemented as a macro in order to all stopping at the site
|
||||
/// of the call.
|
||||
///
|
||||
/// Example usage:
|
||||
/// EA_DEBUG_BREAK();
|
||||
///
|
||||
/// The EA_DEBUG_BREAK function must be implemented on a per-platform basis.
|
||||
/// On a PC, you would normally define this to function to be the inline
|
||||
/// assembly: "asm int 3", which tells the debugger to stop here immediately.
|
||||
/// A very basic platform-independent implementation of EA_DEBUG_BREAK could
|
||||
/// be the following:
|
||||
/// void EA_DEBUG_BREAK()
|
||||
/// {
|
||||
/// atoi(""); // Place a breakpoint here if you want to catch breaks.
|
||||
/// }
|
||||
///
|
||||
/// The EA_DEBUG_BREAK default behaviour here can be disabled or changed by
|
||||
/// globally defining EA_DEBUG_BREAK_DEFINED and implementing an alternative
|
||||
/// implementation of it. Our implementation here doesn't simply always have
|
||||
/// it be defined externally because a major convenience of EA_DEBUG_BREAK
|
||||
/// being inline is that it stops right on the troublesome line of code and
|
||||
/// not in another function.
|
||||
///
|
||||
#if ! defined EA_DEBUG_BREAK && ! defined EA_DEBUG_BREAK_DEFINED
|
||||
#if defined(EA_PLATFORM_SONY) && defined(EA_PROCESSOR_X86_64)
|
||||
#define EA_DEBUG_BREAK() do { { __asm volatile ("int $0x41"); } } while(0)
|
||||
#elif defined _MSC_VER
|
||||
#define EA_DEBUG_BREAK() __debugbreak()
|
||||
#elif EA_COMPILER_HAS_BUILTIN(__builtin_debugtrap)
|
||||
#define EA_DEBUG_BREAK() __builtin_debugtrap()
|
||||
#elif (defined(EA_PROCESSOR_X86) || defined(EA_PROCESSOR_X86_64)) && defined(__GNUC__)
|
||||
// Using __asm__ here instead of asm is more compatible with clang when compiling in c99 mode.
|
||||
#define EA_DEBUG_BREAK() __asm__("int3")
|
||||
#elif defined(EA_PROCESSOR_ARM64) && defined(__GNUC__)
|
||||
#define EA_DEBUG_BREAK() asm("brk 10")
|
||||
#elif defined(EA_PROCESSOR_ARM) && defined(__APPLE__)
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#define EA_DEBUG_BREAK() kill( getpid(), SIGINT )
|
||||
#elif defined(EA_PROCESSOR_ARM) && defined(__GNUC__)
|
||||
#define EA_DEBUG_BREAK() asm("BKPT 10") // The 10 is arbitrary. It's just a unique id.
|
||||
#elif defined(EA_PROCESSOR_ARM) && defined(__ARMCC_VERSION)
|
||||
#define EA_DEBUG_BREAK() __breakpoint(10)
|
||||
#else
|
||||
#define EA_DEBUG_BREAK() *(int*)(0) = 0
|
||||
#endif
|
||||
|
||||
#define EA_DEBUG_BREAK_DEFINED
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// EA_CRASH
|
||||
///
|
||||
/// Executes an invalid memory write, which should result in an exception
|
||||
/// on most platforms.
|
||||
///
|
||||
#if !defined(EA_CRASH) && !defined(EA_CRASH_DEFINED)
|
||||
#define EA_CRASH() *(volatile int*)(0) = 0
|
||||
|
||||
#define EA_CRASH_DEFINED
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// EA_CURRENT_FUNCTION
|
||||
///
|
||||
/// Provides a consistent way to get the current function name as a macro
|
||||
/// like the __FILE__ and __LINE__ macros work. The C99 standard specifies
|
||||
/// that __func__ be provided by the compiler, but most compilers don't yet
|
||||
/// follow that convention. However, many compilers have an alternative.
|
||||
///
|
||||
/// We also define EA_CURRENT_FUNCTION_SUPPORTED for when it is not possible
|
||||
/// to have EA_CURRENT_FUNCTION work as expected.
|
||||
///
|
||||
/// Defined inside a function because otherwise the macro might not be
|
||||
/// defined and code below might not compile. This happens with some
|
||||
/// compilers.
|
||||
///
|
||||
#ifndef EA_CURRENT_FUNCTION
|
||||
#if defined __GNUC__ || (defined __ICC && __ICC >= 600)
|
||||
#define EA_CURRENT_FUNCTION __PRETTY_FUNCTION__
|
||||
#elif defined(__FUNCSIG__)
|
||||
#define EA_CURRENT_FUNCTION __FUNCSIG__
|
||||
#elif (defined __INTEL_COMPILER && __INTEL_COMPILER >= 600) || (defined __IBMCPP__ && __IBMCPP__ >= 500) || (defined CS_UNDEFINED_STRING && CS_UNDEFINED_STRING >= 0x4200)
|
||||
#define EA_CURRENT_FUNCTION __FUNCTION__
|
||||
#elif defined __BORLANDC__ && __BORLANDC__ >= 0x550
|
||||
#define EA_CURRENT_FUNCTION __FUNC__
|
||||
#elif defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901
|
||||
#define EA_CURRENT_FUNCTION __func__
|
||||
#else
|
||||
#define EA_CURRENT_FUNCTION "(unknown function)"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace EA {
|
||||
namespace Assert {
|
||||
namespace Detail
|
||||
{
|
||||
// The Forwarder class is deprecated on compilers that support variadic macros. Avoiding
|
||||
// the temporary instances created by this code can result in significant code size savings.
|
||||
// Code outside of the EAAssert library shouldn't be referencing API in the Detail namespace.
|
||||
#ifdef EA_COMPILER_NO_VARIADIC_MACROS
|
||||
#define EA_ASSERT_PREFIX_DEPRECATED
|
||||
#define EA_ASSERT_POSTFIX_DEPRECATED
|
||||
#else
|
||||
#define EA_ASSERT_PREFIX_DEPRECATED EA_PREFIX_DEPRECATED
|
||||
#define EA_ASSERT_POSTFIX_DEPRECATED EA_POSTFIX_DEPRECATED
|
||||
#endif
|
||||
|
||||
struct Forwarder
|
||||
{
|
||||
const char* mExpr;
|
||||
const char* mFunction;
|
||||
const char* mFilename;
|
||||
int mLine;
|
||||
Forwarder(const char* expr, const char* filename, int line, const char* function) : mExpr(expr), mFunction(function), mFilename(filename), mLine(line) {}
|
||||
EA_ASSERT_PREFIX_DEPRECATED bool Call(const char* msg, ...) const EA_ASSERT_POSTFIX_DEPRECATED
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
bool ret = (*GetFailureCallback())(mExpr, mFilename, mLine, mFunction, msg, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef EA_COMPILER_NO_VARIADIC_MACROS
|
||||
#define EA_ASSERT_FORMATTED_HANDLER_CALL(EXPR, FILE, LINE, FUNCTION, FMT) EA::Assert::Detail::Forwarder(EXPR, FILE, LINE, FUNCTION).Call FMT
|
||||
#else
|
||||
#define EA_ASSERT_FORMATTED_HANDLER_CALL(EXPR, FILE, LINE, FUNCTION, FMT) EA::Assert::Detail::VCall(EXPR, FILE, LINE, FUNCTION, EA_ASSERT_EXPAND_VA_ARGS FMT)
|
||||
#define EA_ASSERT_EXPAND_VA_ARGS(...) __VA_ARGS__
|
||||
#endif
|
||||
|
||||
}}}
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// EA_COMPILETIME_ASSERT
|
||||
///
|
||||
/// EA_COMPILETIME_ASSERT is a macro for compile time assertion checks, useful for
|
||||
/// validating *constant* expressions. The advantage over using the ASSERT,
|
||||
/// VERIFY, etc. macros is that errors are caught at compile time instead
|
||||
/// of runtime.
|
||||
///
|
||||
/// This EA_COMPILETIME_ASSERT has a weakness in that when used at global scope (outside
|
||||
/// functions) there can be two such statements on the same line of a given
|
||||
/// file and some compilers might complain about this.
|
||||
///
|
||||
/// Example:
|
||||
/// EA_COMPILETIME_ASSERT(sizeof(int) == 4);
|
||||
///
|
||||
#ifndef EA_COMPILETIME_ASSERT
|
||||
#if defined(EA_COMPILER_EDG) || defined(EA_COMPILER_CLANG)
|
||||
// Ideally static_assert would be used wherever possible because it allows for improved error reporting.
|
||||
// However, using static_assert with Clang currently breaks code using EAOffsetOf. We need to fix this
|
||||
// macro on clang before enabling the use of static_assert.
|
||||
#define EAASSERT_TOKEN_PASTE(a,b) a ## b
|
||||
#define EAASSERT_CONCATENATE_HELPER(a,b) EAASSERT_TOKEN_PASTE(a,b)
|
||||
#define EA_COMPILETIME_ASSERT(expr) \
|
||||
EA_DISABLE_CLANG_WARNING(-Wunknown-pragmas); /* Disable warnings about unknown pragmas in case -Wunused-local-typedefs is not supported*/ \
|
||||
EA_DISABLE_CLANG_WARNING(-Wunused-local-typedef); \
|
||||
typedef char EAASSERT_CONCATENATE_HELPER(compileTimeAssert,__LINE__) [((expr) != 0) ? 1 : -1]; \
|
||||
EA_RESTORE_CLANG_WARNING() \
|
||||
EA_RESTORE_CLANG_WARNING()
|
||||
#else
|
||||
#define EA_COMPILETIME_ASSERT(expr) static_assert(expr, EA_STRINGIFY(expr))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef EA_CT_ASSERT
|
||||
#define EA_CT_ASSERT EA_COMPILETIME_ASSERT
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef EA_DEBUG
|
||||
#ifndef EA_ASSERT_ENABLED
|
||||
#define EA_ASSERT_ENABLED 1
|
||||
#endif
|
||||
#ifndef EA_PANIC_ENABLED
|
||||
#define EA_PANIC_ENABLED 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef EA_ASSERT_ENABLED
|
||||
#ifdef __cplusplus
|
||||
#ifndef EA_ASSERT
|
||||
#define EA_ASSERT(expr) \
|
||||
EA_DISABLE_VC_WARNING(4127) \
|
||||
do { \
|
||||
EA_ANALYSIS_ASSUME(expr); \
|
||||
if (!(expr) && EA::Assert::Detail::Call(#expr, __FILE__, __LINE__, EA_CURRENT_FUNCTION)) \
|
||||
EA_DEBUG_BREAK(); \
|
||||
else \
|
||||
((void)0);\
|
||||
} while(0) \
|
||||
EA_RESTORE_VC_WARNING()
|
||||
#endif
|
||||
#ifndef EA_ASSERT_MSG
|
||||
#define EA_ASSERT_MSG(expr, msg) \
|
||||
EA_DISABLE_VC_WARNING(4127) \
|
||||
do { \
|
||||
EA_ANALYSIS_ASSUME(expr); \
|
||||
if (!(expr) && EA::Assert::Detail::Call(#expr, __FILE__, __LINE__, EA_CURRENT_FUNCTION, msg)) \
|
||||
EA_DEBUG_BREAK(); \
|
||||
else \
|
||||
((void)0);\
|
||||
} while(0) \
|
||||
EA_RESTORE_VC_WARNING()
|
||||
#endif
|
||||
#ifndef EA_ASSERT_FORMATTED
|
||||
#define EA_ASSERT_FORMATTED(expr, fmt) if (!(expr) && EA_ASSERT_FORMATTED_HANDLER_CALL(#expr, __FILE__, __LINE__, EA_CURRENT_FUNCTION, fmt)) EA_DEBUG_BREAK(); else ((void)0)
|
||||
#endif
|
||||
#ifndef EA_FAIL
|
||||
#define EA_FAIL() if ( EA::Assert::Detail::Call("EA_FAIL", __FILE__, __LINE__, EA_CURRENT_FUNCTION)) EA_DEBUG_BREAK(); else ((void)0)
|
||||
#endif
|
||||
#ifndef EA_FAIL_MSG
|
||||
#define EA_FAIL_MSG(msg) if ( EA::Assert::Detail::Call("EA_FAIL", __FILE__, __LINE__, EA_CURRENT_FUNCTION, msg)) EA_DEBUG_BREAK(); else ((void)0)
|
||||
#endif
|
||||
#ifndef EA_FAIL_FORMATTED
|
||||
#define EA_FAIL_FORMATTED(fmt) if (EA_ASSERT_FORMATTED_HANDLER_CALL("EA_FAIL", __FILE__, __LINE__, EA_CURRENT_FUNCTION, fmt)) EA_DEBUG_BREAK(); else ((void)0)
|
||||
#endif
|
||||
#else
|
||||
#ifndef EA_ASSERT
|
||||
#define EA_ASSERT(expr) \
|
||||
EA_DISABLE_VC_WARNING(4127)\
|
||||
do {\
|
||||
EA_ANALYSIS_ASSUME(expr);\
|
||||
if(!(expr))\
|
||||
{\
|
||||
printf("\nEA_ASSERT(%s) failed in %s(%d)\n", #expr, __FILE__, __LINE__); EA_DEBUG_BREAK();\
|
||||
}\
|
||||
else\
|
||||
{\
|
||||
((void)0);\
|
||||
}\
|
||||
} while(0)\
|
||||
EA_RESTORE_VC_WARNING()
|
||||
#endif
|
||||
#ifndef EA_ASSERT_MSG
|
||||
#define EA_ASSERT_MSG(expr, msg) \
|
||||
EA_DISABLE_VC_WARNING(4127)\
|
||||
do\
|
||||
{ \
|
||||
EA_ANALYSIS_ASSUME(expr); \
|
||||
if (!(expr)) \
|
||||
{\
|
||||
printf("\nEA_ASSERT(%s) failed in %s(%d): %s\n", #expr, __FILE__, __LINE__, msg);EA_DEBUG_BREAK();\
|
||||
}\
|
||||
else \
|
||||
{ \
|
||||
((void)0); \
|
||||
} \
|
||||
} while(0) \
|
||||
EA_RESTORE_VC_WARNING()
|
||||
#endif
|
||||
#ifndef EA_ASSERT_FORMATTED
|
||||
#define EA_ASSERT_FORMATTED(expr, fmt) \
|
||||
EA_DISABLE_VC_WARNING(4127) \
|
||||
do {\
|
||||
EA_ANALYSIS_ASSUME(expr); \
|
||||
if (!(expr)) \
|
||||
{ \
|
||||
printf fmt; EA_DEBUG_BREAK(); EA_DEBUG_BREAK(); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
((void)0); \
|
||||
} \
|
||||
} while(0) \
|
||||
EA_RESTORE_VC_WARNING()
|
||||
#endif
|
||||
#ifndef EA_FAIL
|
||||
#define EA_FAIL() \
|
||||
EA_DISABLE_VC_WARNING(4127) \
|
||||
do {\
|
||||
printf("\nEA_FAIL: %s(%d)\n", __FILE__, __LINE__); EA_DEBUG_BREAK(); \
|
||||
} while(0) \
|
||||
EA_RESTORE_VC_WARNING()
|
||||
#endif
|
||||
#ifndef EA_FAIL_MSG
|
||||
#define EA_FAIL_MSG(msg) \
|
||||
EA_DISABLE_VC_WARNING(4127) \
|
||||
do {\
|
||||
printf("\nEA_FAIL: %s(%d): %s\n", __FILE__, __LINE__, msg); EA_DEBUG_BREAK(); \
|
||||
} while(0) \
|
||||
EA_RESTORE_VC_WARNING()
|
||||
#endif
|
||||
#ifndef EA_FAIL_FORMATTED
|
||||
#define EA_FAIL_FORMATTED(fmt) \
|
||||
EA_DISABLE_VC_WARNING(4127) \
|
||||
do {\
|
||||
printf fmt; EA_DEBUG_BREAK(); \
|
||||
} while(0) \
|
||||
EA_RESTORE_VC_WARNING()
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#ifndef EA_ASSERT
|
||||
#define EA_ASSERT(expr) ((void)0)
|
||||
#endif
|
||||
#ifndef EA_ASSERT_MSG
|
||||
#define EA_ASSERT_MSG(expr, msg) ((void)0)
|
||||
#endif
|
||||
#ifndef EA_ASSERT_FORMATTED
|
||||
#define EA_ASSERT_FORMATTED(expr, fmt) ((void)0)
|
||||
#endif
|
||||
#ifndef EA_FAIL
|
||||
#define EA_FAIL() ((void)0)
|
||||
#endif
|
||||
#ifndef EA_FAIL_MSG
|
||||
#define EA_FAIL_MSG(msg) ((void)0)
|
||||
#endif
|
||||
#ifndef EA_FAIL_FORMATTED
|
||||
#define EA_FAIL_FORMATTED(fmt) ((void)0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
/// EA_PANIC
|
||||
///
|
||||
// EA_PANIC is a macro for runtime assertion checks in release builds. The difference
|
||||
// between using the EA_ASSERT is rather than performing a EA_DEBUG_BREAK, EA_CRASH is
|
||||
// used instead.
|
||||
///
|
||||
// What this provides is a conditional forced crash on non-final builds since EA_ASSERT
|
||||
// is only enabled for debug builds which define a handler. The largest motivation
|
||||
// for using EA_PANIC over EA_ASSERT should be when one wants to explicitly catch
|
||||
// critical asserts in release builds.
|
||||
/// Example:
|
||||
/// EA_PANIC(myVar == theirVar);
|
||||
///
|
||||
#ifdef EA_PANIC_ENABLED
|
||||
#ifdef __cplusplus
|
||||
#ifndef EA_PANIC
|
||||
#define EA_PANIC(expr) \
|
||||
EA_DISABLE_VC_WARNING(4127) \
|
||||
do { \
|
||||
EA_ANALYSIS_ASSUME(expr); \
|
||||
if (!(expr)) { \
|
||||
EA::Assert::Detail::Call(#expr, __FILE__, __LINE__, EA_CURRENT_FUNCTION); EA_CRASH(); \
|
||||
} else ((void)0); \
|
||||
} while(0) \
|
||||
EA_RESTORE_VC_WARNING()
|
||||
#endif
|
||||
#ifndef EA_PANIC_MSG
|
||||
#define EA_PANIC_MSG(expr, msg) \
|
||||
EA_DISABLE_VC_WARNING(4127) \
|
||||
do { \
|
||||
EA_ANALYSIS_ASSUME(expr); \
|
||||
if (!(expr)) { \
|
||||
EA::Assert::Detail::Call(#expr, __FILE__, __LINE__, EA_CURRENT_FUNCTION, msg); EA_CRASH(); \
|
||||
} else ((void)0); \
|
||||
} while(0) \
|
||||
EA_RESTORE_VC_WARNING()
|
||||
#endif
|
||||
#ifndef EA_PANIC_FORMATTED
|
||||
#define EA_PANIC_FORMATTED(expr, fmt) \
|
||||
EA_DISABLE_VC_WARNING(4127) \
|
||||
do { \
|
||||
EA_ANALYSIS_ASSUME(expr); \
|
||||
if (!(expr)) { \
|
||||
EA_ASSERT_FORMATTED_HANDLER_CALL(#expr, __FILE__, __LINE__, EA_CURRENT_FUNCTION, fmt); EA_CRASH(); \
|
||||
} else ((void)0); \
|
||||
} while(0) \
|
||||
EA_RESTORE_VC_WARNING()
|
||||
#endif
|
||||
#else
|
||||
#ifndef EA_PANIC
|
||||
#define EA_PANIC(expr) \
|
||||
EA_DISABLE_VC_WARNING(4127) \
|
||||
do { \
|
||||
EA_ANALYSIS_ASSUME(expr); \
|
||||
if (!(expr)) { \
|
||||
printf("\nEA_PANIC(%s) failed in %s(%d)\n", #expr, __FILE__, __LINE__); EA_CRASH(); \
|
||||
} else ((void)0); \
|
||||
} while(0) \
|
||||
EA_RESTORE_VC_WARNING()
|
||||
#endif
|
||||
#ifndef EA_PANIC_MSG
|
||||
#define EA_PANIC_MSG(expr, msg) \
|
||||
EA_DISABLE_VC_WARNING(4127) \
|
||||
do { \
|
||||
EA_ANALYSIS_ASSUME(expr); \
|
||||
if (!(expr)) { \
|
||||
printf("\nEA_PANIC(%s) failed in %s(%d): %s\n", #expr, __FILE__, __LINE__, msg); EA_CRASH(); \
|
||||
} else ((void)0); \
|
||||
} while(0) \
|
||||
EA_RESTORE_VC_WARNING()
|
||||
#endif
|
||||
#ifndef EA_PANIC_FORMATTED
|
||||
#define EA_PANIC_FORMATTED(expr, fmt) \
|
||||
EA_DISABLE_VC_WARNING(4127) \
|
||||
do { \
|
||||
EA_ANALYSIS_ASSUME(expr); \
|
||||
if (!(expr)) { \
|
||||
printf fmt; EA_CRASH(); \
|
||||
} else ((void)0); \
|
||||
} while(0) \
|
||||
EA_RESTORE_VC_WARNING()
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#ifndef EA_PANIC
|
||||
#define EA_PANIC(expr) ((void)0)
|
||||
#endif
|
||||
#ifndef EA_PANIC_MSG
|
||||
#define EA_PANIC_MSG(expr, msg) ((void)0)
|
||||
#endif
|
||||
#ifndef EA_PANIC_FORMATTED
|
||||
#define EA_PANIC_FORMATTED(expr, fmt) ((void)0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // EA_ASSERT_HAVE_OWN_HEADER
|
||||
|
||||
// We provide some synonyms for the message style macros, because we couldn't reach common ground
|
||||
// and there was too much existing code using different versions. It's not pretty, but relatively harmless
|
||||
#ifndef EA_ASSERT_M
|
||||
#define EA_ASSERT_M EA_ASSERT_MSG
|
||||
#endif
|
||||
#ifndef EA_ASSERT_MESSAGE
|
||||
#define EA_ASSERT_MESSAGE EA_ASSERT_MSG
|
||||
#endif
|
||||
#ifndef EA_FAIL_M
|
||||
#define EA_FAIL_M EA_FAIL_MSG
|
||||
#endif
|
||||
#ifndef EA_FAIL_MESSAGE
|
||||
#define EA_FAIL_MESSAGE EA_FAIL_MSG
|
||||
#endif
|
||||
#ifndef EA_PANIC_M
|
||||
#define EA_PANIC_M EA_PANIC_MSG
|
||||
#endif
|
||||
#ifndef EA_PANIC_MESSAGE
|
||||
#define EA_PANIC_MESSAGE EA_PANIC_MSG
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,69 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
\file
|
||||
Define the major, minor and patch versions.
|
||||
*/
|
||||
|
||||
#ifndef EAASSERT_VERSION_H
|
||||
#define EAASSERT_VERSION_H
|
||||
|
||||
// Define the major, minor and patch versions.
|
||||
// This information is updated with each release.
|
||||
|
||||
//! This define indicates the major version number for the filesys package.
|
||||
//! \sa EAASSERT_VERSION_MAJOR
|
||||
#define EAASSERT_VERSION_MAJOR 1
|
||||
//! This define indicates the minor version number for the filesys package.
|
||||
//! \sa EAASSERT_VERSION_MINOR
|
||||
#define EAASSERT_VERSION_MINOR 5
|
||||
//! This define indicates the patch version number for the filesys package.
|
||||
//! \sa EAASSERT_VERSION_PATCH
|
||||
#define EAASSERT_VERSION_PATCH 8
|
||||
|
||||
/*!
|
||||
* This is a utility macro that users may use to create a single version number
|
||||
* that can be compared against EAASSERT_VERSION.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* \code
|
||||
*
|
||||
* #if EAASSERT_VERSION > EAASSERT_CREATE_VERSION_NUMBER( 1, 1, 0 )
|
||||
* printf("Filesys version is greater than 1.1.0.\n");
|
||||
* #endif
|
||||
*
|
||||
* \endcode
|
||||
*/
|
||||
#define EAASSERT_CREATE_VERSION_NUMBER( major_ver, minor_ver, patch_ver ) \
|
||||
((major_ver) * 1000000 + (minor_ver) * 1000 + (patch_ver))
|
||||
|
||||
/*!
|
||||
* This macro is an aggregate of the major, minor and patch version numbers.
|
||||
* \sa EAASSERT_CREATE_VERSION_NUMBER
|
||||
*/
|
||||
#define EAASSERT_VERSION \
|
||||
EAASSERT_CREATE_VERSION_NUMBER( EAASSERT_VERSION_MAJOR, EAASSERT_VERSION_MINOR, EAASSERT_VERSION_PATCH )
|
||||
|
||||
#define EAASSERT_VERSION_MAJOR_STR EAASSERT_VERSION_STRINGIFY(EAASSERT_VERSION_MAJOR)
|
||||
#if EAASSERT_VERSION_MINOR >= 10
|
||||
#define EAASSERT_VERSION_MINOR_STR EAASSERT_VERSION_STRINGIFY(EAASSERT_VERSION_MINOR)
|
||||
#else
|
||||
#define EAASSERT_VERSION_MINOR_STR "0" EAASSERT_VERSION_STRINGIFY(EAASSERT_VERSION_MINOR)
|
||||
#endif
|
||||
|
||||
#if EAASSERT_VERSION_PATCH >= 10
|
||||
#define EAASSERT_VERSION_PATCH_STR EAASSERT_VERSION_STRINGIFY(EAASSERT_VERSION_PATCH)
|
||||
#else
|
||||
#define EAASSERT_VERSION_PATCH_STR "0" EAASSERT_VERSION_STRINGIFY(EAASSERT_VERSION_PATCH)
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* This macro returns a string version of the macro
|
||||
* \sa EAASSERT_VERSION_STRING
|
||||
*/
|
||||
#define EAASSERT_VERSION_STRING EAASSERT_VERSION_MAJOR_STR "." EAASSERT_VERSION_MINOR_STR "." EAASSERT_VERSION_PATCH_STR
|
||||
|
||||
#endif // EAASSERT_VERSION_H
|
||||
@@ -0,0 +1,140 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "EAAssert/eaassert.h"
|
||||
|
||||
#ifndef EA_ASSERT_HAVE_OWN_HEADER
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined(EA_PLATFORM_MICROSOFT)
|
||||
#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0400)
|
||||
#undef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#endif
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#pragma warning(push,0)
|
||||
#include <Windows.h> // ::IsDebuggerPresent
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#if !defined(EA_ASSERT_VSNPRINTF)
|
||||
#if defined(EA_PLATFORM_MICROSOFT)
|
||||
#define EA_ASSERT_VSNPRINTF _vsnprintf
|
||||
#define EA_ASSERT_SNPRINTF _snprintf
|
||||
#else
|
||||
#define EA_ASSERT_VSNPRINTF vsnprintf
|
||||
#define EA_ASSERT_SNPRINTF snprintf
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
namespace EA {
|
||||
namespace Assert {
|
||||
namespace Detail {
|
||||
namespace {
|
||||
|
||||
#if defined(EA_ASSERT_ENABLED)
|
||||
static void PlatformPrint(const char *str)
|
||||
{
|
||||
#if defined(EA_PLATFORM_MICROSOFT)
|
||||
if (IsDebuggerPresent())
|
||||
{
|
||||
::OutputDebugStringA(str);
|
||||
}
|
||||
#endif
|
||||
|
||||
puts(str);
|
||||
|
||||
#if defined(EA_PLATFORM_MOBILE)
|
||||
fflush(stdout); // Mobile platforms need this because otherwise you can easily lose output if the device crashes.
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
bool DefaultFailureCallback(const char* expr, const char* filename, int line, const char* function, const char* msg, va_list args)
|
||||
{
|
||||
#if defined(EA_ASSERT_ENABLED)
|
||||
const int largeEnough = 2048;
|
||||
char output[largeEnough + 1] = {};
|
||||
char fmtMsg[largeEnough + 1] = {};
|
||||
|
||||
int len = EA_ASSERT_VSNPRINTF(fmtMsg, largeEnough, msg, args);
|
||||
|
||||
if(len==0)
|
||||
{
|
||||
len = EA_ASSERT_SNPRINTF(fmtMsg, largeEnough, "none");
|
||||
}
|
||||
|
||||
// different platforms return different values for the error, but in both
|
||||
// cases it'll be out of bounds, so clamp the return value to largeEnough.
|
||||
if (len < 0 || len > largeEnough)
|
||||
len = largeEnough;
|
||||
|
||||
fmtMsg[len] = '\0';
|
||||
|
||||
len = EA_ASSERT_SNPRINTF(output, largeEnough,
|
||||
"%s(%d) : EA_ASSERT failed: '%s' in function: %s\n, message: %s",
|
||||
filename, line, expr, function, fmtMsg);
|
||||
if (len < 0 || len > largeEnough)
|
||||
len = largeEnough;
|
||||
|
||||
output[len] = '\0';
|
||||
|
||||
PlatformPrint(output);
|
||||
#else
|
||||
EA_UNUSED(expr);
|
||||
EA_UNUSED(filename);
|
||||
EA_UNUSED(line);
|
||||
EA_UNUSED(function);
|
||||
EA_UNUSED(msg);
|
||||
EA_UNUSED(args);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
FailureCallback gFailureCallback = &DefaultFailureCallback;
|
||||
}}
|
||||
|
||||
void SetFailureCallback(FailureCallback failureCallback)
|
||||
{
|
||||
Detail::gFailureCallback = failureCallback;
|
||||
}
|
||||
|
||||
FailureCallback GetFailureCallback()
|
||||
{
|
||||
return Detail::gFailureCallback;
|
||||
}
|
||||
|
||||
bool Detail::VCall(const char *expr, const char *filename, int line, const char *function, const char *msg, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
bool ret = (*GetFailureCallback())(expr, filename, line, function, msg, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Detail::Call(const char *expr, const char *filename, int line, const char *function)
|
||||
{
|
||||
// Pass an empty string as msg parameter. Some FailureCallback implementation (Frostbite)
|
||||
// will display only msg and discard the rest of the data when msg is non empty.
|
||||
return VCall(expr, filename, line, function, "");
|
||||
}
|
||||
|
||||
bool Detail::Call(const char *expr, const char *filename, int line, const char *function, const char* msg)
|
||||
{
|
||||
return VCall(expr, filename, line, function, "%s", msg);
|
||||
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,8 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// EAMain/EAEntryPointMain.inl contains C++ code but it exposes the application entry point with C linkage.
|
||||
|
||||
#include "EAMain/EAEntryPointMain.inl"
|
||||
#include "EATest/EASTLNewOperatorGuard.inl"
|
||||
@@ -0,0 +1,58 @@
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Copyright (C) Electronic Arts Inc. All rights reserved.
|
||||
#-------------------------------------------------------------------------------------------
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# CMake info
|
||||
#-------------------------------------------------------------------------------------------
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
project(EAAssertTest CXX)
|
||||
include(CTest)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Defines
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
|
||||
add_definitions(-D_CHAR16T)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Compiler Flags
|
||||
#-------------------------------------------------------------------------------------------
|
||||
set (CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/packages/EASTL/scripts/CMake")
|
||||
include(CommonCppFlags)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Source files
|
||||
#-------------------------------------------------------------------------------------------
|
||||
file(GLOB EAASSERTTEST_SOURCES "TestEAAssert.cpp")
|
||||
set(SOURCES ${EAASSERTTEST_SOURCES})
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Executable definition
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_executable(EAAssertTest ${SOURCES})
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Dependencies
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_subdirectory(packages/EABase)
|
||||
add_subdirectory(packages/EAMain)
|
||||
add_subdirectory(packages/EASTL)
|
||||
add_subdirectory(packages/EAStdC)
|
||||
add_subdirectory(packages/EATest)
|
||||
add_subdirectory(packages/EAThread)
|
||||
|
||||
target_link_libraries(EAAssertTest EABase)
|
||||
target_link_libraries(EAAssertTest EAMain)
|
||||
target_link_libraries(EAAssertTest EASTL)
|
||||
target_link_libraries(EAAssertTest EAStdC)
|
||||
target_link_libraries(EAAssertTest EATest)
|
||||
target_link_libraries(EAAssertTest EAThread)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Run Unit tests and verify the results.
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_test(EAAssertTestRuns EAAssertTest)
|
||||
set_tests_properties (EAAssertTestRuns PROPERTIES PASS_REGULAR_EXPRESSION "RETURNCODE=0")
|
||||
|
||||
@@ -0,0 +1,187 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <EAAssert/eaassert.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable: 4127)
|
||||
#endif
|
||||
|
||||
#include "EAMain/EAEntryPointMain.inl"
|
||||
#include "EATest/EASTLNewOperatorGuard.inl"
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
const char* expectedExpr = 0;
|
||||
const char* expectedFilename = 0;
|
||||
const char* expectedFunction = 0;
|
||||
const char* expectedMessage = 0;
|
||||
int expectedLine = 0;
|
||||
bool assertCalled = false;
|
||||
bool expressionCalled = false;
|
||||
}
|
||||
|
||||
static void Expect(const char* expr, const char* filename, int line, const char* function, const char* msg)
|
||||
{
|
||||
expectedExpr = expr;
|
||||
expectedFilename = filename;
|
||||
expectedFunction = function;
|
||||
expectedMessage = msg;
|
||||
expectedLine = line;
|
||||
}
|
||||
|
||||
// similar to assert in libc, but this function is not compiled out in a
|
||||
// release build
|
||||
// \param condition should be true when EA_ASSERT_ENABLED is defined,
|
||||
// false when EA_ASSERT_ENABLED is not defined.
|
||||
// \param always the condition should be true regardless of whether
|
||||
// EA_ASSERT_ENABLED is defined or not.
|
||||
static void TestCondition(bool condition, bool always)
|
||||
{
|
||||
if (always)
|
||||
{
|
||||
if (!condition)
|
||||
{
|
||||
EA::EAMain::Report("Test failed\n");
|
||||
EA_DEBUG_BREAK();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(EA_ASSERT_ENABLED)
|
||||
if (!condition)
|
||||
{
|
||||
EA::EAMain::Report("Test failed\n");
|
||||
EA_DEBUG_BREAK();
|
||||
}
|
||||
#else
|
||||
if (condition)
|
||||
{
|
||||
EA::EAMain::Report("Test failed\n");
|
||||
EA_DEBUG_BREAK();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool EAAssertFailure(const char* expr, const char* filename, int line, const char* function, const char* msg, va_list args)
|
||||
{
|
||||
assertCalled = true;
|
||||
|
||||
TestCondition(0 == strcmp(expr, expectedExpr), false);
|
||||
TestCondition(0 != strstr(filename, expectedFilename), false);
|
||||
TestCondition(0 != strstr(function, expectedFunction), false);
|
||||
|
||||
const int size = 2048;
|
||||
char fmtMsg[size + 1] = {};
|
||||
vsprintf(fmtMsg, msg, args);
|
||||
|
||||
TestCondition(0 == strcmp(fmtMsg, expectedMessage), false);
|
||||
TestCondition(line == expectedLine, false);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TestExpression(bool *x)
|
||||
{
|
||||
*x = !*x;
|
||||
|
||||
return *x;
|
||||
}
|
||||
|
||||
EA_COMPILETIME_ASSERT(true);
|
||||
|
||||
int EAMain(int argc, char**)
|
||||
{
|
||||
EA::Assert::SetFailureCallback(&EAAssertFailure);
|
||||
|
||||
EA_COMPILETIME_ASSERT(true);
|
||||
|
||||
#ifndef EA_COMPILER_GNUC
|
||||
// TODO(rparolin): Disabling this test on GCC because the compiler correctly wanrs that the output of EA_OFFSETOF is
|
||||
// not constexpr. Unfortunately, the implementation is attempting to support calculating offsets within
|
||||
// non-standard-layout types which is not supported by the Cpp Standard. Fix required.
|
||||
{
|
||||
struct OffsetOfTestStruct
|
||||
{
|
||||
int member;
|
||||
};
|
||||
|
||||
// Note:
|
||||
//
|
||||
// User code currently exists that uses EA_COMPILETIME_ASSERT with results from EA_OFFSETOF.
|
||||
// Modifying the implementation of either EA_COMPILETIME_ASSERT or EA_OFFSETOF could cause this
|
||||
// code to break. (We have observed failures on clang.)
|
||||
//
|
||||
// See also:
|
||||
// - EAStdC's EAOffsetOf works properly with static_assert, but also needs to suppress compiler
|
||||
// warnings to compile warning free in all situations. We chose not to perform this suppression
|
||||
// in EABase's EA_OFFSETOF because it would leak into files including eabase.
|
||||
EA_COMPILETIME_ASSERT(EA_OFFSETOF(OffsetOfTestStruct, member) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
assertCalled = false;
|
||||
EA_ASSERT(true);
|
||||
TestCondition(assertCalled == false, true);
|
||||
|
||||
const char* testMsg = "The quick brown fox jumps over the lazy dog.";
|
||||
|
||||
const char* mainName = "EAMain";
|
||||
|
||||
assertCalled = false;
|
||||
Expect("3 == 4", __FILE__, __LINE__ + 1, mainName, testMsg);
|
||||
EA_ASSERT_M(3 == 4, testMsg);
|
||||
TestCondition(assertCalled, false);
|
||||
|
||||
assertCalled = false;
|
||||
Expect("3 == 4", __FILE__, __LINE__ + 1, mainName, testMsg);
|
||||
EA_ASSERT_MESSAGE(3 == 4, testMsg);
|
||||
TestCondition(assertCalled, false);
|
||||
|
||||
assertCalled = false;
|
||||
Expect("3 == 4", __FILE__, __LINE__ + 1, mainName, testMsg);
|
||||
EA_ASSERT_MSG(3 == 4, testMsg);
|
||||
TestCondition(assertCalled, false);
|
||||
|
||||
assertCalled = false;
|
||||
Expect("8 == 2", __FILE__, __LINE__ + 1, mainName, testMsg);
|
||||
EA_ASSERT_FORMATTED(8 == 2, ("The quick brown fox jumps over the %s dog.", "lazy"));
|
||||
TestCondition(assertCalled, false);
|
||||
|
||||
assertCalled = false;
|
||||
Expect("3 % 8 == 2", __FILE__, __LINE__ + 1, mainName, "");
|
||||
EA_ASSERT(3 % 8 == 2);
|
||||
TestCondition(assertCalled, false);
|
||||
|
||||
bool expectToBeSet = false;
|
||||
if (false)
|
||||
EA_ASSERT(false);
|
||||
else
|
||||
expectToBeSet = true;
|
||||
TestCondition(expectToBeSet, true);
|
||||
|
||||
// Regression test for checking whether an expression is compiled
|
||||
// out when asserts are disabled.
|
||||
EA_ASSERT(TestExpression(&expressionCalled));
|
||||
TestCondition(expressionCalled, false);
|
||||
|
||||
// Ensure that the unconditional assertion format behaves correctly
|
||||
Expect("EA_FAIL", __FILE__, __LINE__ + 1, mainName, "");
|
||||
EA_FAIL();
|
||||
|
||||
Expect("EA_FAIL", __FILE__, __LINE__ + 1, mainName, testMsg);
|
||||
EA_FAIL_MSG(testMsg);
|
||||
|
||||
Expect("EA_FAIL", __FILE__, __LINE__ + 1, mainName, testMsg);
|
||||
EA_FAIL_FORMATTED(("%s", testMsg));
|
||||
|
||||
EA::EAMain::Report("Test complete - all tests passed.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// We can't override EA_ASSERTS failure callback so we won't be able to test EAAssert in C but at least we can
|
||||
// prove it builds our macros correctly
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <EAAssert/eaassert.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable: 4127)
|
||||
#endif
|
||||
|
||||
int EAMain(int argc, char** argv)
|
||||
{
|
||||
const char* testMsg = "The quick brown fox jumps over the lazy dog.";
|
||||
int nErrorCount = 0;
|
||||
int expectToBeSet = 0;
|
||||
|
||||
EA_COMPILETIME_ASSERT(1);
|
||||
EA_ASSERT(1);
|
||||
|
||||
EA_UNUSED(testMsg);
|
||||
EA_UNUSED(expectToBeSet);
|
||||
|
||||
EA_ASSERT_M(4 == 4, testMsg);
|
||||
EA_ASSERT_MESSAGE(4 == 4, testMsg);
|
||||
EA_ASSERT_MSG(4 == 4, testMsg);
|
||||
EA_ASSERT_FORMATTED(8 == 8, ("The quick brown fox jumps over the %s dog.", "lazy"));
|
||||
EA_ASSERT(3 % 8 == 3);
|
||||
|
||||
|
||||
expectToBeSet = 0;
|
||||
if (0)
|
||||
EA_ASSERT(0);
|
||||
else
|
||||
expectToBeSet = 1;
|
||||
EA_ASSERT(expectToBeSet == 1);
|
||||
|
||||
EA_PANIC_M(4 == 4, testMsg);
|
||||
EA_PANIC_MESSAGE(4 == 4, testMsg);
|
||||
EA_PANIC_MSG(4 == 4, testMsg);
|
||||
EA_PANIC_FORMATTED(8 == 8, ("The quick brown fox jumps over the %s dog.", "lazy"));
|
||||
EA_PANIC(3 % 8 == 3);
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
tags
|
||||
cscope.out
|
||||
**/*.swp
|
||||
**/*.swo
|
||||
.swp
|
||||
*.swp
|
||||
.swo
|
||||
.TMP
|
||||
-.d
|
||||
eastl_build_out
|
||||
build_bench
|
||||
bench.bat
|
||||
build.bat
|
||||
.p4config
|
||||
|
||||
## CMake generated files
|
||||
CMakeCache.txt
|
||||
cmake_install.cmake
|
||||
|
||||
## Patch files
|
||||
*.patch
|
||||
|
||||
## For Visual Studio Generated projects
|
||||
*.sln
|
||||
**/*.vcxproj
|
||||
**/*.vcxproj.filters
|
||||
*.VC.opendb
|
||||
*.sdf
|
||||
**/*.suo
|
||||
**/*.user
|
||||
.vs/*
|
||||
**/Debug/*
|
||||
CMakeFiles/*
|
||||
EASTL.dir/**
|
||||
RelWithDebInfo/*
|
||||
Release/*
|
||||
Win32/*
|
||||
x64/*
|
||||
MinSizeRel/*
|
||||
build*/*
|
||||
Testing/*
|
||||
%ALLUSERSPROFILE%/*
|
||||
|
||||
# Buck
|
||||
/buck-out/
|
||||
/.buckd/
|
||||
/buckaroo/
|
||||
.buckconfig.local
|
||||
BUCKAROO_DEPS
|
||||
@@ -0,0 +1,18 @@
|
||||
[submodule "test/packages/EAMain"]
|
||||
path = test/packages/EAMain
|
||||
url = git@github.com:electronicarts/EAMain.git
|
||||
[submodule "test/packages/EATest"]
|
||||
path = test/packages/EATest
|
||||
url = git@github.com:electronicarts/EATest.git
|
||||
[submodule "test/packages/EAStdC"]
|
||||
path = test/packages/EAStdC
|
||||
url = git@github.com:electronicarts/EAStdC.git
|
||||
[submodule "test/packages/EAAssert"]
|
||||
path = test/packages/EAAssert
|
||||
url = git@github.com:electronicarts/EAAssert.git
|
||||
[submodule "test/packages/EAThread"]
|
||||
path = test/packages/EAThread
|
||||
url = git@github.com:electronicarts/EAThread.git
|
||||
[submodule "test/packages/EASTL"]
|
||||
path = test/packages/EASTL
|
||||
url = git@github.com:electronicarts/EASTL.git
|
||||
@@ -0,0 +1,4 @@
|
||||
tags
|
||||
|
||||
.p4config
|
||||
/.git/
|
||||
@@ -0,0 +1,68 @@
|
||||
language: cpp
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
- windows
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
- msvc
|
||||
|
||||
env:
|
||||
- EA_CONFIG=Debug
|
||||
- EA_CONFIG=Release
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- george-edison55-precise-backports
|
||||
- llvm-toolchain-trusty-7
|
||||
packages:
|
||||
- cmake
|
||||
- cmake-data
|
||||
- g++-7
|
||||
- clang-7
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- os: osx
|
||||
compiler: gcc
|
||||
- os: osx
|
||||
compiler: msvc
|
||||
- os: linux
|
||||
compiler: msvc
|
||||
- os: windows
|
||||
compiler: clang
|
||||
- os: windows
|
||||
compiler: gcc
|
||||
|
||||
# Handle git submodules yourself
|
||||
git:
|
||||
submodules: false
|
||||
|
||||
# Use sed to replace the SSH URL with the public URL, then initialize submodules
|
||||
before_install:
|
||||
- sed --version >/dev/null 2>&1 && sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules || sed -i "" 's/git@github.com:/https:\/\/github.com\//' .gitmodules
|
||||
- git submodule update --init
|
||||
|
||||
install:
|
||||
- if [[ "$CXX" == "g++" ]]; then export CC="gcc-7" ;fi
|
||||
- if [[ "$CXX" == "g++" ]]; then export CXX="g++-7" ;fi
|
||||
- if [[ "$CXX" == "clang++" && "${TRAVIS_OS_NAME}" != "osx" ]]; then export CC="clang-7" ;fi
|
||||
- if [[ "$CXX" == "clang++" && "${TRAVIS_OS_NAME}" != "osx" ]]; then export CXX="clang++-7" ;fi
|
||||
|
||||
# Universal Setup
|
||||
before_script:
|
||||
- mkdir build_$EA_CONFIG
|
||||
- cd build_$EA_CONFIG
|
||||
- cmake .. -DEABASE_BUILD_TESTS:BOOL=ON
|
||||
- cmake --build . --config $EA_CONFIG
|
||||
|
||||
script:
|
||||
# Run Tests
|
||||
- cd $TRAVIS_BUILD_DIR/build_$EA_CONFIG/test
|
||||
- ctest -C $EA_CONFIG -V || exit 1
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Copyright (C) Electronic Arts Inc. All rights reserved.
|
||||
#-------------------------------------------------------------------------------------------
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
project(EABase CXX)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Options
|
||||
#-------------------------------------------------------------------------------------------
|
||||
option(EABASE_BUILD_TESTS "Enable generation of build files for tests" OFF)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Package Tests
|
||||
#-------------------------------------------------------------------------------------------
|
||||
if(EABASE_BUILD_TESTS)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Defines
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_definitions(-D_CHAR16T)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Header only library
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_library(EABase INTERFACE)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Include dirs
|
||||
#-------------------------------------------------------------------------------------------
|
||||
target_include_directories(EABase INTERFACE include/Common)
|
||||
@@ -0,0 +1,73 @@
|
||||
## Contributing
|
||||
|
||||
Before you can contribute, EA must have a Contributor License Agreement (CLA) on file that has been signed by each contributor.
|
||||
You can sign here: [Go to CLA](https://electronicarts.na1.echosign.com/public/esignWidget?wid=CBFCIBAA3AAABLblqZhByHRvZqmltGtliuExmuV-WNzlaJGPhbSRg2ufuPsM3P0QmILZjLpkGslg24-UJtek*)
|
||||
|
||||
### Pull Request Policy
|
||||
|
||||
All code contributions are submitted as [Github pull requests](https://help.github.com/articles/using-pull-requests/). All pull requests will be reviewed by a maintainer according to the guidelines found in the next section.
|
||||
|
||||
Your pull request should:
|
||||
|
||||
* merge cleanly
|
||||
* come with tests
|
||||
* tests should be minimal and stable
|
||||
* fail before your fix is applied
|
||||
* pass the test suite
|
||||
* code formatting is encoded in clang format
|
||||
* limit using clang format on new code
|
||||
* do not deviate from style already established in the files
|
||||
|
||||
|
||||
### Running the Unit Tests
|
||||
|
||||
EAAssert uses CMake as its build system.
|
||||
|
||||
* Create and navigate to "your_build_folder":
|
||||
* mkdir your_build_folder && cd your_build_folder
|
||||
* Generate build scripts:
|
||||
* cmake source_folder -DEABASE_BUILD_TESTS:BOOL=ON
|
||||
* Build unit tests for "your_config":
|
||||
* cmake --build . --config your_config
|
||||
* Run the unit tests for "your_config" from the test folder:
|
||||
* cd test && ctest -C your_config
|
||||
|
||||
|
||||
Here is an example batch file.
|
||||
```batch
|
||||
set build_folder=out
|
||||
mkdir %build_folder%
|
||||
pushd %build_folder%
|
||||
call cmake .. -DEABASE_BUILD_TESTS:BOOL=ON
|
||||
call cmake --build . --config Release
|
||||
call cmake --build . --config Debug
|
||||
call cmake --build . --config RelWithDebInfo
|
||||
call cmake --build . --config MinSizeRel
|
||||
pushd test
|
||||
call ctest -C Release
|
||||
call ctest -C Debug
|
||||
call ctest -C RelWithDebInfo
|
||||
call ctest -C MinSizeRel
|
||||
popd
|
||||
popd
|
||||
```
|
||||
|
||||
Here is an example bash file
|
||||
```bash
|
||||
build_folder=out
|
||||
mkdir $build_folder
|
||||
pushd $build_folder
|
||||
cmake .. -DEABASE_BUILD_TESTS:BOOL=ON
|
||||
cmake --build . --config Release
|
||||
cmake --build . --config Debug
|
||||
cmake --build . --config RelWithDebInfo
|
||||
cmake --build . --config MinSizeRel
|
||||
pushd test
|
||||
ctest -C Release
|
||||
ctest -C Debug
|
||||
ctest -C RelWithDebInfo
|
||||
ctest -C MinSizeRel
|
||||
popd
|
||||
popd
|
||||
```
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright (C) 2017 Electronic Arts Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of
|
||||
its contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
@@ -0,0 +1,26 @@
|
||||
# EABase
|
||||
|
||||
[](https://travis-ci.org/electronicarts/EABase)
|
||||
|
||||
EABase is a small set of header files that define platform-independent data types and macros.
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
Please see [Introduction](doc/EABase.html).
|
||||
|
||||
|
||||
## Compiling sources
|
||||
|
||||
Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on compiling and testing the source.
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
Roberto Parolin is the current EABase owner within EA and is responsible for the open source repository.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Modified BSD License (3-Clause BSD license) see the file LICENSE in the project root.
|
||||
|
||||
@@ -0,0 +1,309 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>EABase Future Plans</title>
|
||||
<style type="text/css">
|
||||
.SmallBody{
|
||||
font-size: 10pt
|
||||
}
|
||||
|
||||
body
|
||||
{
|
||||
font-family: Palatino Linotype, Book Antiqua, Times New Roman;
|
||||
font-size: 11pt;
|
||||
}
|
||||
|
||||
h1
|
||||
{
|
||||
font-family: Verdana;
|
||||
display: block;
|
||||
background-color: #FFF0B0;
|
||||
border: solid 2px black;
|
||||
font-size: 16pt;
|
||||
font-weight: bold;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
h2
|
||||
{
|
||||
font-size: 14pt;
|
||||
font-family: Verdana;
|
||||
border-bottom: 2px solid black;
|
||||
}
|
||||
|
||||
h3
|
||||
{
|
||||
font-family: Verdana;
|
||||
font-size: 13pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.code-example
|
||||
{
|
||||
display: block;
|
||||
background-color: #e0e0f0;
|
||||
margin-left: 3em;
|
||||
margin-right: 3em;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
padding: 8px;
|
||||
border: solid 2px #a0a0d0;
|
||||
font-family: monospace;
|
||||
font-size: 10pt;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.code-example-span
|
||||
{
|
||||
font-family: monospace;
|
||||
font-size: 10pt;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.code-example-comment
|
||||
{
|
||||
background-color: #e0e0f0;
|
||||
padding: 0px 0px;
|
||||
font-family: monospace;
|
||||
font-size: 10pt;
|
||||
white-space: pre;
|
||||
color: #999999;
|
||||
margin: auto auto;
|
||||
}
|
||||
|
||||
|
||||
.faq-question
|
||||
{
|
||||
background-color: #D0E0D0;
|
||||
font-size: 12pt;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.5em;
|
||||
margin-top: 0em;
|
||||
padding-left:8px;
|
||||
padding-right:8px;
|
||||
padding-top:2px;
|
||||
padding-bottom:2px
|
||||
}
|
||||
|
||||
.faq-answer
|
||||
{
|
||||
display: block;
|
||||
margin: 4pt 1em 0.5em 1em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>EABase
|
||||
</h1>
|
||||
<h3>What is EABase?
|
||||
</h3>
|
||||
<p>EABase is a small set of header files that define platform-independent
|
||||
data types and macros. As such it is similar to many projects that have
|
||||
a platform.h, system.h, defines.h, etc. file. The difference is that
|
||||
EABase is very comprehensive and is the annointed Electronic Arts
|
||||
worldwide standard for new projects. </p>
|
||||
<p>With respect to the base types and definitions, many of these are
|
||||
already present in the most recent C language standard, though the C++
|
||||
standard has yet to formally adopt them. EABase bridges the gap and
|
||||
defines these values if they aren't already defined. With respect to
|
||||
compiler and platform definitions, EABase provides a standard reliable
|
||||
means of identifying or specifying compilers, platforms, endian-ness,
|
||||
alignment attributes, etc. </p>
|
||||
<h3>Usage notes </h3>
|
||||
<p>You probably don't want to use float_t and double_t. They are there for C99 compatibility but are rarely what you want to use, since their size is variable.</p>
|
||||
<p>Prid8, etc. are somewhat painful and ugly to use and you may find you don't like them. They too are for C99 compatibility.</p>
|
||||
<p>intptr_t is not a pointer to an int; it's an int with the same size as a pointer, so you can safely store pointers in it.</p>
|
||||
<p>EA::result_type is rarely used and exists for backwards compatibility.</p>
|
||||
<h3>What specifically does EABase define?</h3>
|
||||
<p>Here we list the things EABase defines, grouped by category. These
|
||||
defines are up to date as of the file modification date listed at the
|
||||
top of this file.</p>
|
||||
<h4>Base Types and Definitions<br>
|
||||
|
||||
</h4>
|
||||
|
||||
<div style="margin-left: 40px;">bool8_t, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t, float_t, double_t, (EAStdC package implements int128_t)<br>
|
||||
|
||||
intptr_t, uintptr_t, intmax_t, uintmax_t, ssize_t<br>
|
||||
|
||||
char8_t, char16_t, char32_t<br>
|
||||
|
||||
INT8_C(), UINT8_C(), etc.<br>
|
||||
|
||||
INT8_MIN, INT8_MAX, UINT8_MAX, etc.<br>
|
||||
|
||||
PRId8, PRId16, PRId32, etc, SCNd8, SCNd16, SCNd32, etc.</div>
|
||||
|
||||
<h4>Result Types and Definitions<br>
|
||||
|
||||
</h4>
|
||||
|
||||
<div style="margin-left: 40px;">EA::result_type<br>
|
||||
|
||||
EA::SUCCESS, EA::FAILURE<br>
|
||||
|
||||
EA_SUCCEEDED(), EA_FAILED()</div>
|
||||
|
||||
<h4>Compiler Definitions<br>
|
||||
|
||||
</h4>
|
||||
|
||||
<div style="margin-left: 40px;">EA_COMPILER_GNUC<br>
|
||||
|
||||
EA_COMPILER_SN<br>
|
||||
|
||||
EA_COMPILER_MSVC<br>
|
||||
|
||||
EA_COMPILER_METROWERKS<br>
|
||||
|
||||
EA_COMPILER_INTEL<br>
|
||||
|
||||
EA_COMPILER_BORLANDC<br>
|
||||
|
||||
<br>
|
||||
|
||||
EA_COMPILER_VERSION = <integer><br>
|
||||
|
||||
EA_COMPILER_NAME = <string><br>
|
||||
|
||||
EA_COMPILER_STRING = <string><br>
|
||||
|
||||
<br>
|
||||
|
||||
EA_COMPILER_NO_STATIC_CONSTANTS<br>
|
||||
|
||||
EA_COMPILER_NO_TEMPLATE_SPECIALIZATION<br>
|
||||
|
||||
EA_COMPILER_NO_TEMPLATE_PARTIAL_SPECIALIZATION<br>
|
||||
|
||||
EA_COMPILER_NO_MEMBER_TEMPLATES<br>
|
||||
|
||||
EA_COMPILER_NO_MEMBER_TEMPLATE_SPECIALIZATION<br>
|
||||
|
||||
EA_COMPILER_NO_TEMPLATE_TEMPLATES<br>
|
||||
|
||||
EA_COMPILER_NO_MEMBER_TEMPLATE_FRIENDS<br>
|
||||
|
||||
EA_COMPILER_NO_VOID_RETURNS<br>
|
||||
|
||||
EA_COMPILER_NO_COVARIANT_RETURN_TYPE<br>
|
||||
|
||||
EA_COMPILER_NO_DEDUCED_TYPENAME<br>
|
||||
|
||||
EA_COMPILER_NO_ARGUMENT_DEPENDENT_LOOKUP<br>
|
||||
|
||||
EA_COMPILER_NO_EXCEPTION_STD_NAMESPACE<br>
|
||||
|
||||
EA_COMPILER_NO_EXPLICIT_FUNCTION_TEMPLATE_ARGUMENTS<br>
|
||||
|
||||
EA_COMPILER_NO_EXCEPTIONS<br>
|
||||
|
||||
EA_COMPILER_NO_UNWIND<br>
|
||||
|
||||
<br>
|
||||
|
||||
EA_COMPILER_IS_ANSIC<br>
|
||||
|
||||
EA_COMPILER_IS_C99<br>
|
||||
|
||||
EA_COMPILER_HAS_C99_TYPES<br>
|
||||
EA_COMPILER_IS_CPLUSPLUS<br>
|
||||
|
||||
EA_COMPILER_MANAGED_CPP</div>
|
||||
<h4>Utilities<br>
|
||||
</h4>
|
||||
<div style="margin-left: 40px;">
|
||||
|
||||
<p>EA_ALIGN_OF()<br>
|
||||
EA_PREFIX_ALIGN()<br>
|
||||
|
||||
EA_POSTFIX_ALIGN()<br>
|
||||
EA_ALIGNED()<br>
|
||||
|
||||
EA_PACKED()<br>
|
||||
EA_LIKELY()<br>
|
||||
EA_UNLIKELY()<br>
|
||||
EA_ASSUME()<br>
|
||||
EA_PURE<br>
|
||||
EA_WCHAR_T_NON_NATIVE<br>
|
||||
|
||||
EA_WCHAR_SIZE<br>
|
||||
EA_RESTRICT<br>
|
||||
EA_DEPRECATED<br>
|
||||
EA_PREFIX_DEPRECATED<br>
|
||||
EA_POSTFIX_DEPRECATED <br>
|
||||
EA_FORCE_INLINE<br>
|
||||
EA_NO_INLINE<br>
|
||||
EA_PREFIX_NO_INLINE<br>
|
||||
EA_POSTFIX_NO_INLINE <br>
|
||||
EA_PASCAL<br>
|
||||
|
||||
EA_PASCAL_FUNC()<br>
|
||||
|
||||
EA_SSE = [0 | 1]<br>
|
||||
|
||||
EA_IMPORT<br>
|
||||
|
||||
EA_EXPORT<br>
|
||||
EA_OVERRIDE<br>
|
||||
EA_INIT_PRIORITY<br>
|
||||
EA_MAY_ALIAS<br>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<h4>Platform Definitions<br>
|
||||
|
||||
</h4>
|
||||
|
||||
<div style="margin-left: 40px;"><br>
|
||||
|
||||
|
||||
EA_PLATFORM_MAC<br>
|
||||
|
||||
EA_PLATFORM_OSX<br>
|
||||
EA_PLATFORM_IPHONE<br>
|
||||
EA_PLATFORM_ANDROID<br>
|
||||
EA_PLATFORM_LINUX<br>
|
||||
|
||||
EA_PLATFORM_WINDOWS<br>
|
||||
|
||||
EA_PLATFORM_WIN32<br>
|
||||
|
||||
EA_PLATFORM_WIN64<br>
|
||||
|
||||
EA_PLATFORM_HPUX<br>
|
||||
|
||||
EA_PLATFORM_SUN<br>
|
||||
|
||||
<br>
|
||||
|
||||
EA_PLATFORM_NAME<br>
|
||||
|
||||
EA_PLATFORM_DESCRIPTION<br>
|
||||
|
||||
EA_PROCESSOR_POWERPC, EA_PROCESSOR_X86, EA_PROCESSOR_ARM, etc.<br>
|
||||
|
||||
EA_SYSTEM_LITTLE_ENDIAN, EA_SYSTEM_BIG_ENDIAN<br>
|
||||
|
||||
EA_ASM_STYLE_ATT, EA_ASM_STYLE_INTEL, EA_ASM_STYLE_MOTOROLA<br>
|
||||
|
||||
EA_PLATFORM_PTR_SIZE<br>
|
||||
EA_PLATFORM_WORD_SIZE</div>
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
<hr style="width: 100%; height: 2px;"><br>
|
||||
|
||||
<br>
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
|
||||
|
||||
</body>
|
||||
</html>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,738 @@
|
||||
/*-----------------------------------------------------------------------------
|
||||
* config/eaplatform.h
|
||||
*
|
||||
* Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
*-----------------------------------------------------------------------------
|
||||
* Currently supported platform indentification defines include:
|
||||
*/
|
||||
#ifdef EA_PLATFORM_PS4 // ifdef for code stripping purposes
|
||||
// EA_PLATFORM_PS4 (EA_PLATFORM_KETTLE)
|
||||
#endif
|
||||
#ifdef EA_PLATFORM_XBOXONE // ifdef for code stripping purposes
|
||||
// EA_PLATFORM_XBOXONE (EA_PLATFORM_CAPILANO)
|
||||
// EA_PLATFORM_XBOXONE_XDK (EA_PLATFORM_CAPILANO_XDK), set by capilano_config package
|
||||
// EA_PLATFORM_XBOXONE_ADK (EA_PLATFORM_CAPILANO_ADK), set by capilano_config package
|
||||
#endif
|
||||
// EA_PLATFORM_ANDROID
|
||||
// EA_PLATFORM_APPLE
|
||||
// EA_PLATFORM_IPHONE
|
||||
// EA_PLATFORM_IPHONE_SIMULATOR
|
||||
// EA_PLATFORM_OSX
|
||||
// EA_PLATFORM_LINUX
|
||||
// EA_PLATFORM_SAMSUNG_TV
|
||||
// EA_PLATFORM_WINDOWS
|
||||
// EA_PLATFORM_WIN32
|
||||
// EA_PLATFORM_WIN64
|
||||
// EA_PLATFORM_WINDOWS_PHONE
|
||||
// EA_PLATFORM_WINRT
|
||||
// EA_PLATFORM_SUN
|
||||
// EA_PLATFORM_LRB (Larrabee)
|
||||
// EA_PLATFORM_POSIX (pseudo-platform; may be defined along with another platform like EA_PLATFORM_LINUX, EA_PLATFORM_UNIX, EA_PLATFORM_QNX)
|
||||
// EA_PLATFORM_UNIX (pseudo-platform; may be defined along with another platform like EA_PLATFORM_LINUX)
|
||||
// EA_PLATFORM_CYGWIN (pseudo-platform; may be defined along with another platform like EA_PLATFORM_LINUX)
|
||||
// EA_PLATFORM_MINGW (pseudo-platform; may be defined along with another platform like EA_PLATFORM_WINDOWS)
|
||||
// EA_PLATFORM_MICROSOFT (pseudo-platform; may be defined along with another platform like EA_PLATFORM_WINDOWS)
|
||||
//
|
||||
// EA_ABI_ARM_LINUX (a.k.a. "eabi". for all platforms that use the CodeSourcery GNU/Linux toolchain, like Android)
|
||||
// EA_ABI_ARM_APPLE (similar to eabi but not identical)
|
||||
// EA_ABI_ARM64_APPLE (similar to eabi but not identical) https://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html
|
||||
// EA_ABI_ARM_WINCE (similar to eabi but not identical)
|
||||
//
|
||||
// Other definitions emanated from this file inclue:
|
||||
// EA_PLATFORM_NAME = <string>
|
||||
// EA_PLATFORM_DESCRIPTION = <string>
|
||||
// EA_PROCESSOR_XXX
|
||||
// EA_MISALIGNED_SUPPORT_LEVEL=0|1|2
|
||||
// EA_SYSTEM_LITTLE_ENDIAN | EA_SYSTEM_BIG_ENDIAN
|
||||
// EA_ASM_STYLE_ATT | EA_ASM_STYLE_INTEL | EA_ASM_STYLE_MOTOROLA
|
||||
// EA_PLATFORM_PTR_SIZE = <integer size in bytes>
|
||||
// EA_PLATFORM_WORD_SIZE = <integer size in bytes>
|
||||
// EA_CACHE_LINE_SIZE = <integer size in bytes>
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
/*
|
||||
EA_PLATFORM_MOBILE
|
||||
EA_PLATFORM_MOBILE is a peer to EA_PLATORM_DESKTOP and EA_PLATFORM_CONSOLE. Their definition is qualitative rather
|
||||
than quantitative, and refers to the general (usually weaker) capabilities of the machine. Mobile devices have a
|
||||
similar set of weaknesses that are useful to generally categorize. The primary motivation is to avoid code that
|
||||
tests for multiple mobile platforms on a line and needs to be updated every time we get a new one.
|
||||
For example, mobile platforms tend to have weaker ARM processors, don't have full multiple processor support,
|
||||
are hand-held, don't have mice (though may have touch screens or basic cursor controls), have writable solid
|
||||
state permanent storage. Production user code shouldn't have too many expectations about the meaning of this define.
|
||||
|
||||
EA_PLATFORM_DESKTOP
|
||||
This is similar to EA_PLATFORM_MOBILE in its qualitative nature and refers to platforms that are powerful.
|
||||
For example, they nearly always have virtual memory, mapped memory, hundreds of GB of writable disk storage,
|
||||
TCP/IP network connections, mice, keyboards, 512+ MB of RAM, multiprocessing, multiple display support.
|
||||
Production user code shouldn't have too many expectations about the meaning of this define.
|
||||
|
||||
EA_PLATFORM_CONSOLE
|
||||
This is similar to EA_PLATFORM_MOBILE in its qualitative nature and refers to platforms that are consoles.
|
||||
This means platforms that are connected to TVs, are fairly powerful (especially graphics-wise), are tightly
|
||||
controlled by vendors, tend not to have mapped memory, tend to have TCP/IP, don't have multiple process support
|
||||
though they might have multiple CPUs, support TV output only. Production user code shouldn't have too many
|
||||
expectations about the meaning of this define.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef INCLUDED_eaplatform_H
|
||||
#define INCLUDED_eaplatform_H
|
||||
|
||||
|
||||
// Cygwin
|
||||
// This is a pseudo-platform which will be defined along with EA_PLATFORM_LINUX when
|
||||
// using the Cygwin build environment.
|
||||
#if defined(__CYGWIN__)
|
||||
#define EA_PLATFORM_CYGWIN 1
|
||||
#define EA_PLATFORM_DESKTOP 1
|
||||
#endif
|
||||
|
||||
// MinGW
|
||||
// This is a pseudo-platform which will be defined along with EA_PLATFORM_WINDOWS when
|
||||
// using the MinGW Windows build environment.
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
#define EA_PLATFORM_MINGW 1
|
||||
#define EA_PLATFORM_DESKTOP 1
|
||||
#endif
|
||||
|
||||
#if defined(EA_PLATFORM_PS4) || defined(__ORBIS__) || defined(EA_PLATFORM_KETTLE)
|
||||
// PlayStation 4
|
||||
// Orbis was Sony's code-name for the platform, which is now obsolete.
|
||||
// Kettle was an EA-specific code-name for the platform, which is now obsolete.
|
||||
#if defined(EA_PLATFORM_PS4)
|
||||
#undef EA_PLATFORM_PS4
|
||||
#endif
|
||||
#define EA_PLATFORM_PS4 1
|
||||
|
||||
// Backward compatibility:
|
||||
#if defined(EA_PLATFORM_KETTLE)
|
||||
#undef EA_PLATFORM_KETTLE
|
||||
#endif
|
||||
// End backward compatbility
|
||||
|
||||
#define EA_PLATFORM_KETTLE 1
|
||||
#define EA_PLATFORM_NAME "PS4"
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "PS4 on x64"
|
||||
#define EA_PLATFORM_CONSOLE 1
|
||||
#define EA_PLATFORM_SONY 1
|
||||
#define EA_PLATFORM_POSIX 1
|
||||
// #define EA_POSIX_THREADS_AVAILABLE 1 // POSIX threading API is available but discouraged. Sony indicated use of the scePthreads* API is preferred.
|
||||
#define EA_PROCESSOR_X86_64 1
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#define EA_ASM_STYLE_ATT 1
|
||||
#endif
|
||||
|
||||
#elif defined(EA_PLATFORM_XBOXONE) || defined(_DURANGO) || defined(_XBOX_ONE) || defined(EA_PLATFORM_CAPILANO) || defined(_GAMING_XBOX)
|
||||
// XBox One
|
||||
// Durango was Microsoft's code-name for the platform, which is now obsolete.
|
||||
// Microsoft uses _DURANGO instead of some variation of _XBOX, though it's not natively defined by the compiler.
|
||||
// Capilano was an EA-specific code-name for the platform, which is now obsolete.
|
||||
#if defined(EA_PLATFORM_XBOXONE)
|
||||
#undef EA_PLATFORM_XBOXONE
|
||||
#endif
|
||||
#define EA_PLATFORM_XBOXONE 1
|
||||
|
||||
// Backward compatibility:
|
||||
#if defined(EA_PLATFORM_CAPILANO)
|
||||
#undef EA_PLATFORM_CAPILANO
|
||||
#endif
|
||||
#define EA_PLATFORM_CAPILANO 1
|
||||
#if defined(EA_PLATFORM_CAPILANO_XDK) && !defined(EA_PLATFORM_XBOXONE_XDK)
|
||||
#define EA_PLATFORM_XBOXONE_XDK 1
|
||||
#endif
|
||||
#if defined(EA_PLATFORM_CAPILANO_ADK) && !defined(EA_PLATFORM_XBOXONE_ADK)
|
||||
#define EA_PLATFORM_XBOXONE_ADK 1
|
||||
#endif
|
||||
// End backward compatibility
|
||||
|
||||
#if !defined(_DURANGO)
|
||||
#define _DURANGO
|
||||
#endif
|
||||
#define EA_PLATFORM_NAME "XBox One"
|
||||
//#define EA_PROCESSOR_X86 Currently our policy is that we don't define this, even though x64 is something of a superset of x86.
|
||||
#define EA_PROCESSOR_X86_64 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "XBox One on x64"
|
||||
#define EA_ASM_STYLE_INTEL 1
|
||||
#define EA_PLATFORM_CONSOLE 1
|
||||
#define EA_PLATFORM_MICROSOFT 1
|
||||
|
||||
// WINAPI_FAMILY defines - mirrored from winapifamily.h
|
||||
#define EA_WINAPI_FAMILY_APP 1000
|
||||
#define EA_WINAPI_FAMILY_DESKTOP_APP 1001
|
||||
#define EA_WINAPI_FAMILY_PHONE_APP 1002
|
||||
#define EA_WINAPI_FAMILY_TV_APP 1003
|
||||
#define EA_WINAPI_FAMILY_TV_TITLE 1004
|
||||
#define EA_WINAPI_FAMILY_GAMES 1006
|
||||
|
||||
#if defined(WINAPI_FAMILY)
|
||||
#include <winapifamily.h>
|
||||
#if defined(WINAPI_FAMILY_TV_TITLE) && WINAPI_FAMILY == WINAPI_FAMILY_TV_TITLE
|
||||
#define EA_WINAPI_FAMILY EA_WINAPI_FAMILY_TV_TITLE
|
||||
#elif defined(WINAPI_FAMILY_DESKTOP_APP) && WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP
|
||||
#define EA_WINAPI_FAMILY EA_WINAPI_FAMILY_DESKTOP_APP
|
||||
#elif defined(WINAPI_FAMILY_GAMES) && WINAPI_FAMILY == WINAPI_FAMILY_GAMES
|
||||
#define EA_WINAPI_FAMILY EA_WINAPI_FAMILY_GAMES
|
||||
#else
|
||||
#error Unsupported WINAPI_FAMILY
|
||||
#endif
|
||||
#else
|
||||
#error WINAPI_FAMILY should always be defined on Capilano.
|
||||
#endif
|
||||
|
||||
// Macro to determine if a partition is enabled.
|
||||
#define EA_WINAPI_FAMILY_PARTITION(Partition) (Partition)
|
||||
|
||||
#if EA_WINAPI_FAMILY == EA_WINAPI_FAMILY_DESKTOP_APP
|
||||
#define EA_WINAPI_PARTITION_CORE 1
|
||||
#define EA_WINAPI_PARTITION_DESKTOP 1
|
||||
#define EA_WINAPI_PARTITION_APP 1
|
||||
#define EA_WINAPI_PARTITION_PC_APP 0
|
||||
#define EA_WIANPI_PARTITION_PHONE 0
|
||||
#define EA_WINAPI_PARTITION_TV_APP 0
|
||||
#define EA_WINAPI_PARTITION_TV_TITLE 0
|
||||
#define EA_WINAPI_PARTITION_GAMES 0
|
||||
#elif EA_WINAPI_FAMILY == EA_WINAPI_FAMILY_TV_TITLE
|
||||
#define EA_WINAPI_PARTITION_CORE 1
|
||||
#define EA_WINAPI_PARTITION_DESKTOP 0
|
||||
#define EA_WINAPI_PARTITION_APP 0
|
||||
#define EA_WINAPI_PARTITION_PC_APP 0
|
||||
#define EA_WIANPI_PARTITION_PHONE 0
|
||||
#define EA_WINAPI_PARTITION_TV_APP 0
|
||||
#define EA_WINAPI_PARTITION_TV_TITLE 1
|
||||
#define EA_WINAPI_PARTITION_GAMES 0
|
||||
#elif EA_WINAPI_FAMILY == EA_WINAPI_FAMILY_GAMES
|
||||
#define EA_WINAPI_PARTITION_CORE 1
|
||||
#define EA_WINAPI_PARTITION_DESKTOP 0
|
||||
#define EA_WINAPI_PARTITION_APP 0
|
||||
#define EA_WINAPI_PARTITION_PC_APP 0
|
||||
#define EA_WIANPI_PARTITION_PHONE 0
|
||||
#define EA_WINAPI_PARTITION_TV_APP 0
|
||||
#define EA_WINAPI_PARTITION_TV_TITLE 0
|
||||
#define EA_WINAPI_PARTITION_GAMES 1
|
||||
#else
|
||||
#error Unsupported WINAPI_FAMILY
|
||||
#endif
|
||||
|
||||
#if EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_GAMES)
|
||||
#define CS_UNDEFINED_STRING 1
|
||||
#define CS_UNDEFINED_STRING 1
|
||||
#endif
|
||||
|
||||
#if EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_TV_TITLE)
|
||||
#define EA_PLATFORM_XBOXONE_XDK 1
|
||||
#endif
|
||||
#elif defined(EA_PLATFORM_LRB) || defined(__LRB__) || (defined(__EDG__) && defined(__ICC) && defined(__x86_64__))
|
||||
#undef EA_PLATFORM_LRB
|
||||
#define EA_PLATFORM_LRB 1
|
||||
#define EA_PLATFORM_NAME "Larrabee"
|
||||
#define EA_PLATFORM_DESCRIPTION "Larrabee on LRB1"
|
||||
#define EA_PROCESSOR_X86_64 1
|
||||
#if defined(BYTE_ORDER) && (BYTE_ORDER == 4321)
|
||||
#define EA_SYSTEM_BIG_ENDIAN 1
|
||||
#else
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define EA_PROCESSOR_LRB 1
|
||||
#define EA_PROCESSOR_LRB1 1 // Larrabee version 1
|
||||
#define EA_ASM_STYLE_ATT 1 // Both types of asm style
|
||||
#define EA_ASM_STYLE_INTEL 1 // are supported.
|
||||
#define EA_PLATFORM_DESKTOP 1
|
||||
|
||||
// Android (Google phone OS)
|
||||
#elif defined(EA_PLATFORM_ANDROID) || defined(__ANDROID__)
|
||||
#undef EA_PLATFORM_ANDROID
|
||||
#define EA_PLATFORM_ANDROID 1
|
||||
#define EA_PLATFORM_LINUX 1
|
||||
#define EA_PLATFORM_UNIX 1
|
||||
#define EA_PLATFORM_POSIX 1
|
||||
#define EA_PLATFORM_NAME "Android"
|
||||
#define EA_ASM_STYLE_ATT 1
|
||||
#if defined(__arm__)
|
||||
#define EA_ABI_ARM_LINUX 1 // a.k.a. "ARM eabi"
|
||||
#define EA_PROCESSOR_ARM32 1
|
||||
#define EA_PLATFORM_DESCRIPTION "Android on ARM"
|
||||
#elif defined(__aarch64__)
|
||||
#define EA_PROCESSOR_ARM64 1
|
||||
#define EA_PLATFORM_DESCRIPTION "Android on ARM64"
|
||||
#elif defined(__i386__)
|
||||
#define EA_PROCESSOR_X86 1
|
||||
#define EA_PLATFORM_DESCRIPTION "Android on x86"
|
||||
#elif defined(__x86_64)
|
||||
#define EA_PROCESSOR_X86_64 1
|
||||
#define EA_PLATFORM_DESCRIPTION "Android on x64"
|
||||
#else
|
||||
#error Unknown processor
|
||||
#endif
|
||||
#if !defined(EA_SYSTEM_BIG_ENDIAN) && !defined(EA_SYSTEM_LITTLE_ENDIAN)
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#endif
|
||||
#define EA_PLATFORM_MOBILE 1
|
||||
|
||||
// Samsung SMART TV - a Linux-based smart TV
|
||||
#elif defined(EA_PLATFORM_SAMSUNG_TV)
|
||||
#undef EA_PLATFORM_SAMSUNG_TV
|
||||
#define EA_PLATFORM_SAMSUNG_TV 1
|
||||
#define EA_PLATFORM_LINUX 1
|
||||
#define EA_PLATFORM_UNIX 1
|
||||
#define EA_PLATFORM_POSIX 1
|
||||
#define EA_PLATFORM_NAME "SamsungTV"
|
||||
#define EA_PLATFORM_DESCRIPTION "Samsung SMART TV on ARM"
|
||||
#define EA_ASM_STYLE_ATT 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PROCESSOR_ARM32 1
|
||||
#define EA_ABI_ARM_LINUX 1 // a.k.a. "ARM eabi"
|
||||
#define EA_PROCESSOR_ARM7 1
|
||||
|
||||
#elif defined(__APPLE__) && __APPLE__
|
||||
#include <TargetConditionals.h>
|
||||
|
||||
// Apple family of operating systems.
|
||||
#define EA_PLATFORM_APPLE
|
||||
#define EA_PLATFORM_POSIX 1
|
||||
|
||||
// iPhone
|
||||
// TARGET_OS_IPHONE will be undefined on an unknown compiler, and will be defined on gcc.
|
||||
#if defined(EA_PLATFORM_IPHONE) || defined(__IPHONE__) || (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) || (defined(TARGET_IPHONE_SIMULATOR) && TARGET_IPHONE_SIMULATOR)
|
||||
#undef EA_PLATFORM_IPHONE
|
||||
#define EA_PLATFORM_IPHONE 1
|
||||
#define EA_PLATFORM_NAME "iPhone"
|
||||
#define EA_ASM_STYLE_ATT 1
|
||||
#define EA_POSIX_THREADS_AVAILABLE 1
|
||||
#if defined(__arm__)
|
||||
#define EA_ABI_ARM_APPLE 1
|
||||
#define EA_PROCESSOR_ARM32 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "iPhone on ARM"
|
||||
#elif defined(__aarch64__) || defined(__AARCH64)
|
||||
#define EA_ABI_ARM64_APPLE 1
|
||||
#define EA_PROCESSOR_ARM64 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "iPhone on ARM64"
|
||||
#elif defined(__i386__)
|
||||
#define EA_PLATFORM_IPHONE_SIMULATOR 1
|
||||
#define EA_PROCESSOR_X86 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "iPhone simulator on x86"
|
||||
#elif defined(__x86_64) || defined(__amd64)
|
||||
#define EA_PROCESSOR_X86_64 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "iPhone simulator on x64"
|
||||
#else
|
||||
#error Unknown processor
|
||||
#endif
|
||||
#define EA_PLATFORM_MOBILE 1
|
||||
|
||||
// Macintosh OSX
|
||||
// TARGET_OS_MAC is defined by the Metrowerks and older AppleC compilers.
|
||||
// Howerver, TARGET_OS_MAC is defined to be 1 in all cases.
|
||||
// __i386__ and __intel__ are defined by the GCC compiler.
|
||||
// __dest_os is defined by the Metrowerks compiler.
|
||||
// __MACH__ is defined by the Metrowerks and GCC compilers.
|
||||
// powerc and __powerc are defined by the Metrowerks and GCC compilers.
|
||||
#elif defined(EA_PLATFORM_OSX) || defined(__MACH__) || (defined(__MSL__) && (__dest_os == __mac_os_x))
|
||||
#undef EA_PLATFORM_OSX
|
||||
#define EA_PLATFORM_OSX 1
|
||||
#define EA_PLATFORM_UNIX 1
|
||||
#define EA_PLATFORM_POSIX 1
|
||||
//#define EA_PLATFORM_BSD 1 We don't currently define this. OSX has some BSD history but a lot of the API is different.
|
||||
#define EA_PLATFORM_NAME "OSX"
|
||||
#if defined(__i386__) || defined(__intel__)
|
||||
#define EA_PROCESSOR_X86 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "OSX on x86"
|
||||
#elif defined(__x86_64) || defined(__amd64)
|
||||
#define EA_PROCESSOR_X86_64 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "OSX on x64"
|
||||
#elif defined(__arm__)
|
||||
#define EA_ABI_ARM_APPLE 1
|
||||
#define EA_PROCESSOR_ARM32 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "OSX on ARM"
|
||||
#elif defined(__aarch64__) || defined(__AARCH64)
|
||||
#define EA_ABI_ARM64_APPLE 1
|
||||
#define EA_PROCESSOR_ARM64 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "OSX on ARM64"
|
||||
#elif defined(__POWERPC64__) || defined(__powerpc64__)
|
||||
#define EA_PROCESSOR_POWERPC 1
|
||||
#define EA_PROCESSOR_POWERPC_64 1
|
||||
#define EA_SYSTEM_BIG_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "OSX on PowerPC 64"
|
||||
#elif defined(__POWERPC__) || defined(__powerpc__)
|
||||
#define EA_PROCESSOR_POWERPC 1
|
||||
#define EA_PROCESSOR_POWERPC_32 1
|
||||
#define EA_SYSTEM_BIG_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "OSX on PowerPC"
|
||||
#else
|
||||
#error Unknown processor
|
||||
#endif
|
||||
#if defined(__GNUC__)
|
||||
#define EA_ASM_STYLE_ATT 1
|
||||
#else
|
||||
#define EA_ASM_STYLE_MOTOROLA 1
|
||||
#endif
|
||||
#define EA_PLATFORM_DESKTOP 1
|
||||
#else
|
||||
#error Unknown Apple Platform
|
||||
#endif
|
||||
|
||||
// Linux
|
||||
// __linux and __linux__ are defined by the GCC and Borland compiler.
|
||||
// __i386__ and __intel__ are defined by the GCC compiler.
|
||||
// __i386__ is defined by the Metrowerks compiler.
|
||||
// _M_IX86 is defined by the Borland compiler.
|
||||
// __sparc__ is defined by the GCC compiler.
|
||||
// __powerpc__ is defined by the GCC compiler.
|
||||
// __ARM_EABI__ is defined by GCC on an ARM v6l (Raspberry Pi 1)
|
||||
// __ARM_ARCH_7A__ is defined by GCC on an ARM v7l (Raspberry Pi 2)
|
||||
#elif defined(EA_PLATFORM_LINUX) || (defined(__linux) || defined(__linux__))
|
||||
#undef EA_PLATFORM_LINUX
|
||||
#define EA_PLATFORM_LINUX 1
|
||||
#define EA_PLATFORM_UNIX 1
|
||||
#define EA_PLATFORM_POSIX 1
|
||||
#define EA_PLATFORM_NAME "Linux"
|
||||
#if defined(__i386__) || defined(__intel__) || defined(_M_IX86)
|
||||
#define EA_PROCESSOR_X86 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "Linux on x86"
|
||||
#elif defined(__ARM_ARCH_7A__) || defined(__ARM_EABI__)
|
||||
#define EA_ABI_ARM_LINUX 1
|
||||
#define EA_PROCESSOR_ARM32 1
|
||||
#define EA_PLATFORM_DESCRIPTION "Linux on ARM 6/7 32-bits"
|
||||
#elif defined(__aarch64__) || defined(__AARCH64)
|
||||
#define EA_PROCESSOR_ARM64 1
|
||||
#define EA_PLATFORM_DESCRIPTION "Linux on ARM64"
|
||||
#elif defined(__x86_64__)
|
||||
#define EA_PROCESSOR_X86_64 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "Linux on x64"
|
||||
#elif defined(__powerpc64__)
|
||||
#define EA_PROCESSOR_POWERPC 1
|
||||
#define EA_PROCESSOR_POWERPC_64 1
|
||||
#define EA_SYSTEM_BIG_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "Linux on PowerPC 64"
|
||||
#elif defined(__powerpc__)
|
||||
#define EA_PROCESSOR_POWERPC 1
|
||||
#define EA_PROCESSOR_POWERPC_32 1
|
||||
#define EA_SYSTEM_BIG_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "Linux on PowerPC"
|
||||
#else
|
||||
#error Unknown processor
|
||||
#error Unknown endianness
|
||||
#endif
|
||||
#if defined(__GNUC__)
|
||||
#define EA_ASM_STYLE_ATT 1
|
||||
#endif
|
||||
#define EA_PLATFORM_DESKTOP 1
|
||||
|
||||
|
||||
#elif defined(EA_PLATFORM_BSD) || (defined(__BSD__) || defined(__FreeBSD__))
|
||||
#undef EA_PLATFORM_BSD
|
||||
#define EA_PLATFORM_BSD 1
|
||||
#define EA_PLATFORM_UNIX 1
|
||||
#define EA_PLATFORM_POSIX 1 // BSD's posix complaince is not identical to Linux's
|
||||
#define EA_PLATFORM_NAME "BSD Unix"
|
||||
#if defined(__i386__) || defined(__intel__)
|
||||
#define EA_PROCESSOR_X86 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "BSD on x86"
|
||||
#elif defined(__x86_64__)
|
||||
#define EA_PROCESSOR_X86_64 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "BSD on x64"
|
||||
#elif defined(__powerpc64__)
|
||||
#define EA_PROCESSOR_POWERPC 1
|
||||
#define EA_PROCESSOR_POWERPC_64 1
|
||||
#define EA_SYSTEM_BIG_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "BSD on PowerPC 64"
|
||||
#elif defined(__powerpc__)
|
||||
#define EA_PROCESSOR_POWERPC 1
|
||||
#define EA_PROCESSOR_POWERPC_32 1
|
||||
#define EA_SYSTEM_BIG_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "BSD on PowerPC"
|
||||
#else
|
||||
#error Unknown processor
|
||||
#error Unknown endianness
|
||||
#endif
|
||||
#if !defined(EA_PLATFORM_FREEBSD) && defined(__FreeBSD__)
|
||||
#define EA_PLATFORM_FREEBSD 1 // This is a variation of BSD.
|
||||
#endif
|
||||
#if defined(__GNUC__)
|
||||
#define EA_ASM_STYLE_ATT 1
|
||||
#endif
|
||||
#define EA_PLATFORM_DESKTOP 1
|
||||
|
||||
|
||||
#elif defined(EA_PLATFORM_WINDOWS_PHONE)
|
||||
#undef EA_PLATFORM_WINDOWS_PHONE
|
||||
#define EA_PLATFORM_WINDOWS_PHONE 1
|
||||
#define EA_PLATFORM_NAME "Windows Phone"
|
||||
#if defined(_M_AMD64) || defined(_AMD64_) || defined(__x86_64__)
|
||||
#define EA_PROCESSOR_X86_64 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "Windows Phone on x64"
|
||||
#elif defined(_M_IX86) || defined(_X86_)
|
||||
#define EA_PROCESSOR_X86 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "Windows Phone on X86"
|
||||
#elif defined(_M_ARM)
|
||||
#define EA_ABI_ARM_WINCE 1
|
||||
#define EA_PROCESSOR_ARM32 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "Windows Phone on ARM"
|
||||
#else //Possibly other Windows Phone variants
|
||||
#error Unknown processor
|
||||
#error Unknown endianness
|
||||
#endif
|
||||
#define EA_PLATFORM_MICROSOFT 1
|
||||
|
||||
// WINAPI_FAMILY defines - mirrored from winapifamily.h
|
||||
#define EA_WINAPI_FAMILY_APP 1
|
||||
#define EA_WINAPI_FAMILY_DESKTOP_APP 2
|
||||
#define EA_WINAPI_FAMILY_PHONE_APP 3
|
||||
|
||||
#if defined(WINAPI_FAMILY)
|
||||
#include <winapifamily.h>
|
||||
#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
|
||||
#define EA_WINAPI_FAMILY EA_WINAPI_FAMILY_PHONE_APP
|
||||
#else
|
||||
#error Unsupported WINAPI_FAMILY for Windows Phone
|
||||
#endif
|
||||
#else
|
||||
#error WINAPI_FAMILY should always be defined on Windows Phone.
|
||||
#endif
|
||||
|
||||
// Macro to determine if a partition is enabled.
|
||||
#define EA_WINAPI_FAMILY_PARTITION(Partition) (Partition)
|
||||
|
||||
// Enable the appropriate partitions for the current family
|
||||
#if EA_WINAPI_FAMILY == EA_WINAPI_FAMILY_PHONE_APP
|
||||
# define EA_WINAPI_PARTITION_CORE 1
|
||||
# define EA_WINAPI_PARTITION_PHONE 1
|
||||
# define EA_WINAPI_PARTITION_APP 1
|
||||
#else
|
||||
# error Unsupported WINAPI_FAMILY for Windows Phone
|
||||
#endif
|
||||
|
||||
|
||||
// Windows
|
||||
// _WIN32 is defined by the VC++, Intel and GCC compilers.
|
||||
// _WIN64 is defined by the VC++, Intel and GCC compilers.
|
||||
// __WIN32__ is defined by the Borland compiler.
|
||||
// __INTEL__ is defined by the Metrowerks compiler.
|
||||
// _M_IX86, _M_AMD64 and _M_IA64 are defined by the VC++, Intel, and Borland compilers.
|
||||
// _X86_, _AMD64_, and _IA64_ are defined by the Metrowerks compiler.
|
||||
// _M_ARM is defined by the VC++ compiler.
|
||||
#elif (defined(EA_PLATFORM_WINDOWS) || (defined(_WIN32) || defined(__WIN32__) || defined(_WIN64))) && !defined(CS_UNDEFINED_STRING)
|
||||
#undef EA_PLATFORM_WINDOWS
|
||||
#define EA_PLATFORM_WINDOWS 1
|
||||
#define EA_PLATFORM_NAME "Windows"
|
||||
#ifdef _WIN64 // VC++ defines both _WIN32 and _WIN64 when compiling for Win64.
|
||||
#define EA_PLATFORM_WIN64 1
|
||||
#else
|
||||
#define EA_PLATFORM_WIN32 1
|
||||
#endif
|
||||
#if defined(_M_AMD64) || defined(_AMD64_) || defined(__x86_64__)
|
||||
#define EA_PROCESSOR_X86_64 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "Windows on x64"
|
||||
#elif defined(_M_IX86) || defined(_X86_)
|
||||
#define EA_PROCESSOR_X86 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "Windows on X86"
|
||||
#elif defined(_M_IA64) || defined(_IA64_)
|
||||
#define EA_PROCESSOR_IA64 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "Windows on IA-64"
|
||||
#elif defined(_M_ARM)
|
||||
#define EA_ABI_ARM_WINCE 1
|
||||
#define EA_PROCESSOR_ARM32 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "Windows on ARM"
|
||||
#elif defined(_M_ARM64)
|
||||
#define EA_PROCESSOR_ARM64 1
|
||||
#define EA_SYSTEM_LITTLE_ENDIAN 1
|
||||
#define EA_PLATFORM_DESCRIPTION "Windows on ARM64"
|
||||
#else //Possibly other Windows CE variants
|
||||
#error Unknown processor
|
||||
#error Unknown endianness
|
||||
#endif
|
||||
#if defined(__GNUC__)
|
||||
#define EA_ASM_STYLE_ATT 1
|
||||
#elif defined(_MSC_VER) || defined(__BORLANDC__) || defined(__ICL)
|
||||
#define EA_ASM_STYLE_INTEL 1
|
||||
#endif
|
||||
#define EA_PLATFORM_DESKTOP 1
|
||||
#define EA_PLATFORM_MICROSOFT 1
|
||||
|
||||
// WINAPI_FAMILY defines to support Windows 8 Metro Apps - mirroring winapifamily.h in the Windows 8 SDK
|
||||
#define EA_WINAPI_FAMILY_APP 1000
|
||||
#define EA_WINAPI_FAMILY_DESKTOP_APP 1001
|
||||
#define EA_WINAPI_FAMILY_GAMES 1006
|
||||
|
||||
#if defined(WINAPI_FAMILY)
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push, 0)
|
||||
#endif
|
||||
#include <winapifamily.h>
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
#if defined(WINAPI_FAMILY_DESKTOP_APP) && WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP
|
||||
#define EA_WINAPI_FAMILY EA_WINAPI_FAMILY_DESKTOP_APP
|
||||
#elif defined(WINAPI_FAMILY_APP) && WINAPI_FAMILY == WINAPI_FAMILY_APP
|
||||
#define EA_WINAPI_FAMILY EA_WINAPI_FAMILY_APP
|
||||
#elif defined(WINAPI_FAMILY_GAMES) && WINAPI_FAMILY == WINAPI_FAMILY_GAMES
|
||||
#define EA_WINAPI_FAMILY EA_WINAPI_FAMILY_GAMES
|
||||
#else
|
||||
#error Unsupported WINAPI_FAMILY
|
||||
#endif
|
||||
#else
|
||||
#define EA_WINAPI_FAMILY EA_WINAPI_FAMILY_DESKTOP_APP
|
||||
#endif
|
||||
|
||||
#define EA_WINAPI_PARTITION_DESKTOP 1
|
||||
#define EA_WINAPI_PARTITION_APP 1
|
||||
#define EA_WINAPI_PARTITION_GAMES (EA_WINAPI_FAMILY == EA_WINAPI_FAMILY_GAMES)
|
||||
|
||||
#define EA_WINAPI_FAMILY_PARTITION(Partition) (Partition)
|
||||
|
||||
// EA_PLATFORM_WINRT
|
||||
// This is a subset of Windows which is used for tablets and the "Metro" (restricted) Windows user interface.
|
||||
// WinRT doesn't doesn't have access to the Windows "desktop" API, but WinRT can nevertheless run on
|
||||
// desktop computers in addition to tablets. The Windows Phone API is a subset of WinRT and is not included
|
||||
// in it due to it being only a part of the API.
|
||||
#if defined(__cplusplus_winrt)
|
||||
#define EA_PLATFORM_WINRT 1
|
||||
#endif
|
||||
|
||||
// Sun (Solaris)
|
||||
// __SUNPRO_CC is defined by the Sun compiler.
|
||||
// __sun is defined by the GCC compiler.
|
||||
// __i386 is defined by the Sun and GCC compilers.
|
||||
// __sparc is defined by the Sun and GCC compilers.
|
||||
#else
|
||||
#error Unknown platform
|
||||
#error Unknown processor
|
||||
#error Unknown endianness
|
||||
#endif
|
||||
|
||||
#ifndef EA_PROCESSOR_ARM
|
||||
#if defined(EA_PROCESSOR_ARM32) || defined(EA_PROCESSOR_ARM64) || defined(EA_PROCESSOR_ARM7)
|
||||
#define EA_PROCESSOR_ARM
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// EA_PLATFORM_PTR_SIZE
|
||||
// Platform pointer size; same as sizeof(void*).
|
||||
// This is not the same as sizeof(int), as int is usually 32 bits on
|
||||
// even 64 bit platforms.
|
||||
//
|
||||
// _WIN64 is defined by Win64 compilers, such as VC++.
|
||||
// _M_IA64 is defined by VC++ and Intel compilers for IA64 processors.
|
||||
// __LP64__ is defined by HP compilers for the LP64 standard.
|
||||
// _LP64 is defined by the GCC and Sun compilers for the LP64 standard.
|
||||
// __ia64__ is defined by the GCC compiler for IA64 processors.
|
||||
// __arch64__ is defined by the Sparc compiler for 64 bit processors.
|
||||
// __mips64__ is defined by the GCC compiler for MIPS processors.
|
||||
// __powerpc64__ is defined by the GCC compiler for PowerPC processors.
|
||||
// __64BIT__ is defined by the AIX compiler for 64 bit processors.
|
||||
// __sizeof_ptr is defined by the ARM compiler (armcc, armcpp).
|
||||
//
|
||||
#ifndef EA_PLATFORM_PTR_SIZE
|
||||
#if defined(__WORDSIZE) // Defined by some variations of GCC.
|
||||
#define EA_PLATFORM_PTR_SIZE ((__WORDSIZE) / 8)
|
||||
#elif defined(_WIN64) || defined(__LP64__) || defined(_LP64) || defined(_M_IA64) || defined(__ia64__) || defined(__arch64__) || defined(__aarch64__) || defined(__mips64__) || defined(__64BIT__) || defined(__Ptr_Is_64)
|
||||
#define EA_PLATFORM_PTR_SIZE 8
|
||||
#elif defined(__CC_ARM) && (__sizeof_ptr == 8)
|
||||
#define EA_PLATFORM_PTR_SIZE 8
|
||||
#else
|
||||
#define EA_PLATFORM_PTR_SIZE 4
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// EA_PLATFORM_WORD_SIZE
|
||||
// This defines the size of a machine word. This will be the same as
|
||||
// the size of registers on the machine but not necessarily the same
|
||||
// as the size of pointers on the machine. A number of 64 bit platforms
|
||||
// have 64 bit registers but 32 bit pointers.
|
||||
//
|
||||
#ifndef EA_PLATFORM_WORD_SIZE
|
||||
#define EA_PLATFORM_WORD_SIZE EA_PLATFORM_PTR_SIZE
|
||||
#endif
|
||||
|
||||
// EA_PLATFORM_MIN_MALLOC_ALIGNMENT
|
||||
// This defines the minimal alignment that the platform's malloc
|
||||
// implementation will return. This should be used when writing custom
|
||||
// allocators to ensure that the alignment matches that of malloc
|
||||
#ifndef EA_PLATFORM_MIN_MALLOC_ALIGNMENT
|
||||
#if defined(EA_PLATFORM_APPLE)
|
||||
#define EA_PLATFORM_MIN_MALLOC_ALIGNMENT 16
|
||||
#elif defined(EA_PLATFORM_ANDROID) && defined(EA_PROCESSOR_ARM)
|
||||
#define EA_PLATFORM_MIN_MALLOC_ALIGNMENT 8
|
||||
#elif defined(EA_PLATFORM_ANDROID) && defined(EA_PROCESSOR_X86_64)
|
||||
#define EA_PLATFORM_MIN_MALLOC_ALIGNMENT 8
|
||||
#else
|
||||
#define EA_PLATFORM_MIN_MALLOC_ALIGNMENT (EA_PLATFORM_PTR_SIZE * 2)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// EA_MISALIGNED_SUPPORT_LEVEL
|
||||
// Specifies if the processor can read and write built-in types that aren't
|
||||
// naturally aligned.
|
||||
// 0 - not supported. Likely causes an exception.
|
||||
// 1 - supported but slow.
|
||||
// 2 - supported and fast.
|
||||
//
|
||||
#ifndef EA_MISALIGNED_SUPPORT_LEVEL
|
||||
#if defined(EA_PROCESSOR_X86_64)
|
||||
#define EA_MISALIGNED_SUPPORT_LEVEL 2
|
||||
#else
|
||||
#define EA_MISALIGNED_SUPPORT_LEVEL 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Macro to determine if a Windows API partition is enabled. Always false on non Microsoft platforms.
|
||||
#if !defined(EA_WINAPI_FAMILY_PARTITION)
|
||||
#define EA_WINAPI_FAMILY_PARTITION(Partition) (0)
|
||||
#endif
|
||||
|
||||
|
||||
// EA_CACHE_LINE_SIZE
|
||||
// Specifies the cache line size broken down by compile target.
|
||||
// This the expected best guess values for the targets that we can make at compilation time.
|
||||
|
||||
#ifndef EA_CACHE_LINE_SIZE
|
||||
#if defined(EA_PROCESSOR_X86)
|
||||
#define EA_CACHE_LINE_SIZE 32 // This is the minimum possible value.
|
||||
#elif defined(EA_PROCESSOR_X86_64)
|
||||
#define EA_CACHE_LINE_SIZE 64 // This is the minimum possible value
|
||||
#elif defined(EA_PROCESSOR_ARM32)
|
||||
#define EA_CACHE_LINE_SIZE 32 // This varies between implementations and is usually 32 or 64.
|
||||
#elif defined(EA_PROCESSOR_ARM64)
|
||||
#define EA_CACHE_LINE_SIZE 64 // Cache line Cortex-A8 (64 bytes) http://shervinemami.info/armAssembly.html however this remains to be mostly an assumption at this stage
|
||||
#elif (EA_PLATFORM_WORD_SIZE == 4)
|
||||
#define EA_CACHE_LINE_SIZE 32 // This is the minimum possible value
|
||||
#else
|
||||
#define EA_CACHE_LINE_SIZE 64 // This is the minimum possible value
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif // INCLUDED_eaplatform_H
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,877 @@
|
||||
/*-----------------------------------------------------------------------------
|
||||
* eahave.h
|
||||
*
|
||||
* Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
This file's functionality is preliminary and won't be considered stable until
|
||||
a future EABase version.
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
This header identifies if the given facilities are available in the
|
||||
standard build environment the current compiler/linker/standard library/
|
||||
operating system combination. This file may in some cases #include standard
|
||||
headers in order to make availability determinations, such as to check
|
||||
compiler or SDK version numbers. However, it cannot be perfect.
|
||||
This header does not identify compiler features, as those are defined in
|
||||
eacompiler.h and eacompilertraits.h. Rather this header is about library support.
|
||||
This header does not identify platform or library conventions either, such
|
||||
as whether the file paths use \ or / for directory separators.
|
||||
|
||||
We provide three types of HAVE features here:
|
||||
|
||||
- EA_HAVE_XXX_FEATURE - Have compiler feature.
|
||||
Identifies if the compiler has or lacks some feature in the
|
||||
current build. Sometimes you need to check to see if the
|
||||
compiler is running in some mode in able to write portable code
|
||||
against it. For example, some compilers (e.g. VC++) have a
|
||||
mode in which all language extensions are disabled. If you want
|
||||
to write code that works with that but still uses the extensions
|
||||
when available then you can check #if defined(EA_HAVE_EXTENSIONS_FEATURE).
|
||||
Features can be forcibly cancelled via EA_NO_HAVE_XXX_FEATURE.
|
||||
EA_NO_HAVE is useful for a build system or user to override the
|
||||
defaults because it happens to know better.
|
||||
|
||||
- EA_HAVE_XXX_H - Have header file information.
|
||||
Identifies if a given header file is available to the current
|
||||
compile configuration. For example, some compilers provide a
|
||||
malloc.h header, while others don't. For the former we define
|
||||
EA_HAVE_MALLOC_H, while for the latter it remains undefined.
|
||||
If a header is missing then it may still be that the functions
|
||||
the header usually declares are declared in some other header.
|
||||
EA_HAVE_XXX does not include the possibility that our own code
|
||||
provides versions of these headers, and in fact a purpose of
|
||||
EA_HAVE_XXX is to decide if we should be using our own because
|
||||
the system doesn't provide one.
|
||||
Header availability can be forcibly cancelled via EA_NO_HAVE_XXX_H.
|
||||
EA_NO_HAVE is useful for a build system or user to override the
|
||||
defaults because it happens to know better.
|
||||
|
||||
- EA_HAVE_XXX_DECL - Have function declaration information.
|
||||
Identifies if a given function declaration is provided by
|
||||
the current compile configuration. For example, some compiler
|
||||
standard libraries declare a wcslen function, while others
|
||||
don't. For the former we define EA_HAVE_WCSLEN_DECL, while for
|
||||
the latter it remains undefined. If a declaration of a function
|
||||
is missing then we assume the implementation is missing as well.
|
||||
EA_HAVE_XXX_DECL does not include the possibility that our
|
||||
own code provides versions of these declarations, and in fact a
|
||||
purpose of EA_HAVE_XXX_DECL is to decide if we should be using
|
||||
our own because the system doesn't provide one.
|
||||
Declaration availability can be forcibly cancelled via EA_NO_HAVE_XXX_DECL.
|
||||
EA_NO_HAVE is useful for a build system or user to override the
|
||||
defaults because it happens to know better.
|
||||
|
||||
- EA_HAVE_XXX_IMPL - Have function implementation information.
|
||||
Identifies if a given function implementation is provided by
|
||||
the current compile and link configuration. For example, it's
|
||||
commonly the case that console platforms declare a getenv function
|
||||
but don't provide a linkable implementation.
|
||||
In this case the user needs to provide such a function manually
|
||||
as part of the link. If the implementation is available then
|
||||
we define EA_HAVE_GETENV_IMPL, otherwise it remains undefined.
|
||||
Beware that sometimes a function may not seem to be present in
|
||||
the Standard Library but in reality you need to link some auxiliary
|
||||
provided library for it. An example of this is the Unix real-time
|
||||
functions such as clock_gettime.
|
||||
EA_HAVE_XXX_IMPL does not include the possibility that our
|
||||
own code provides versions of these implementations, and in fact a
|
||||
purpose of EA_HAVE_XXX_IMPL is to decide if we should be using
|
||||
our own because the system doesn't provide one.
|
||||
Implementation availability can be forcibly cancelled via EA_NO_HAVE_XXX_IMPL.
|
||||
EA_NO_HAVE is useful for a build system or user to override the
|
||||
defaults because it happens to know better.
|
||||
|
||||
It's not practical to define EA_HAVE macros for every possible header,
|
||||
declaration, and implementation, and so the user must simply know that
|
||||
some headers, declarations, and implementations tend to require EA_HAVE
|
||||
checking. Nearly every C Standard Library we've seen has a <string.h>
|
||||
header, a strlen declaration, and a linkable strlen implementation,
|
||||
so there's no need to provide EA_HAVE support for this. On the other hand
|
||||
it's commonly the case that the C Standard Library doesn't have a malloc.h
|
||||
header or an inet_ntop declaration.
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#ifndef INCLUDED_eahave_H
|
||||
#define INCLUDED_eahave_H
|
||||
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
|
||||
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
|
||||
#pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
|
||||
#endif
|
||||
|
||||
/* EA_HAVE_XXX_FEATURE */
|
||||
|
||||
#if !defined(EA_HAVE_EXTENSIONS_FEATURE) && !defined(EA_NO_HAVE_EXTENSIONS_FEATURE)
|
||||
#define EA_HAVE_EXTENSIONS_FEATURE 1
|
||||
#endif
|
||||
|
||||
|
||||
/* EA_HAVE_XXX_LIBRARY */
|
||||
|
||||
// Dinkumware
|
||||
#if !defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && !defined(EA_NO_HAVE_DINKUMWARE_CPP_LIBRARY)
|
||||
#if defined(__cplusplus)
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#include <cstddef> // Need to trigger the compilation of yvals.h without directly using <yvals.h> because it might not exist.
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) && defined(_CPPLIB_VER) /* If using the Dinkumware Standard library... */
|
||||
#define EA_HAVE_DINKUMWARE_CPP_LIBRARY 1
|
||||
#else
|
||||
#define EA_NO_HAVE_DINKUMWARE_CPP_LIBRARY 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// GCC libstdc++
|
||||
#if !defined(EA_HAVE_LIBSTDCPP_LIBRARY) && !defined(EA_NO_HAVE_LIBSTDCPP_LIBRARY)
|
||||
#if defined(__GLIBCXX__) /* If using libstdc++ ... */
|
||||
#define EA_HAVE_LIBSTDCPP_LIBRARY 1
|
||||
#else
|
||||
#define EA_NO_HAVE_LIBSTDCPP_LIBRARY 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Clang libc++
|
||||
#if !defined(EA_HAVE_LIBCPP_LIBRARY) && !defined(EA_NO_HAVE_LIBCPP_LIBRARY)
|
||||
#if EA_HAS_INCLUDE_AVAILABLE
|
||||
#if EA_HAS_INCLUDE(<__config>)
|
||||
#define EA_HAVE_LIBCPP_LIBRARY 1 // We could also #include <ciso646> and check if defined(_LIBCPP_VERSION).
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EA_HAVE_LIBCPP_LIBRARY)
|
||||
#define EA_NO_HAVE_LIBCPP_LIBRARY 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
/* EA_HAVE_XXX_H */
|
||||
|
||||
// #include <sys/types.h>
|
||||
#if !defined(EA_HAVE_SYS_TYPES_H) && !defined(EA_NO_HAVE_SYS_TYPES_H)
|
||||
#define EA_HAVE_SYS_TYPES_H 1
|
||||
#endif
|
||||
|
||||
// #include <io.h> (and not sys/io.h or asm/io.h)
|
||||
#if !defined(EA_HAVE_IO_H) && !defined(EA_NO_HAVE_IO_H)
|
||||
// Unix doesn't have Microsoft's <io.h> but has the same functionality in <fcntl.h> and <sys/stat.h>.
|
||||
#if defined(EA_PLATFORM_MICROSOFT)
|
||||
#define EA_HAVE_IO_H 1
|
||||
#else
|
||||
#define EA_NO_HAVE_IO_H 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <inttypes.h>
|
||||
#if !defined(EA_HAVE_INTTYPES_H) && !defined(EA_NO_HAVE_INTTYPES_H)
|
||||
#if !defined(EA_PLATFORM_MICROSOFT)
|
||||
#define EA_HAVE_INTTYPES_H 1
|
||||
#else
|
||||
#define EA_NO_HAVE_INTTYPES_H 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <unistd.h>
|
||||
#if !defined(EA_HAVE_UNISTD_H) && !defined(EA_NO_HAVE_UNISTD_H)
|
||||
#if defined(EA_PLATFORM_UNIX)
|
||||
#define EA_HAVE_UNISTD_H 1
|
||||
#else
|
||||
#define EA_NO_HAVE_UNISTD_H 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <sys/time.h>
|
||||
#if !defined(EA_HAVE_SYS_TIME_H) && !defined(EA_NO_HAVE_SYS_TIME_H)
|
||||
#if !defined(EA_PLATFORM_MICROSOFT) && !defined(_CPPLIB_VER) /* _CPPLIB_VER indicates Dinkumware. */
|
||||
#define EA_HAVE_SYS_TIME_H 1 /* defines struct timeval */
|
||||
#else
|
||||
#define EA_NO_HAVE_SYS_TIME_H 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <ptrace.h>
|
||||
#if !defined(EA_HAVE_SYS_PTRACE_H) && !defined(EA_NO_HAVE_SYS_PTRACE_H)
|
||||
#if defined(EA_PLATFORM_UNIX) && !defined(__CYGWIN__) && (defined(EA_PLATFORM_DESKTOP) || defined(EA_PLATFORM_SERVER))
|
||||
#define EA_HAVE_SYS_PTRACE_H 1 /* declares the ptrace function */
|
||||
#else
|
||||
#define EA_NO_HAVE_SYS_PTRACE_H 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <sys/stat.h>
|
||||
#if !defined(EA_HAVE_SYS_STAT_H) && !defined(EA_NO_HAVE_SYS_STAT_H)
|
||||
#if (defined(EA_PLATFORM_UNIX) && !(defined(EA_PLATFORM_SONY) && defined(EA_PLATFORM_CONSOLE))) || defined(__APPLE__) || defined(EA_PLATFORM_ANDROID)
|
||||
#define EA_HAVE_SYS_STAT_H 1 /* declares the stat struct and function */
|
||||
#else
|
||||
#define EA_NO_HAVE_SYS_STAT_H 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <locale.h>
|
||||
#if !defined(EA_HAVE_LOCALE_H) && !defined(EA_NO_HAVE_LOCALE_H)
|
||||
#define EA_HAVE_LOCALE_H 1
|
||||
#endif
|
||||
|
||||
// #include <signal.h>
|
||||
#if !defined(EA_HAVE_SIGNAL_H) && !defined(EA_NO_HAVE_SIGNAL_H)
|
||||
#if !defined(EA_PLATFORM_BSD) && !defined(EA_PLATFORM_SONY) && !defined(CS_UNDEFINED_STRING)
|
||||
#define EA_HAVE_SIGNAL_H 1
|
||||
#else
|
||||
#define EA_NO_HAVE_SIGNAL_H 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <sys/signal.h>
|
||||
#if !defined(EA_HAVE_SYS_SIGNAL_H) && !defined(EA_NO_HAVE_SYS_SIGNAL_H)
|
||||
#if defined(EA_PLATFORM_BSD) || defined(EA_PLATFORM_SONY)
|
||||
#define EA_HAVE_SYS_SIGNAL_H 1
|
||||
#else
|
||||
#define EA_NO_HAVE_SYS_SIGNAL_H 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <pthread.h>
|
||||
#if !defined(EA_HAVE_PTHREAD_H) && !defined(EA_NO_HAVE_PTHREAD_H)
|
||||
#if defined(EA_PLATFORM_UNIX) || defined(EA_PLATFORM_APPLE) || defined(EA_PLATFORM_POSIX)
|
||||
#define EA_HAVE_PTHREAD_H 1 /* It can be had under Microsoft/Windows with the http://sourceware.org/pthreads-win32/ library */
|
||||
#else
|
||||
#define EA_NO_HAVE_PTHREAD_H 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <wchar.h>
|
||||
#if !defined(EA_HAVE_WCHAR_H) && !defined(EA_NO_HAVE_WCHAR_H)
|
||||
#if defined(EA_PLATFORM_DESKTOP) && defined(EA_PLATFORM_UNIX) && defined(EA_PLATFORM_SONY) && defined(EA_PLATFORM_APPLE)
|
||||
#define EA_HAVE_WCHAR_H 1
|
||||
#else
|
||||
#define EA_NO_HAVE_WCHAR_H 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <malloc.h>
|
||||
#if !defined(EA_HAVE_MALLOC_H) && !defined(EA_NO_HAVE_MALLOC_H)
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#define EA_HAVE_MALLOC_H 1
|
||||
#else
|
||||
#define EA_NO_HAVE_MALLOC_H 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <alloca.h>
|
||||
#if !defined(EA_HAVE_ALLOCA_H) && !defined(EA_NO_HAVE_ALLOCA_H)
|
||||
#if !defined(EA_HAVE_MALLOC_H) && !defined(EA_PLATFORM_SONY)
|
||||
#define EA_HAVE_ALLOCA_H 1
|
||||
#else
|
||||
#define EA_NO_HAVE_ALLOCA_H 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <execinfo.h>
|
||||
#if !defined(EA_HAVE_EXECINFO_H) && !defined(EA_NO_HAVE_EXECINFO_H)
|
||||
#if (defined(EA_PLATFORM_LINUX) || defined(EA_PLATFORM_OSX)) && !defined(EA_PLATFORM_ANDROID)
|
||||
#define EA_HAVE_EXECINFO_H 1
|
||||
#else
|
||||
#define EA_NO_HAVE_EXECINFO_H 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <semaphore.h> (Unix semaphore support)
|
||||
#if !defined(EA_HAVE_SEMAPHORE_H) && !defined(EA_NO_HAVE_SEMAPHORE_H)
|
||||
#if defined(EA_PLATFORM_UNIX)
|
||||
#define EA_HAVE_SEMAPHORE_H 1
|
||||
#else
|
||||
#define EA_NO_HAVE_SEMAPHORE_H 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <dirent.h> (Unix semaphore support)
|
||||
#if !defined(EA_HAVE_DIRENT_H) && !defined(EA_NO_HAVE_DIRENT_H)
|
||||
#if defined(EA_PLATFORM_UNIX) && !defined(EA_PLATFORM_CONSOLE)
|
||||
#define EA_HAVE_DIRENT_H 1
|
||||
#else
|
||||
#define EA_NO_HAVE_DIRENT_H 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <array>, <forward_list>, <ununordered_set>, <unordered_map>
|
||||
#if !defined(EA_HAVE_CPP11_CONTAINERS) && !defined(EA_NO_HAVE_CPP11_CONTAINERS)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 520) // Dinkumware. VS2010+
|
||||
#define EA_HAVE_CPP11_CONTAINERS 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4004) // Actually GCC 4.3 supports array and unordered_
|
||||
#define EA_HAVE_CPP11_CONTAINERS 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1)
|
||||
#define EA_HAVE_CPP11_CONTAINERS 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_CONTAINERS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <atomic>
|
||||
#if !defined(EA_HAVE_CPP11_ATOMIC) && !defined(EA_NO_HAVE_CPP11_ATOMIC)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 540) // Dinkumware. VS2012+
|
||||
#define EA_HAVE_CPP11_ATOMIC 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4007)
|
||||
#define EA_HAVE_CPP11_ATOMIC 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1)
|
||||
#define EA_HAVE_CPP11_ATOMIC 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_ATOMIC 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <condition_variable>
|
||||
#if !defined(EA_HAVE_CPP11_CONDITION_VARIABLE) && !defined(EA_NO_HAVE_CPP11_CONDITION_VARIABLE)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 540) // Dinkumware. VS2012+
|
||||
#define EA_HAVE_CPP11_CONDITION_VARIABLE 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4007)
|
||||
#define EA_HAVE_CPP11_CONDITION_VARIABLE 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1)
|
||||
#define EA_HAVE_CPP11_CONDITION_VARIABLE 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_CONDITION_VARIABLE 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <mutex>
|
||||
#if !defined(EA_HAVE_CPP11_MUTEX) && !defined(EA_NO_HAVE_CPP11_MUTEX)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 540) // Dinkumware. VS2012+
|
||||
#define EA_HAVE_CPP11_MUTEX 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4007)
|
||||
#define EA_HAVE_CPP11_MUTEX 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1)
|
||||
#define EA_HAVE_CPP11_MUTEX 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_MUTEX 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <thread>
|
||||
#if !defined(EA_HAVE_CPP11_THREAD) && !defined(EA_NO_HAVE_CPP11_THREAD)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 540) // Dinkumware. VS2012+
|
||||
#define EA_HAVE_CPP11_THREAD 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4007)
|
||||
#define EA_HAVE_CPP11_THREAD 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1)
|
||||
#define EA_HAVE_CPP11_THREAD 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_THREAD 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <future>
|
||||
#if !defined(EA_HAVE_CPP11_FUTURE) && !defined(EA_NO_HAVE_CPP11_FUTURE)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 540) // Dinkumware. VS2012+
|
||||
#define EA_HAVE_CPP11_FUTURE 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4005)
|
||||
#define EA_HAVE_CPP11_FUTURE 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1)
|
||||
#define EA_HAVE_CPP11_FUTURE 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_FUTURE 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
// #include <type_traits>
|
||||
#if !defined(EA_HAVE_CPP11_TYPE_TRAITS) && !defined(EA_NO_HAVE_CPP11_TYPE_TRAITS)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 540) // Dinkumware. VS2012+
|
||||
#define EA_HAVE_CPP11_TYPE_TRAITS 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4007) // Prior versions of libstdc++ have incomplete support for C++11 type traits.
|
||||
#define EA_HAVE_CPP11_TYPE_TRAITS 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1)
|
||||
#define EA_HAVE_CPP11_TYPE_TRAITS 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_TYPE_TRAITS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <tuple>
|
||||
#if !defined(EA_HAVE_CPP11_TUPLES) && !defined(EA_NO_HAVE_CPP11_TUPLES)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 520) // Dinkumware. VS2010+
|
||||
#define EA_HAVE_CPP11_TUPLES 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)
|
||||
#define EA_HAVE_CPP11_TUPLES 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1)
|
||||
#define EA_HAVE_CPP11_TUPLES 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_TUPLES 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <regex>
|
||||
#if !defined(EA_HAVE_CPP11_REGEX) && !defined(EA_NO_HAVE_CPP11_REGEX)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 540) && (defined(_HAS_EXCEPTIONS) && _HAS_EXCEPTIONS) // Dinkumware. VS2012+
|
||||
#define EA_HAVE_CPP11_REGEX 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4003)
|
||||
#define EA_HAVE_CPP11_REGEX 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1)
|
||||
#define EA_HAVE_CPP11_REGEX 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_REGEX 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <random>
|
||||
#if !defined(EA_HAVE_CPP11_RANDOM) && !defined(EA_NO_HAVE_CPP11_RANDOM)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 520) // Dinkumware. VS2010+
|
||||
#define EA_HAVE_CPP11_RANDOM 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4005)
|
||||
#define EA_HAVE_CPP11_RANDOM 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1)
|
||||
#define EA_HAVE_CPP11_RANDOM 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_RANDOM 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <chrono>
|
||||
#if !defined(EA_HAVE_CPP11_CHRONO) && !defined(EA_NO_HAVE_CPP11_CHRONO)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 540) // Dinkumware. VS2012+
|
||||
#define EA_HAVE_CPP11_CHRONO 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4007) // chrono was broken in glibc prior to 4.7.
|
||||
#define EA_HAVE_CPP11_CHRONO 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1)
|
||||
#define EA_HAVE_CPP11_CHRONO 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_CHRONO 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <scoped_allocator>
|
||||
#if !defined(EA_HAVE_CPP11_SCOPED_ALLOCATOR) && !defined(EA_NO_HAVE_CPP11_SCOPED_ALLOCATOR)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 540) // Dinkumware. VS2012+
|
||||
#define EA_HAVE_CPP11_SCOPED_ALLOCATOR 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4007)
|
||||
#define EA_HAVE_CPP11_SCOPED_ALLOCATOR 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1)
|
||||
#define EA_HAVE_CPP11_SCOPED_ALLOCATOR 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_SCOPED_ALLOCATOR 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <initializer_list>
|
||||
#if !defined(EA_HAVE_CPP11_INITIALIZER_LIST) && !defined(EA_NO_HAVE_CPP11_INITIALIZER_LIST)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 520) && !defined(EA_COMPILER_NO_INITIALIZER_LISTS) // Dinkumware. VS2010+
|
||||
#define EA_HAVE_CPP11_INITIALIZER_LIST 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_CLANG) && (EA_COMPILER_VERSION >= 301) && !defined(EA_COMPILER_NO_INITIALIZER_LISTS) && !defined(EA_PLATFORM_APPLE)
|
||||
#define EA_HAVE_CPP11_INITIALIZER_LIST 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBCPP_LIBRARY) && defined(EA_COMPILER_CLANG) && (EA_COMPILER_VERSION >= 301) && !defined(EA_COMPILER_NO_INITIALIZER_LISTS) && !defined(EA_PLATFORM_APPLE)
|
||||
#define EA_HAVE_CPP11_INITIALIZER_LIST 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4004) && !defined(EA_COMPILER_NO_INITIALIZER_LISTS) && !defined(EA_PLATFORM_APPLE)
|
||||
#define EA_HAVE_CPP11_INITIALIZER_LIST 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1) && !defined(EA_COMPILER_NO_INITIALIZER_LISTS)
|
||||
#define EA_HAVE_CPP11_INITIALIZER_LIST 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_INITIALIZER_LIST 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <system_error>
|
||||
#if !defined(EA_HAVE_CPP11_SYSTEM_ERROR) && !defined(EA_NO_HAVE_CPP11_SYSTEM_ERROR)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 520) && !(defined(_HAS_CPP0X) && _HAS_CPP0X) // Dinkumware. VS2010+
|
||||
#define EA_HAVE_CPP11_SYSTEM_ERROR 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_CLANG) && (EA_COMPILER_VERSION >= 301) && !defined(EA_PLATFORM_APPLE)
|
||||
#define EA_HAVE_CPP11_SYSTEM_ERROR 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4004) && !defined(EA_PLATFORM_APPLE)
|
||||
#define EA_HAVE_CPP11_SYSTEM_ERROR 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1)
|
||||
#define EA_HAVE_CPP11_SYSTEM_ERROR 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_SYSTEM_ERROR 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <codecvt>
|
||||
#if !defined(EA_HAVE_CPP11_CODECVT) && !defined(EA_NO_HAVE_CPP11_CODECVT)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 520) // Dinkumware. VS2010+
|
||||
#define EA_HAVE_CPP11_CODECVT 1
|
||||
// Future versions of libc++ may support this header. However, at the moment there isn't
|
||||
// a reliable way of detecting if this header is available.
|
||||
//#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4008)
|
||||
// #define EA_HAVE_CPP11_CODECVT 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1)
|
||||
#define EA_HAVE_CPP11_CODECVT 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_CODECVT 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// #include <typeindex>
|
||||
#if !defined(EA_HAVE_CPP11_TYPEINDEX) && !defined(EA_NO_HAVE_CPP11_TYPEINDEX)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 520) // Dinkumware. VS2010+
|
||||
#define EA_HAVE_CPP11_TYPEINDEX 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4006)
|
||||
#define EA_HAVE_CPP11_TYPEINDEX 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1)
|
||||
#define EA_HAVE_CPP11_TYPEINDEX 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_TYPEINDEX 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/* EA_HAVE_XXX_DECL */
|
||||
|
||||
#if !defined(EA_HAVE_mkstemps_DECL) && !defined(EA_NO_HAVE_mkstemps_DECL)
|
||||
#if defined(EA_PLATFORM_APPLE) || defined(CS_UNDEFINED_STRING)
|
||||
#define EA_HAVE_mkstemps_DECL 1
|
||||
#else
|
||||
#define EA_NO_HAVE_mkstemps_DECL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EA_HAVE_gettimeofday_DECL) && !defined(EA_NO_HAVE_gettimeofday_DECL)
|
||||
#if defined(EA_PLATFORM_POSIX) /* Posix means Linux, Unix, and Macintosh OSX, among others (including Linux-based mobile platforms). */
|
||||
#define EA_HAVE_gettimeofday_DECL 1
|
||||
#else
|
||||
#define EA_NO_HAVE_gettimeofday_DECL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EA_HAVE_strcasecmp_DECL) && !defined(EA_NO_HAVE_strcasecmp_DECL)
|
||||
#if !defined(EA_PLATFORM_MICROSOFT)
|
||||
#define EA_HAVE_strcasecmp_DECL 1 /* This is found as stricmp when not found as strcasecmp */
|
||||
#define EA_HAVE_strncasecmp_DECL 1
|
||||
#else
|
||||
#define EA_HAVE_stricmp_DECL 1
|
||||
#define EA_HAVE_strnicmp_DECL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EA_HAVE_mmap_DECL) && !defined(EA_NO_HAVE_mmap_DECL)
|
||||
#if defined(EA_PLATFORM_POSIX)
|
||||
#define EA_HAVE_mmap_DECL 1 /* mmap functionality varies significantly between systems. */
|
||||
#else
|
||||
#define EA_NO_HAVE_mmap_DECL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EA_HAVE_fopen_DECL) && !defined(EA_NO_HAVE_fopen_DECL)
|
||||
#define EA_HAVE_fopen_DECL 1 /* C FILE functionality such as fopen */
|
||||
#endif
|
||||
|
||||
#if !defined(EA_HAVE_ISNAN) && !defined(EA_NO_HAVE_ISNAN)
|
||||
#if defined(EA_PLATFORM_MICROSOFT) && !defined(EA_PLATFORM_MINGW)
|
||||
#define EA_HAVE_ISNAN(x) _isnan(x) /* declared in <math.h> */
|
||||
#define EA_HAVE_ISINF(x) !_finite(x)
|
||||
#elif defined(EA_PLATFORM_APPLE)
|
||||
#define EA_HAVE_ISNAN(x) std::isnan(x) /* declared in <cmath> */
|
||||
#define EA_HAVE_ISINF(x) std::isinf(x)
|
||||
#elif defined(EA_PLATFORM_ANDROID)
|
||||
#define EA_HAVE_ISNAN(x) __builtin_isnan(x) /* There are a number of standard libraries for Android and it's hard to tell them apart, so just go with builtins */
|
||||
#define EA_HAVE_ISINF(x) __builtin_isinf(x)
|
||||
#elif defined(__GNUC__) && defined(__CYGWIN__)
|
||||
#define EA_HAVE_ISNAN(x) __isnand(x) /* declared nowhere, it seems. */
|
||||
#define EA_HAVE_ISINF(x) __isinfd(x)
|
||||
#else
|
||||
#define EA_HAVE_ISNAN(x) std::isnan(x) /* declared in <cmath> */
|
||||
#define EA_HAVE_ISINF(x) std::isinf(x)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EA_HAVE_itoa_DECL) && !defined(EA_NO_HAVE_itoa_DECL)
|
||||
#if defined(EA_COMPILER_MSVC)
|
||||
#define EA_HAVE_itoa_DECL 1
|
||||
#else
|
||||
#define EA_NO_HAVE_itoa_DECL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EA_HAVE_nanosleep_DECL) && !defined(EA_NO_HAVE_nanosleep_DECL)
|
||||
#if (defined(EA_PLATFORM_UNIX) && !defined(EA_PLATFORM_SONY)) || defined(EA_PLATFORM_IPHONE) || defined(EA_PLATFORM_OSX) || defined(EA_PLATFORM_SONY) || defined(CS_UNDEFINED_STRING)
|
||||
#define EA_HAVE_nanosleep_DECL 1
|
||||
#else
|
||||
#define EA_NO_HAVE_nanosleep_DECL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EA_HAVE_utime_DECL) && !defined(EA_NO_HAVE_utime_DECL)
|
||||
#if defined(EA_PLATFORM_MICROSOFT)
|
||||
#define EA_HAVE_utime_DECL _utime
|
||||
#elif EA_PLATFORM_UNIX
|
||||
#define EA_HAVE_utime_DECL utime
|
||||
#else
|
||||
#define EA_NO_HAVE_utime_DECL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EA_HAVE_ftruncate_DECL) && !defined(EA_NO_HAVE_ftruncate_DECL)
|
||||
#if !defined(__MINGW32__)
|
||||
#define EA_HAVE_ftruncate_DECL 1
|
||||
#else
|
||||
#define EA_NO_HAVE_ftruncate_DECL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EA_HAVE_localtime_DECL) && !defined(EA_NO_HAVE_localtime_DECL)
|
||||
#define EA_HAVE_localtime_DECL 1
|
||||
#endif
|
||||
|
||||
#if !defined(EA_HAVE_pthread_getattr_np_DECL) && !defined(EA_NO_HAVE_pthread_getattr_np_DECL)
|
||||
#if defined(EA_PLATFORM_LINUX)
|
||||
#define EA_HAVE_pthread_getattr_np_DECL 1
|
||||
#else
|
||||
#define EA_NO_HAVE_pthread_getattr_np_DECL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* EA_HAVE_XXX_IMPL*/
|
||||
|
||||
#if !defined(EA_HAVE_WCHAR_IMPL) && !defined(EA_NO_HAVE_WCHAR_IMPL)
|
||||
#if defined(EA_PLATFORM_DESKTOP)
|
||||
#define EA_HAVE_WCHAR_IMPL 1 /* Specifies if wchar_t string functions are provided, such as wcslen, wprintf, etc. Implies EA_HAVE_WCHAR_H */
|
||||
#else
|
||||
#define EA_NO_HAVE_WCHAR_IMPL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EA_HAVE_getenv_IMPL) && !defined(EA_NO_HAVE_getenv_IMPL)
|
||||
#if (defined(EA_PLATFORM_DESKTOP) || defined(EA_PLATFORM_UNIX)) && !defined(EA_PLATFORM_WINRT)
|
||||
#define EA_HAVE_getenv_IMPL 1
|
||||
#else
|
||||
#define EA_NO_HAVE_getenv_IMPL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EA_HAVE_setenv_IMPL) && !defined(EA_NO_HAVE_setenv_IMPL)
|
||||
#if defined(EA_PLATFORM_UNIX) && defined(EA_PLATFORM_POSIX)
|
||||
#define EA_HAVE_setenv_IMPL 1
|
||||
#else
|
||||
#define EA_NO_HAVE_setenv_IMPL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EA_HAVE_unsetenv_IMPL) && !defined(EA_NO_HAVE_unsetenv_IMPL)
|
||||
#if defined(EA_PLATFORM_UNIX) && defined(EA_PLATFORM_POSIX)
|
||||
#define EA_HAVE_unsetenv_IMPL 1
|
||||
#else
|
||||
#define EA_NO_HAVE_unsetenv_IMPL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EA_HAVE_putenv_IMPL) && !defined(EA_NO_HAVE_putenv_IMPL)
|
||||
#if (defined(EA_PLATFORM_DESKTOP) || defined(EA_PLATFORM_UNIX)) && !defined(EA_PLATFORM_WINRT)
|
||||
#define EA_HAVE_putenv_IMPL 1 /* With Microsoft compilers you may need to use _putenv, as they have deprecated putenv. */
|
||||
#else
|
||||
#define EA_NO_HAVE_putenv_IMPL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EA_HAVE_time_IMPL) && !defined(EA_NO_HAVE_time_IMPL)
|
||||
#define EA_HAVE_time_IMPL 1
|
||||
#define EA_HAVE_clock_IMPL 1
|
||||
#endif
|
||||
|
||||
// <cstdio> fopen()
|
||||
#if !defined(EA_HAVE_fopen_IMPL) && !defined(EA_NO_HAVE_fopen_IMPL)
|
||||
#define EA_HAVE_fopen_IMPL 1 /* C FILE functionality such as fopen */
|
||||
#endif
|
||||
|
||||
// <arpa/inet.h> inet_ntop()
|
||||
#if !defined(EA_HAVE_inet_ntop_IMPL) && !defined(EA_NO_HAVE_inet_ntop_IMPL)
|
||||
#if (defined(EA_PLATFORM_UNIX) || defined(EA_PLATFORM_POSIX)) && !defined(EA_PLATFORM_SONY) && !defined(CS_UNDEFINED_STRING)
|
||||
#define EA_HAVE_inet_ntop_IMPL 1 /* This doesn't identify if the platform SDK has some alternative function that does the same thing; */
|
||||
#define EA_HAVE_inet_pton_IMPL 1 /* it identifies strictly the <arpa/inet.h> inet_ntop and inet_pton functions. For example, Microsoft has InetNtop in <Ws2tcpip.h> */
|
||||
#else
|
||||
#define EA_NO_HAVE_inet_ntop_IMPL 1
|
||||
#define EA_NO_HAVE_inet_pton_IMPL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// <time.h> clock_gettime()
|
||||
#if !defined(EA_HAVE_clock_gettime_IMPL) && !defined(EA_NO_HAVE_clock_gettime_IMPL)
|
||||
#if defined(EA_PLATFORM_LINUX) || defined(__CYGWIN__) || (defined(_POSIX_TIMERS) && (_POSIX_TIMERS > 0)) || (defined(EA_PLATFORM_POSIX) && defined(_CPPLIB_VER) /*Dinkumware*/)
|
||||
#define EA_HAVE_clock_gettime_IMPL 1 /* You need to link the 'rt' library to get this */
|
||||
#else
|
||||
#define EA_NO_HAVE_clock_gettime_IMPL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EA_HAVE_getcwd_IMPL) && !defined(EA_NO_HAVE_getcwd_IMPL)
|
||||
#if (defined(EA_PLATFORM_DESKTOP) || defined(EA_PLATFORM_UNIX)) && !defined(EA_PLATFORM_ANDROID) && !defined(EA_PLATFORM_WINRT)
|
||||
#define EA_HAVE_getcwd_IMPL 1 /* With Microsoft compilers you may need to use _getcwd, as they have deprecated getcwd. And in any case it's present at <direct.h> */
|
||||
#else
|
||||
#define EA_NO_HAVE_getcwd_IMPL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EA_HAVE_tmpnam_IMPL) && !defined(EA_NO_HAVE_tmpnam_IMPL)
|
||||
#if (defined(EA_PLATFORM_DESKTOP) || defined(EA_PLATFORM_UNIX)) && !defined(EA_PLATFORM_ANDROID)
|
||||
#define EA_HAVE_tmpnam_IMPL 1
|
||||
#else
|
||||
#define EA_NO_HAVE_tmpnam_IMPL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// nullptr, the built-in C++11 type.
|
||||
// This EA_HAVE is deprecated, as EA_COMPILER_NO_NULLPTR is more appropriate, given that nullptr is a compiler-level feature and not a library feature.
|
||||
#if !defined(EA_HAVE_nullptr_IMPL) && !defined(EA_NO_HAVE_nullptr_IMPL)
|
||||
#if defined(EA_COMPILER_NO_NULLPTR)
|
||||
#define EA_NO_HAVE_nullptr_IMPL 1
|
||||
#else
|
||||
#define EA_HAVE_nullptr_IMPL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// <cstddef> std::nullptr_t
|
||||
// Note that <EABase/nullptr.h> implements a portable nullptr implementation, but this
|
||||
// EA_HAVE specifically refers to std::nullptr_t from the standard libraries.
|
||||
#if !defined(EA_HAVE_nullptr_t_IMPL) && !defined(EA_NO_HAVE_nullptr_t_IMPL)
|
||||
#if defined(EA_COMPILER_CPP11_ENABLED)
|
||||
// VS2010+ with its default Dinkumware standard library.
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1600) && defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY)
|
||||
#define EA_HAVE_nullptr_t_IMPL 1
|
||||
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) // clang/llvm libc++
|
||||
#define EA_HAVE_nullptr_t_IMPL 1
|
||||
|
||||
#elif defined(EA_HAVE_LIBSTDCPP_LIBRARY) // GNU libstdc++
|
||||
// Unfortunately __GLIBCXX__ date values don't go strictly in version ordering.
|
||||
#if (__GLIBCXX__ >= 20110325) && (__GLIBCXX__ != 20120702) && (__GLIBCXX__ != 20110428)
|
||||
#define EA_HAVE_nullptr_t_IMPL 1
|
||||
#else
|
||||
#define EA_NO_HAVE_nullptr_t_IMPL 1
|
||||
#endif
|
||||
|
||||
// We simply assume that the standard library (e.g. Dinkumware) provides std::nullptr_t.
|
||||
#elif defined(__clang__)
|
||||
#define EA_HAVE_nullptr_t_IMPL 1
|
||||
|
||||
// With GCC compiler >= 4.6, std::nullptr_t is always defined in <cstddef>, in practice.
|
||||
#elif defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4006)
|
||||
#define EA_HAVE_nullptr_t_IMPL 1
|
||||
|
||||
// The EDG compiler provides nullptr, but uses an older standard library that doesn't support std::nullptr_t.
|
||||
#elif defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 403)
|
||||
#define EA_HAVE_nullptr_t_IMPL 1
|
||||
|
||||
#else
|
||||
#define EA_NO_HAVE_nullptr_t_IMPL 1
|
||||
#endif
|
||||
#else
|
||||
#define EA_NO_HAVE_nullptr_t_IMPL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// <exception> std::terminate
|
||||
#if !defined(EA_HAVE_std_terminate_IMPL) && !defined(EA_NO_HAVE_std_terminate_IMPL)
|
||||
#if !defined(EA_PLATFORM_IPHONE) && !defined(EA_PLATFORM_ANDROID)
|
||||
#define EA_HAVE_std_terminate_IMPL 1 /* iOS doesn't appear to provide an implementation for std::terminate under the armv6 target. */
|
||||
#else
|
||||
#define EA_NO_HAVE_std_terminate_IMPL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// <iterator>: std::begin, std::end, std::prev, std::next, std::move_iterator.
|
||||
#if !defined(EA_HAVE_CPP11_ITERATOR_IMPL) && !defined(EA_NO_HAVE_CPP11_ITERATOR_IMPL)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 520) && !(defined(_HAS_CPP0X) && _HAS_CPP0X) // Dinkumware. VS2010+
|
||||
#define EA_HAVE_CPP11_ITERATOR_IMPL 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4006)
|
||||
#define EA_HAVE_CPP11_ITERATOR_IMPL 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1)
|
||||
#define EA_HAVE_CPP11_ITERATOR_IMPL 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_ITERATOR_IMPL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// <memory>: std::weak_ptr, std::shared_ptr, std::unique_ptr, std::bad_weak_ptr, std::owner_less
|
||||
#if !defined(EA_HAVE_CPP11_SMART_POINTER_IMPL) && !defined(EA_NO_HAVE_CPP11_SMART_POINTER_IMPL)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 520) && !(defined(_HAS_CPP0X) && _HAS_CPP0X) // Dinkumware. VS2010+
|
||||
#define EA_HAVE_CPP11_SMART_POINTER_IMPL 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4004)
|
||||
#define EA_HAVE_CPP11_SMART_POINTER_IMPL 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1)
|
||||
#define EA_HAVE_CPP11_SMART_POINTER_IMPL 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_SMART_POINTER_IMPL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// <functional>: std::function, std::mem_fn, std::bad_function_call, std::is_bind_expression, std::is_placeholder, std::reference_wrapper, std::hash, std::bind, std::ref, std::cref.
|
||||
#if !defined(EA_HAVE_CPP11_FUNCTIONAL_IMPL) && !defined(EA_NO_HAVE_CPP11_FUNCTIONAL_IMPL)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 520) && !(defined(_HAS_CPP0X) && _HAS_CPP0X) // Dinkumware. VS2010+
|
||||
#define EA_HAVE_CPP11_FUNCTIONAL_IMPL 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4004)
|
||||
#define EA_HAVE_CPP11_FUNCTIONAL_IMPL 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1)
|
||||
#define EA_HAVE_CPP11_FUNCTIONAL_IMPL 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_FUNCTIONAL_IMPL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// <exception> std::current_exception, std::rethrow_exception, std::exception_ptr, std::make_exception_ptr
|
||||
#if !defined(EA_HAVE_CPP11_EXCEPTION_IMPL) && !defined(EA_NO_HAVE_CPP11_EXCEPTION_IMPL)
|
||||
#if defined(EA_HAVE_DINKUMWARE_CPP_LIBRARY) && (_CPPLIB_VER >= 520) && !(defined(_HAS_CPP0X) && _HAS_CPP0X) // Dinkumware. VS2010+
|
||||
#define EA_HAVE_CPP11_EXCEPTION_IMPL 1
|
||||
#elif defined(EA_COMPILER_CPP11_ENABLED) && defined(EA_HAVE_LIBSTDCPP_LIBRARY) && defined(EA_COMPILER_GNUC) && (EA_COMPILER_VERSION >= 4004)
|
||||
#define EA_HAVE_CPP11_EXCEPTION_IMPL 1
|
||||
#elif defined(EA_HAVE_LIBCPP_LIBRARY) && (_LIBCPP_VERSION >= 1)
|
||||
#define EA_HAVE_CPP11_EXCEPTION_IMPL 1
|
||||
#else
|
||||
#define EA_NO_HAVE_CPP11_EXCEPTION_IMPL 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
/* Implementations that all platforms seem to have: */
|
||||
/*
|
||||
alloca
|
||||
malloc
|
||||
calloc
|
||||
strtoll
|
||||
strtoull
|
||||
vsprintf
|
||||
vsnprintf
|
||||
*/
|
||||
|
||||
/* Implementations that we don't care about: */
|
||||
/*
|
||||
bcopy -- Just use memmove or some customized equivalent. bcopy offers no practical benefit.
|
||||
strlcpy -- So few platforms have this built-in that we get no benefit from using it. Use EA::StdC::Strlcpy instead.
|
||||
strlcat -- "
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------
|
||||
EABASE_USER_HAVE_HEADER
|
||||
|
||||
This allows the user to define a header file to be #included after the
|
||||
eahave.h's contents are compiled. A primary use of this is to override
|
||||
the contents of this header file. You can define the overhead header
|
||||
file name in-code or define it globally as part of your build file.
|
||||
|
||||
Example usage:
|
||||
#define EABASE_USER_HAVE_HEADER "MyHaveOverrides.h"
|
||||
#include <EABase/eahave.h>
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef EABASE_USER_HAVE_HEADER
|
||||
#include EABASE_USER_HAVE_HEADER
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* Header include guard */
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*-----------------------------------------------------------------------------
|
||||
* earesult.h
|
||||
*
|
||||
* Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#ifndef INCLUDED_earesult_H
|
||||
#define INCLUDED_earesult_H
|
||||
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
|
||||
#pragma once /* Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. */
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/* This result type is width-compatible with most systems. */
|
||||
typedef int32_t ea_result_type;
|
||||
|
||||
|
||||
namespace EA
|
||||
{
|
||||
typedef int32_t result_type;
|
||||
|
||||
enum
|
||||
{
|
||||
#ifndef SUCCESS
|
||||
// Deprecated
|
||||
// Note: a public MS header has created a define of this name which causes a build error. Fortunately they
|
||||
// define it to 0 which is compatible.
|
||||
// see: WindowsSDK\8.1.51641-fb\installed\Include\um\RasError.h
|
||||
SUCCESS = 0,
|
||||
#endif
|
||||
// Deprecated
|
||||
FAILURE = -1,
|
||||
|
||||
// These values are now the preferred constants
|
||||
EA_SUCCESS = 0,
|
||||
EA_FAILURE = -1,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/* Macro to simplify testing for success. */
|
||||
#ifndef EA_SUCCEEDED
|
||||
#define EA_SUCCEEDED(result) ((result) >= 0)
|
||||
#endif
|
||||
|
||||
/* Macro to simplfify testing for general failure. */
|
||||
#ifndef EA_FAILED
|
||||
#define EA_FAILED(result) ((result) < 0)
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*-----------------------------------------------------------------------------
|
||||
* eastdarg.h
|
||||
*
|
||||
* Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#ifndef INCLUDED_eastdarg_H
|
||||
#define INCLUDED_eastdarg_H
|
||||
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
// VA_ARG_COUNT
|
||||
//
|
||||
// Returns the number of arguments passed to a macro's ... argument.
|
||||
// This applies to macros only and not functions.
|
||||
//
|
||||
// Example usage:
|
||||
// assert(VA_ARG_COUNT() == 0);
|
||||
// assert(VA_ARG_COUNT(a) == 1);
|
||||
// assert(VA_ARG_COUNT(a, b) == 2);
|
||||
// assert(VA_ARG_COUNT(a, b, c) == 3);
|
||||
//
|
||||
#if !defined(VA_ARG_COUNT)
|
||||
#define VA_ARG_COUNT(...) VA_ARG_COUNT_II((VA_ARG_COUNT_PREFIX_ ## __VA_ARGS__ ## _VA_ARG_COUNT_POSTFIX,32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0))
|
||||
#define VA_ARG_COUNT_II(__args) VA_ARG_COUNT_I __args
|
||||
#define VA_ARG_COUNT_PREFIX__VA_ARG_COUNT_POSTFIX ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,0
|
||||
#define VA_ARG_COUNT_I(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,N,...) N
|
||||
#endif
|
||||
|
||||
|
||||
// va_copy
|
||||
//
|
||||
// va_copy is required by C++11
|
||||
// C++11 and C99 require va_copy to be #defined and implemented.
|
||||
// http://en.cppreference.com/w/cpp/utility/variadic/va_copy
|
||||
//
|
||||
// Example usage:
|
||||
// void Func(char* p, ...){
|
||||
// va_list args, argsCopy;
|
||||
// va_start(args, p);
|
||||
// va_copy(argsCopy, args);
|
||||
// (use args)
|
||||
// (use argsCopy, which acts the same as args)
|
||||
// va_end(args);
|
||||
// va_end(argsCopy);
|
||||
// }
|
||||
//
|
||||
#ifndef va_copy
|
||||
#if defined(__va_copy) // GCC and others define this for non-C99 compatibility.
|
||||
#define va_copy(dest, src) __va_copy((dest), (src))
|
||||
#else
|
||||
// This may not work for some platforms, depending on their ABI.
|
||||
// It works for Microsoft x86,x64, and PowerPC-based platforms.
|
||||
#define va_copy(dest, src) memcpy(&(dest), &(src), sizeof(va_list))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// va_list_reference
|
||||
//
|
||||
// va_list_reference is not part of the C or C++ standards.
|
||||
// It allows you to pass a va_list by reference to another
|
||||
// function instead of by value. You cannot simply use va_list&
|
||||
// as that won't work with many va_list implementations because
|
||||
// they are implemented as arrays (which can't be passed by
|
||||
// reference to a function without decaying to a pointer).
|
||||
//
|
||||
// Example usage:
|
||||
// void Test(va_list_reference args){
|
||||
// printf("%d", va_arg(args, int));
|
||||
// }
|
||||
// void Func(char* p, ...){
|
||||
// va_list args;
|
||||
// va_start(args, p);
|
||||
// Test(args); // Upon return args will be modified.
|
||||
// va_end(args);
|
||||
// }
|
||||
#ifndef va_list_reference
|
||||
#if defined(EA_PLATFORM_MICROSOFT) || (EA_PLATFORM_PTR_SIZE == 4) || (defined(EA_PLATFORM_APPLE) && defined(EA_PROCESSOR_ARM64)) || defined(CS_UNDEFINED_STRING) || (defined(EA_PLATFORM_ANDROID) && defined(EA_PROCESSOR_ARM64))
|
||||
// This is required for platform ABIs in which va_list is a struct or pointer.
|
||||
#define va_list_reference va_list&
|
||||
#else
|
||||
// This is required for platform ABIs in which va_list is defined to be an array.
|
||||
#define va_list_reference va_list
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /* Header include guard */
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*-----------------------------------------------------------------------------
|
||||
* eaunits.h
|
||||
*
|
||||
* Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#ifndef INCLUDED_eaunits_h
|
||||
#define INCLUDED_eaunits_h
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
|
||||
#pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
|
||||
#endif
|
||||
|
||||
// Defining common SI unit macros.
|
||||
//
|
||||
// The mebibyte is a multiple of the unit byte for digital information. Technically a
|
||||
// megabyte (MB) is a power of ten, while a mebibyte (MiB) is a power of two,
|
||||
// appropriate for binary machines. Many Linux distributions use the unit, but it is
|
||||
// not widely acknowledged within the industry or media.
|
||||
// Reference: https://en.wikipedia.org/wiki/Mebibyte
|
||||
//
|
||||
// Examples:
|
||||
// auto size1 = EA_KILOBYTE(16);
|
||||
// auto size2 = EA_MEGABYTE(128);
|
||||
// auto size3 = EA_MEBIBYTE(8);
|
||||
// auto size4 = EA_GIBIBYTE(8);
|
||||
|
||||
// define byte for completeness
|
||||
#define EA_BYTE(x) (x)
|
||||
|
||||
// Decimal SI units
|
||||
#define EA_KILOBYTE(x) (size_t(x) * 1000)
|
||||
#define EA_MEGABYTE(x) (size_t(x) * 1000 * 1000)
|
||||
#define EA_GIGABYTE(x) (size_t(x) * 1000 * 1000 * 1000)
|
||||
#define EA_TERABYTE(x) (size_t(x) * 1000 * 1000 * 1000 * 1000)
|
||||
#define EA_PETABYTE(x) (size_t(x) * 1000 * 1000 * 1000 * 1000 * 1000)
|
||||
#define EA_EXABYTE(x) (size_t(x) * 1000 * 1000 * 1000 * 1000 * 1000 * 1000)
|
||||
|
||||
// Binary SI units
|
||||
#define EA_KIBIBYTE(x) (size_t(x) * 1024)
|
||||
#define EA_MEBIBYTE(x) (size_t(x) * 1024 * 1024)
|
||||
#define EA_GIBIBYTE(x) (size_t(x) * 1024 * 1024 * 1024)
|
||||
#define EA_TEBIBYTE(x) (size_t(x) * 1024 * 1024 * 1024 * 1024)
|
||||
#define EA_PEBIBYTE(x) (size_t(x) * 1024 * 1024 * 1024 * 1024 * 1024)
|
||||
#define EA_EXBIBYTE(x) (size_t(x) * 1024 * 1024 * 1024 * 1024 * 1024 * 1024)
|
||||
|
||||
#endif // INCLUDED_earesult_H
|
||||
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,102 @@
|
||||
/*-----------------------------------------------------------------------------
|
||||
* nullptr.h
|
||||
*
|
||||
* Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#include <EABase/eahave.h>
|
||||
|
||||
|
||||
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
|
||||
#pragma once /* Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result. */
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(EA_COMPILER_CPP11_ENABLED) && !defined(EA_COMPILER_NO_NULLPTR) && !defined(EA_HAVE_nullptr_t_IMPL)
|
||||
// The compiler supports nullptr, but the standard library doesn't implement a declaration for std::nullptr_t. So we provide one.
|
||||
namespace std { typedef decltype(nullptr) nullptr_t; }
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#if defined(EA_COMPILER_NO_NULLPTR) // If the compiler lacks a native version...
|
||||
|
||||
namespace std
|
||||
{
|
||||
class nullptr_t
|
||||
{
|
||||
public:
|
||||
template<class T> // When tested a pointer, acts as 0.
|
||||
operator T*() const
|
||||
{ return 0; }
|
||||
|
||||
template<class C, class T> // When tested as a member pointer, acts as 0.
|
||||
operator T C::*() const
|
||||
{ return 0; }
|
||||
|
||||
typedef void* (nullptr_t::*bool_)() const;
|
||||
operator bool_() const // An rvalue of type std::nullptr_t can be converted to an rvalue of type bool; the resulting value is false.
|
||||
{ return false; } // We can't use operator bool(){ return false; } because bool is convertable to int which breaks other required functionality.
|
||||
|
||||
// We can't enable this without generating warnings about nullptr being uninitialized after being used when created without "= {}".
|
||||
//void* mSizeofVoidPtr; // sizeof(nullptr_t) == sizeof(void*). Needs to be public if nullptr_t is to be a POD.
|
||||
|
||||
private:
|
||||
void operator&() const; // Address cannot be taken.
|
||||
};
|
||||
|
||||
inline nullptr_t nullptr_get()
|
||||
{
|
||||
nullptr_t n = { }; // std::nullptr exists.
|
||||
return n;
|
||||
}
|
||||
|
||||
#if !defined(nullptr) // If somebody hasn't already defined nullptr in a custom way...
|
||||
#define nullptr nullptr_get()
|
||||
#endif
|
||||
|
||||
} // namespace std
|
||||
|
||||
|
||||
template<class T>
|
||||
inline bool operator==(T* p, const std::nullptr_t)
|
||||
{ return p == 0; }
|
||||
|
||||
template<class T>
|
||||
inline bool operator==(const std::nullptr_t, T* p)
|
||||
{ return p == 0; }
|
||||
|
||||
template<class T, class U>
|
||||
inline bool operator==(T U::* p, const std::nullptr_t)
|
||||
{ return p == 0; }
|
||||
|
||||
template<class T, class U>
|
||||
inline bool operator==(const std::nullptr_t, T U::* p)
|
||||
{ return p == 0; }
|
||||
|
||||
inline bool operator==(const std::nullptr_t, const std::nullptr_t)
|
||||
{ return true; }
|
||||
|
||||
inline bool operator!=(const std::nullptr_t, const std::nullptr_t)
|
||||
{ return false; }
|
||||
|
||||
inline bool operator<(const std::nullptr_t, const std::nullptr_t)
|
||||
{ return false; }
|
||||
|
||||
inline bool operator>(const std::nullptr_t, const std::nullptr_t)
|
||||
{ return false; }
|
||||
|
||||
inline bool operator<=(const std::nullptr_t, const std::nullptr_t)
|
||||
{ return true; }
|
||||
|
||||
inline bool operator>=(const std::nullptr_t, const std::nullptr_t)
|
||||
{ return true; }
|
||||
|
||||
|
||||
using std::nullptr_t; // exported to global namespace.
|
||||
using std::nullptr_get; // exported to global namespace.
|
||||
|
||||
#endif // EA_COMPILER_NO_NULLPTR
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*-----------------------------------------------------------------------------
|
||||
* version.h
|
||||
*
|
||||
* Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef INCLUDED_EABASE_VERSION_H
|
||||
#define INCLUDED_EABASE_VERSION_H
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// EABASE_VERSION
|
||||
//
|
||||
// We more or less follow the conventional EA packaging approach to versioning
|
||||
// here. A primary distinction here is that minor versions are defined as two
|
||||
// digit entities (e.g. .03") instead of minimal digit entities ".3"). The logic
|
||||
// here is that the value is a counter and not a floating point fraction.
|
||||
// Note that the major version doesn't have leading zeros.
|
||||
//
|
||||
// Example version strings:
|
||||
// "0.91.00" // Major version 0, minor version 91, patch version 0.
|
||||
// "1.00.00" // Major version 1, minor and patch version 0.
|
||||
// "3.10.02" // Major version 3, minor version 10, patch version 02.
|
||||
// "12.03.01" // Major version 12, minor version 03, patch version
|
||||
//
|
||||
// Example usage:
|
||||
// printf("EABASE version: %s", EABASE_VERSION);
|
||||
// printf("EABASE version: %d.%d.%d", EABASE_VERSION_N / 10000 % 100, EABASE_VERSION_N / 100 % 100, EABASE_VERSION_N % 100);
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EABASE_VERSION
|
||||
#define EABASE_VERSION "2.09.12"
|
||||
#define EABASE_VERSION_N 20912
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,67 @@
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Copyright (C) Electronic Arts Inc. All rights reserved.
|
||||
#-------------------------------------------------------------------------------------------
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# CMake info
|
||||
#-------------------------------------------------------------------------------------------
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
project(EABaseTest CXX)
|
||||
include(CTest)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Defines
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
|
||||
add_definitions(-D_CHAR16T)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Compiler Flags
|
||||
#-------------------------------------------------------------------------------------------
|
||||
set (CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/packages/EASTL/scripts/CMake")
|
||||
include(CommonCppFlags)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Source files
|
||||
#-------------------------------------------------------------------------------------------
|
||||
file(GLOB EABASETEST_SOURCES "source/TestEABase.cpp" "source/TestEABase.h")
|
||||
set(SOURCES ${EABASETEST_SOURCES})
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Executable definition
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_executable(EABaseTest ${SOURCES})
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Dependencies
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_subdirectory(packages/EAAssert)
|
||||
add_subdirectory(packages/EAMain)
|
||||
add_subdirectory(packages/EASTL)
|
||||
add_subdirectory(packages/EAStdC)
|
||||
add_subdirectory(packages/EATest)
|
||||
add_subdirectory(packages/EAThread)
|
||||
|
||||
target_link_libraries(EABaseTest EAAssert)
|
||||
target_link_libraries(EABaseTest EAMain)
|
||||
target_link_libraries(EABaseTest EASTL)
|
||||
target_link_libraries(EABaseTest EAStdC)
|
||||
target_link_libraries(EABaseTest EATest)
|
||||
target_link_libraries(EABaseTest EAThread)
|
||||
|
||||
set(THREADS_PREFER_PTHREAD_FLAG ON)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if((NOT APPLE) AND (NOT WIN32))
|
||||
target_link_libraries(EABaseTest ${EASTLTest_Libraries} Threads::Threads rt)
|
||||
else()
|
||||
target_link_libraries(EABaseTest ${EASTLTest_Libraries} Threads::Threads)
|
||||
endif()
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Run Unit tests and verify the results.
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_test(EABaseTestRuns EABaseTest)
|
||||
set_tests_properties (EABaseTestRuns PROPERTIES PASS_REGULAR_EXPRESSION "RETURNCODE=0")
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
// EAMain/EAEntryPointMain.inl contains C++ code but it exposes the application entry point with C linkage.
|
||||
|
||||
#include "EAMain/EAEntryPointMain.inl"
|
||||
#include "EATest/EASTLNewOperatorGuard.inl"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,40 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#include <EABase/version.h>
|
||||
|
||||
|
||||
// What we do here is verify that EA_PRAGMA_ONCE_SUPPORTED works as intended.
|
||||
// This header file should be #included two times by TestEABase.cpp
|
||||
// in order to test this.
|
||||
|
||||
#if defined(EA_PRAGMA_ONCE_SUPPORTED)
|
||||
#pragma once
|
||||
const int EABaseOncePerTranslationUnitTestVariable = 0; // This should get compiled only once ever for a compilation unit.
|
||||
#else
|
||||
// Just implement a classic manual header include guard.
|
||||
// In this case we aren't really testing anything.
|
||||
#ifndef TESTEABASE_H
|
||||
#define TESTEABASE_H
|
||||
const int EABaseOncePerTranslationUnitTestVariable = 0;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// EA_EXTERN_TEMPLATE / EA_COMPILER_NO_EXTERN_TEMPLATE
|
||||
|
||||
#if defined(__cplusplus)
|
||||
template <typename T>
|
||||
struct eabase_template
|
||||
{
|
||||
T value;
|
||||
T GetValue() const { return value; }
|
||||
};
|
||||
|
||||
EA_EXTERN_TEMPLATE(struct eabase_template<char>);
|
||||
#endif
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,34 @@
|
||||
// The purpose of this compilation unit is to test EABase in the absence of other system headers.
|
||||
// For example TestEABase.cpp directly includes system headers like ctype.h, stddef.h, stdarg, etc.
|
||||
// However, these headers make it impossible to verify that certain definitions are being provided
|
||||
// by EABase instead of the system headers being included directly.
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
// This structure tests that EABase types are properly defined.
|
||||
struct EABaseDefinedTypesStruct
|
||||
{
|
||||
char8_t mChar8_t;
|
||||
char16_t mChar16_t;
|
||||
char32_t mChar32_t;
|
||||
wchar_t mWchar_t;
|
||||
bool8_t mBool8_t;
|
||||
int8_t mInt8_t;
|
||||
int16_t mInt16_t;
|
||||
int32_t mInt32_t;
|
||||
int64_t mInt64_t;
|
||||
uint8_t mUint8_t;
|
||||
uint16_t mUint16_t;
|
||||
uint32_t mUint32_t;
|
||||
uint64_t mUint64_t;
|
||||
intmax_t mIntmax_t;
|
||||
uintmax_t mUintmax_t;
|
||||
size_t mSize_t;
|
||||
ssize_t mSsize_t;
|
||||
float_t mFloat_t;
|
||||
double_t mDouble_t;
|
||||
intptr_t mIntptr_t;
|
||||
uintptr_t mUintptr_t;
|
||||
ptrdiff_t mPtrdiff_t;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
tags
|
||||
/build/
|
||||
build.bat
|
||||
@@ -0,0 +1,18 @@
|
||||
[submodule "test/packages/EATest"]
|
||||
path = test/packages/EATest
|
||||
url = git@github.com:electronicarts/EATest.git
|
||||
[submodule "test/packages/EAStdC"]
|
||||
path = test/packages/EAStdC
|
||||
url = git@github.com:electronicarts/EAStdC.git
|
||||
[submodule "test/packages/EAAssert"]
|
||||
path = test/packages/EAAssert
|
||||
url = git@github.com:electronicarts/EAAssert.git
|
||||
[submodule "test/packages/EAThread"]
|
||||
path = test/packages/EAThread
|
||||
url = git@github.com:electronicarts/EAThread.git
|
||||
[submodule "test/packages/EASTL"]
|
||||
path = test/packages/EASTL
|
||||
url = git@github.com:electronicarts/EASTL.git
|
||||
[submodule "test/packages/EABase"]
|
||||
path = test/packages/EABase
|
||||
url = git@github.com:electronicarts/EABase.git
|
||||
@@ -0,0 +1,71 @@
|
||||
language: cpp
|
||||
|
||||
cache:
|
||||
- ccache: true
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
- windows
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
- msvc
|
||||
|
||||
env:
|
||||
- EA_CONFIG=Debug
|
||||
- EA_CONFIG=Release
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- george-edison55-precise-backports
|
||||
- llvm-toolchain-trusty-7
|
||||
packages:
|
||||
- cmake
|
||||
- cmake-data
|
||||
- g++-7
|
||||
- clang-7
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- os: osx
|
||||
compiler: gcc
|
||||
- os: osx
|
||||
compiler: msvc
|
||||
- os: linux
|
||||
compiler: msvc
|
||||
- os: windows
|
||||
compiler: clang
|
||||
- os: windows
|
||||
compiler: gcc
|
||||
|
||||
# Handle git submodules yourself
|
||||
git:
|
||||
submodules: false
|
||||
|
||||
# Use sed to replace the SSH URL with the public URL, then initialize submodules
|
||||
before_install:
|
||||
- sed --version >/dev/null 2>&1 && sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules || sed -i "" 's/git@github.com:/https:\/\/github.com\//' .gitmodules
|
||||
- git submodule update --init
|
||||
|
||||
install:
|
||||
- if [[ "$CXX" == "g++" ]]; then export CC="gcc-7" ;fi
|
||||
- if [[ "$CXX" == "g++" ]]; then export CXX="g++-7" ;fi
|
||||
- if [[ "$CXX" == "clang++" && "${TRAVIS_OS_NAME}" != "osx" ]]; then export CC="clang-7" ;fi
|
||||
- if [[ "$CXX" == "clang++" && "${TRAVIS_OS_NAME}" != "osx" ]]; then export CXX="clang++-7" ;fi
|
||||
|
||||
# Universal Setup
|
||||
before_script:
|
||||
- mkdir build_$EA_CONFIG
|
||||
- cd build_$EA_CONFIG
|
||||
- cmake .. -DEAMAIN_BUILD_TESTS:BOOL=ON
|
||||
- cmake --build . --config $EA_CONFIG
|
||||
|
||||
script:
|
||||
# Run Tests
|
||||
- cd $TRAVIS_BUILD_DIR/build_$EA_CONFIG/test
|
||||
- ctest -C $EA_CONFIG -V || exit 1
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Copyright (C) Electronic Arts Inc. All rights reserved.
|
||||
#-------------------------------------------------------------------------------------------
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
project(EAMain CXX)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Options
|
||||
#-------------------------------------------------------------------------------------------
|
||||
option(EAMAIN_BUILD_TESTS "Enable generation of build files for tests" OFF)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Compiler Flags
|
||||
#-------------------------------------------------------------------------------------------
|
||||
set (CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/test/packages/EASTL/scripts/CMake")
|
||||
include(CommonCppFlags)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Library definition
|
||||
#-------------------------------------------------------------------------------------------
|
||||
file(GLOB EAMAIN_SOURCES "source/*.cpp" "source/internal/*.cpp")
|
||||
add_library(EAMain ${EAMAIN_SOURCES})
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Package Tests
|
||||
#-------------------------------------------------------------------------------------------
|
||||
if(EAMAIN_BUILD_TESTS)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Defines
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_definitions(-D_CHAR16T)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-DEAMAIN_NETWORK_CHANNEL_PORT=8080)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Export Include Directories
|
||||
#-------------------------------------------------------------------------------------------
|
||||
target_include_directories(EAMain PUBLIC include)
|
||||
target_include_directories(EAMain PUBLIC source)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Package Dependencies
|
||||
#-------------------------------------------------------------------------------------------
|
||||
target_link_libraries(EAMain EABase)
|
||||
target_link_libraries(EAMain EAAssert)
|
||||
target_link_libraries(EAMain EAStdC)
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
## Contributing
|
||||
|
||||
Before you can contribute, EA must have a Contributor License Agreement (CLA) on file that has been signed by each contributor.
|
||||
You can sign here: [Go to CLA](https://electronicarts.na1.echosign.com/public/esignWidget?wid=CBFCIBAA3AAABLblqZhByHRvZqmltGtliuExmuV-WNzlaJGPhbSRg2ufuPsM3P0QmILZjLpkGslg24-UJtek*)
|
||||
|
||||
### Pull Request Policy
|
||||
|
||||
All code contributions are submitted as [Github pull requests](https://help.github.com/articles/using-pull-requests/). All pull requests will be reviewed by a maintainer according to the guidelines found in the next section.
|
||||
|
||||
Your pull request should:
|
||||
|
||||
* merge cleanly
|
||||
* come with tests
|
||||
* tests should be minimal and stable
|
||||
* fail before your fix is applied
|
||||
* pass the test suite
|
||||
* code formatting is encoded in clang format
|
||||
* limit using clang format on new code
|
||||
* do not deviate from style already established in the files
|
||||
|
||||
### Running the Unit Tests
|
||||
|
||||
EAAssert uses CMake as its build system.
|
||||
|
||||
* Create and navigate to "your_build_folder":
|
||||
* mkdir your_build_folder && cd your_build_folder
|
||||
* Generate build scripts:
|
||||
* cmake source_folder -DEAMAIN_BUILD_TESTS:BOOL=ON
|
||||
* Build unit tests for "your_config":
|
||||
* cmake --build . --config your_config
|
||||
* Run the unit tests for "your_config" from the test folder:
|
||||
* cd test && ctest -C your_config
|
||||
|
||||
|
||||
Here is an example batch file.
|
||||
```batch
|
||||
set build_folder=out
|
||||
mkdir %build_folder%
|
||||
pushd %build_folder%
|
||||
call cmake .. -DEAMAIN_BUILD_TESTS:BOOL=ON
|
||||
call cmake --build . --config Release
|
||||
call cmake --build . --config Debug
|
||||
call cmake --build . --config RelWithDebInfo
|
||||
call cmake --build . --config MinSizeRel
|
||||
pushd test
|
||||
call ctest -C Release
|
||||
call ctest -C Debug
|
||||
call ctest -C RelWithDebInfo
|
||||
call ctest -C MinSizeRel
|
||||
popd
|
||||
popd
|
||||
```
|
||||
|
||||
Here is an example bash file
|
||||
```bash
|
||||
build_folder=out
|
||||
mkdir $build_folder
|
||||
pushd $build_folder
|
||||
cmake .. -DEAMAIN_BUILD_TESTS:BOOL=ON
|
||||
cmake --build . --config Release
|
||||
cmake --build . --config Debug
|
||||
cmake --build . --config RelWithDebInfo
|
||||
cmake --build . --config MinSizeRel
|
||||
pushd test
|
||||
ctest -C Release
|
||||
ctest -C Debug
|
||||
ctest -C RelWithDebInfo
|
||||
ctest -C MinSizeRel
|
||||
popd
|
||||
popd
|
||||
```
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright (C) 2017 Electronic Arts Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of
|
||||
its contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
@@ -0,0 +1,26 @@
|
||||
# EAMain
|
||||
|
||||
[](https://travis-ci.org/electronicarts/EAMain)
|
||||
|
||||
EAMain provides a multi-platform entry point used for platforms that don't support console output, return codes and command-line arguments.
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
Please see [Introduction](doc/EAMain.html).
|
||||
|
||||
|
||||
## Compiling sources
|
||||
|
||||
Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on compiling and testing the source.
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
Roberto Parolin is the current EAMain owner within EA and is responsible for the open source repository.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Modified BSD License (3-Clause BSD license) see the file LICENSE in the project root.
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
body
|
||||
{
|
||||
font-family: Palatino Linotype, Book Antiqua, Times New Roman;
|
||||
font-size: 11pt;
|
||||
}
|
||||
|
||||
h1
|
||||
{
|
||||
font-family: Verdana;
|
||||
display: block;
|
||||
background-color: #FFF0B0;
|
||||
border: solid 2px black;
|
||||
font-size: 16pt;
|
||||
font-weight: bold;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
h2
|
||||
{
|
||||
font-size: 14pt;
|
||||
font-family: Verdana;
|
||||
border-bottom: 2px solid black;
|
||||
}
|
||||
|
||||
h3
|
||||
{
|
||||
font-family: Verdana;
|
||||
font-size: 13pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.code-example
|
||||
{
|
||||
display: block;
|
||||
background-color: #e0e0f0;
|
||||
margin-left: 3em;
|
||||
margin-right: 3em;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
padding: 8px;
|
||||
border: solid 2px #a0a0d0;
|
||||
font-family: monospace;
|
||||
font-size: 10pt;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.code-example-span
|
||||
{
|
||||
font-family: monospace;
|
||||
font-size: 10pt;
|
||||
white-space: pre;
|
||||
}
|
||||
|
||||
.code-example-comment
|
||||
{
|
||||
background-color: #e0e0f0;
|
||||
padding: 0px 0px;
|
||||
font-family: monospace;
|
||||
font-size: 10pt;
|
||||
white-space: pre;
|
||||
color: #999999;
|
||||
margin: auto auto;
|
||||
}
|
||||
|
||||
|
||||
.faq-question
|
||||
{
|
||||
background-color: #D0E0D0;
|
||||
font-size: 12pt;
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.5em;
|
||||
margin-top: 0em;
|
||||
padding-left:8px;
|
||||
padding-right:8px;
|
||||
padding-top:2px;
|
||||
padding-bottom:2px
|
||||
}
|
||||
|
||||
.faq-answer
|
||||
{
|
||||
display: block;
|
||||
margin: 4pt 1em 0.5em 1em;
|
||||
}
|
||||
@@ -0,0 +1,291 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EAMAIN_EAENTRYPOINTMAIN_INL
|
||||
#define EAMAIN_EAENTRYPOINTMAIN_INL
|
||||
|
||||
#include <EAMain/internal/Version.h>
|
||||
#include <EAMain/EAMain.h>
|
||||
#include <EAMain/EAMainExit.h>
|
||||
|
||||
#include <EAMain/internal/EAMainStartupShutdown.h>
|
||||
|
||||
#if defined(EA_PLATFORM_WINDOWS)
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#include <EAStdC/EAString.h>
|
||||
#include <malloc.h>
|
||||
#define NOMINMAX
|
||||
#include <Windows.h>
|
||||
#undef NOMINMAX
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
#endif
|
||||
|
||||
|
||||
/// EAEntryPointMain
|
||||
///
|
||||
/// Provides a platform-independent main entry function. The user must implement
|
||||
/// this function himself. Different platforms have different variations of
|
||||
/// main and some platforms have multiple variations of main within the platform.
|
||||
/// EAEnrtyPointMain is a universal entrypoint which you can use to implement a platform-
|
||||
/// and string encoding- independent main entrypoint.
|
||||
///
|
||||
/// You use this function by #including "EATestApp/EAMain.h" and implementing the
|
||||
/// function. You don't need to use this function and this code is neither seen
|
||||
/// nor compiled if you don't use it. It is merely a convenience to deal with
|
||||
/// platform indepdence in a proper way and also a reference for how to do such
|
||||
/// a thing manually.
|
||||
///
|
||||
/// Microsoft-specific:
|
||||
/// By default an 8 bit C Standard main is implemented unless EAMAIN_MAIN_16 is defined.
|
||||
/// If EAMAIN_MAIN_16 is defined under a supporting Microsoft platform then either
|
||||
/// wWinMain or wmain is used. You need to use EAMAIN_MAIN_16 under Microsoft platforms if
|
||||
/// you want arguments to be in Unicode, as Windows 8 bit arguments are not UTF8 or any
|
||||
/// kind of Unicode.
|
||||
///
|
||||
/// Example usage:
|
||||
/// #include <EAMain/EAEntryPointMain.inl>
|
||||
///
|
||||
/// int EAMain(int argc, char** argv){
|
||||
/// printf("hello world");
|
||||
/// }
|
||||
///
|
||||
extern "C" int EAMain(int argc, char** argv);
|
||||
|
||||
namespace EA
|
||||
{
|
||||
namespace EAMain
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
EAMAIN_API extern EAMainFunction gEAMainFunction;
|
||||
|
||||
EAMAIN_API const char *ExtractPrintServerAddress(int argc, char **argv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Windows compilers #define _CONSOLE when the intended target is a console application instead of
|
||||
// a windows application.
|
||||
// Note: _CONSOLE doesn't seem to be getting defined automatically (at least for native nant builds).
|
||||
// Temporarily define _CONSOLE ourselves to allow the build to work on windows.
|
||||
#ifndef _CONSOLE
|
||||
#define _CONSOLE
|
||||
#endif
|
||||
|
||||
// Windows RT-based applications need to use Microsoft's Managed C++ extensions with their
|
||||
// Windows::ApplicationModel::Core::IFrameworkView class, as opposed to class C main(argc, argv).
|
||||
// Additionally, a new kind of main is required with the signature: int main(Platform::Array<Platform::String^>^ args).
|
||||
// The code below doesn't call EAEntryPointMain directly, but the WinRTRunner that it calls will call EAEntryPointMain.
|
||||
#if (defined(EA_PLATFORM_MICROSOFT) && !defined(CS_UNDEFINED_STRING) && !EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP))
|
||||
|
||||
// Allow the user to define their own WinRT application entry point should
|
||||
// they have a need to create their own IApplicationView.
|
||||
//
|
||||
// In most cases this shouldn't ever be touched. Likely, if you find you're
|
||||
// having to manipulate this then your application is in a state where it
|
||||
// has grown beyond EAMain's scope and you would be better served with a
|
||||
// custom entry point.
|
||||
#ifndef EAMAIN_WINRT_APPLICATION_ENTRY
|
||||
#define EAMAIN_WINRT_APPLICATION_ENTRY() { EA::EAMain::Internal::gEAMainFunction = ::EAMain; EA::EAMain::Internal::StartWinRtApplication(); }
|
||||
#endif
|
||||
|
||||
namespace EA
|
||||
{
|
||||
namespace EAMain
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
EAMAIN_API void StartWinRtApplication();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Platform::MTAThread]
|
||||
int main(Platform::Array<Platform::String^>^ /*args*/)
|
||||
{
|
||||
#if defined(EAMAIN_USE_INITFINI)
|
||||
EAMainInit();
|
||||
#endif
|
||||
|
||||
EA::EAMain::InitializeSignalHandler();
|
||||
|
||||
EAMAIN_WINRT_APPLICATION_ENTRY();
|
||||
|
||||
#if defined(EAMAIN_USE_INITFINI)
|
||||
EAMainFini();
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#elif defined(EA_PLATFORM_WINDOWS)
|
||||
#pragma warning(push, 0)
|
||||
#include <Windows.h>
|
||||
#include <shellapi.h>
|
||||
#pragma comment(lib, "shell32.lib")
|
||||
#pragma warning(pop)
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// To do: Some platforms may require reading the command line from a file.
|
||||
// Do we automatically do this for those platforms? Probably try to open a default file.
|
||||
// Do we support loading from a file from any platform? Probably so.
|
||||
#if defined(EAMAIN_USE_INITFINI)
|
||||
EAMainInit();
|
||||
#endif
|
||||
|
||||
EA::EAMain::Internal::gEAMainFunction = ::EAMain;
|
||||
|
||||
EA::EAMain::CommandLine commandLine(argc, argv);
|
||||
|
||||
const char *printServerAddress = EA::EAMain::Internal::ExtractPrintServerAddress(commandLine.Argc(), commandLine.Argv());
|
||||
EA::EAMain::Internal::EAMainStartup(printServerAddress);
|
||||
|
||||
EA::EAMain::InitializeSignalHandler();
|
||||
|
||||
int returnValue = EA::EAMain::Internal::gEAMainFunction(commandLine.Argc(), commandLine.Argv());
|
||||
|
||||
EA::EAMain::Internal::EAMainShutdown(returnValue);
|
||||
|
||||
#if defined(EAMAIN_USE_INITFINI)
|
||||
EAMainFini();
|
||||
#endif
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
int WINAPI wWinMainShared(HINSTANCE /*instance*/, HINSTANCE /*prevInstance*/, LPWSTR wCmdLine, int /*cmdShow*/)
|
||||
{
|
||||
int returnValue = 1;
|
||||
int argc = 0;
|
||||
wchar_t** wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
||||
|
||||
EA::EAMain::Internal::gEAMainFunction = ::EAMain;
|
||||
|
||||
if(wargv)
|
||||
{
|
||||
char8_t** argv = (char8_t**)_malloca(argc * sizeof(char8_t*));
|
||||
__analysis_assume(argv != NULL);
|
||||
|
||||
for(int i = 0; i < argc; i++)
|
||||
{
|
||||
argv[i] = NULL;
|
||||
const int requiredStrlen = EA::StdC::Strlcpy(argv[i], wargv[i], 0);
|
||||
argv[i] = (char8_t *)_malloca(sizeof(char8_t) * (requiredStrlen + 1));
|
||||
EA::StdC::Strlcpy(argv[i], wargv[i], requiredStrlen + 1);
|
||||
}
|
||||
|
||||
#if defined(EAMAIN_USE_INITFINI)
|
||||
EAMainInit();
|
||||
#endif
|
||||
|
||||
const char *printServerAddress = EA::EAMain::Internal::ExtractPrintServerAddress(argc, argv);
|
||||
EA::EAMain::Internal::EAMainStartup(printServerAddress);
|
||||
|
||||
EA::EAMain::InitializeSignalHandler();
|
||||
|
||||
returnValue = EA::EAMain::Internal::gEAMainFunction(argc, argv);
|
||||
EA::EAMain::Internal::EAMainShutdown(returnValue);
|
||||
|
||||
#if defined(EAMAIN_USE_INITFINI)
|
||||
EAMainFini();
|
||||
#endif
|
||||
LocalFree(wargv);
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
#if defined(EAMAIN_MAIN_16)
|
||||
int WINAPI wWinMain(HINSTANCE instance, HINSTANCE prevInstance, LPWSTR wCmdLine, int cmdShow)
|
||||
{
|
||||
return wWinMainShared(instance, prevInstance, wCmdLine, cmdShow);
|
||||
}
|
||||
#else
|
||||
int WINAPI WinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prevInstance, _In_ LPSTR cmdLine, _In_ int cmdShow)
|
||||
{
|
||||
size_t wCapacity = strlen(cmdLine) * 3; // UTF8 -> UCS2 requires at most 3 times the bytes.
|
||||
wchar_t* wCmdLine = (wchar_t*)_malloca(wCapacity);
|
||||
EA::StdC::Strlcpy(wCmdLine, cmdLine, wCapacity);
|
||||
|
||||
return wWinMainShared(instance, prevInstance, wCmdLine, cmdShow);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
#if defined(EA_PLATFORM_WINDOWS) && defined(EA_MAIN_16)
|
||||
int wmain(int argc, wchar_t** wargv)
|
||||
{
|
||||
EA::EAMain::Internal::gEAMainFunction = ::EAMain;
|
||||
|
||||
// Allocate and convert-copy wargv to argv.
|
||||
char8_t** argv = (char8_t**)_malloca(argc * sizeof(char8_t*));
|
||||
|
||||
for(int i = 0; i < argc; i++)
|
||||
{
|
||||
argv[i] = NULL;
|
||||
const int requiredStrlen = EA::StdC::Strlcpy(argv[i], wargv[i], 0);
|
||||
argv[i] = (char8_t)_malloca(sizeof(char8_t) * (requiredStrlen + 1));
|
||||
EA::StdC::Strlcpy(argv[i], wargv[i], requiredStrlen + 1);
|
||||
}
|
||||
|
||||
#if defined(EAMAIN_USE_INITFINI)
|
||||
EAMainInit();
|
||||
#endif
|
||||
|
||||
const char *printServerAddress = EA::EAMain::Internal::ExtractPrintServerAddress(argc, argv);
|
||||
EA::EAMain::Internal::EAMainStartup(printServerAddress);
|
||||
|
||||
EA::EAMain::InitializeSignalHandler();
|
||||
|
||||
int returnValue = EA::EAMain::Internal::gEAMainFunction(argc, argv);
|
||||
EA::EAMain::Internal::EAMainShutdown(returnValue);
|
||||
|
||||
#if defined(EAMAIN_USE_INITFINI)
|
||||
EAMainFini();
|
||||
#endif
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
#else
|
||||
#if !defined(EAMAIN_FORCE_MAIN_USAGE) // If the user defines EAMAIN_FORCE_MAIN_USAGE before #including this file, then main is used even if we don't normally use it for the given platform.
|
||||
#if defined(EA_PLATFORM_IPHONE)
|
||||
#define main iosMain
|
||||
extern "C" int iosMain(int argc, char** argv);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// To do: Some platforms may require reading the command line from a file.
|
||||
// Do we automatically do this for those platforms? Probably try to open a default file.
|
||||
// Do we support loading from a file from any platform? Probably so.
|
||||
#if defined(EAMAIN_USE_INITFINI)
|
||||
EAMainInit();
|
||||
#endif
|
||||
|
||||
EA::EAMain::Internal::gEAMainFunction = ::EAMain;
|
||||
|
||||
EA::EAMain::CommandLine commandLine(argc, argv);
|
||||
|
||||
const char *printServerAddress = EA::EAMain::Internal::ExtractPrintServerAddress(commandLine.Argc(), commandLine.Argv());
|
||||
EA::EAMain::Internal::EAMainStartup(printServerAddress);
|
||||
|
||||
EA::EAMain::InitializeSignalHandler();
|
||||
|
||||
int returnValue = EA::EAMain::Internal::gEAMainFunction(commandLine.Argc(), commandLine.Argv());
|
||||
|
||||
EA::EAMain::Internal::EAMainShutdown(returnValue);
|
||||
|
||||
#if defined(EAMAIN_USE_INITFINI)
|
||||
EAMainFini();
|
||||
#endif
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#endif // header include guard
|
||||
@@ -0,0 +1,211 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Provides a print server for retrieving console output and a simple
|
||||
// command line parser.
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EAMAIN_H
|
||||
#define EAMAIN_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0) // Microsoft headers generate warnings at our higher warning levels.
|
||||
#pragma warning(disable: 4530) // C++ exception handler used, but unwind semantics are not enabled.
|
||||
#pragma warning(disable: 4548) // Expression before comma has no effect; expected expression with side-effect.
|
||||
#pragma warning(disable: 4251) // class (some template) needs to have dll-interface to be used by clients.
|
||||
#endif
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#include <EAMain/internal/Version.h>
|
||||
|
||||
namespace EA
|
||||
{
|
||||
namespace EAMain
|
||||
{
|
||||
typedef int (*EAMainFunction)(int, char **);
|
||||
}
|
||||
}
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#include <stddef.h>
|
||||
#include <limits.h>
|
||||
#include <stdarg.h>
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
namespace EA
|
||||
{
|
||||
namespace EAMain
|
||||
{
|
||||
typedef void (*ReportFunction)(const char8_t*);
|
||||
EAMAIN_API void SetReportFunction(ReportFunction pReportFunction);
|
||||
EAMAIN_API ReportFunction GetReportFunction();
|
||||
EAMAIN_API ReportFunction GetDefaultReportFunction();
|
||||
|
||||
/// Report
|
||||
/// Provides a way to call Report with sprintf-style arguments.
|
||||
/// This function will call the Report function after formatting the output.
|
||||
/// This function acts just like printf, except that the output goes to the
|
||||
/// given report function.
|
||||
///
|
||||
/// The user needs to supply a newline if the user wants newlines, as the report
|
||||
/// function will not append one. The user may supply multiple newlines if desired.
|
||||
/// This is a low level function which user code can use to directly write
|
||||
/// information to the debug output. This function is also used by the higher
|
||||
/// level functionality here to write output.
|
||||
///
|
||||
/// This function is the equivalent of ReportVerbosity(0, pFormat, ...).
|
||||
///
|
||||
/// Example usage:
|
||||
/// Report("Time passed: %d\n", timeDelta);
|
||||
///
|
||||
EAMAIN_API void Report(const char8_t* pFormat, ...);
|
||||
|
||||
/// ReportVerbosity
|
||||
/// Same as Report, but is silent unless GetVerbosity() is >= the value specified as minVerbosity.
|
||||
/// Typically to do a non-error trace print, you would specify a minVerbosity of 1.
|
||||
/// If you are writing an error output, you can specify minVerbosity or 0, which is the same
|
||||
/// as calling Report().
|
||||
///
|
||||
/// Example usage:
|
||||
/// ReportVerbosity(1, "Time passed: %d\n", timeDelta);
|
||||
///
|
||||
EAMAIN_API void ReportVerbosity(unsigned minVerbosity, const char8_t* pFormat, ...);
|
||||
|
||||
/// VReport
|
||||
/// Called by EATest Report Wrapper to preserve the optional variable arguments
|
||||
///
|
||||
EAMAIN_API void VReport(const char8_t* pFormat, va_list arguments);
|
||||
|
||||
/// VReportVerbosity
|
||||
/// Called by EATest ReportVerbosity Wrapper to preserve the optional variable arguments
|
||||
///
|
||||
EAMAIN_API void VReportVerbosity(unsigned minVerbosity, const char8_t* pFormat, va_list arguments);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
/// GetVerbosity / SetVerbosity
|
||||
///
|
||||
/// A value of 0 means to output just error results.
|
||||
/// A value > 0 means to output more. This Test library doesn't itself
|
||||
/// use this verbosity value; it's intended for the application to use
|
||||
/// it while tracing test output.
|
||||
///
|
||||
EAMAIN_API unsigned GetVerbosity();
|
||||
EAMAIN_API void SetVerbosity(unsigned verbosity);
|
||||
|
||||
/// PlatformStartup / PlatformShutdown
|
||||
///
|
||||
/// Execute any necessary per-platform startup / shutdown code.
|
||||
/// This should be executed once as the first line of main() and
|
||||
/// once as the last line of main().
|
||||
///
|
||||
|
||||
/// DEPRECATED
|
||||
/// Please use the PlatformStartup(int argc, char **argv) preferably
|
||||
EAMAIN_API void PlatformStartup();
|
||||
|
||||
EAMAIN_API void PlatformStartup(int argc, char **argv);
|
||||
|
||||
EAMAIN_API void PlatformStartup(const char *printServerNetworkAddress);
|
||||
|
||||
EAMAIN_API void PlatformShutdown(int nError);
|
||||
|
||||
/// CommandLine
|
||||
///
|
||||
/// Implements a small command line parser.
|
||||
///
|
||||
/// Example usage:
|
||||
/// int main(int argc, char** argv) {
|
||||
/// CommandLine cmdLine(argc, argv);
|
||||
/// printf("%d", cmdLine.Argc());
|
||||
/// }
|
||||
///
|
||||
class EAMAIN_API CommandLine
|
||||
{
|
||||
public:
|
||||
enum Flags
|
||||
{
|
||||
FLAG_NONE = 0,
|
||||
FLAG_NO_PROGRAM_NAME = 1 << 0
|
||||
};
|
||||
|
||||
static const char DEFAULT_DELIMITER = ':';
|
||||
static const int MAX_COMMANDLINE_ARGS = 128;
|
||||
|
||||
CommandLine(int argc, char** argv);
|
||||
explicit CommandLine(const char *commandLineString);
|
||||
CommandLine(const char *commandLineString, unsigned int flags);
|
||||
~CommandLine();
|
||||
|
||||
int FindSwitch(const char *pSwitch, bool bCaseSensitive = false, const char **pResult = NULL, int nStartingIndex = 0, char delimiter = DEFAULT_DELIMITER) const;
|
||||
bool HasHelpSwitch() const;
|
||||
|
||||
int Argc() const
|
||||
{
|
||||
return mArgc;
|
||||
}
|
||||
|
||||
char** Argv() const
|
||||
{
|
||||
return mArgv;
|
||||
}
|
||||
|
||||
const char *Arg(int pos) const
|
||||
{
|
||||
if (pos <= mArgc)
|
||||
{
|
||||
return mArgv[pos];
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private:
|
||||
void ParseCommandLine(const char *args, unsigned int flags);
|
||||
|
||||
int mArgc;
|
||||
char** mArgv;
|
||||
char* mCommandLine;
|
||||
};
|
||||
|
||||
|
||||
} //namespace EAMain
|
||||
|
||||
#if (defined(EA_PLATFORM_MICROSOFT) && !defined(CS_UNDEFINED_STRING) && !EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP))
|
||||
namespace EAMain
|
||||
{
|
||||
// Helper class for spawning tests in a separate thread on WinRT platforms, works around <future> include issues.
|
||||
class IWinRTRunner
|
||||
{
|
||||
public:
|
||||
virtual ~IWinRTRunner() {}
|
||||
virtual void Run(int argc = 0, char** argv = NULL) = 0;
|
||||
virtual bool IsFinished() = 0;
|
||||
virtual void ReportResult() = 0;
|
||||
};
|
||||
|
||||
EAMAIN_API IWinRTRunner* CreateWinRTRunner();
|
||||
}
|
||||
#elif defined(EA_PLATFORM_KETTLE)
|
||||
namespace EAMain
|
||||
{
|
||||
// By default EAMain will spawn a thread on Kettle which calls Gnm::submitDone to prevent
|
||||
// the OS frome terminating the application.
|
||||
//
|
||||
// Applications that want to use the GPU (and will therefore need to call submitDone themselves)
|
||||
// can call DisableSubmitDoneThread() after EAMain() is called. No calls to submitDone will be made
|
||||
// by this thread once DisableSubmitDoneThread() returns.
|
||||
//
|
||||
// Note: For thread safety, this function must be called from the same thread that EAMain is called from.
|
||||
void DisableSubmitDoneThread();
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace EA
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // Header include guard
|
||||
@@ -0,0 +1,48 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Provides an exit function for clients to immediately close the application
|
||||
// without needing to throw an exception or call abort.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EAMAINEXIT_H
|
||||
#define EAMAINEXIT_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0) // Microsoft headers generate warnings at our higher warning levels.
|
||||
#pragma warning(disable: 4530) // C++ exception handler used, but unwind semantics are not enabled.
|
||||
#pragma warning(disable: 4548) // Expression before comma has no effect; expected expression with side-effect.
|
||||
#pragma warning(disable: 4251) // class (some template) needs to have dll-interface to be used by clients.
|
||||
#endif
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#include <EAMain/internal/Version.h>
|
||||
|
||||
namespace EA {
|
||||
namespace EAMain {
|
||||
enum ExitCodes {
|
||||
ExitCode_Succeeded,
|
||||
ExitCode_Asserted,
|
||||
ExitCode_SignalAbort,
|
||||
ExitCode_SignalSegmentationViolation,
|
||||
ExitCode_SignalIllegalInstruction,
|
||||
ExitCode_SignalHangup,
|
||||
ExitCode_SignalFloatingPointException,
|
||||
ExitCode_SignalBusError,
|
||||
ExitCode_Unknown,
|
||||
ExitCode_Max
|
||||
};
|
||||
|
||||
EAMAIN_API EA_NO_INLINE void Exit(int exitcode);
|
||||
|
||||
EAMAIN_API EA_NO_INLINE void InitializeSignalHandler();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif // Header include guard
|
||||
@@ -0,0 +1,66 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EAMAIN_EAENTRYPOINTMAIN_INITFINI_H
|
||||
#define EAMAIN_EAENTRYPOINTMAIN_INITFINI_H
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// This is a file that you can #include before #including <EAMain/EAEntryPointMain.inl>
|
||||
// If you #include this file or otherwise #define EAMAIN_USE_INITFINI then you are
|
||||
// expected to provide the extern "C" function implementations below in your
|
||||
// application. These two functions will be called before EAMain and after EAMain
|
||||
// respectively, to give the application a chance to do things like set up and
|
||||
// shutdown a custom memory manager.
|
||||
//
|
||||
// Example usage:
|
||||
// #include <EAMain/EAMainInitFini.inl>
|
||||
// #include <EAMain/EAEntryPointMain.inl>
|
||||
//
|
||||
// extern "C" void EAMainInit()
|
||||
// {
|
||||
// using namespace EA::Allocator;
|
||||
//
|
||||
// EA::EAMain::PlatformStartup();
|
||||
// SetGeneralAllocator(&gEAGeneralAllocator); // This example assumes you are using a heap named as such.
|
||||
// gEAGeneralAllocator.SetOption(GeneralAllocatorDebug::kOptionEnablePtrValidation, 0);
|
||||
// gEAGeneralAllocator.SetAutoHeapValidation(GeneralAllocator::kHeapValidationLevelBasic, 64);
|
||||
// }
|
||||
//
|
||||
// void EAMainFini()
|
||||
// {
|
||||
// if(EA::EAMain::GetVerbosity() > 0)
|
||||
// EA::Allocator::gEAGeneralAllocator.TraceAllocatedMemory();
|
||||
// EA::EAMain::PlatformShutdown(gTestResult);
|
||||
// }
|
||||
//
|
||||
// int EAMain(int argc, char** argv)
|
||||
// {
|
||||
// . . .
|
||||
// }
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef EAMAIN_EAENTRYPOINTMAIN_INL
|
||||
#error EAMainInitFini.inl must be included before EAMainEntryPoint.inl
|
||||
#endif
|
||||
|
||||
/// EAMainInit / EAMainFini
|
||||
///
|
||||
/// This functions are declared here, but must be defined in user code.
|
||||
///
|
||||
extern "C" void EAMainInit();
|
||||
extern "C" void EAMainFini();
|
||||
|
||||
|
||||
/// EAMAIN_USE_INITFINI
|
||||
///
|
||||
/// Defined or not defined. When defined it directs EAEntryPointMain.inl to call
|
||||
/// EAMainInit before EAMain and call EAMainFini after EAMain returns.
|
||||
///
|
||||
#if !defined(EAMAIN_USE_INITFINI)
|
||||
#define EAMAIN_USE_INITFINI 1
|
||||
#endif
|
||||
|
||||
|
||||
#endif // header include guard
|
||||
@@ -0,0 +1,26 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef IPHONEENTRY_H
|
||||
#define IPHONEENTRY_H
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace EA
|
||||
{
|
||||
namespace EAMain
|
||||
{
|
||||
// Allows the user to specify their own custom Application Delegate, to
|
||||
// replace the one defined in IPhoneEntry.mm. Be warned that if you want
|
||||
// to run tests on the EATech Build Farm, you may need to implement some
|
||||
// of the behaviours of the EAMainAppDelegate in your custom delegate,
|
||||
// specifically the "Tests complete" alert.
|
||||
void SetAppDelegateName(const char* delegateName);
|
||||
|
||||
// Accessors for command-line arguments
|
||||
int GetArgC();
|
||||
char** GetArgV();
|
||||
}
|
||||
}
|
||||
#endif // Header include guard
|
||||
@@ -0,0 +1,57 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EAMAIN_ICHANNEL_H
|
||||
#define EAMAIN_ICHANNEL_H
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#include <EAMain/internal/Version.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#include <stdio.h>
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
namespace EA
|
||||
{
|
||||
namespace EAMain
|
||||
{
|
||||
// -----------------------------------------------------------
|
||||
// Interface for EAMain channels
|
||||
// -----------------------------------------------------------
|
||||
class EAMAIN_API IChannel
|
||||
{
|
||||
public:
|
||||
virtual ~IChannel() {}
|
||||
virtual void Init() {}
|
||||
virtual void Send(const char8_t* pData) {}
|
||||
virtual void Shutdown() {}
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------
|
||||
// Basic channel that echos to stdout.
|
||||
// -----------------------------------------------------------
|
||||
class EAMAIN_API PrintfChannel : public IChannel
|
||||
{
|
||||
public:
|
||||
virtual ~PrintfChannel() {}
|
||||
virtual void Send(const char8_t* pData);
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------
|
||||
// Channel that serializes output data to a file.
|
||||
// -----------------------------------------------------------
|
||||
class EAMAIN_API FileChannel : public IChannel
|
||||
{
|
||||
public:
|
||||
virtual ~FileChannel() {}
|
||||
virtual void Init();
|
||||
virtual void Send(const char8_t* pData);
|
||||
virtual void Shutdown();
|
||||
|
||||
private:
|
||||
FILE* mFileHandle;
|
||||
};
|
||||
}}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EAMAIN_PRINTMANAGER_H
|
||||
#define EAMAIN_PRINTMANAGER_H
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#include <EAMain/internal/Version.h>
|
||||
|
||||
#define TO_STRING(x) #x
|
||||
#define MACRO_TO_STRING(x) TO_STRING(x)
|
||||
|
||||
namespace EA
|
||||
{
|
||||
namespace EAMain
|
||||
{
|
||||
class IChannel;
|
||||
|
||||
enum EAMainChannel
|
||||
{
|
||||
CHANNEL_PRINTF = 0,
|
||||
CHANNEL_NETWORK,
|
||||
CHANNEL_FILE,
|
||||
CHANNEL_MAX
|
||||
};
|
||||
|
||||
class EAMAIN_API PrintManager
|
||||
{
|
||||
public:
|
||||
PrintManager();
|
||||
static PrintManager& Instance();
|
||||
|
||||
void Startup(const char8_t* ServerIP);
|
||||
void Shutdown();
|
||||
|
||||
void Send(const char8_t* pData);
|
||||
void Add(EAMainChannel channel, IChannel* instance);
|
||||
void Remove(EAMainChannel channel, IChannel* instance);
|
||||
void ClearChannel(EAMainChannel channel);
|
||||
|
||||
private:
|
||||
IChannel* m_Channels[CHANNEL_MAX];
|
||||
};
|
||||
}}
|
||||
|
||||
#endif // header include guard
|
||||
@@ -0,0 +1,27 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EAMAIN_EAENTRYPOINTMAIN_INTERNAL_STARTUPSHUTDOWN_H
|
||||
#define EAMAIN_EAENTRYPOINTMAIN_INTERNAL_STARTUPSHUTDOWN_H
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#include <EAMain/internal/EAMainPrintManager.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#include <stdio.h>
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
namespace EA
|
||||
{
|
||||
namespace EAMain
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
EAMAIN_API void EAMainStartup(const char* printServerAddress = NULL);
|
||||
EAMAIN_API int EAMainShutdown(int errorCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // header include guard
|
||||
@@ -0,0 +1,83 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EAMAIN_EAENTRYPOINTMAIN_INTERNAL_STARTUPSHUTDOWN_H
|
||||
#define EAMAIN_EAENTRYPOINTMAIN_INTERNAL_STARTUPSHUTDOWN_H
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#include <EAMain/internal/EAMainPrintManager.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#include <stdio.h>
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
namespace EA
|
||||
{
|
||||
namespace EAMain
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
|
||||
// Handle the internal EAMain main start-up
|
||||
//
|
||||
inline void EAMainStartup(const char8_t* ServerIP = NULL)
|
||||
{
|
||||
static bool sEAMainShutdown_StartupHandled = false;
|
||||
|
||||
if(!sEAMainShutdown_StartupHandled)
|
||||
{
|
||||
sEAMainShutdown_StartupHandled = true;
|
||||
|
||||
// Running under NAnt output only appears when the buffer is filled if we allow the default buffering scheme for printf.
|
||||
setvbuf(stdout, NULL, _IONBF, BUFSIZ);
|
||||
setvbuf(stderr, NULL, _IONBF, BUFSIZ);
|
||||
|
||||
// Startup the print manager
|
||||
//
|
||||
EA::EAMain::PrintManager::Instance().Startup(ServerIP);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Handle the internal EAMain main shutdown
|
||||
//
|
||||
inline int EAMainShutdown(int errorCount)
|
||||
{
|
||||
static bool sEAMainShutdown_ShutdownHandled = false;
|
||||
|
||||
if(!sEAMainShutdown_ShutdownHandled)
|
||||
{
|
||||
sEAMainShutdown_ShutdownHandled = true;
|
||||
|
||||
// Handle the application specific exit code.
|
||||
//
|
||||
#if defined(EA_PLATFORM_IPHONE)
|
||||
// Get test result. (iOS 5 bug prevents iPhone Runner from getting this from the exit code)
|
||||
if (errorCount == 0)
|
||||
Report("\nAll tests completed successfully.\n");
|
||||
else
|
||||
Report("\nTests failed. Total error count: %d\n", errorCount);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
#if !defined(EA_PLATFORM_DESKTOP) && !defined(EA_PLATFORM_SERVER) // TODO: change define to something related to the StdC library used on the system.
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
// Required so the EAMainPrintServer can terminate with the correct error code.
|
||||
//
|
||||
EA::EAMain::Report("RETURNCODE=%d\n", errorCount);
|
||||
|
||||
// Shutdown the EAMain print manager.
|
||||
//
|
||||
EA::EAMain::PrintManager::Instance().Shutdown();
|
||||
}
|
||||
|
||||
return errorCount;
|
||||
}
|
||||
} //namespace Internal
|
||||
} // namespace EAMain
|
||||
} // namespace EA
|
||||
|
||||
#endif // header include guard
|
||||
@@ -0,0 +1,116 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EAMAIN_INTERNAL_VERSION_H
|
||||
#define EAMAIN_INTERNAL_VERSION_H
|
||||
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// EAMAIN_VERSION
|
||||
//
|
||||
// EAMain, at least from version `2.15.0`, adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
|
||||
//
|
||||
// Example usage:
|
||||
// printf("EAMAIN version: %s", EAMAIN_VERSION);
|
||||
// printf("EAMAIN version: %d.%d.%d", EAMAIN_VERSION_N / 10000 % 100, EAMAIN_VERSION_N / 100 % 100, EAMAIN_VERSION_N % 100);
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EAMAIN_VERSION
|
||||
#define EAMAIN_VERSION "3.01.01"
|
||||
#define EAMAIN_VERSION_N ((EA_MAIN_VERSION_MAJOR * 10000) + (EA_MAIN_VERSION_MINOR * 100) + (EA_MAIN_VERSION_PATCH))
|
||||
#endif
|
||||
|
||||
#if defined _MSC_VER
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
/*
|
||||
This file provides a version number of the EAMain package for your own code to check against.
|
||||
|
||||
Major, minor and patch versions are defined and updated each release.
|
||||
*/
|
||||
|
||||
// Define the major, minor and patch versions.
|
||||
// This information is updated with each release.
|
||||
|
||||
//! This define indicates the major version number for the package.
|
||||
//! \sa EA_MAIN_VERSION
|
||||
#define EA_MAIN_VERSION_MAJOR 3
|
||||
//! This define indicates the minor version number for the package.
|
||||
//! \sa EA_MAIN_VERSION
|
||||
#define EA_MAIN_VERSION_MINOR 0
|
||||
//! This define indicates the patch version number for the package.
|
||||
//! \sa EA_MAIN_VERSION
|
||||
#define EA_MAIN_VERSION_PATCH 1
|
||||
//! This define can be used for convenience when printing the version number
|
||||
//! \sa EA_MAIN_VERSION
|
||||
#define EA_MAIN_VERSION_STRING EA_MAIN_VERSION
|
||||
|
||||
/*!
|
||||
* This is a utility macro that users may use to create a single version number
|
||||
* that can be compared against EA_MAIN_VERSION.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* \code
|
||||
*
|
||||
* #if EA_MAIN_VERSION > EA_MAIN_CREATE_VERSION_NUMBER( 1, 1, 0 )
|
||||
* printf("EAMain version is greater than 1.1.0.\n");
|
||||
* #endif
|
||||
*
|
||||
* \endcode
|
||||
*/
|
||||
#define EA_MAIN_CREATE_VERSION_NUMBER( major_ver, minor_ver, patch_ver ) \
|
||||
((major_ver) * 1000000 + (minor_ver) * 1000 + (patch_ver))
|
||||
|
||||
/*!
|
||||
* This macro is an aggregate of the major, minor and patch version numbers.
|
||||
* \sa EA_MAIN_CREATE_VERSION_NUMBER
|
||||
*/
|
||||
#define EA_MAIN_VERSION \
|
||||
EA_MAIN_CREATE_VERSION_NUMBER( EA_MAIN_VERSION_MAJOR, EA_MAIN_VERSION_MINOR, EA_MAIN_VERSION_PATCH )
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// EAMAIN_DLL
|
||||
//
|
||||
// Defined as 0 or 1. The default is dependent on the definition of EA_DLL.
|
||||
// If EA_DLL is defined, then EAMAIN_DLL is 1, else EAMAIN_DLL is 0.
|
||||
// EA_DLL is a define that controls DLL builds within the EAConfig build system.
|
||||
//
|
||||
#ifndef EAMAIN_DLL
|
||||
#if defined(EA_DLL)
|
||||
#define EAMAIN_DLL 1
|
||||
#else
|
||||
#define EAMAIN_DLL 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef EAMAIN_API // If the build file hasn't already defined this to be dllexport...
|
||||
#if defined(EAMAIN_DLL) && EAMAIN_DLL
|
||||
#if defined(_MSC_VER)
|
||||
#define EAMAIN_API __declspec(dllimport)
|
||||
#define EAMAIN_LOCAL
|
||||
#elif defined(__CYGWIN__)
|
||||
#define EAMAIN_API __attribute__((dllimport))
|
||||
#define EAMAIN_LOCAL
|
||||
#elif (defined(__GNUC__) && (__GNUC__ >= 4))
|
||||
#define EAMAIN_API __attribute__ ((visibility("default")))
|
||||
#define EAMAIN_LOCAL __attribute__ ((visibility("hidden")))
|
||||
#else
|
||||
#define EAMAIN_API
|
||||
#define EAMAIN_LOCAL
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define EAMAIN_API
|
||||
#define EAMAIN_LOCAL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // Header include guard
|
||||
@@ -0,0 +1,10 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EAMAIN_VERSION_H
|
||||
#define EAMAIN_VERSION_H
|
||||
|
||||
#include <EAMain/internal/Version.h>
|
||||
|
||||
#endif // EA_MAIN_VERSION_H
|
||||
@@ -0,0 +1,337 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "EABase/eabase.h"
|
||||
#if (defined(EA_PLATFORM_MICROSOFT) && !defined(CS_UNDEFINED_STRING) && !EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP))
|
||||
#include <EAAssert/eaassert.h>
|
||||
#include <EAMain/EAMain.h>
|
||||
#include <EAStdC/EASprintf.h>
|
||||
#include <EAStdC/EAString.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#pragma warning(disable: 4472 4355) // additional warnings generated by XDK with VS2015
|
||||
#include <memory>
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <Windows.h>
|
||||
|
||||
#if defined EA_PLATFORM_CAPILANO
|
||||
#if defined EAMAIN_CAPILANO_DX12
|
||||
#include <d3d12_x.h>
|
||||
#else
|
||||
#include <d3d11_x.h>
|
||||
#endif
|
||||
#endif
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
namespace EA
|
||||
{
|
||||
namespace EAMain
|
||||
{
|
||||
|
||||
// Application - implements the required functionality for a application
|
||||
ref class ApplicationView sealed : public Windows::ApplicationModel::Core::IFrameworkView
|
||||
{
|
||||
public:
|
||||
// IFrameworkView Methods
|
||||
virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView);
|
||||
virtual void SetWindow(Windows::UI::Core::CoreWindow^ window) {}
|
||||
virtual void Load(Platform::String^ entryPoint);
|
||||
virtual void Run();
|
||||
virtual void Uninitialize();
|
||||
private:
|
||||
char *mCommandLine;
|
||||
#if EA_PLATFORM_CAPILANO
|
||||
#if defined EAMAIN_CAPILANO_DX12
|
||||
ID3D12CommandQueue* mpCommandQueue;
|
||||
#else
|
||||
ID3DXboxPerformanceContext* mpD3DXboxPerfContext;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void CreateDeviceResources();
|
||||
void OnActivated( Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args );
|
||||
};
|
||||
|
||||
// ApplicationSource - responsible for creating the Application instance and passing it back to the system
|
||||
ref class ApplicationViewSource : Windows::ApplicationModel::Core::IFrameworkViewSource
|
||||
{
|
||||
public:
|
||||
virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView()
|
||||
{
|
||||
return ref new ApplicationView();
|
||||
}
|
||||
};
|
||||
|
||||
void OutputAppTransition(const char* transition, const wchar_t* sender, const wchar_t* args)
|
||||
{
|
||||
char msg[1024];
|
||||
|
||||
EA::StdC::Snprintf(msg, EAArrayCount(msg), "****\n app is %s.\n sender: ", transition);
|
||||
EA::StdC::Strlcat(msg, sender, EAArrayCount(msg));
|
||||
EA::StdC::Strlcat(msg, "\n args: ", EAArrayCount(msg));
|
||||
EA::StdC::Strlcat(msg, args, EAArrayCount(msg));
|
||||
EA::StdC::Strlcat(msg, "\n****\n", EAArrayCount(msg));
|
||||
|
||||
OutputDebugStringA(msg);
|
||||
}
|
||||
|
||||
void ApplicationView::CreateDeviceResources()
|
||||
{
|
||||
#if defined EA_PLATFORM_CAPILANO
|
||||
#if defined EAMAIN_CAPILANO_DX12
|
||||
ID3D12Device* pD3DDevice;
|
||||
|
||||
HRESULT hr = D3D12CreateDevice(
|
||||
nullptr, // specify null to use the default adapter
|
||||
D3D_FEATURE_LEVEL_11_0,
|
||||
__uuidof(ID3D12Device),
|
||||
(void**)&pD3DDevice
|
||||
);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
OutputDebugStringA("Failed to create device. Suspending will not work for this application.");
|
||||
return;
|
||||
}
|
||||
|
||||
D3D12XBOX_COMMAND_QUEUE_DESC queueDesc = {};
|
||||
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
||||
queueDesc.EngineOrPipeIndex = 0;
|
||||
queueDesc.QueueIndex = 0;
|
||||
|
||||
hr = pD3DDevice->CreateCommandQueueX(&queueDesc, __uuidof(ID3D12CommandQueue), (void**)&mpCommandQueue);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
OutputDebugStringA("Failed to create command queue. Suspending will not work for this application.");
|
||||
}
|
||||
|
||||
if (pD3DDevice) { pD3DDevice->Release(); pD3DDevice = NULL; }
|
||||
#else
|
||||
// This flag adds support for surfaces with a different color channel ordering than the API default.
|
||||
// It is recommended usage, and is required for compatibility with Direct2D.
|
||||
UINT creationFlags = D3D11_CREATE_DEVICE_INSTRUMENTED;
|
||||
|
||||
// This array defines the set of DirectX hardware feature levels this app will support.
|
||||
// Note the ordering should be preserved.
|
||||
// Don't forget to declare your application's minimum required feature level in its
|
||||
// description. All applications are assumed to support 9.1 unless otherwise stated.
|
||||
D3D_FEATURE_LEVEL featureLevels[] =
|
||||
{
|
||||
D3D_FEATURE_LEVEL_11_0
|
||||
};
|
||||
|
||||
// Create the DX11 API device object, and get a corresponding context.
|
||||
ID3D11Device* pD3DDevice;
|
||||
ID3D11DeviceContext* pD3DDeviceContext;
|
||||
|
||||
HRESULT hr = D3D11CreateDevice(
|
||||
nullptr, // specify null to use the default adapter
|
||||
D3D_DRIVER_TYPE_HARDWARE,
|
||||
nullptr, // leave as nullptr unless software device
|
||||
creationFlags, // optionally set debug and Direct2D compatibility flags
|
||||
featureLevels, // list of feature levels this app can support
|
||||
ARRAYSIZE(featureLevels), // number of entries in above list
|
||||
D3D11_SDK_VERSION, // always set this to D3D11_SDK_VERSION
|
||||
&pD3DDevice, // returns the Direct3D device created
|
||||
NULL, // returns feature level of device created
|
||||
&pD3DDeviceContext // returns the device immediate context
|
||||
);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
OutputDebugStringA("Failed to create device. Suspending will not work for this application.");
|
||||
return;
|
||||
}
|
||||
|
||||
hr = pD3DDevice->QueryInterface(__uuidof(mpD3DXboxPerfContext), (void **)&mpD3DXboxPerfContext);
|
||||
|
||||
if (FAILED(hr))
|
||||
{
|
||||
OutputDebugStringA("Failed to get perfcontext. Suspending will not work for this application.");
|
||||
}
|
||||
|
||||
if (pD3DDevice) { pD3DDevice->Release(); pD3DDevice = NULL; }
|
||||
if (pD3DDeviceContext) { pD3DDeviceContext->Release(); pD3DDeviceContext = NULL; }
|
||||
#endif
|
||||
#else
|
||||
// Do nothing
|
||||
#endif
|
||||
}
|
||||
|
||||
// Called by the system. Perform application initialization here,
|
||||
// hooking application wide events, etc.
|
||||
void ApplicationView::Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView)
|
||||
{
|
||||
using namespace Platform;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::ApplicationModel;
|
||||
using namespace Windows::ApplicationModel::Core;
|
||||
using namespace Windows::ApplicationModel::Activation;
|
||||
|
||||
// Creates any resources required by the platform to run an application / enable a particular feature set (like GPU profiling or suspend/resume)
|
||||
CreateDeviceResources();
|
||||
|
||||
#pragma warning(push)
|
||||
// Disables warning for MS class 'Windows::Foundation::TypedEventHandler<TSender,TResult>::{ctor}::__abi_PointerToMemberCapture'
|
||||
// "layout of class may have changed from a previous version of the compiler due to better packing of member 'Windows::Foundation::TypedEventHandler<TSender,TResult>::{ctor}::__abi_PointerToMemberCapture::member'"
|
||||
#pragma warning(disable:4371)
|
||||
applicationView->Activated += ref new Windows::Foundation::TypedEventHandler< CoreApplicationView^, IActivatedEventArgs^ >( this, &ApplicationView::OnActivated );
|
||||
#pragma warning(pop)
|
||||
CoreApplication::Suspending += ref new EventHandler<SuspendingEventArgs^>([this](Object^ sender, SuspendingEventArgs^ args) {
|
||||
OutputAppTransition("suspending", sender ? sender->ToString()->Data() : L"NULL", args ? args->ToString()->Data() : L"NULL");
|
||||
#if defined EA_PLATFORM_CAPILANO
|
||||
#if defined EAMAIN_CAPILANO_DX12
|
||||
mpCommandQueue->SuspendX(0);
|
||||
#else
|
||||
mpD3DXboxPerfContext->Suspend(0);
|
||||
#endif
|
||||
#endif
|
||||
});
|
||||
CoreApplication::Resuming += ref new EventHandler<Object^>([this](Object^ sender, Object^ args) {
|
||||
OutputAppTransition("resuming", sender ? sender->ToString()->Data() : L"NULL", args ? args->ToString()->Data() : L"NULL");
|
||||
#if defined EA_PLATFORM_CAPILANO
|
||||
#if defined EAMAIN_CAPILANO_DX12
|
||||
mpCommandQueue->ResumeX();
|
||||
#else
|
||||
mpD3DXboxPerfContext->Resume();
|
||||
#endif
|
||||
#endif
|
||||
});
|
||||
CoreApplication::Exiting += ref new EventHandler<Object^>([](Object^ sender, Object^ args) {
|
||||
OutputAppTransition("exiting", sender ? sender->ToString()->Data() : L"NULL", args ? args->ToString()->Data() : L"NULL");
|
||||
});
|
||||
}
|
||||
|
||||
static char *ConvertLaunchArgsToMultibyte(LPCWSTR rawArgumentString, int rawArgumentStringLength)
|
||||
{
|
||||
int bufferSize = WideCharToMultiByte(
|
||||
CP_UTF8,
|
||||
0,
|
||||
rawArgumentString,
|
||||
rawArgumentStringLength,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
char *commandLine = static_cast<char *>(calloc(bufferSize + 1, 1));
|
||||
int rv = WideCharToMultiByte(
|
||||
CP_UTF8,
|
||||
0,
|
||||
rawArgumentString,
|
||||
rawArgumentStringLength,
|
||||
commandLine,
|
||||
bufferSize + 1,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
commandLine[bufferSize] = 0;
|
||||
EA_ASSERT(rv == bufferSize);
|
||||
EA_UNUSED(rv); // avoids warnings in opt builds regarding unused variables
|
||||
|
||||
return commandLine;
|
||||
}
|
||||
|
||||
static char *ReadArgsFromFile()
|
||||
{
|
||||
FILE *fp = fopen("EAMainArgsFile.txt", "rb");
|
||||
|
||||
if (fp == NULL)
|
||||
{
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
size_t fileSize;
|
||||
fseek(fp, 0, SEEK_END);
|
||||
fileSize = static_cast<size_t>(ftell(fp));
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
char *argsBuffer = static_cast<char *>(calloc(fileSize + 1, 1));
|
||||
|
||||
if (fread(argsBuffer, 1, fileSize, fp) != fileSize)
|
||||
{
|
||||
goto error_return_free_buffer;
|
||||
}
|
||||
|
||||
return argsBuffer;
|
||||
|
||||
error_return_free_buffer:
|
||||
free(argsBuffer);
|
||||
fclose(fp);
|
||||
|
||||
error_return:
|
||||
return static_cast<char *>(calloc(1, 1));
|
||||
}
|
||||
|
||||
void ApplicationView::OnActivated( Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args )
|
||||
{
|
||||
if (args->Kind == Windows::ApplicationModel::Activation::ActivationKind::Launch)
|
||||
{
|
||||
Windows::ApplicationModel::Activation::LaunchActivatedEventArgs ^launchArgs = (Windows::ApplicationModel::Activation::LaunchActivatedEventArgs ^) args;
|
||||
Platform::String ^argumentString = launchArgs->Arguments;
|
||||
LPCWSTR rawArgumentString = argumentString->Data();
|
||||
int rawArgumentStringLength = argumentString->Length();
|
||||
|
||||
if (rawArgumentString == NULL || wcslen(rawArgumentString) == 0)
|
||||
{
|
||||
mCommandLine = ReadArgsFromFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
mCommandLine = ConvertLaunchArgsToMultibyte(rawArgumentString, rawArgumentStringLength);
|
||||
}
|
||||
}
|
||||
Windows::UI::Core::CoreWindow::GetForCurrentThread()->Activate();
|
||||
}
|
||||
|
||||
void ApplicationView::Load(Platform::String^ entryPoint)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
// Called by the system after initialization is complete. This implements the traditional game loop.
|
||||
void ApplicationView::Run()
|
||||
{
|
||||
using namespace EA::EAMain;
|
||||
std::unique_ptr<IWinRTRunner> winRTRunner(CreateWinRTRunner());
|
||||
|
||||
CommandLine commandline(mCommandLine, CommandLine::FLAG_NO_PROGRAM_NAME);
|
||||
|
||||
winRTRunner->Run(commandline.Argc(),commandline.Argv());
|
||||
do
|
||||
{
|
||||
// ProcessEvents will throw if the process is exiting, allowing us to
|
||||
// break out of the loop. This will be cleaned up when we get proper
|
||||
// process lifetime management online in a future release.
|
||||
Windows::UI::Core::CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(Windows::UI::Core::CoreProcessEventsOption::ProcessAllIfPresent);
|
||||
} while(!winRTRunner->IsFinished());
|
||||
|
||||
winRTRunner->ReportResult();
|
||||
Windows::ApplicationModel::Core::CoreApplication::Exit();
|
||||
|
||||
free(mCommandLine);
|
||||
mCommandLine = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void ApplicationView::Uninitialize()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
namespace Internal
|
||||
{
|
||||
EAMAIN_API void StartWinRtApplication()
|
||||
{
|
||||
// To do: store args so they can be passed to EAEntryPointMain.
|
||||
Windows::ApplicationModel::Core::CoreApplication::Run(ref new ApplicationViewSource());
|
||||
}
|
||||
} // namespace Internal
|
||||
} // namespace EAMain
|
||||
} // namespace EA
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,749 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable: 4530 4548 4509)
|
||||
#pragma warning(disable: 6320) // Exception-filter expression is the constant EXCEPTION_EXECUTE_HANDLER.
|
||||
#pragma warning(disable: 4472 4355) // additional warnings generated by XDK with VS2015
|
||||
#endif
|
||||
|
||||
#include <EAAssert/eaassert.h>
|
||||
#include <EAMain/EAMain.h>
|
||||
#include <eathread/eathread.h>
|
||||
#include <eathread/eathread_atomic.h>
|
||||
#ifdef EA_PLATFORM_ANDROID
|
||||
#include <eathread/eathread_futex.h>
|
||||
#endif
|
||||
#include <EAStdC/EAString.h>
|
||||
#include <EAStdC/EASprintf.h>
|
||||
#include <EAStdC/EADateTime.h>
|
||||
#include <EAStdC/EAProcess.h>
|
||||
#include <EAMain/internal/EAMainStartupShutdown.h>
|
||||
#include <EAMain/internal/EAMainPrintManager.h>
|
||||
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#if defined(EA_PLATFORM_MICROSOFT)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <Windows.h>
|
||||
#elif defined(__APPLE__) // OS X, iPhone, iPad, etc.
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/sysctl.h>
|
||||
#import <mach/mach.h>
|
||||
#import <mach/mach_host.h>
|
||||
#elif defined(EA_PLATFORM_BSD)
|
||||
#include <sys/types.h>
|
||||
#include <sys/ptrace.h>
|
||||
#elif defined(EA_HAVE_SYS_PTRACE_H)
|
||||
#include <unistd.h>
|
||||
#include <sys/ptrace.h>
|
||||
#elif defined(EA_PLATFORM_ANDROID)
|
||||
#include <unistd.h>
|
||||
#include <android/log.h>
|
||||
#endif
|
||||
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// EA_COMPILER_VA_COPY_REQUIRED
|
||||
//
|
||||
// This is already present in EABase version >= 2.00.40a report may not cause a flush
|
||||
// See EABase for documentation.
|
||||
//
|
||||
#ifndef EA_COMPILER_VA_COPY_REQUIRED
|
||||
#if (EABASE_VERSION_N < 20040) // If not already handled by EABase...
|
||||
#if ((defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__)) && (!defined(__i386__) || defined(__x86_64__)) && !defined(__ppc__) && !defined(__PPC__) && !defined(__PPC64__)
|
||||
#define EA_COMPILER_VA_COPY_REQUIRED 1
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
namespace EA
|
||||
{
|
||||
namespace EAMain
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
EAMAIN_API EAMainFunction gEAMainFunction;
|
||||
|
||||
/// ReportDefault
|
||||
///
|
||||
/// This is the default report function.
|
||||
/// It does not append any newlines to the output nor does it require
|
||||
/// the user to do so. It simply passes on the input to stdout.
|
||||
/// If the user wants the output to have a newline, the user must supply it.
|
||||
/// This allows the user to report multiple text items to the same line if desired.
|
||||
/// It does not send the input to stderr, as the output of a unit test
|
||||
/// is deemed to be test results (success or failure) and not errors.
|
||||
///
|
||||
#ifdef EA_PLATFORM_ANDROID
|
||||
static const size_t ANDROID_REPORT_BUFFER_SIZE = 1023;
|
||||
static char gAndroidReportBuffer[ANDROID_REPORT_BUFFER_SIZE + 1];
|
||||
static char *gAndroidReportBufferWritePtr = gAndroidReportBuffer;
|
||||
static EA::Thread::Futex gBufferFutex;
|
||||
static EA::Thread::ThreadTime gLastThreadTime = EA::Thread::kTimeoutImmediate;
|
||||
static EA::Thread::ThreadTime gMinTimeBetweenPrints = EA::Thread::ThreadTime(1);
|
||||
|
||||
// This function assumes that the buffer futex above is held
|
||||
// prior to entry. Please ensure that the buffer futex is either
|
||||
// held by the calling code.
|
||||
static void FlushAndroidReportBuffer()
|
||||
{
|
||||
if (gAndroidReportBufferWritePtr != gAndroidReportBuffer)
|
||||
{
|
||||
*gAndroidReportBufferWritePtr = 0;
|
||||
__android_log_write(ANDROID_LOG_INFO, "EAMain", gAndroidReportBuffer);
|
||||
|
||||
// We found that if the OS is spammed too quickly with log info, it stops taking output from the app
|
||||
// because it thinks it's a DDOS attack. So we sleep to give the OS time in the case the last
|
||||
// log output was too recent.
|
||||
EA::Thread::ThreadTime currentTime = EA::Thread::GetThreadTime();
|
||||
if (gLastThreadTime != EA::Thread::kTimeoutImmediate &&
|
||||
((currentTime - gLastThreadTime) < gMinTimeBetweenPrints))
|
||||
{
|
||||
EA::Thread::ThreadSleep(gMinTimeBetweenPrints);
|
||||
}
|
||||
gLastThreadTime = currentTime;
|
||||
|
||||
gAndroidReportBufferWritePtr = gAndroidReportBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
static void AppendToReportBuffer(char8_t c)
|
||||
{
|
||||
char *ptr = gAndroidReportBufferWritePtr;
|
||||
char *end = &gAndroidReportBuffer[ANDROID_REPORT_BUFFER_SIZE];
|
||||
|
||||
if (ptr >= end)
|
||||
{
|
||||
FlushAndroidReportBuffer();
|
||||
}
|
||||
|
||||
*gAndroidReportBufferWritePtr++ = c;
|
||||
}
|
||||
|
||||
static void AndroidReport(const char8_t *pMessage)
|
||||
{
|
||||
using namespace EA::StdC;
|
||||
using namespace EA::Thread;
|
||||
|
||||
AutoFutex autoFutex(gBufferFutex);
|
||||
|
||||
size_t messageLength = Strlen(pMessage);
|
||||
for (size_t i = 0; i < messageLength; ++i)
|
||||
{
|
||||
char8_t c = pMessage[i];
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '\n':
|
||||
FlushAndroidReportBuffer();
|
||||
break;
|
||||
default:
|
||||
AppendToReportBuffer(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ReportDefault(const char8_t* pMessage)
|
||||
{
|
||||
if (!pMessage)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// It's possible that the underlying print back end can't handle large
|
||||
// output sizes. For example, the OutputDebugStringA call below drops
|
||||
// chars beyond about 4096.
|
||||
size_t length = EA::StdC::Strlen(pMessage); // It might be faster to make a custom Strlen which quits after N chars.
|
||||
const size_t kMaxLength = 1024;
|
||||
|
||||
if(length > kMaxLength)
|
||||
{
|
||||
for(size_t i = 0, copiedLength = 0; i < length; i += copiedLength)
|
||||
{
|
||||
char8_t buffer[kMaxLength + 1];
|
||||
size_t c;
|
||||
|
||||
copiedLength = ((length - i) >= kMaxLength) ? kMaxLength : (length - i);
|
||||
for(c = 0; c < copiedLength; c++)
|
||||
buffer[c] = pMessage[i + c];
|
||||
buffer[c] = 0;
|
||||
ReportDefault(buffer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(EA_PLATFORM_MICROSOFT) && !defined(CS_UNDEFINED_STRING) // No need to do this for Microsoft console platforms, as the fputs below covers that.
|
||||
OutputDebugStringA(pMessage);
|
||||
#endif
|
||||
|
||||
#if defined(EA_PLATFORM_ANDROID)
|
||||
// Android doesn't implement stdio (e.g. fputs), though sometimes we use compiler
|
||||
// linking statements to redirect stdio functions to our own implementations which
|
||||
// allow it to work.
|
||||
//
|
||||
// __android_log_write can write only 512 bytes at a time. Normally we don't write
|
||||
// so much text in unit test output, but if this becomes a problem then we can loop
|
||||
// and write blocks of the output. The primary downside to such an approach is that
|
||||
// __android_log_write appends a \n to your output for each call. See the EAStdC
|
||||
// EASprintfCore.cpp code for example loop code.
|
||||
AndroidReport(pMessage);
|
||||
#else
|
||||
fputs(pMessage, stdout);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
EAMAIN_API const char *ExtractPrintServerAddress(int argc, char **argv)
|
||||
{
|
||||
CommandLine commandLine(argc, argv);
|
||||
const char *printServerAddress = NULL;
|
||||
|
||||
if (commandLine.FindSwitch("PrintServerIPAddress", false, &printServerAddress, 0, '=') >= 0)
|
||||
{
|
||||
if (EA::StdC::Strlen(printServerAddress) > 0)
|
||||
{
|
||||
return printServerAddress;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ReportFunction gpReportFunction = EA::EAMain::Internal::ReportDefault;
|
||||
EAMAIN_API void SetReportFunction(ReportFunction pReportFunction)
|
||||
{
|
||||
gpReportFunction = pReportFunction;
|
||||
}
|
||||
|
||||
EAMAIN_API ReportFunction GetReportFunction()
|
||||
{
|
||||
return gpReportFunction;
|
||||
}
|
||||
|
||||
EAMAIN_API ReportFunction GetDefaultReportFunction()
|
||||
{
|
||||
using namespace EA::EAMain::Internal;
|
||||
|
||||
return ReportDefault;
|
||||
}
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// GetVerbosity / SetVerbosity
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
unsigned gVerbosity = 0; // 0 means to display just failures.
|
||||
|
||||
EAMAIN_API unsigned GetVerbosity()
|
||||
{
|
||||
return gVerbosity;
|
||||
}
|
||||
|
||||
|
||||
EAMAIN_API void SetVerbosity(unsigned verbosity)
|
||||
{
|
||||
gVerbosity = verbosity;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ReportVaList
|
||||
//
|
||||
static void ReportVaList(unsigned minVerbosity, ReportFunction pReportFunction, const char8_t* pFormat, va_list arguments)
|
||||
{
|
||||
if(pFormat && (GetVerbosity() >= minVerbosity))
|
||||
{
|
||||
#if defined(EA_PLATFORM_DESKTOP)
|
||||
const int kBufferSize = 2048;
|
||||
#else
|
||||
const int kBufferSize = 512;
|
||||
#endif
|
||||
char buffer[kBufferSize];
|
||||
|
||||
#if defined(EA_COMPILER_VA_COPY_REQUIRED)
|
||||
va_list argumentsSaved;
|
||||
va_copy(argumentsSaved, arguments);
|
||||
#endif
|
||||
|
||||
const int nReturnValue = EA::StdC::Vsnprintf(buffer, kBufferSize, pFormat, arguments);
|
||||
|
||||
if(!pReportFunction)
|
||||
pReportFunction = gpReportFunction;
|
||||
|
||||
if(pReportFunction)
|
||||
{
|
||||
if((nReturnValue >= 0) && (nReturnValue < (int)kBufferSize))
|
||||
pReportFunction(buffer);
|
||||
else if(nReturnValue < 0) // If we simply didn't have enough buffer space.
|
||||
{
|
||||
pReportFunction("Invalid format specified.\n Format: ");
|
||||
pReportFunction(pFormat);
|
||||
}
|
||||
else // Else we simply didn't have enough buffer space.
|
||||
{
|
||||
char* pBuffer = static_cast<char *>(calloc(nReturnValue + 1, 1));
|
||||
|
||||
if(pBuffer)
|
||||
{
|
||||
#if defined(EA_COMPILER_VA_COPY_REQUIRED)
|
||||
va_end(arguments);
|
||||
va_copy(arguments, argumentsSaved);
|
||||
#endif
|
||||
|
||||
EA::StdC::Vsnprintf(pBuffer, nReturnValue + 1, pFormat, arguments);
|
||||
pReportFunction(pBuffer);
|
||||
free(pBuffer);
|
||||
}
|
||||
else
|
||||
pReportFunction("Unable to allocate buffer space for large printf.\n");
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(EA_COMPILER_VA_COPY_REQUIRED)
|
||||
// The caller will call va_end(arguments)
|
||||
va_end(argumentsSaved);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Report
|
||||
//
|
||||
EAMAIN_API void Report(const char8_t* pFormat, ...)
|
||||
{
|
||||
va_list arguments;
|
||||
va_start(arguments, pFormat);
|
||||
ReportVaList(0, gpReportFunction, pFormat, arguments);
|
||||
va_end(arguments);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// ReportVerbosity
|
||||
//
|
||||
EAMAIN_API void ReportVerbosity(unsigned minVerbosity, const char8_t* pFormat, ...)
|
||||
{
|
||||
va_list arguments;
|
||||
va_start(arguments, pFormat);
|
||||
ReportVaList(minVerbosity, gpReportFunction, pFormat, arguments);
|
||||
va_end(arguments);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// VReport
|
||||
//
|
||||
EAMAIN_API void VReport(const char8_t* pFormat, va_list arguments)
|
||||
{
|
||||
ReportVaList(0, gpReportFunction, pFormat, arguments);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// VReportVerbosity
|
||||
//
|
||||
EAMAIN_API void VReportVerbosity(unsigned minVerbosity, const char8_t* pFormat, va_list arguments)
|
||||
{
|
||||
ReportVaList(minVerbosity, gpReportFunction, pFormat, arguments);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PlatformStartup
|
||||
//
|
||||
EAMAIN_API void PlatformStartup()
|
||||
{
|
||||
// Routed to EAMainStartup to centralize
|
||||
// the platform specific startup code.
|
||||
PlatformStartup(NULL);
|
||||
}
|
||||
|
||||
EAMAIN_API void PlatformStartup(int argc, char **argv)
|
||||
{
|
||||
const char *printServerNetworkAddress = Internal::ExtractPrintServerAddress(argc, argv);
|
||||
|
||||
PlatformStartup(printServerNetworkAddress);
|
||||
}
|
||||
|
||||
EAMAIN_API void PlatformStartup(const char *printServerNetworkAddress)
|
||||
{
|
||||
// Routed to EAMainStartup to centralize
|
||||
// the platform specific startup code.
|
||||
EA::EAMain::Internal::EAMainStartup(printServerNetworkAddress);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// PlatformShutdown
|
||||
//
|
||||
EAMAIN_API void PlatformShutdown(int errorCount)
|
||||
{
|
||||
#ifdef EA_PLATFORM_ANDROID
|
||||
// The Android reporting functions will flush the output buffers
|
||||
// when a newline is encountered. Calling AndroidReport with a
|
||||
// single newline will cause any accumulated output to flush to
|
||||
// the log.
|
||||
//
|
||||
// An alternative would be to call the FlushAndroidReportBuffer
|
||||
// function but doing so would necessitate having separate locks
|
||||
// for both FlushAndroidReportBuffer and AndroidReport, as both
|
||||
// of these could be caused at the same time. To avoid this
|
||||
// complication, FlushAndroidReportBuffer will only be called by
|
||||
// AndroidReport or its children.
|
||||
// -mburke
|
||||
Internal::AndroidReport("\n");
|
||||
#endif
|
||||
// Routed to EAMainShutdown to centralize
|
||||
// the platform specific shutdown code.
|
||||
EA::EAMain::Internal::EAMainShutdown(errorCount);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// CommandLine
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
CommandLine::CommandLine(int argc, char** argv)
|
||||
: mArgc(argc)
|
||||
, mArgv(NULL)
|
||||
, mCommandLine(NULL)
|
||||
{
|
||||
mArgv = static_cast<char **>(calloc(argc + 1, sizeof(char *)));
|
||||
EA_ASSERT(mArgv != NULL);
|
||||
|
||||
for (int i = 0; i < argc; ++i)
|
||||
{
|
||||
mArgv[i] = argv[i];
|
||||
}
|
||||
|
||||
mArgv[argc] = NULL;
|
||||
|
||||
// Microsoft fails to support argc/argv on Xenon. Sometimes it works; sometimes it doesn't.
|
||||
}
|
||||
|
||||
CommandLine::CommandLine(const char *args)
|
||||
: mArgc(0),
|
||||
mArgv(NULL),
|
||||
mCommandLine(NULL)
|
||||
{
|
||||
ParseCommandLine(args, FLAG_NONE);
|
||||
}
|
||||
|
||||
CommandLine::CommandLine(const char *args, unsigned int flags)
|
||||
: mArgc(0),
|
||||
mArgv(NULL),
|
||||
mCommandLine(NULL)
|
||||
{
|
||||
ParseCommandLine(args, flags);
|
||||
}
|
||||
|
||||
|
||||
CommandLine::~CommandLine()
|
||||
{
|
||||
if (mArgv)
|
||||
{
|
||||
free(mArgv);
|
||||
mArgv = NULL;
|
||||
}
|
||||
|
||||
if (mCommandLine)
|
||||
{
|
||||
free(mCommandLine);
|
||||
mCommandLine = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/// Stristr
|
||||
/// We implement this here because it isn't consistently present with all compiler-supplied C libraries.
|
||||
static char* Stristr(const char* s1, const char* s2)
|
||||
{
|
||||
const char* cp = s1;
|
||||
|
||||
if(!*s2)
|
||||
return (char*)s1;
|
||||
|
||||
while(*cp)
|
||||
{
|
||||
const char* s = cp;
|
||||
const char* t = s2;
|
||||
|
||||
while(*s && *t && (tolower(*s) == tolower(*t)))
|
||||
++s, ++t;
|
||||
|
||||
if(*t == 0)
|
||||
return (char*)cp;
|
||||
++cp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Returns position switch is found at. Returns -1 if not found
|
||||
int CommandLine::FindSwitch(const char* pSwitch, bool bCaseSensitive, const char** pResult, int nStartingIndex, char delimeter) const
|
||||
{
|
||||
const char8_t kSwitchIDs[] = { '-', '/' };
|
||||
const int kSwitchIDCount = sizeof(kSwitchIDs)/sizeof(kSwitchIDs[0]);
|
||||
static const char sEmptyString[] = { 0 };
|
||||
|
||||
if(nStartingIndex < 0)
|
||||
{
|
||||
nStartingIndex = 0;
|
||||
}
|
||||
|
||||
if (pResult)
|
||||
{
|
||||
*pResult = sEmptyString;
|
||||
}
|
||||
|
||||
// Here we move the input pSwitch past any one leading switch indicator such as '-'.
|
||||
for(int i = 0; i < kSwitchIDCount; ++i)
|
||||
{
|
||||
if(*pSwitch == kSwitchIDs[i])
|
||||
{
|
||||
++pSwitch;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const size_t nSwitchLength = strlen(pSwitch);
|
||||
|
||||
if (!nSwitchLength || (nStartingIndex >= mArgc))
|
||||
return -1;
|
||||
|
||||
for(int i = nStartingIndex; i < mArgc; ++i)
|
||||
{
|
||||
const char *sCurrent = mArgv[i];
|
||||
|
||||
if(strlen(sCurrent) >= 2) // Enough, for example, for "-x".
|
||||
{
|
||||
int j;
|
||||
|
||||
// Make sure the string starts with a switch ID (e.g. '-').
|
||||
for(j = 0; j < kSwitchIDCount; ++j)
|
||||
{
|
||||
if(sCurrent[0] == kSwitchIDs[j])
|
||||
break;
|
||||
}
|
||||
|
||||
if(j < kSwitchIDCount) // If a leading '-' was found...
|
||||
{
|
||||
const char* pCurrent = bCaseSensitive ? strstr(sCurrent + 1, pSwitch) : Stristr(sCurrent + 1, pSwitch);
|
||||
const char* pCStr = sCurrent;
|
||||
|
||||
if(pCurrent == (pCStr + 1)) // If the user's input switch matched at least the start of the current argument switch...
|
||||
{
|
||||
pCurrent += nSwitchLength; // Move pCurrent past the input switch.
|
||||
|
||||
// At this point, we require that *pCurrent is either 0 or delimeter.
|
||||
if((*pCurrent == 0) || (*pCurrent == delimeter))
|
||||
{
|
||||
// We have a match. Now possibly return a result string.
|
||||
if(*pCurrent == delimeter)
|
||||
{
|
||||
if(*++pCurrent)
|
||||
{
|
||||
if(pResult)
|
||||
{
|
||||
*pResult = pCurrent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool CommandLine::HasHelpSwitch() const
|
||||
{
|
||||
if((FindSwitch("-help", false, NULL, 0) >= 0) ||
|
||||
(FindSwitch("-h", false, NULL, 0) >= 0) ||
|
||||
(FindSwitch("-?", false, NULL, 0) >= 0))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CommandLine::ParseCommandLine(const char *inputCommandLine, unsigned int flags)
|
||||
{
|
||||
size_t commandLineLength = strlen(inputCommandLine);
|
||||
size_t allocSize = commandLineLength + 1;
|
||||
size_t startOffset = 0;
|
||||
|
||||
if (flags & FLAG_NO_PROGRAM_NAME)
|
||||
{
|
||||
allocSize += 1;
|
||||
startOffset = 1;
|
||||
}
|
||||
|
||||
char *commandLine = static_cast<char *>(calloc(allocSize, 1));
|
||||
EA_ASSERT(commandLine != NULL);
|
||||
|
||||
memcpy(commandLine + startOffset, inputCommandLine, commandLineLength);
|
||||
|
||||
int argc = 0;
|
||||
char **argv = static_cast<char **>(calloc(MAX_COMMANDLINE_ARGS, sizeof(char *)));
|
||||
EA_ASSERT(argv != NULL);
|
||||
|
||||
char *start = commandLine + startOffset;
|
||||
char *ptr = start;
|
||||
char *end = start + commandLineLength;
|
||||
bool isQuoted = false;
|
||||
const char quote = '"';
|
||||
|
||||
if (flags & FLAG_NO_PROGRAM_NAME)
|
||||
{
|
||||
argv[argc++] = commandLine;
|
||||
}
|
||||
|
||||
while (ptr < end)
|
||||
{
|
||||
// The two cases this parser handles for quotes are:
|
||||
// "this is a quoted parameter"; and
|
||||
// -D:"this is a quoted parameter"
|
||||
// The parser does not handle edge cases like
|
||||
// "this is a quoted parameter"and"this is the same"
|
||||
char *quoteStart = NULL;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
while ((ptr < end) && !isspace((unsigned char)*ptr))
|
||||
{
|
||||
if (*ptr == quote && !isQuoted)
|
||||
{
|
||||
isQuoted = true;
|
||||
quoteStart = ptr;
|
||||
}
|
||||
|
||||
++ptr;
|
||||
}
|
||||
|
||||
if (isQuoted)
|
||||
{
|
||||
if (*(ptr - 1) == quote)
|
||||
{
|
||||
// If we find a quote, shift the whole string back
|
||||
// by one character, ie:
|
||||
// -D:"this is a quoted parameter"
|
||||
// becomes
|
||||
// -D:this is a quoted parameter"
|
||||
// The trailing quote is removed below when we place
|
||||
// a null terminator at the end of our argument.
|
||||
memmove(quoteStart, quoteStart + 1, (end - quoteStart));
|
||||
--end;
|
||||
ptr -= 2;
|
||||
isQuoted = false;
|
||||
break;
|
||||
}
|
||||
++ptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ptr != start)
|
||||
{
|
||||
*ptr = 0;
|
||||
|
||||
argv[argc++] = start;
|
||||
++ptr;
|
||||
}
|
||||
|
||||
while ((ptr < end) && isspace((unsigned char)*ptr))
|
||||
{
|
||||
++ptr;
|
||||
}
|
||||
|
||||
start = ptr;
|
||||
}
|
||||
|
||||
mArgc = argc;
|
||||
mArgv = argv;
|
||||
mCommandLine = commandLine;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// WinRT-based Windows:
|
||||
#if (defined(EA_PLATFORM_MICROSOFT) && !defined(CS_UNDEFINED_STRING) && !EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP))
|
||||
|
||||
EA_DISABLE_VC_WARNING(4350 4571 4625 4626 4265)
|
||||
#include <future>
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
extern "C" int EAMain(int argc, char** argv);
|
||||
|
||||
namespace EA
|
||||
{
|
||||
|
||||
namespace EAMain
|
||||
{
|
||||
|
||||
class WinRTRunner : public IWinRTRunner
|
||||
{
|
||||
private:
|
||||
// The copy/assignment operator is explicitly inaccessible due to the base class 'IWinRTRunner' containing a member
|
||||
// that is non-copyable (eg. std::future).
|
||||
WinRTRunner(const WinRTRunner &);
|
||||
WinRTRunner& operator=(const WinRTRunner &);
|
||||
|
||||
public:
|
||||
WinRTRunner() {}
|
||||
|
||||
virtual void Run(int argc, char** argv) override
|
||||
{
|
||||
mResult = std::async(std::launch::async, [=]() {
|
||||
|
||||
const char *printServerAddress = Internal::ExtractPrintServerAddress(argc, argv);
|
||||
EA::EAMain::Internal::EAMainStartup(printServerAddress);
|
||||
|
||||
int result = EA::EAMain::Internal::gEAMainFunction(argc, argv);
|
||||
EA::EAMain::Internal::EAMainShutdown(result);
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
virtual bool IsFinished() override { return mResult.wait_for(std::chrono::milliseconds(33)) == std::future_status::ready; }
|
||||
|
||||
virtual void ReportResult() override
|
||||
{
|
||||
char output[100];
|
||||
EA::StdC::Snprintf(output, EAArrayCount(output), "EXIT(%d)\n", mResult.get());
|
||||
|
||||
// Using OutputDebugStringA directly here as opposed to Report as someone may overload
|
||||
// the default reporter. And this is what counts for EARunner to know what to do.
|
||||
OutputDebugStringA(output);
|
||||
}
|
||||
|
||||
std::future<int> mResult;
|
||||
};
|
||||
|
||||
EAMAIN_API IWinRTRunner* CreateWinRTRunner()
|
||||
{
|
||||
return new WinRTRunner();
|
||||
}
|
||||
|
||||
} // namespace EAMain
|
||||
|
||||
} // namespace EA
|
||||
|
||||
#endif // WinRT-based Windows
|
||||
@@ -0,0 +1,156 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <EAMain/EAMainExit.h>
|
||||
#include <EAMain/EAMain.h>
|
||||
|
||||
#include <EAStdC/EAMemory.h>
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#if defined(EA_PLATFORM_SONY) || defined(EA_PLATFORM_ANDROID)
|
||||
// All of these platforms require complex handling of exceptions and signals. No apparent solution yet.
|
||||
#elif defined(EA_PLATFORM_LINUX)
|
||||
#include <sys/signal.h>
|
||||
#elif defined(EA_PLATFORM_APPLE) || defined(EA_PLATFORM_WINDOWS) || defined(EA_PLATFORM_XBOXONE) || defined(EA_PLATFORM_CAPILANO) || defined(CS_UNDEFINED_STRING)
|
||||
#include <csignal>
|
||||
#endif
|
||||
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
#include <EAMain/internal/EAMainStartupShutdown.h>
|
||||
|
||||
namespace EA {
|
||||
namespace EAMain {
|
||||
const char* gExitCodeNames[ExitCode_Max] =
|
||||
{
|
||||
"Succeeded",
|
||||
"Asserted",
|
||||
"Abort Signal",
|
||||
"Segmentation Fault Signal",
|
||||
"Illegal Instruction Signal",
|
||||
"Hangup Signal",
|
||||
"Floating Point Exception Signal",
|
||||
"BusError Signal",
|
||||
"Unkown",
|
||||
};
|
||||
|
||||
void Exit(int exitcode)
|
||||
{
|
||||
int index = (exitcode < 0 || exitcode >= ExitCode_Max) ? exitcode = ExitCode_Unknown : exitcode;
|
||||
Report("======================================================================\nEA::Main::Exit called with exitcode %d (%s)!\nThe caller wanted to immediately end execution!\n======================================================================\n", exitcode, gExitCodeNames[index]);
|
||||
#if !defined(EA_PLATFORM_ANDROID)
|
||||
Internal::EAMainShutdown(exitcode);
|
||||
std::exit(exitcode);
|
||||
#else
|
||||
PlatformShutdown(exitcode);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(EA_PLATFORM_SONY) || defined(EA_PLATFORM_ANDROID) || defined(CS_UNDEFINED_STRING)
|
||||
void InitializeSignalHandler() {
|
||||
// Do nothing. No solution for signal/exception handling on this platform yet.
|
||||
}
|
||||
|
||||
#elif defined(EA_PLATFORM_WINDOWS) || defined(EA_PLATFORM_XBOXONE) || defined(EA_PLATFORM_CAPILANO) || defined(CS_UNDEFINED_STRING)
|
||||
void InitializeSignalHandler()
|
||||
{
|
||||
// Do nothing. Unhandled exception filter will handle creating a minidump on
|
||||
// this platform which will contain more actionable information than a trapped
|
||||
// signal.
|
||||
}
|
||||
|
||||
#elif defined(EA_PLATFORM_APPLE) || defined(EA_PLATFORM_IPHONE)
|
||||
int SignalToExitCode(int signal) {
|
||||
switch(signal)
|
||||
{
|
||||
case SIGABRT:
|
||||
return ExitCode_SignalAbort;
|
||||
case SIGSEGV:
|
||||
return ExitCode_SignalSegmentationViolation;
|
||||
case SIGILL:
|
||||
return ExitCode_SignalIllegalInstruction;
|
||||
case SIGFPE:
|
||||
return ExitCode_SignalFloatingPointException;
|
||||
case SIGHUP:
|
||||
return ExitCode_SignalHangup;
|
||||
case SIGBUS:
|
||||
return ExitCode_SignalBusError;
|
||||
default:
|
||||
return ExitCode_Unknown;
|
||||
};
|
||||
}
|
||||
|
||||
void HandleSignal(int signal) {
|
||||
EA::EAMain::Exit(SignalToExitCode(signal));
|
||||
}
|
||||
|
||||
void InitializeSignalHandler() {
|
||||
std::signal(SIGABRT, HandleSignal);
|
||||
std::signal(SIGSEGV, HandleSignal);
|
||||
std::signal(SIGILL, HandleSignal);
|
||||
std::signal(SIGFPE, HandleSignal);
|
||||
std::signal(SIGHUP, HandleSignal);
|
||||
std::signal(SIGBUS, HandleSignal);
|
||||
}
|
||||
#elif defined(EA_PLATFORM_LINUX)
|
||||
int SignalToExitCode(int signal) {
|
||||
switch(signal)
|
||||
{
|
||||
case SIGABRT:
|
||||
return ExitCode_SignalAbort;
|
||||
case SIGSEGV:
|
||||
return ExitCode_SignalSegmentationViolation;
|
||||
case SIGILL:
|
||||
return ExitCode_SignalIllegalInstruction;
|
||||
case SIGHUP:
|
||||
return ExitCode_SignalHangup;
|
||||
case SIGFPE:
|
||||
return ExitCode_SignalFloatingPointException;
|
||||
case SIGBUS:
|
||||
return ExitCode_SignalBusError;
|
||||
default:
|
||||
return ExitCode_Unknown;
|
||||
};
|
||||
}
|
||||
|
||||
struct sigaction ABRTAction;
|
||||
struct sigaction SEGVAction;
|
||||
struct sigaction SIGILLAction;
|
||||
struct sigaction SIGHUPAction;
|
||||
struct sigaction SIGFPEAction;
|
||||
struct sigaction SIGBUSAction;
|
||||
|
||||
void HandleSignal(int signal, siginfo_t *sigInfo, void *context) {
|
||||
EA::EAMain::Exit(SignalToExitCode(signal));
|
||||
}
|
||||
|
||||
void InitializeSignalHandler() {
|
||||
ABRTAction.sa_sigaction = HandleSignal;
|
||||
ABRTAction.sa_flags = SA_SIGINFO;
|
||||
SEGVAction.sa_sigaction = HandleSignal;
|
||||
SEGVAction.sa_flags = SA_SIGINFO;
|
||||
SIGILLAction.sa_sigaction = HandleSignal;
|
||||
SIGILLAction.sa_flags = SA_SIGINFO;
|
||||
SIGHUPAction.sa_sigaction = HandleSignal;
|
||||
SIGHUPAction.sa_flags = SA_SIGINFO;
|
||||
SIGFPEAction.sa_sigaction = HandleSignal;
|
||||
SIGFPEAction.sa_flags = SA_SIGINFO;
|
||||
SIGBUSAction.sa_sigaction = HandleSignal;
|
||||
SIGBUSAction.sa_flags = SA_SIGINFO;
|
||||
|
||||
sigaction(SIGABRT, &ABRTAction, NULL);
|
||||
sigaction(SIGSEGV, &SEGVAction, NULL);
|
||||
sigaction(SIGILL, &SIGILLAction, NULL);
|
||||
sigaction(SIGHUP, &SIGHUPAction, NULL);
|
||||
sigaction(SIGFPE, &SIGFPEAction, NULL);
|
||||
sigaction(SIGBUS, &SIGBUSAction, NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include <EAMainPrintf.h>
|
||||
#include <EAMain/internal/EAMainPrintManager.h>
|
||||
#include <EAStdC/EASprintf.h>
|
||||
|
||||
namespace EA
|
||||
{
|
||||
namespace EAMain
|
||||
{
|
||||
class IChannel;
|
||||
|
||||
namespace Messages
|
||||
{
|
||||
void Print(const char* pData)
|
||||
{
|
||||
PrintManager::Instance().Send(pData);
|
||||
}
|
||||
|
||||
}}} // namespaces
|
||||
@@ -0,0 +1,21 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EAMAIN_PRINTF_H
|
||||
#define EAMAIN_PRINTF_H
|
||||
|
||||
#include <EAMain/internal/Version.h>
|
||||
|
||||
namespace EA
|
||||
{
|
||||
namespace EAMain
|
||||
{
|
||||
class IChannel;
|
||||
|
||||
namespace Messages
|
||||
{
|
||||
EAMAIN_API void Print(const char* pData);
|
||||
}}}
|
||||
|
||||
#endif // header include guard
|
||||
@@ -0,0 +1,57 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "EAMain/EAMain.h"
|
||||
#include "EABase/eabase.h"
|
||||
#include "EAAssert/eaassert.h"
|
||||
#include <EAMain/internal/EAMainPrintManager.h>
|
||||
#include <EAMain/internal/EAMainChannels.h>
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
namespace EA {
|
||||
namespace EAMain {
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Printf Channel
|
||||
//------------------------------------------------------------
|
||||
void PrintfChannel::Send(const char8_t* pData)
|
||||
{
|
||||
// Route to default print function
|
||||
EA::EAMain::GetDefaultReportFunction()(pData);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
// File Channel
|
||||
//------------------------------------------------------------
|
||||
void FileChannel::Init()
|
||||
{
|
||||
mFileHandle = fopen("eamain_output.txt", "w");
|
||||
EA_ASSERT_MSG(mFileHandle, "invalid file handle");
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
void FileChannel::Send(const char8_t* pData)
|
||||
{
|
||||
EA_ASSERT_MSG(mFileHandle, "invalid file handle");
|
||||
fputs(pData, mFileHandle);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
void FileChannel::Shutdown()
|
||||
{
|
||||
EA_ASSERT_MSG(mFileHandle, "invalid file handle");
|
||||
fclose(mFileHandle);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,154 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <EAMain/EAMain.h>
|
||||
#include <EAMain/internal/EAMainPrintManager.h>
|
||||
#include <EAMain/internal/EAMainChannels.h>
|
||||
#include <internal/NetworkChannel.h>
|
||||
#include <EAAssert/eaassert.h>
|
||||
#include <EAStdC/EAString.h>
|
||||
#include <EAMainPrintf.h>
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
|
||||
#include <string.h>
|
||||
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
namespace EA {
|
||||
namespace EAMain {
|
||||
|
||||
//------------------------------------------------------------
|
||||
// STATICS
|
||||
//------------------------------------------------------------
|
||||
static PrintManager gPrintManager;
|
||||
static PrintfChannel gPrintfChannel;
|
||||
static FileChannel gFileChannel;
|
||||
//------------------------------------------------------------
|
||||
|
||||
|
||||
//------------------------------------------------------------
|
||||
PrintManager& PrintManager::Instance()
|
||||
{
|
||||
return gPrintManager;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
PrintManager::PrintManager()
|
||||
{
|
||||
memset(m_Channels, 0, sizeof(m_Channels));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
void PrintManager::Send(const char8_t* pData)
|
||||
{
|
||||
// Broadcast the message to all the registered channels.
|
||||
for(int i = 0; i < CHANNEL_MAX; i++)
|
||||
{
|
||||
if(m_Channels[i])
|
||||
m_Channels[i]->Send(pData);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
void PrintManager::Add(EAMainChannel channel, IChannel* instance)
|
||||
{
|
||||
EA_ASSERT_MSG(instance, "invalid channel instance");
|
||||
EA_ASSERT_MSG(m_Channels[channel] == NULL, "channel already added to the list");
|
||||
|
||||
if(instance != NULL && m_Channels[channel] == NULL)
|
||||
{
|
||||
// Initialize the channel, then add it to the channel vector.
|
||||
instance->Init();
|
||||
|
||||
// Add the channel to the array
|
||||
m_Channels[channel] = instance;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
void PrintManager::ClearChannel(EAMainChannel channel)
|
||||
{
|
||||
if (m_Channels[channel] != NULL)
|
||||
{
|
||||
IChannel* instance = m_Channels[channel];
|
||||
|
||||
// Shut down the channel.
|
||||
instance->Shutdown();
|
||||
|
||||
// Remove the channel from the array.
|
||||
m_Channels[channel] = NULL;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------
|
||||
void PrintManager::Remove(EAMainChannel channel, IChannel* instance)
|
||||
{
|
||||
EA_ASSERT_MSG(instance, "invalid channel instance");
|
||||
EA_ASSERT_MSG(m_Channels[channel] != NULL, "channel not added to list yet");
|
||||
|
||||
if(instance != NULL && m_Channels[channel] != NULL)
|
||||
{
|
||||
// Shut down the channel.
|
||||
instance->Shutdown();
|
||||
|
||||
// Remove the channel from the array.
|
||||
m_Channels[channel] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
void PrintManager::Startup(const char8_t* printServerAddress)
|
||||
{
|
||||
// Register PrintManager print function with the reporting module.
|
||||
//
|
||||
#if EAMAIN_DISABLE_DEFAULT_NETWORK_CHANNEL
|
||||
if (!printServerAddress)
|
||||
{
|
||||
Add(CHANNEL_PRINTF, &gPrintfChannel);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
EA::EAMain::SetReportFunction(EA::EAMain::Messages::Print);
|
||||
if (!printServerAddress)
|
||||
{
|
||||
printServerAddress = MACRO_TO_STRING(EAMAIN_NETWORK_CHANNEL_IP);
|
||||
}
|
||||
const char8_t* server = printServerAddress;
|
||||
const char8_t* portStr = strchr(printServerAddress, ':');
|
||||
|
||||
int port = EAMAIN_NETWORK_CHANNEL_PORT;
|
||||
char8_t serverBuff[64] = { 0 };
|
||||
if (portStr != NULL)
|
||||
{
|
||||
port = EA::StdC::AtoI32(portStr + 1);
|
||||
server = EA::StdC::Strncpy(serverBuff, server, portStr - server);
|
||||
}
|
||||
|
||||
IChannel *networkChannel = Internal::CreateNetworkChannel(server, port);
|
||||
if (networkChannel)
|
||||
{
|
||||
Add(CHANNEL_NETWORK, networkChannel);
|
||||
}
|
||||
else
|
||||
{
|
||||
Add(CHANNEL_PRINTF, &gPrintfChannel);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
void PrintManager::Shutdown()
|
||||
{
|
||||
for(int i = 0; i < CHANNEL_MAX; i++)
|
||||
{
|
||||
if(m_Channels[i])
|
||||
{
|
||||
m_Channels[i]->Shutdown();
|
||||
m_Channels[i] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
@@ -0,0 +1,166 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <EAMain/internal/EAMainStartupShutdown.h>
|
||||
#include <EAMain/EAMain.h>
|
||||
#include <EAMain/EAMainExit.h>
|
||||
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0) // Microsoft headers generate warnings at our higher warning levels.
|
||||
#pragma warning(disable: 4702) // Unreachable code detected.
|
||||
#endif
|
||||
|
||||
#if defined(EA_PLATFORM_MICROSOFT)
|
||||
#if defined(EA_PLATFORM_WINDOWS_PHONE) || defined(EA_PLATFORM_WINRT)
|
||||
#define EAMAIN_HAVE_UNHANDLED_EXCEPTION_FILTER 0
|
||||
#else
|
||||
#if !defined(WIN32_LEAN_AND_MEAN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#if defined(EA_PLATFORM_CAPILANO)
|
||||
#include <xdk.h>
|
||||
#endif
|
||||
EA_DISABLE_ALL_VC_WARNINGS();
|
||||
#include <Windows.h>
|
||||
#include <DbgHelp.h>
|
||||
EA_RESTORE_ALL_VC_WARNINGS();
|
||||
#include <EAStdC/EASprintf.h>
|
||||
#define EAMAIN_HAVE_UNHANDLED_EXCEPTION_FILTER 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(EAMAIN_HAVE_UNHANDLED_EXCEPTION_FILTER)
|
||||
#define EAMAIN_HAVE_UNHANDLED_EXCEPTION_FILTER 0
|
||||
#endif
|
||||
|
||||
namespace EA
|
||||
{
|
||||
namespace EAMain
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
#if EAMAIN_HAVE_UNHANDLED_EXCEPTION_FILTER
|
||||
static LONG WINAPI EAMainUnhandledExceptionFilter(LPEXCEPTION_POINTERS exception)
|
||||
{
|
||||
EA::EAMain::Report("\n");
|
||||
EA::EAMain::Report("===============================================================================\n");
|
||||
EA::EAMain::Report("ATTENTION ATTENTION ATTENTION ATTENTION ATTENTION ATTENTION ATTENTION ATTENTION\n");
|
||||
EA::EAMain::Report("An unhandled exception has been detected. This likely means the application is \n");
|
||||
EA::EAMain::Report("crashing.\n\n");
|
||||
EA::EAMain::Report("(This message is courtesy of EAMain but does not mean that EAMain is\n");
|
||||
EA::EAMain::Report("the cause of the crash.)\n");
|
||||
EA::EAMain::Report("===============================================================================\n");
|
||||
|
||||
#if EAMAIN_MINIDUMP_SUPPORTED
|
||||
char8_t szPath[MAX_PATH];
|
||||
char8_t szFileName[MAX_PATH];
|
||||
HANDLE hDumpFile;
|
||||
SYSTEMTIME stLocalTime;
|
||||
MINIDUMP_EXCEPTION_INFORMATION ExpParam;
|
||||
BOOL bMiniDumpSuccessful;
|
||||
|
||||
#if defined(EA_PLATFORM_CAPILANO)
|
||||
const char8_t* pszDrive = "G:\\";
|
||||
#else
|
||||
const char8_t* pszDrive = "C:\\";
|
||||
#endif
|
||||
|
||||
GetLocalTime( &stLocalTime );
|
||||
EA::StdC::Snprintf(szPath, EAArrayCount(szPath), "%sMiniDumps\\", pszDrive);
|
||||
CreateDirectoryA(szPath, NULL );
|
||||
|
||||
EA::StdC::Snprintf(szFileName, EAArrayCount(szFileName), "%sMiniDump-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp",
|
||||
szPath,
|
||||
stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
|
||||
stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond,
|
||||
GetCurrentProcessId(), GetCurrentThreadId());
|
||||
|
||||
EA::EAMain::Report("Creating Dump File: %s - ", szFileName);
|
||||
hDumpFile = CreateFileA(szFileName, GENERIC_READ|GENERIC_WRITE,
|
||||
FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);
|
||||
EA::EAMain::Report("%s (Error: %d) \n", hDumpFile != INVALID_HANDLE_VALUE ? "Success" : "Failure", hDumpFile != INVALID_HANDLE_VALUE ? 0 : HRESULT_FROM_WIN32(GetLastError()));
|
||||
|
||||
ExpParam.ThreadId = GetCurrentThreadId();
|
||||
ExpParam.ExceptionPointers = exception;
|
||||
ExpParam.ClientPointers = TRUE;
|
||||
bMiniDumpSuccessful = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
|
||||
hDumpFile, MiniDumpWithDataSegs, &ExpParam, NULL, NULL);
|
||||
|
||||
EA::EAMain::Report("Dump %s (Error: %d)\n", bMiniDumpSuccessful == TRUE ? "Successful" : "Failed - so deleted minidump file", bMiniDumpSuccessful == TRUE ? 0 : HRESULT_FROM_WIN32(GetLastError()));
|
||||
if (bMiniDumpSuccessful == FALSE)
|
||||
{
|
||||
DeleteFileA(szFileName);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
EAMainShutdown(1);
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
#endif
|
||||
|
||||
void EAMainStartup(const char8_t* printServerAddress)
|
||||
{
|
||||
static bool sEAMainShutdown_StartupHandled = false;
|
||||
if(!sEAMainShutdown_StartupHandled)
|
||||
{
|
||||
sEAMainShutdown_StartupHandled = true;
|
||||
|
||||
#if EAMAIN_HAVE_UNHANDLED_EXCEPTION_FILTER
|
||||
SetUnhandledExceptionFilter(EAMainUnhandledExceptionFilter);
|
||||
#endif
|
||||
|
||||
// Running under NAnt output only appears when the buffer is filled if we allow the default buffering scheme for printf.
|
||||
setvbuf(stdout, NULL, _IONBF, BUFSIZ);
|
||||
setvbuf(stderr, NULL, _IONBF, BUFSIZ);
|
||||
|
||||
// Startup the print manager
|
||||
//
|
||||
EA::EAMain::PrintManager::Instance().Startup(printServerAddress);
|
||||
}
|
||||
}
|
||||
|
||||
int EAMainShutdown(int errorCount)
|
||||
{
|
||||
static bool sEAMainShutdown_ShutdownHandled = false;
|
||||
if(!sEAMainShutdown_ShutdownHandled)
|
||||
{
|
||||
sEAMainShutdown_ShutdownHandled = true;
|
||||
|
||||
// Handle the application specific exit code.
|
||||
//
|
||||
#if defined(EA_PLATFORM_IPHONE)
|
||||
// Get test result. (iOS 5 bug prevents iPhone Runner from getting this from the exit code)
|
||||
if (errorCount == 0)
|
||||
Report("\nAll tests completed successfully.\n");
|
||||
else
|
||||
Report("\nTests failed. Total error count: %d\n", errorCount);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
#if !defined(EA_PLATFORM_DESKTOP) && !defined(EA_PLATFORM_SERVER) // TODO: change define to something related to the StdC library used on the system.
|
||||
fflush(stdout);
|
||||
#endif
|
||||
|
||||
// Required so the EAMainPrintServer can terminate with the correct error code.
|
||||
//
|
||||
EA::EAMain::Report("\nRETURNCODE=%d\n", errorCount);
|
||||
|
||||
// Shutdown the EAMain print manager.
|
||||
//
|
||||
EA::EAMain::PrintManager::Instance().Shutdown();
|
||||
}
|
||||
|
||||
return errorCount;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
@@ -0,0 +1,603 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#include <EAAssert/eaassert.h>
|
||||
#include <EAMain/internal/EAMainChannels.h>
|
||||
|
||||
#if defined(EA_PLATFORM_IPHONE)
|
||||
#define EAMAIN_HAS_NETWORK_CHANNEL 1
|
||||
#define EAMAIN_FREOPEN_SUPPORTED 1
|
||||
#endif
|
||||
|
||||
#if defined(EA_PLATFORM_WINRT)
|
||||
#define EAMAIN_HAS_NETWORK_CHANNEL 1
|
||||
#define EAMAIN_FREOPEN_SUPPORTED 0
|
||||
#endif
|
||||
|
||||
#if defined(EA_PLATFORM_WINDOWS_PHONE) && !defined(EAMAIN_HAS_NETWORK_CHANNEL)
|
||||
#define EAMAIN_HAS_NETWORK_CHANNEL 1
|
||||
#define EAMAIN_FREOPEN_SUPPORTED 0
|
||||
#endif
|
||||
|
||||
// winrt-arm configurations do not have winsock, so for these configurations
|
||||
// we disable the use of the network channel.
|
||||
#if defined(_MSC_VER) && !defined(EA_PLATFORM_WINDOWS_PHONE) && defined(EA_PROCESSOR_ARM) && defined(EAMAIN_HAS_NETWORK_CHANNEL)
|
||||
#undef EAMAIN_HAS_NETWORK_CHANNEL
|
||||
#endif
|
||||
|
||||
#if defined(EA_PLATFORM_CAPILANO) && !defined(EAMAIN_HAS_NETWORK_CHANNEL)
|
||||
#define EAMAIN_HAS_NETWORK_CHANNEL 1
|
||||
#define EAMAIN_FREOPEN_SUPPORTED 1
|
||||
#endif
|
||||
|
||||
#if !defined(EAMAIN_HAS_NETWORK_CHANNEL)
|
||||
#define EAMAIN_HAS_NETWORK_CHANNEL 0
|
||||
#endif
|
||||
|
||||
#if !defined(EAMAIN_FREOPEN_SUPPORTED)
|
||||
#define EAMAIN_FREOPEN_SUPPORTED 0
|
||||
#endif
|
||||
|
||||
#if EAMAIN_HAS_NETWORK_CHANNEL
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
|
||||
#if defined(WINAPI_FAMILY)
|
||||
#undef WINAPI_FAMILY
|
||||
#endif
|
||||
|
||||
#define WINAPI_FAMILY WINAPI_FAMILY_DESKTOP_APP
|
||||
|
||||
#include <WinSock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
|
||||
#pragma comment(lib, "Ws2_32.lib")
|
||||
|
||||
#if defined(EA_PLATFORM_WINDOWS_PHONE)
|
||||
#pragma warning(disable:4265)
|
||||
#include <thread>
|
||||
#else
|
||||
// Restoring VC warnings on Windows Phone causes some warnings to pop
|
||||
// up down below, emanating from std::thread. In order to have some
|
||||
// coverage of this code, warnings are re-enabled on other platforms.
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
#endif
|
||||
|
||||
#define SocketGetLastError() WSAGetLastError()
|
||||
#define snprintf _snprintf
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#if !defined(EA_PLATFORM_SONY)
|
||||
#include <netdb.h>
|
||||
#else
|
||||
#include <net.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
typedef int SOCKET;
|
||||
const int INVALID_SOCKET = -1;
|
||||
const int SOCKET_ERROR = -1;
|
||||
#define SD_SEND SHUT_WR
|
||||
#define closesocket close
|
||||
#define WSAECONNREFUSED ECONNREFUSED
|
||||
#define WSAENETUNREACH ENETUNREACH
|
||||
#define SocketGetLastError() errno
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "eathread/eathread_thread.h"
|
||||
#include "EAStdC/EAMemory.h"
|
||||
#include "EAStdC/EAString.h"
|
||||
#include "EAStdC/EASprintf.h"
|
||||
|
||||
namespace EA
|
||||
{
|
||||
namespace EAMain
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
class NetworkChannel : public IChannel
|
||||
{
|
||||
SOCKET m_socket;
|
||||
char m_serverAddressStorage[128];
|
||||
char m_port[6];
|
||||
const char *m_serverAddress;
|
||||
|
||||
static void SleepThread(int milliseconds);
|
||||
|
||||
public:
|
||||
NetworkChannel();
|
||||
|
||||
virtual ~NetworkChannel();
|
||||
virtual void Init();
|
||||
virtual void Send(const char8_t *data);
|
||||
virtual void Shutdown();
|
||||
|
||||
void SetServerPort(const char *server, const char *port);
|
||||
bool Connect();
|
||||
};
|
||||
|
||||
static NetworkChannel g_NetworkChannelInstance;
|
||||
|
||||
void NetworkChannel::SleepThread(int milliseconds)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(EA_PLATFORM_WINDOWS_PHONE)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
|
||||
#else
|
||||
Sleep(milliseconds);
|
||||
#endif
|
||||
#else
|
||||
usleep(milliseconds * 1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
NetworkChannel::NetworkChannel()
|
||||
: m_socket(INVALID_SOCKET)
|
||||
, m_serverAddress(&m_serverAddressStorage[0])
|
||||
{
|
||||
EA::StdC::Memset8(m_serverAddressStorage, 0, sizeof m_serverAddressStorage);
|
||||
EA::StdC::Memset8(m_port, 0, sizeof m_port);
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
WSAData wsaData = {};
|
||||
WSAStartup(MAKEWORD(2, 2), &wsaData);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void LogNetworkError(const char *format, ...)
|
||||
{
|
||||
(void)format;
|
||||
}
|
||||
|
||||
NetworkChannel::~NetworkChannel()
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
WSACleanup();
|
||||
#endif
|
||||
}
|
||||
|
||||
void NetworkChannel::Init()
|
||||
{
|
||||
}
|
||||
|
||||
void NetworkChannel::Send(const char8_t *data)
|
||||
{
|
||||
char *buffer = const_cast<char *>(data);
|
||||
ssize_t bufferLength = static_cast<ssize_t>(strlen(buffer));
|
||||
ssize_t bytesSent = 0;
|
||||
while (bytesSent < bufferLength)
|
||||
{
|
||||
ssize_t result = send(m_socket, buffer + bytesSent, static_cast<int>(bufferLength - bytesSent), 0);
|
||||
|
||||
if (result == SOCKET_ERROR)
|
||||
{
|
||||
bool reconnected = false;
|
||||
LogNetworkError("[NetworkChannel::Send] Reconnecting...");
|
||||
|
||||
for (int i = 0; i < 20; ++i)
|
||||
{
|
||||
Shutdown();
|
||||
|
||||
if (!Connect())
|
||||
{
|
||||
LogNetworkError("[NetworkChannel::Send] Send failed: %d", SocketGetLastError());
|
||||
}
|
||||
else
|
||||
{
|
||||
reconnected = true;
|
||||
break;
|
||||
}
|
||||
|
||||
SleepThread(500);
|
||||
}
|
||||
|
||||
if (!reconnected)
|
||||
{
|
||||
LogNetworkError("[NetworkChannel::Send] Unable to connect, aborting.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bytesSent += result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkChannel::Shutdown()
|
||||
{
|
||||
// Closing the socket does not wait for pending data to be sent.
|
||||
// To ensure that all data has been sent, the write end of the
|
||||
// socket must first be shut down. This sends a FIN packet to
|
||||
// the receiver after all data has been sent and acknowledged
|
||||
// by the receiver. This must also be paired with a call to
|
||||
// recv to ensure that all pending readable data has been
|
||||
// read.
|
||||
shutdown(m_socket, SD_SEND);
|
||||
|
||||
char buffer[128];
|
||||
|
||||
for (;;)
|
||||
{
|
||||
ssize_t rv = recv(m_socket, buffer, (int)sizeof buffer, 0);
|
||||
|
||||
if (rv <= 0)
|
||||
{
|
||||
// We can assume that a graceful shutdown has occurred
|
||||
// when rv == 0. If rv < 0 an error has occurred, but
|
||||
// we are not at a point where we can easily recover, so
|
||||
// this code will just shutdown the socket and exit the
|
||||
// program if an error happens here.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
closesocket(m_socket);
|
||||
m_socket = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
void NetworkChannel::SetServerPort(const char *server, const char *port)
|
||||
{
|
||||
using namespace EA::StdC;
|
||||
|
||||
// If, somehow, the server name string is longer than the storge
|
||||
// allocated, allocate some space for it on the C-heap. Not ideal,
|
||||
// may actually fail some tests, but the alternative would be
|
||||
// no output from EAMain at all.
|
||||
if (Strlcpy(m_serverAddressStorage, server, sizeof m_serverAddressStorage) > (sizeof m_serverAddressStorage))
|
||||
{
|
||||
size_t serverNameLength = Strlen(server);
|
||||
|
||||
char *ptr = static_cast<char *>(calloc(serverNameLength + 1, 1));
|
||||
Strlcpy(ptr, server, serverNameLength + 1);
|
||||
|
||||
m_serverAddress = ptr;
|
||||
}
|
||||
|
||||
// Valid port numbers are in the range [1, 65535] so will have
|
||||
// always 5 digits max.
|
||||
EA_ASSERT(sizeof m_port == 6);
|
||||
Strlcpy(m_port, port, sizeof m_port);
|
||||
}
|
||||
|
||||
bool NetworkChannel::Connect()
|
||||
{
|
||||
EA_ASSERT(m_serverAddress != NULL);
|
||||
EA_ASSERT(m_port != NULL);
|
||||
|
||||
bool result = false;
|
||||
SOCKET remoteSocket = INVALID_SOCKET;
|
||||
const int MAX_RETRIES = 250;
|
||||
|
||||
#if !defined(EA_PLATFORM_SONY)
|
||||
struct addrinfo hints = {};
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
addrinfo *p = NULL;
|
||||
|
||||
if (getaddrinfo(m_serverAddress, m_port, &hints, &p) != 0)
|
||||
{
|
||||
LogNetworkError("[NetworkChannel::Connect] Cannot connect to %s:%s", m_serverAddress, m_port);
|
||||
goto ErrorReturn;
|
||||
}
|
||||
for (struct addrinfo *endpoint = p; endpoint != NULL; endpoint = endpoint->ai_next)
|
||||
#endif
|
||||
|
||||
{
|
||||
#if !defined(EA_PLATFORM_SONY)
|
||||
remoteSocket = socket(endpoint->ai_family, endpoint->ai_socktype, endpoint->ai_protocol);
|
||||
#else
|
||||
remoteSocket = sceNetSocket("EAMain Socket", SCE_NET_AF_INET, SCE_NET_SOCK_STREAM, 0);
|
||||
#endif
|
||||
if (remoteSocket == INVALID_SOCKET)
|
||||
{
|
||||
LogNetworkError("[NetworkChannel::Connect] Cannot create socket");
|
||||
goto ErrorReturn;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
if (endpoint->ai_family == AF_INET6)
|
||||
{
|
||||
DWORD v6only = 0;
|
||||
setsockopt(remoteSocket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&v6only, sizeof v6only);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < MAX_RETRIES; ++i)
|
||||
{
|
||||
#if !defined(EA_PLATFORM_SONY)
|
||||
int connectResult = connect(remoteSocket, endpoint->ai_addr, (int)endpoint->ai_addrlen);
|
||||
#else
|
||||
char *p;
|
||||
SceNetInPort_t port = strtol(m_port, &p, 10);
|
||||
|
||||
SceNetSockaddrIn sin;
|
||||
EA::StdC::Memset8(&sin, 0, sizeof sin);
|
||||
sin.sin_len = sizeof(sin);
|
||||
sin.sin_family = SCE_NET_AF_INET;
|
||||
if (sceNetInetPton(SCE_NET_AF_INET, m_serverAddress, &sin.sin_addr) <= 0)
|
||||
{
|
||||
LogNetworkError("[NetworkChannel::Connect] Cannot connect to %s:%s", m_serverAddress, m_port);
|
||||
goto ErrorReturn;
|
||||
}
|
||||
|
||||
sin.sin_port = sceNetHtons(port);
|
||||
sin.sin_vport = sceNetHtons(SCE_NET_ADHOC_PORT);
|
||||
int connectResult = sceNetConnect(remoteSocket, (SceNetSockaddr *)&sin, sizeof(sin));
|
||||
#endif
|
||||
if (connectResult == 0)
|
||||
{
|
||||
result = true;
|
||||
m_socket = remoteSocket;
|
||||
goto SuccessReturn;
|
||||
}
|
||||
|
||||
switch (SocketGetLastError())
|
||||
{
|
||||
case WSAENETUNREACH:
|
||||
SleepThread(20);
|
||||
continue;
|
||||
default:
|
||||
LogNetworkError("[NetworkChannel::Connect] Cannot connect to socket");
|
||||
goto ErrorReturn;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ErrorReturn:
|
||||
if (remoteSocket != INVALID_SOCKET)
|
||||
{
|
||||
LogNetworkError("[NetworkChannel::Connect] FAILED");
|
||||
closesocket(remoteSocket);
|
||||
}
|
||||
|
||||
SuccessReturn:
|
||||
#if !defined(EA_PLATFORM_SONY)
|
||||
if (p)
|
||||
{
|
||||
freeaddrinfo(p);
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
static IChannel *CreateNetworkChannelImpl(const char *server, int port)
|
||||
{
|
||||
char portString[6];
|
||||
|
||||
if (port > 65536 || port < 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf(portString, sizeof portString, "%d", port);
|
||||
portString[5] = 0;
|
||||
|
||||
g_NetworkChannelInstance.SetServerPort(server, portString);
|
||||
|
||||
if (g_NetworkChannelInstance.Connect())
|
||||
{
|
||||
return &g_NetworkChannelInstance;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if !EAMAIN_FREOPEN_SUPPORTED
|
||||
IChannel *CreateNetworkChannel(const char *server, int port)
|
||||
{
|
||||
// On platforms where we do not support freopen on standard
|
||||
// IO streams, we create a raw network channel.
|
||||
return CreateNetworkChannelImpl(server, port);
|
||||
}
|
||||
#else
|
||||
static EA::Thread::Thread g_PrintThread;
|
||||
static volatile bool g_PrintThreadDone;
|
||||
static FILE *g_RedirectedStdoutHandle;
|
||||
static FILE *g_RedirectedStderrHandle;
|
||||
|
||||
class StdoutWrapperChannel : public IChannel
|
||||
{
|
||||
NetworkChannel &m_channel;
|
||||
bool m_shutdown;
|
||||
|
||||
StdoutWrapperChannel& operator=(const StdoutWrapperChannel&);
|
||||
StdoutWrapperChannel(const StdoutWrapperChannel&);
|
||||
|
||||
public:
|
||||
StdoutWrapperChannel(NetworkChannel &channel)
|
||||
: m_channel(channel)
|
||||
, m_shutdown(false)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~StdoutWrapperChannel();
|
||||
|
||||
virtual void Init()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Send(const char8_t *data)
|
||||
{
|
||||
fputs(data, stdout);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
virtual void Shutdown()
|
||||
{
|
||||
if (g_RedirectedStdoutHandle)
|
||||
{
|
||||
fclose(g_RedirectedStdoutHandle);
|
||||
}
|
||||
|
||||
if (g_RedirectedStderrHandle)
|
||||
{
|
||||
fclose(g_RedirectedStderrHandle);
|
||||
}
|
||||
|
||||
g_PrintThreadDone = true;
|
||||
|
||||
if (g_PrintThread.GetStatus() == EA::Thread::Thread::kStatusRunning)
|
||||
{
|
||||
g_PrintThread.WaitForEnd();
|
||||
}
|
||||
|
||||
m_channel.Shutdown();
|
||||
m_shutdown = true;
|
||||
}
|
||||
};
|
||||
|
||||
StdoutWrapperChannel::~StdoutWrapperChannel()
|
||||
{
|
||||
if (!m_shutdown)
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
static bool ReadFromFile(FILE *file)
|
||||
{
|
||||
static const int BUFFER_SIZE = 1024;
|
||||
static char buffer[BUFFER_SIZE + 1];
|
||||
bool haveRead = false;
|
||||
|
||||
// This is a tortuous way of checking to see if there is data
|
||||
// available but the goal here is to prevent this thread from
|
||||
// blocking if nothing is ready. Blocking could be desirable
|
||||
// if we were only reading from one stream but because this
|
||||
// code attempts to read from both stdout and stderr we do not
|
||||
// want it to block on reading one while the other is receiving
|
||||
// important information.
|
||||
|
||||
// Another possibility would be to use non-blocking IO but this
|
||||
// would require different implementations for different
|
||||
// platforms.
|
||||
long currentPosition = ftell(file);
|
||||
fseek(file, 0, SEEK_END);
|
||||
long endPosition = ftell(file);
|
||||
|
||||
if (endPosition > currentPosition)
|
||||
{
|
||||
size_t bytesAvailable = static_cast<size_t>(endPosition - currentPosition);
|
||||
|
||||
fseek(file, currentPosition, SEEK_SET);
|
||||
while (bytesAvailable > 0)
|
||||
{
|
||||
size_t bytesToRead = (bytesAvailable > BUFFER_SIZE) ? BUFFER_SIZE : bytesAvailable;
|
||||
|
||||
size_t bytesRead = fread(buffer, 1, bytesToRead, file);
|
||||
buffer[bytesRead] = 0;
|
||||
|
||||
g_NetworkChannelInstance.Send(buffer);
|
||||
|
||||
bytesAvailable -= bytesRead;
|
||||
}
|
||||
|
||||
haveRead = true;
|
||||
}
|
||||
|
||||
return haveRead;
|
||||
}
|
||||
|
||||
static char g_StdoutLogPath[256];
|
||||
static char g_StderrLogPath[256];
|
||||
|
||||
static intptr_t PrintFunction(void *)
|
||||
{
|
||||
FILE *stdoutLog = fopen(g_StdoutLogPath, "rb");
|
||||
FILE *stderrLog = fopen(g_StderrLogPath, "rb");
|
||||
|
||||
while (!g_PrintThreadDone)
|
||||
{
|
||||
// It might look neater to combine these file reads into
|
||||
// the if statement but this was not done because the
|
||||
// shortcircuting of the left hand condition prevented
|
||||
// the right hand condition from being evaluated, but
|
||||
// every iteration should read from both sources.
|
||||
bool haveReadStdout = ReadFromFile(stdoutLog);
|
||||
bool haveReadStderr = ReadFromFile(stderrLog);
|
||||
|
||||
if (!haveReadStdout && !haveReadStderr)
|
||||
{
|
||||
EA::Thread::ThreadSleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
fflush(stdout); ReadFromFile(stdoutLog); fclose(stdoutLog);
|
||||
fflush(stderr); ReadFromFile(stderrLog); fclose(stderrLog);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
IChannel *CreateNetworkChannel(const char *server, int port)
|
||||
{
|
||||
#if defined(EA_PLATFORM_CAPILANO)
|
||||
if (IsDebuggerPresent())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
EA::Thread::ThreadParameters threadParameters;
|
||||
|
||||
char *STDOUT_LOG_NAME = "stdout.log";
|
||||
const char *STDERR_LOG_NAME = "stderr.log";
|
||||
|
||||
threadParameters.mnPriority = EA::Thread::kThreadPriorityMax;
|
||||
|
||||
#if defined EA_PLATFORM_IPHONE
|
||||
char temporaryDirectory[256];
|
||||
confstr(_CS_DARWIN_USER_TEMP_DIR, temporaryDirectory, sizeof temporaryDirectory);
|
||||
|
||||
EA::StdC::Snprintf(g_StdoutLogPath, sizeof g_StdoutLogPath, "%s/%s", temporaryDirectory, STDOUT_LOG_NAME);
|
||||
EA::StdC::Snprintf(g_StderrLogPath, sizeof g_StderrLogPath, "%s/%s", temporaryDirectory, STDERR_LOG_NAME);
|
||||
#elif defined EA_PLATFORM_CAPILANO
|
||||
EA::StdC::Snprintf(g_StdoutLogPath, sizeof g_StdoutLogPath, "T:\\%s", STDOUT_LOG_NAME);
|
||||
EA::StdC::Snprintf(g_StderrLogPath, sizeof g_StderrLogPath, "T:\\%s", STDERR_LOG_NAME);
|
||||
#else
|
||||
EA::StdC::Strlcpy(g_StdoutLogPath, STDOUT_LOG_NAME, sizeof g_StdoutLogPath);
|
||||
EA::StdC::Strlcpy(g_StderrLogPath, STDERR_LOG_NAME, sizeof g_StderrLogPath);
|
||||
#endif
|
||||
|
||||
fprintf(stdout, ""); fflush(stdout);
|
||||
fprintf(stderr, ""); fflush(stderr);
|
||||
|
||||
g_RedirectedStdoutHandle = freopen(g_StdoutLogPath, "wb", stdout);
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
g_RedirectedStderrHandle = freopen(g_StderrLogPath, "wb", stderr);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
|
||||
if (CreateNetworkChannelImpl(server, port) != NULL)
|
||||
{
|
||||
g_PrintThread.Begin(PrintFunction, NULL, &threadParameters);
|
||||
}
|
||||
|
||||
return new StdoutWrapperChannel(g_NetworkChannelInstance);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
namespace EA
|
||||
{
|
||||
namespace EAMain
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
IChannel *CreateNetworkChannel(const char *server, int port)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,21 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef EAMAIN_INTERNAL_NETWORKCHANNEL_H
|
||||
#define EAMAIN_INTERNAL_NETWORKCHANNEL_H
|
||||
|
||||
#include <EAMain/internal/EAMainChannels.h>
|
||||
|
||||
namespace EA
|
||||
{
|
||||
namespace EAMain
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
IChannel *CreateNetworkChannel(const char *connection, int port);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,108 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <kernel.h>
|
||||
#include <sceerror.h>
|
||||
#include <gnm.h>
|
||||
#include "EAAssert/eaassert.h"
|
||||
|
||||
#define SUBMIT_DEBUG_PRINT(arg)
|
||||
|
||||
namespace EA
|
||||
{
|
||||
namespace EAMain
|
||||
{
|
||||
namespace Internal
|
||||
{
|
||||
static ScePthread gSubmitDoneThread;
|
||||
static SceKernelSema gSubmitDoneSema;
|
||||
volatile static bool gShutdownSubmitDoneThread = false;
|
||||
|
||||
void* SubmitDoneThreadFunction(void *)
|
||||
{
|
||||
int result;
|
||||
EA_UNUSED(result);
|
||||
|
||||
SUBMIT_DEBUG_PRINT("Started submit done thread\n");
|
||||
for(;;)
|
||||
{
|
||||
const int microsecondsPerSecond = 1000000;
|
||||
SceKernelUseconds timeout = 2 * microsecondsPerSecond;
|
||||
result = sceKernelWaitSema(gSubmitDoneSema, 1, &timeout);
|
||||
EA_ASSERT(result == SCE_OK || result == SCE_KERNEL_ERROR_ETIMEDOUT);
|
||||
|
||||
if(gShutdownSubmitDoneThread)
|
||||
{
|
||||
// Break out to avoid calling submitDone
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
SUBMIT_DEBUG_PRINT("submitDone\n");
|
||||
|
||||
#if SCE_ORBIS_SDK_VERSION >= 0x01000051u && SCE_ORBIS_SDK_VERSION != 0x01000071u
|
||||
// Only perform the submitDone call if we are above SDK version 1.00.051
|
||||
// but not 1.00.071 since the requirement was temporarily removed in that release.
|
||||
// This is not required in previous or later SDK versions.
|
||||
sce::Gnm::submitDone();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
SUBMIT_DEBUG_PRINT("Ending submit done thread\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void StartSubmitDoneThread()
|
||||
{
|
||||
int result;
|
||||
EA_UNUSED(result);
|
||||
|
||||
SUBMIT_DEBUG_PRINT("Starting submit done thread\n");
|
||||
|
||||
result = sceKernelCreateSema(&gSubmitDoneSema, "submit done semaphore", 0, 0, 1, nullptr);
|
||||
EA_ASSERT(result == SCE_OK);
|
||||
|
||||
result = scePthreadCreate(&gSubmitDoneThread, NULL, SubmitDoneThreadFunction, NULL, "submit done thread");
|
||||
EA_ASSERT(result == SCE_OK);
|
||||
}
|
||||
|
||||
void ShutdownSubmitDoneThread()
|
||||
{
|
||||
if(!gShutdownSubmitDoneThread)
|
||||
{
|
||||
SUBMIT_DEBUG_PRINT("Disabling submit done thread\n");
|
||||
int result;
|
||||
EA_UNUSED(result);
|
||||
|
||||
// Indicate that the submit done thread should exit
|
||||
gShutdownSubmitDoneThread = true;
|
||||
|
||||
// Signal semaphore to unblock the submit done thread
|
||||
result = sceKernelSignalSema(gSubmitDoneSema, 1);
|
||||
EA_ASSERT(result == SCE_OK);
|
||||
|
||||
// Wait for the thread to exit
|
||||
result = scePthreadJoin(gSubmitDoneThread, nullptr);
|
||||
EA_ASSERT(result == SCE_OK);
|
||||
|
||||
// Free up kernel resources
|
||||
result = sceKernelDeleteSema(gSubmitDoneSema);
|
||||
EA_ASSERT(result == SCE_OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DisableSubmitDoneThread()
|
||||
{
|
||||
using namespace EA::EAMain::Internal;
|
||||
|
||||
ShutdownSubmitDoneThread();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#undef SUBMIT_DEBUG_PRINT
|
||||
@@ -0,0 +1,59 @@
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Copyright (C) Electronic Arts Inc. All rights reserved.
|
||||
#-------------------------------------------------------------------------------------------
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# CMake info
|
||||
#-------------------------------------------------------------------------------------------
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
project(EAMainTest CXX)
|
||||
include(CTest)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Defines
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
|
||||
add_definitions(-D_CHAR16T)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Compiler Flags
|
||||
#-------------------------------------------------------------------------------------------
|
||||
set (CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/packages/EASTL/scripts/CMake")
|
||||
include(CommonCppFlags)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Source files
|
||||
#-------------------------------------------------------------------------------------------
|
||||
file(GLOB EAMAINTEST_SOURCES "source/Main/Main.cpp")
|
||||
set(SOURCES ${EAMAINTEST_SOURCES})
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Executable definition
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_executable(EAMainTest ${SOURCES})
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Dependencies
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_subdirectory(packages/EAAssert)
|
||||
add_subdirectory(packages/EABase)
|
||||
add_subdirectory(packages/EASTL)
|
||||
add_subdirectory(packages/EAStdC)
|
||||
add_subdirectory(packages/EATest)
|
||||
add_subdirectory(packages/EAThread)
|
||||
|
||||
target_link_libraries(EAMainTest EABase)
|
||||
target_link_libraries(EAMainTest EAAssert)
|
||||
target_link_libraries(EAMainTest EAMain)
|
||||
target_link_libraries(EAMainTest EASTL)
|
||||
target_link_libraries(EAMainTest EAStdC)
|
||||
target_link_libraries(EAMainTest EATest)
|
||||
target_link_libraries(EAMainTest EAThread)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Run Unit tests and verify the results.
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_test(EAMainTestRuns EAMainTest -testargpassing)
|
||||
set_tests_properties (EAMainTestRuns PROPERTIES PASS_REGULAR_EXPRESSION "RETURNCODE=0")
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void CrashHelper(int *p)
|
||||
{
|
||||
*p = 0;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#include <EAMain/EAMain.h>
|
||||
#include <EAMain/EAEntryPointMain.inl>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0)
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#if defined(EA_COMPILER_MSVC) && defined(EA_PLATFORM_MICROSOFT)
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
void* operator new[](size_t size, const char* /*pName*/, int /*flags*/, unsigned /*debugFlags*/, const char* /*file*/, int /*line*/)
|
||||
{
|
||||
return operator new[](size);
|
||||
}
|
||||
|
||||
void* operator new[](size_t size, size_t /*alignment*/, size_t /*alignmentOffset*/, const char* /*pName*/,
|
||||
int /*flags*/, unsigned /*debugFlags*/, const char* /*file*/, int /*line*/)
|
||||
{
|
||||
return operator new[](size);
|
||||
}
|
||||
|
||||
void CrashHelper(int *ptr);
|
||||
|
||||
int EAMain(int argc, char** argv)
|
||||
{
|
||||
CrashHelper(NULL);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,283 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#include <EAMain/EAMain.h>
|
||||
#include <EAMain/EAMainInitFini.inl>
|
||||
#include <EAMain/EAEntryPointMain.inl>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0)
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#if defined(EA_COMPILER_MSVC) && defined(EA_PLATFORM_MICROSOFT)
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void* operator new[](size_t size, const char* /*pName*/, int /*flags*/, unsigned /*debugFlags*/, const char* /*file*/, int /*line*/)
|
||||
{
|
||||
return operator new[](size);
|
||||
}
|
||||
|
||||
void* operator new[](size_t size, size_t /*alignment*/, size_t /*alignmentOffset*/, const char* /*pName*/,
|
||||
int /*flags*/, unsigned /*debugFlags*/, const char* /*file*/, int /*line*/)
|
||||
{
|
||||
return operator new[](size);
|
||||
}
|
||||
|
||||
static int TestCommandLineArgs()
|
||||
{
|
||||
using namespace EA::EAMain;
|
||||
|
||||
#define EAMAIN_TEST(x) if (!(x)) { Report("%s(%d): %s\n", __FILE__, __LINE__, #x); ++nErrorCount; } else (void)0
|
||||
#define EAMAIN_TEST_FATAL(x) if (!(x)) { Report("%s(%d): %s\n", __FILE__, __LINE__, #x); ++nErrorCount; return nErrorCount; } else (void)0
|
||||
|
||||
int nErrorCount = 0;
|
||||
|
||||
// This test is disabled on xenon because xenon has implicit command line
|
||||
// construction if argc is zero.
|
||||
{
|
||||
int argc = 0;
|
||||
char *argv[] = { NULL };
|
||||
|
||||
CommandLine commandLine(argc, argv);
|
||||
|
||||
EAMAIN_TEST(commandLine.Argc() == 0);
|
||||
EAMAIN_TEST(commandLine.Argv() != NULL);
|
||||
EAMAIN_TEST(commandLine.FindSwitch("-x") == -1);
|
||||
EAMAIN_TEST(commandLine.Arg(0) == nullptr);
|
||||
EAMAIN_TEST(commandLine.Argv()[0] == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
int argc = 1;
|
||||
char arg[] = "program.elf";
|
||||
char *argv[] = { arg };
|
||||
|
||||
CommandLine commandLine(argc, argv);
|
||||
|
||||
EAMAIN_TEST(commandLine.Argc() == 1);
|
||||
EAMAIN_TEST_FATAL(commandLine.Argv() != NULL);
|
||||
EAMAIN_TEST(strcmp(commandLine.Argv()[0], "program.elf") == 0);
|
||||
EAMAIN_TEST(strcmp(commandLine.Arg(0), "program.elf") == 0);
|
||||
EAMAIN_TEST(commandLine.FindSwitch("-x") == -1);
|
||||
EAMAIN_TEST(commandLine.Arg(1) == nullptr);
|
||||
EAMAIN_TEST(commandLine.Argv()[1] == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
const char *commandLineString = "program.elf";
|
||||
|
||||
CommandLine commandLine(commandLineString);
|
||||
|
||||
EAMAIN_TEST(commandLine.Argc() == 1);
|
||||
EAMAIN_TEST_FATAL(commandLine.Argv() != NULL);
|
||||
EAMAIN_TEST(strcmp(commandLine.Argv()[0], "program.elf") == 0);
|
||||
EAMAIN_TEST(strcmp(commandLine.Arg(0), "program.elf") == 0);
|
||||
EAMAIN_TEST(commandLine.FindSwitch("-x") == -1);
|
||||
EAMAIN_TEST(commandLine.Arg(1) == nullptr);
|
||||
EAMAIN_TEST(commandLine.Argv()[1] == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
const char *commandLineString = "program.elf arg1 \"arg 2\"";
|
||||
|
||||
CommandLine commandLine(commandLineString);
|
||||
|
||||
EAMAIN_TEST(commandLine.Argc() == 3);
|
||||
EAMAIN_TEST_FATAL(commandLine.Argv() != NULL);
|
||||
EAMAIN_TEST(strcmp(commandLine.Argv()[0], "program.elf") == 0);
|
||||
EAMAIN_TEST(strcmp(commandLine.Arg(0), "program.elf") == 0);
|
||||
EAMAIN_TEST(strcmp(commandLine.Arg(1), "arg1") == 0);
|
||||
EAMAIN_TEST(strcmp(commandLine.Arg(2), "arg 2") == 0);
|
||||
EAMAIN_TEST(commandLine.FindSwitch("-x") == -1);
|
||||
EAMAIN_TEST(commandLine.Arg(3) == nullptr);
|
||||
EAMAIN_TEST(commandLine.Argv()[3] == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
const char *commandLineString = "program.elf -x -y:1";
|
||||
const char *parameter = NULL;
|
||||
|
||||
CommandLine commandLine(commandLineString);
|
||||
|
||||
EAMAIN_TEST(commandLine.Argc() == 3);
|
||||
EAMAIN_TEST_FATAL(commandLine.Argv() != NULL);
|
||||
EAMAIN_TEST(strcmp(commandLine.Arg(0), "program.elf") == 0);
|
||||
EAMAIN_TEST(strcmp(commandLine.Arg(1), "-x") == 0);
|
||||
EAMAIN_TEST(commandLine.FindSwitch("-x") == 1);
|
||||
EAMAIN_TEST(commandLine.FindSwitch("-y", false, ¶meter) == 2);
|
||||
EAMAIN_TEST_FATAL(parameter != NULL);
|
||||
EAMAIN_TEST(strcmp(parameter, "1") == 0);
|
||||
EAMAIN_TEST(commandLine.Arg(3) == nullptr);
|
||||
EAMAIN_TEST(commandLine.Argv()[3] == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
const char *commandLineString = "program.elf -x \"-switch:this switch parameter has spaces\"";
|
||||
const char *parameter = NULL;
|
||||
|
||||
CommandLine commandLine(commandLineString);
|
||||
|
||||
EAMAIN_TEST(commandLine.Argc() == 3);
|
||||
EAMAIN_TEST_FATAL(commandLine.Argv() != NULL);
|
||||
EAMAIN_TEST(strcmp(commandLine.Arg(0), "program.elf") == 0);
|
||||
EAMAIN_TEST(strcmp(commandLine.Arg(1), "-x") == 0);
|
||||
EAMAIN_TEST(commandLine.FindSwitch("-x") == 1);
|
||||
EAMAIN_TEST(commandLine.FindSwitch("-switch", false, ¶meter) == 2);
|
||||
EAMAIN_TEST_FATAL(parameter != NULL);
|
||||
EAMAIN_TEST(strcmp(parameter, "this switch parameter has spaces") == 0);
|
||||
EAMAIN_TEST(commandLine.Arg(3) == nullptr);
|
||||
EAMAIN_TEST(commandLine.Argv()[3] == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
const char *commandLineString = "program.elf -x -switch:\"this switch parameter has spaces\" \"-switch2:as does this one\"";
|
||||
const char *parameter = NULL;
|
||||
|
||||
CommandLine commandLine(commandLineString);
|
||||
|
||||
EAMAIN_TEST(commandLine.Argc() == 4);
|
||||
EAMAIN_TEST_FATAL(commandLine.Argv() != NULL);
|
||||
EAMAIN_TEST(strcmp(commandLine.Arg(0), "program.elf") == 0);
|
||||
EAMAIN_TEST(strcmp(commandLine.Arg(1), "-x") == 0);
|
||||
EAMAIN_TEST(commandLine.FindSwitch("-x") == 1);
|
||||
EAMAIN_TEST(commandLine.FindSwitch("-switch", false, ¶meter) == 2);
|
||||
EAMAIN_TEST_FATAL(parameter != NULL);
|
||||
EAMAIN_TEST(strcmp(parameter, "this switch parameter has spaces") == 0);
|
||||
EAMAIN_TEST(commandLine.Arg(4) == nullptr);
|
||||
EAMAIN_TEST(commandLine.Argv()[4] == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
const char *commandLineString = "-x -switch:\"this switch parameter has spaces\" \"-switch2:as does this one\"";
|
||||
const char *parameter = NULL;
|
||||
|
||||
CommandLine commandLine(commandLineString, CommandLine::FLAG_NO_PROGRAM_NAME);
|
||||
|
||||
EAMAIN_TEST(commandLine.Argc() == 4);
|
||||
EAMAIN_TEST_FATAL(commandLine.Argv() != NULL);
|
||||
EAMAIN_TEST(strcmp(commandLine.Arg(0), "") == 0);
|
||||
EAMAIN_TEST(strcmp(commandLine.Arg(1), "-x") == 0);
|
||||
EAMAIN_TEST(commandLine.FindSwitch("-x") == 1);
|
||||
EAMAIN_TEST(commandLine.FindSwitch("-switch", false, ¶meter) == 2);
|
||||
EAMAIN_TEST_FATAL(parameter != NULL);
|
||||
EAMAIN_TEST(strcmp(parameter, "this switch parameter has spaces") == 0);
|
||||
EAMAIN_TEST(commandLine.Arg(4) == nullptr);
|
||||
EAMAIN_TEST(commandLine.Argv()[4] == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
int argc = 3;
|
||||
char arg0[] = "program.elf";
|
||||
char arg1[] = "-x";
|
||||
char arg2[] = "-switch:this switch parameter has spaces";
|
||||
char *argv[] = { arg0, arg1, arg2 };
|
||||
const char *parameter;
|
||||
|
||||
CommandLine commandLine(argc, argv);
|
||||
|
||||
EAMAIN_TEST(commandLine.Argc() == 3);
|
||||
EAMAIN_TEST_FATAL(commandLine.Argv() != NULL);
|
||||
EAMAIN_TEST(strcmp(commandLine.Arg(0), "program.elf") == 0);
|
||||
EAMAIN_TEST(strcmp(commandLine.Arg(1), "-x") == 0);
|
||||
EAMAIN_TEST(commandLine.FindSwitch("-x") == 1);
|
||||
EAMAIN_TEST(commandLine.FindSwitch("-switch", false, ¶meter) == 2);
|
||||
EAMAIN_TEST_FATAL(parameter != NULL);
|
||||
EAMAIN_TEST(strcmp(parameter, "this switch parameter has spaces") == 0);
|
||||
EAMAIN_TEST(commandLine.Arg(3) == nullptr);
|
||||
EAMAIN_TEST(commandLine.Argv()[3] == nullptr);
|
||||
}
|
||||
|
||||
return nErrorCount;
|
||||
|
||||
#undef EAMAIN_TEST
|
||||
#undef EAMAIN_TEST_FATAL
|
||||
}
|
||||
|
||||
static bool gEAMainInitCalled;
|
||||
|
||||
void EAMainInit()
|
||||
{
|
||||
gEAMainInitCalled = true;
|
||||
}
|
||||
|
||||
void EAMainFini()
|
||||
{
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// EAMain
|
||||
//
|
||||
int EAMain(int argc, char** argv)
|
||||
{
|
||||
using namespace EA::EAMain;
|
||||
|
||||
int nErrorCount(0);
|
||||
|
||||
Report("List of arguments passed:\n");
|
||||
for (int i = 0; i < argc; ++i)
|
||||
{
|
||||
Report("Arg %d: %s\n", i, argv[i]);
|
||||
}
|
||||
Report("\n");
|
||||
|
||||
// Basic test of redirection of stdout/stderr on platforms that support
|
||||
// redirection of these streams.
|
||||
printf("printf(...)\n");
|
||||
fprintf(stdout, "fprintf(stdout, ...)\n");
|
||||
fflush(stdout);
|
||||
|
||||
fprintf(stderr, "fprintf(stderr, ...)\n");
|
||||
fflush(stderr);
|
||||
|
||||
Report("Test of %s.\n", "Report()");
|
||||
Report("Report()\n");
|
||||
|
||||
bool bArgPassed = false;
|
||||
|
||||
for (int i = 0; i < argc; ++i)
|
||||
{
|
||||
if (strcmp(argv[i], "-testargpassing") == 0)
|
||||
{
|
||||
bArgPassed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Windows Phone does not support passing arguments to app bundles when
|
||||
// launching them.
|
||||
#if !defined(EA_PLATFORM_WINDOWS_PHONE)
|
||||
if (!bArgPassed)
|
||||
{
|
||||
Report("Arg not passed!\n");
|
||||
++nErrorCount;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (TestCommandLineArgs() != 0)
|
||||
{
|
||||
Report("Error parsing command line arguments!\n");
|
||||
++nErrorCount;
|
||||
}
|
||||
|
||||
if (!gEAMainInitCalled)
|
||||
{
|
||||
Report("EAMainInit was not called!\n");
|
||||
++nErrorCount;
|
||||
}
|
||||
|
||||
Report("This report statement has \nno terminating newline");
|
||||
|
||||
return nErrorCount;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <EABase/eabase.h>
|
||||
#include <EAMain/EAMain.h>
|
||||
|
||||
EA_DISABLE_ALL_VC_WARNINGS()
|
||||
#include <new>
|
||||
EA_RESTORE_ALL_VC_WARNINGS()
|
||||
|
||||
// Array new is a requirement brought in by EAStdC.
|
||||
void* operator new[](size_t size, const char* /*pName*/, int /*flags*/, unsigned /*debugFlags*/, const char* /*file*/, int /*line*/)
|
||||
{
|
||||
return ::operator new[](size);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// EAMain
|
||||
//
|
||||
#if (defined(EA_PLATFORM_MICROSOFT) && !defined(CS_UNDEFINED_STRING) && !EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP))
|
||||
[Platform::MTAThread]
|
||||
int main(Platform::Array<Platform::String^>^)
|
||||
#elif defined(EA_PLATFORM_IPHONE)
|
||||
extern "C" int iosMain(int, char **)
|
||||
#else
|
||||
int main(int, char**)
|
||||
#endif
|
||||
{
|
||||
using namespace EA::EAMain;
|
||||
|
||||
Report("Test of EAMain without an entry point has succeeded.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (c) Electronic Arts Inc. All rights reserved.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void MyCustomWinRtEntry();
|
||||
|
||||
#define EAMAIN_WINRT_APPLICATION_ENTRY MyCustomWinRtEntry
|
||||
#include <EAAssert/eaassert.h>
|
||||
#include <EABase/eabase.h>
|
||||
#include <EAMain/EAMain.h>
|
||||
#include <EAMain/EAEntryPointMain.inl>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push, 0)
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#if defined(EA_COMPILER_MSVC) && defined(EA_PLATFORM_MICROSOFT)
|
||||
#include <crtdbg.h>
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "eathread/eathread.h"
|
||||
|
||||
void* operator new[](size_t size, const char* /*pName*/, int /*flags*/, unsigned /*debugFlags*/, const char* /*file*/, int /*line*/)
|
||||
{
|
||||
return operator new[](size);
|
||||
}
|
||||
|
||||
void* operator new[](size_t size, size_t /*alignment*/, size_t /*alignmentOffset*/, const char* /*pName*/,
|
||||
int /*flags*/, unsigned /*debugFlags*/, const char* /*file*/, int /*line*/)
|
||||
{
|
||||
return operator new[](size);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// EAMain
|
||||
//
|
||||
|
||||
ref class TestApplicationView sealed : public Windows::ApplicationModel::Core::IFrameworkView
|
||||
{
|
||||
public:
|
||||
TestApplicationView()
|
||||
: mCommandLine("")
|
||||
{}
|
||||
|
||||
// IFrameworkView Methods
|
||||
virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView)
|
||||
{
|
||||
using namespace Windows::ApplicationModel::Activation;
|
||||
using namespace Windows::ApplicationModel::Core;
|
||||
applicationView->Activated += ref new Windows::Foundation::TypedEventHandler< CoreApplicationView^, IActivatedEventArgs^ >( this, &TestApplicationView::OnActivated );
|
||||
}
|
||||
virtual void SetWindow(Windows::UI::Core::CoreWindow^ window) {}
|
||||
virtual void Load(Platform::String^ entryPoint) {}
|
||||
virtual void Run();
|
||||
virtual void Uninitialize() {}
|
||||
void OnActivated( Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args ) {
|
||||
if (args->Kind == Windows::ApplicationModel::Activation::ActivationKind::Launch)
|
||||
{
|
||||
Windows::ApplicationModel::Activation::LaunchActivatedEventArgs ^launchArgs = (Windows::ApplicationModel::Activation::LaunchActivatedEventArgs ^) args;
|
||||
Platform::String ^argumentString = launchArgs->Arguments;
|
||||
|
||||
int bufferSize = WideCharToMultiByte(
|
||||
CP_UTF8,
|
||||
0,
|
||||
argumentString->Data(),
|
||||
argumentString->Length(),
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
mCommandLine = new char[bufferSize + 1];
|
||||
int rv = WideCharToMultiByte(
|
||||
CP_UTF8,
|
||||
0,
|
||||
argumentString->Data(),
|
||||
argumentString->Length(),
|
||||
mCommandLine,
|
||||
bufferSize + 1,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
mCommandLine[bufferSize] = 0;
|
||||
EA_ASSERT(rv == bufferSize);
|
||||
EA_UNUSED(rv);
|
||||
}
|
||||
Windows::UI::Core::CoreWindow::GetForCurrentThread()->Activate();
|
||||
}
|
||||
|
||||
private:
|
||||
char *mCommandLine;
|
||||
};
|
||||
|
||||
void TestApplicationView::Run()
|
||||
{
|
||||
using namespace EA::EAMain;
|
||||
|
||||
IWinRTRunner *runner = CreateWinRTRunner();
|
||||
CommandLine commandLine(mCommandLine, CommandLine::FLAG_NO_PROGRAM_NAME);
|
||||
|
||||
runner->Run(commandLine.Argc(), commandLine.Argv());
|
||||
|
||||
while (!runner->IsFinished())
|
||||
{
|
||||
EA::Thread::ThreadSleep(1);
|
||||
}
|
||||
|
||||
Windows::ApplicationModel::Core::CoreApplication::Exit();
|
||||
}
|
||||
|
||||
ref class TestApplicationViewSource : Windows::ApplicationModel::Core::IFrameworkViewSource
|
||||
{
|
||||
public:
|
||||
virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView()
|
||||
{
|
||||
return ref new TestApplicationView();
|
||||
}
|
||||
};
|
||||
|
||||
int CustomWinRtEntryEAMain(int argc, char **argv)
|
||||
{
|
||||
EA::EAMain::Report("Success!\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MyCustomWinRtEntry()
|
||||
{
|
||||
EA::EAMain::Internal::gEAMainFunction = CustomWinRtEntryEAMain;
|
||||
Windows::ApplicationModel::Core::CoreApplication::Run(ref new TestApplicationViewSource);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
tags
|
||||
cscope.out
|
||||
**/*.swp
|
||||
**/*.swo
|
||||
.swp
|
||||
*.swp
|
||||
.swo
|
||||
.TMP
|
||||
-.d
|
||||
eastl_build_out
|
||||
build_bench
|
||||
bench.bat
|
||||
build.bat
|
||||
.p4config
|
||||
|
||||
## CMake generated files
|
||||
CMakeCache.txt
|
||||
cmake_install.cmake
|
||||
|
||||
## Patch files
|
||||
*.patch
|
||||
|
||||
## For Visual Studio Generated projects
|
||||
*.sln
|
||||
**/*.vcxproj
|
||||
**/*.vcxproj.filters
|
||||
*.VC.opendb
|
||||
*.sdf
|
||||
**/*.suo
|
||||
**/*.user
|
||||
.vs/*
|
||||
**/Debug/*
|
||||
CMakeFiles/*
|
||||
EASTL.dir/**
|
||||
RelWithDebInfo/*
|
||||
Release/*
|
||||
Win32/*
|
||||
x64/*
|
||||
MinSizeRel/*
|
||||
build*/*
|
||||
Testing/*
|
||||
%ALLUSERSPROFILE%/*
|
||||
|
||||
# Buck
|
||||
/buck-out/
|
||||
/.buckd/
|
||||
/buckaroo/
|
||||
.buckconfig.local
|
||||
BUCKAROO_DEPS
|
||||
@@ -0,0 +1,18 @@
|
||||
[submodule "test/packages/EAMain"]
|
||||
path = test/packages/EAMain
|
||||
url = git@github.com:electronicarts/EAMain.git
|
||||
[submodule "test/packages/EATest"]
|
||||
path = test/packages/EATest
|
||||
url = git@github.com:electronicarts/EATest.git
|
||||
[submodule "test/packages/EAAssert"]
|
||||
path = test/packages/EAAssert
|
||||
url = git@github.com:electronicarts/EAAssert.git
|
||||
[submodule "test/packages/EAThread"]
|
||||
path = test/packages/EAThread
|
||||
url = git@github.com:electronicarts/EAThread.git
|
||||
[submodule "test/packages/EASTL"]
|
||||
path = test/packages/EASTL
|
||||
url = git@github.com:electronicarts/EASTL.git
|
||||
[submodule "test/packages/EABase"]
|
||||
path = test/packages/EABase
|
||||
url = git@github.com:electronicarts/EABase.git
|
||||
@@ -0,0 +1,68 @@
|
||||
language: cpp
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
- windows
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
- msvc
|
||||
|
||||
env:
|
||||
- EA_CONFIG=Debug
|
||||
- EA_CONFIG=Release
|
||||
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- george-edison55-precise-backports
|
||||
- llvm-toolchain-trusty-7
|
||||
packages:
|
||||
- cmake
|
||||
- cmake-data
|
||||
- g++-7
|
||||
- clang-7
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- os: osx
|
||||
compiler: gcc
|
||||
- os: osx
|
||||
compiler: msvc
|
||||
- os: linux
|
||||
compiler: msvc
|
||||
- os: windows
|
||||
compiler: clang
|
||||
- os: windows
|
||||
compiler: gcc
|
||||
|
||||
# Handle git submodules yourself
|
||||
git:
|
||||
submodules: false
|
||||
|
||||
# Use sed to replace the SSH URL with the public URL, then initialize submodules
|
||||
before_install:
|
||||
- sed --version >/dev/null 2>&1 && sed -i 's/git@github.com:/https:\/\/github.com\//' .gitmodules || sed -i "" 's/git@github.com:/https:\/\/github.com\//' .gitmodules
|
||||
- git submodule update --init
|
||||
|
||||
install:
|
||||
- if [[ "$CXX" == "g++" ]]; then export CC="gcc-7" ;fi
|
||||
- if [[ "$CXX" == "g++" ]]; then export CXX="g++-7" ;fi
|
||||
- if [[ "$CXX" == "clang++" && "${TRAVIS_OS_NAME}" != "osx" ]]; then export CC="clang-7" ;fi
|
||||
- if [[ "$CXX" == "clang++" && "${TRAVIS_OS_NAME}" != "osx" ]]; then export CXX="clang++-7" ;fi
|
||||
|
||||
# Universal Setup
|
||||
before_script:
|
||||
- mkdir build_$EA_CONFIG
|
||||
- cd build_$EA_CONFIG
|
||||
- cmake .. -DEASTDC_BUILD_TESTS:BOOL=ON
|
||||
- cmake --build . --config $EA_CONFIG
|
||||
|
||||
script:
|
||||
# Run Tests
|
||||
- cd $TRAVIS_BUILD_DIR/build_$EA_CONFIG/test
|
||||
- ctest -C $EA_CONFIG -V || exit 1
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Copyright (C) Electronic Arts Inc. All rights reserved.
|
||||
#-------------------------------------------------------------------------------------------
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
project(EAStdC CXX)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Options
|
||||
#-------------------------------------------------------------------------------------------
|
||||
option(EASTDC_BUILD_TESTS "Enable generation of build files for tests" OFF)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Compiler Flags
|
||||
#-------------------------------------------------------------------------------------------
|
||||
set (CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/test/packages/EASTL/scripts/CMake")
|
||||
include(CommonCppFlags)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Library definition
|
||||
#-------------------------------------------------------------------------------------------
|
||||
file(GLOB EASTDC_SOURCES "source/*.cpp")
|
||||
add_library(EAStdC ${EASTDC_SOURCES})
|
||||
|
||||
if(EASTDC_BUILD_TESTS)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Defines
|
||||
#-------------------------------------------------------------------------------------------
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_definitions(-D_SCL_SECURE_NO_WARNINGS)
|
||||
add_definitions(-D_CHAR16T)
|
||||
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Include directories
|
||||
#-------------------------------------------------------------------------------------------
|
||||
target_include_directories(EAStdC PUBLIC include)
|
||||
|
||||
#-------------------------------------------------------------------------------------------
|
||||
# Dependencies
|
||||
#-------------------------------------------------------------------------------------------
|
||||
target_link_libraries(EAStdC EABase)
|
||||
target_link_libraries(EAStdC EAAssert)
|
||||
target_link_libraries(EAStdC EAThread)
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
## Contributing
|
||||
|
||||
Before you can contribute, EA must have a Contributor License Agreement (CLA) on file that has been signed by each contributor.
|
||||
You can sign here: [Go to CLA](https://electronicarts.na1.echosign.com/public/esignWidget?wid=CBFCIBAA3AAABLblqZhByHRvZqmltGtliuExmuV-WNzlaJGPhbSRg2ufuPsM3P0QmILZjLpkGslg24-UJtek*)
|
||||
|
||||
### Pull Request Policy
|
||||
|
||||
All code contributions are submitted as [Github pull requests](https://help.github.com/articles/using-pull-requests/). All pull requests will be reviewed by a maintainer according to the guidelines found in the next section.
|
||||
|
||||
Your pull request should:
|
||||
|
||||
* merge cleanly
|
||||
* come with tests
|
||||
* tests should be minimal and stable
|
||||
* fail before your fix is applied
|
||||
* pass the test suite
|
||||
* code formatting is encoded in clang format
|
||||
* limit using clang format on new code
|
||||
* do not deviate from style already established in the files
|
||||
|
||||
|
||||
### Running the Unit Tests
|
||||
|
||||
EAAssert uses CMake as its build system.
|
||||
|
||||
* Create and navigate to "your_build_folder":
|
||||
* mkdir your_build_folder && cd your_build_folder
|
||||
* Generate build scripts:
|
||||
* cmake source_folder -DEASTDC_BUILD_TESTS:BOOL=ON
|
||||
* Build unit tests for "your_config":
|
||||
* cmake --build . --config your_config
|
||||
* Run the unit tests for "your_config" from the test folder:
|
||||
* cd test && ctest -C your_config
|
||||
|
||||
|
||||
Here is an example batch file.
|
||||
```batch
|
||||
set build_folder=out
|
||||
mkdir %build_folder%
|
||||
pushd %build_folder%
|
||||
call cmake .. -DEASTDC_BUILD_TESTS:BOOL=ON
|
||||
call cmake --build . --config Release
|
||||
call cmake --build . --config Debug
|
||||
call cmake --build . --config RelWithDebInfo
|
||||
call cmake --build . --config MinSizeRel
|
||||
pushd test
|
||||
call ctest -C Release
|
||||
call ctest -C Debug
|
||||
call ctest -C RelWithDebInfo
|
||||
call ctest -C MinSizeRel
|
||||
popd
|
||||
popd
|
||||
```
|
||||
|
||||
Here is an example bash file
|
||||
```bash
|
||||
build_folder=out
|
||||
mkdir $build_folder
|
||||
pushd $build_folder
|
||||
cmake .. -DEASTDC_BUILD_TESTS:BOOL=ON
|
||||
cmake --build . --config Release
|
||||
cmake --build . --config Debug
|
||||
cmake --build . --config RelWithDebInfo
|
||||
cmake --build . --config MinSizeRel
|
||||
pushd test
|
||||
ctest -C Release
|
||||
ctest -C Debug
|
||||
ctest -C RelWithDebInfo
|
||||
ctest -C MinSizeRel
|
||||
popd
|
||||
popd
|
||||
```
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
Copyright (C) 2017 Electronic Arts Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of Electronic Arts, Inc. ("EA") nor the names of
|
||||
its contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY ELECTRONIC ARTS AND ITS CONTRIBUTORS "AS IS" AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL ELECTRONIC ARTS OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
@@ -0,0 +1,26 @@
|
||||
# EAStdC
|
||||
|
||||
[](https://travis-ci.org/electronicarts/EAStdC)
|
||||
|
||||
EAStdC is a package which implements a number of basic library facilities that are similar to those in the standard C library.
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
Please see [Introduction](doc/EAStdC.html).
|
||||
|
||||
|
||||
## Compiling sources
|
||||
|
||||
Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details on compiling and testing the source.
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
Roberto Parolin is the current EAStdC owner within EA and is responsible for the open source repository.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Modified BSD License (3-Clause BSD license) see the file LICENSE in the project root.
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
|
||||
<Title>EAAlignment</title>
|
||||
|
||||
<link type="text/css" rel="stylesheet" href="UTFDoc.css">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF">
|
||||
<h1>EAAlignment</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
<p>EAAlignment provides a number of utilities for working with variable alignment. These include:</p>
|
||||
<blockquote>
|
||||
<table border="1">
|
||||
<tr>
|
||||
<td><strong>Entity</strong></td>
|
||||
<td><strong>Description</strong></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>EAAlignOf(type)</td>
|
||||
<td valign="top">Macro which returns the alignment of the given type as a constant expression. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>AlignOf<T></td>
|
||||
<td valign="top">Template which returns the alignment of the given type. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>AlignAddressUp<br>
|
||||
AlignAddressDown</td>
|
||||
<td valign="top">Function which aligns an arbitrary address up or down to the next user-supplied power of two. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>AlignObjectUp<br>
|
||||
AlignObjectDown</td>
|
||||
<td valign="top">Function which aligns an arbitrary object up or down to the next user-supplied power of two. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GetAlignment<br>
|
||||
IsAddressAligned<br>
|
||||
IsObjectAligned<T><br>
|
||||
IsAligned<T><br></td>
|
||||
<td valign="top">Gets information about alignment. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>AlignedType</td>
|
||||
<td valign="top">Template which portably allows the re-typing of a class to have a specific alignment. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>AlignedArray</td>
|
||||
<td valign="top">Template which implements an array of an arbitrary class with a given alignment.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>AlignedObject</td>
|
||||
<td valign="top">Template which implements an instance of an arbitrary class with a given alignment.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ReadMisalignedUint16<br>
|
||||
ReadMisalignedUint32<br>
|
||||
ReadMisalignedUint64</td>
|
||||
<td valign="top">Function which safely and portably reads potentially misaligned memory. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>WriteMisalignedUint16<br>
|
||||
WriteMisalignedUint32<br>
|
||||
WriteMisalignedUint64</td>
|
||||
<td valign="top">Function which safely and portably writes potentially misaligned memory. </td>
|
||||
</tr>
|
||||
</table>
|
||||
</blockquote>
|
||||
<p>We'll discuss some of these briefly.</p>
|
||||
<h2>EAAlignOf</h2>
|
||||
<p>EAAlignOf is your basic macro for retrieving the alignment of an object by its type. Recent versions of EABase define EA_ALIGN_OF, so EAAlignOf is currently a duplication of the EABase functionality. </p>
|
||||
<p>Example usage: </p>
|
||||
<pre class="code-example">printf("Alignment of type 'int' is %u.\n", (unsigned)EAAlignOf(int)); </pre>
|
||||
<h2>AlignedType</h2>
|
||||
<p> This class makes an aligned typedef for a given class based on a user-supplied class and alignment. This class exists because of a weakness in VC++ whereby it can only accept __declspec(align) and thus EA_PREFIX_ALIGN usage via an integer literal (e.g. "16") and not an otherwise equivalent constant integral expression (e.g. sizeof Foo).</p>
|
||||
<p>Example usage: </p>
|
||||
<pre class="code-example">const size_t kAlignment = 32; <span class="code-example-comment">// Note that in this case the alignment is defined elsewhere as a non-literal.</span><br>
|
||||
AlignedType<Widget, kAlignment>::Type widgetAlign128;<br>
|
||||
widgetAlign128.DoSomething();</pre>
|
||||
<h2>ReadMisaligned16/32/64</h2>
|
||||
<p>ReadMisaligned reads an unsigned integer from a possibly non-aligned address. The MIPS processor on the PS2, for example, cannot read a 32-bit value from an unaligned address. This function can be used to make reading such misaligned data portable.. </p>
|
||||
<p>Example usage: </p>
|
||||
<pre class="code-example">void DoSomeReading(const char* pData)
|
||||
{
|
||||
uint16_t x = ReadMisalignedUint16(pData);
|
||||
pData += sizeof(uint16_t);
|
||||
|
||||
uint32_t y = ReadMisalignedUint32(pData);
|
||||
pData += sizeof(uint32_t);
|
||||
|
||||
uint64_t z = ReadMisalignedUint64(pData);
|
||||
pData += sizeof(uint64_t);
|
||||
|
||||
...
|
||||
}</pre>
|
||||
<hr>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
</body></html>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
|
||||
|
||||
<title>EABitTricks</title>
|
||||
<link type="text/css" rel="stylesheet" href="UTFDoc.css">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF">
|
||||
<h1>EABitTricks</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
<p>EABitTricks provides a number of integer bit-manipulation utilities that are
|
||||
very fast and simple. For example, it is well-known that (x * 2) can be also
|
||||
accomplished with (x << 1). And while this example may not be useful in practice,
|
||||
there are many more such tricks which have real use, particularly for speeding
|
||||
up code. Some of these tricks may seem odd or even useless, but it turns out
|
||||
that there are surprising uses for many of these.</p>
|
||||
<h2>Notes</h2>
|
||||
<ul>
|
||||
<li>Twos-complement integer storage is assumed. Nearly all modern processors
|
||||
use twos-complement storage.</li>
|
||||
<li>Some tricks assume that right shifts of signed values preserve the sign.
|
||||
While nearly all modern processors and C/C++ compilers support this, some
|
||||
primitive processors don't. By preserving sign, we mean that signed binary
|
||||
(10000000 >> 1) gives (11000000). </li>
|
||||
<li>Only 'tricky' efficient solutions are provided. Obvious brute force loops
|
||||
to do useful things aren't included. We attempt to use branchless and loopless
|
||||
logic where possible.</li>
|
||||
<li>We don't cover magic number tricks for simplifying multiplication and division
|
||||
by constants. For example (x * 17) can also be quickly accomplished with ((x
|
||||
<< 4) + x). Optimized integer multiplication and division tricks such as this
|
||||
is something for a separate library.</li>
|
||||
<li>We don't cover floating point tricks. That is something for a separate library.
|
||||
</li>
|
||||
<li>Implementations here are written as standalone functions for readability.
|
||||
However, the user may find that it's better in some cases to copy the implementation
|
||||
to a macro or to simply copy the implementation directly inline into source
|
||||
code. EABitTricks is meant to be a reference for copy and paste as much as
|
||||
it is meant to be used as-is.</li>
|
||||
<li>Many of these functions are templated instead of taking a given integer
|
||||
type such as uint32_t. The reason for this is that we want 64 bit support
|
||||
and that can be had automatically in most cases by the use of templates. The
|
||||
generated code will be exactly as fast as the case when templates are not
|
||||
used.</li>
|
||||
</ul>
|
||||
<h2>Example usage </h2>
|
||||
<p>All examples presume a <font face="Courier New, Courier, mono" size="-1">#include
|
||||
"Foundation/EABitTricks.h"</font> and assume the using of <font face="Courier New, Courier, mono" size="-1">namespace
|
||||
EA</font>.</p>
|
||||
<p>TurnOffLowestBit</p>
|
||||
<pre class="code-example">int16_t i16 = 0x0005; <span class="code-example-comment">// i16 => 000000101</span>
|
||||
i16 = TurnOffLowestBit(i16); <span class="code-example-comment">// i16 => 000000100</span></pre>
|
||||
IsolateSingle0And1Bits
|
||||
<pre class="code-example">uint32_t u32 = 0xabababab; <span class="code-example-comment"> // u32 => 10101011101010111010101110101011</span>
|
||||
u32 = IsolateSingle0And1Bits(0xabababab); <span class="code-example-comment">// u32 => 11111100011111000111110001111100</span></pre>
|
||||
RoundUpToPowerOf2
|
||||
<pre class="code-example">uint32_t u32 = 66; <span class="code-example-comment">// u32 => 66 (01000010)</span>
|
||||
u32 = RoundUpToPowerOf2(u32); <span class="code-example-comment">// u32 => 128 (10000000)</span></pre>
|
||||
<p> UnsignedMultiplyWouldOverflow</p>
|
||||
<pre class="code-example">bool b = UnsignedMultiplyWouldOverflow(0xffffffff, 0xffffffff); <span class="code-example-comment">// b => true</span> </pre>
|
||||
<h2>Interface</h2>
|
||||
<p>The following is a simple listing of EABitTricks functions as of January 2006.
|
||||
For an up to date listing of current functionality, see EABitTricks.h. Also,
|
||||
the EABitTricks.h file has documentation and example usage for each function.</p>
|
||||
<p>Bit manipulation</p>
|
||||
<pre class="code-example">T TurnOffLowestBit(T x);
|
||||
T IsolateLowestBit(T x);
|
||||
T IsolateLowest0Bit(T x);
|
||||
T GetTrailing0Bits(T x);
|
||||
T GetTrailing1And0Bits(T x);
|
||||
T PropogateLowestBitDownward(T x);
|
||||
T TurnOffLowestContiguousBits(T x);
|
||||
T TurnOnLowest0Bit(T x);
|
||||
uint32_t GetNextWithEqualBitCount(uint32_t x);
|
||||
uint32_t IsolateSingleBits(uint32_t x);
|
||||
uint32_t IsolateSingle0Bits(uint32_t x);
|
||||
uint32_t IsolateSingle0And1Bits(uint32_t x);
|
||||
int32_t ShiftRightSigned(int32_t x, uint32_t n);
|
||||
uint32_t CountTrailing0Bits(uint32_t x);
|
||||
uint32_t CountLeading0Bits(uint32_t x);
|
||||
uint32_t CountBits(uint32_t x);
|
||||
uint32_t CountBits64(uint64_t x);
|
||||
uint32_t RotateLeft(uint32_t x, uint32_t n);
|
||||
uint32_t RotateRight(uint32_t x, uint32_t n);
|
||||
uint32_t ReverseBits(uint32_t x);
|
||||
uint32_t IsolateHighestBit(uint32_t x);
|
||||
uint32_t IsolateHighest0Bit(uint32_t x);
|
||||
uint32_t PropogateHighestBitDownward(uint32_t x);
|
||||
uint32_t GetHighestContiguous0Bits(uint32_t x);
|
||||
T GetBitwiseEquivalence(T x, T y);
|
||||
bool AreLessThan2BitsSet(int32_t x);
|
||||
T GetHighestBit(T t);
|
||||
</pre>
|
||||
<p>Alignment / Power of 2</p>
|
||||
<pre class="code-example">bool IsPowerOf2(T x);
|
||||
uint32_t RoundUpToPowerOf2(uint32_t x);
|
||||
bool IsMultipleOf(T x);
|
||||
bool IsPowerOf2Minus1(T x);
|
||||
uint32_t GetHighestBitPowerOf2(uint32_t x);
|
||||
bool CrossesPowerOf2(T x, T y, T n);
|
||||
bool CrossesPowerOf2(T x, T y);
|
||||
T GetNextGreaterEven(T x);<br>T GetNextGreaterOdd(T x);
|
||||
T RoundUpTo(T x);
|
||||
int32_t RoundUpToEx(T x);
|
||||
T RoundDownTo(T x);
|
||||
T RoundDownToEx(T x);
|
||||
uint32_t Log2(uint32_t x);</pre>
|
||||
<p>Overflow</p>
|
||||
<pre class="code-example">bool SignedAdditionWouldOverflow(T x, T y);
|
||||
bool SignedSubtractionWouldOverflow(T x, T y);
|
||||
bool UnsignedAdditionWouldOverflow(T x, T y);
|
||||
bool UnsignedSubtractionWouldOverflow(T x, T y);
|
||||
bool UnsignedMultiplyWouldOverflow(uint32_t x, uint32_t y);
|
||||
bool SignedMultiplyWouldOverflow(int32_t x, int32_t y);
|
||||
bool UnsignedDivisionWouldOverflow(uint32_t x, uint32_t y);
|
||||
bool SignedDivisionWouldOverflow(int32_t x, int32_t y);
|
||||
int GetAverage(int32_t x, int32_t y);
|
||||
int GetAverage_Ceiling(int32_t x, int32_t y);</pre>
|
||||
<p>Miscellaneous</p>
|
||||
<pre class="code-example">int32_t GetParity(uint32_t32_t x);
|
||||
bool GetIsBigEndian();
|
||||
int32_t ToggleBetween0And1(int32_t x);
|
||||
T ToggleBetweenint32_tegers(T x, T a, T b);
|
||||
bool IsBetween0AndValue(int32_t x, int32_t a);
|
||||
void ExchangeValues(T& x, T& y);
|
||||
T FloorMod(T n, T mod);
|
||||
int32_t GetSign(int32_t32_t x);
|
||||
int32_t GetSignEx(int32_t32_t x);
|
||||
int32_t SignExtend12(int32_t32_t x);
|
||||
int32_t SignExtend24(int32_t32_t x);
|
||||
bool IsUnsigned(T x);
|
||||
#define EAIsUnsigned(x)
|
||||
bool IsTwosComplement();
|
||||
bool IsOnesComplement();
|
||||
bool IsSignMagnitude();
|
||||
bool IsOffsetBinary();
|
||||
#define EAArrayCount(array);</pre>
|
||||
<hr>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
</body></html>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
|
||||
<Title>EAByteCrackers</title>
|
||||
|
||||
<link type="text/css" rel="stylesheet" href="UTFDoc.css">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF">
|
||||
<h1>EAByteCrackers</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
<p>EAByteCrackers is a small utility header file that provides macros for breaking down integers into component bytes and for building up integers from component
|
||||
bytes. These are particularly useful because working with signed values creates opportunities for mistakes, and the macros present in EAByteCrackers remove such
|
||||
possibilities for error. You can run into this need for dealing with signed values when working with Windows "winproc" message packing, for example.</p>
|
||||
<h2>Conventions</h2>
|
||||
<p>Components within an integer are numbered 0-N with 0 referring to the least significant component. Thus, the 32 bit value 0x12345678 consists of byte 0 = 0x78,
|
||||
byte 1 = 0x56, byte 2 = 0x34, and byte 3 = 0x12. This is done like so because the index of the byte is thus equal to its numerical shift within the integer. It
|
||||
also means that byte 2 of a uint32_t refers to the same value as byte 2 of a uint64_t. For example:</p>
|
||||
<pre class="code-example">uint16_t u16 = UINT16_5_FROM_UINT64(0x887766554433221100); <font color="#0066FF">// u16 becomes 0x55</font></pre>
|
||||
<p>Similarly, we have this:</p>
|
||||
<pre class="code-example">uint32_t u32 = UINT32_FROM_UINT8(0x33, 0x22, 0x11, 0x00); <font color="#0066FF">// u32 becomes 0x33221100</font></pre>
|
||||
<p>In the macros, the terms b, w, d, and q are used.</p>
|
||||
<ul>
|
||||
<li>b means 8 bit byte</li>
|
||||
<li>w means 16 bit word</li>
|
||||
<li>d means 32 bit dword</li>
|
||||
<li>q means 64 bit quadword</li>
|
||||
</ul>
|
||||
<h2>Example usage </h2>
|
||||
<p>Basic usage:</p>
|
||||
<pre class="code-example">// Integer breakdown
|
||||
uint8_t u8 = UINT8_0_FROM_UINT16(0x1100); <font color="#0066FF">// u8 becomes 0x00</font>
|
||||
uint8_t u8 = UINT8_2_FROM_UINT64(0x7766554433221100); <font color="#0066FF">// u8 becomes 0x22</font>
|
||||
uint16_t u16 = UINT16_3_FROM_UINT64(0x7766554433221100); <font color="#0066FF">// u16 becomes 0x7766</font>
|
||||
|
||||
// Integer build up
|
||||
uint16_t u16 = UINT16_FROM_UINT8(0x11, 0x00); <font color="#0066FF">// u16 becomes 0x1100</font>
|
||||
uint32_t u32 = UINT32_FROM_UINT8(0x33, 0x22, 0x11, 0x00); <font color="#0066FF">// u32 becomes 0x33221100</font></pre>
|
||||
<p></p>
|
||||
<p>How to safely convert a 32 bit value to two signed 16 bit values:</p>
|
||||
<pre class="code-example">int16_t n0 = (int16_t)UINT16_0_FROM_UINT32(0x1000ffff); <font color="#0066FF">// n0 becomes -1</font>
|
||||
int16_t n1 = (int16_t)UINT16_1_FROM_UINT32(0x1000ffff); <font color="#0066FF">// n1 becomes 4096</font></pre>
|
||||
<p>How to build up a uint64_t from a uint32_t and two uint16_t values:</p>
|
||||
<pre class="code-example">uint64_t u64 = UINT64_FROM_UINT32(0x77665544, UINT32_FROM_UINT16(0x3322, 0x1100)); <font color="#0066FF">// u64 becomes 0x7766554433221100</font>
|
||||
</pre>
|
||||
<h2>Interface</h2>
|
||||
<pre class="code-example"><span class="code-example-comment">// uint8_t byte manipulators</span>
|
||||
#define UINT8_0_FROM_UINT16(w)
|
||||
#define UINT8_1_FROM_UINT16(w)
|
||||
|
||||
#define UINT8_0_FROM_UINT32(d)
|
||||
#define UINT8_1_FROM_UINT32(d)
|
||||
#define UINT8_2_FROM_UINT32(d)
|
||||
#define UINT8_3_FROM_UINT32(d)
|
||||
|
||||
#define UINT8_0_FROM_UINT64(q)
|
||||
#define UINT8_1_FROM_UINT64(q)
|
||||
#define UINT8_2_FROM_UINT64(q)
|
||||
#define UINT8_3_FROM_UINT64(q)
|
||||
#define UINT8_4_FROM_UINT64(q)
|
||||
#define UINT8_5_FROM_UINT64(q)
|
||||
#define UINT8_6_FROM_UINT64(q)
|
||||
#define UINT8_7_FROM_UINT64(q)
|
||||
|
||||
<span class="code-example-comment">// uint16_t byte manipulators</span>
|
||||
#define UINT16_0_FROM_UINT32(d)
|
||||
#define UINT16_1_FROM_UINT32(d)
|
||||
|
||||
#define UINT16_0_FROM_UINT64(q)
|
||||
#define UINT16_1_FROM_UINT64(q)
|
||||
#define UINT16_2_FROM_UINT64(q)
|
||||
#define UINT16_3_FROM_UINT64(q)
|
||||
|
||||
#define UINT16_FROM_UINT8(b1, b0)
|
||||
|
||||
<span class="code-example-comment">// uint32_t byte manipulators</span>
|
||||
#define UINT32_2_FROM_UINT64(q)
|
||||
#define UINT32_1_FROM_UINT64(q)
|
||||
|
||||
#define UINT32_FROM_UINT8(b3, b2, b1, b0)
|
||||
#define UINT32_FROM_UINT16(w1, w0)
|
||||
|
||||
<span class="code-example-comment">// uint64_t byte manipulators</span>
|
||||
#define UINT64_FROM_UINT8(b7, b6, b5, b4, b3, b2, b1, b0)
|
||||
#define UINT64_FROM_UINT16(w3, w2, w1, w0)
|
||||
#define UINT64_FROM_UINT32(d1, d0)
|
||||
</pre>
|
||||
<p></p>
|
||||
<hr>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
|
||||
</body></html>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
|
||||
<Title>EAString</title>
|
||||
|
||||
<link type="text/css" rel="stylesheet" href="UTFDoc.css">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF">
|
||||
<h1>EAString</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
<p>EACRT stands for EA C Runtime. EACRT implements an extensive suite of C string functionality in a portable way. Some of this functionality is the same as what
|
||||
is present in the C standard and in common (but non-portable) extensions to the C standard. EACRT presents a consistent portable interface to its functionality
|
||||
in both 8 bit and 16 bit string form.</p>
|
||||
<p>The C language provides various functions which work with non-portable data types, such as long. EACRT defines all significant data types in terms of portable
|
||||
types such as int32_t and int64_t. </p>
|
||||
<p>Additionally, the EACRT versions of functions are usually faster than the C runtime library versions, usually because the EACRT versions minimize cache misses
|
||||
and branching, whereas typical C runtime libraries optimize for the smallest memory footprint with little or no regard to other performance characteristics.</p>
|
||||
<p>C-style printf functionality is separate from EACRT and is found in <a href="EASprintf.html">EASprintf</a>. Memcpy functionality (which comes from the C string.h
|
||||
header file) is present in <a href="Memcpy.html">EAMemcpy</a>. However, EACRT has a few mem functions itself.</p>
|
||||
<p>In some cases, EACRT simply #defines its function to be the same as the equivalent C function. This is done when the equivalent C function is known to be present
|
||||
and known to conform to the C/C++ language standard correctly.</p>
|
||||
<h2>Extension functions</h2>
|
||||
<p> EACRT provides extended functionality that isn't found in conventional C libraries, but it useful nevertheless.</p>
|
||||
<table width="100%" border="1" cellpadding="3">
|
||||
<tr>
|
||||
<td><b>Function</b></td>
|
||||
<td><b>Description</b></td>
|
||||
<td><b>Signature</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Strlcat</td>
|
||||
<td>Safe variation of strncat</td>
|
||||
<td><font size="-1">char_t* Strlcat(char_t* pDestination, const char_t* pSource, size_t n); </font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Strlcpy</td>
|
||||
<td>Safe variation of strcpy</td>
|
||||
<td><font size="-1">char_t* Strlcpy(char_t* pDestination, const char_t* pSource, size_t n); </font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Stristr</td>
|
||||
<td>Case insensitive version of strstr (find string within string)</td>
|
||||
<td><font size="-1">char_t* Stristr(const char_t* pString, const char_t* pSubString);</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>FtoaEnglish</td>
|
||||
<td>
|
||||
<p>Float to ascii; always use English numeric format, regardless of the current locale.</p>
|
||||
</td>
|
||||
<td><font size="-1">char_t* FtoaEnglish(double dValue, char_t* pResult, int nInputLength, int nPrecision, bool bExponentEnabled); </font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>AtofEnglish</td>
|
||||
<td>Ascii to float; always use English numeric format, regardless of the current locale.</td>
|
||||
<td><font size="-1">double AtofEnglish(const char_t* pString); </font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> StrtodEnglish</td>
|
||||
<td>Same as strtod, but always use English numeric format, regardless of the current locale.</td>
|
||||
<td><font size="-1">double StrtodEnglish(const char_t* pString, char_t** ppStringEnd);</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Memset16</td>
|
||||
<td>Sets 16 bit values in memory (as opposed to memset's 8 bit values)</td>
|
||||
<td><font size="-1">uint16_t* Memset16(void* pDestination, uint16_t c, size_t count); </font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Memset32</td>
|
||||
<td>Sets 32 bit values in memory (as opposed to memset's 8 bit values)</td>
|
||||
<td><font size="-1"> uint32_t* Memset32(void* pDestination, uint32_t c, size_t count);</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Memset64</td>
|
||||
<td>Sets 64 bit values in memory (as opposed to memset's 8 bit values)</td>
|
||||
<td><font size="-1">uint64_t* Memset64(void* pDestination, uint64_t c, size_t count);</font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>MemsetN</td>
|
||||
<td>Sets arbitrarily sized values in memory.</td>
|
||||
<td><font size="-1">void* MemsetN (void* pDestination, const void* pSource, size_t sourceBytes, size_t count); </font></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>EcvtBuf</td>
|
||||
<td>Base function for converting a float to a %e string.</td>
|
||||
<td>
|
||||
<p><font size="-1">char_t* EcvtBuf(double dValue, int nDigitCount, int* decimalPos, int* sign, char_t* buffer); </font></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>FcvtBuf</td>
|
||||
<td>Base function for converting a float to a %f string.</td>
|
||||
<td><font size="-1">char_t* FcvtBuf(double dValue, int nDigitCountAfterDecimal, int* decimalPos, int* sign, char_t* buffer); </font></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p> </p>
|
||||
<h2>Example usage </h2>
|
||||
<p>We provide a random smattering of example code here.</p>
|
||||
<pre class="code-example">char16_t buffer[32] = L"hello ";
|
||||
|
||||
Strcat16(buffer, L"world");
|
||||
</pre>
|
||||
<p>Strlcat:</p>
|
||||
|
||||
<pre class="code-example">char buffer[32];
|
||||
|
||||
Strlcpy8(buffer, "Hello ", sizeof(buffer));
|
||||
Strlcat8(buffer, "world", sizeof(buffer));
|
||||
</pre>
|
||||
<p>U64toa:</p>
|
||||
|
||||
<pre class="code-example">char buffer[32];
|
||||
|
||||
U64toa8(UINT64_C(12345678901234567890), buffer, 16);
|
||||
</pre>
|
||||
<p>AtoI32:</p>
|
||||
|
||||
<pre class="code-example">int32_t x = AtoI328("1234567890");
|
||||
</pre>
|
||||
<p>StrtodEnglish:</p>
|
||||
<pre class="code-example">const char16_t* pString = L"12345.678 123.456 1.23456";
|
||||
|
||||
while(*pString)
|
||||
{
|
||||
double value = StrtodEnglish16(pString, &pString);
|
||||
printf("Field = %f\n, value);
|
||||
}
|
||||
</pre>
|
||||
<p>Memset16:</p>
|
||||
|
||||
<pre class="code-example">uint16_t buffer[50];
|
||||
|
||||
Memset16(buffer, 0x1234, 50);
|
||||
</pre>
|
||||
<h2>Interface</h2>
|
||||
<p>In each of the functions below, there is an char8_t and char16_t version. The actual function that EACRT implements is one with an 8 or 16 appended to the function names listed below. Thus below we have <span class="code-example-span">Strcat(char_t*, char_t*)</span>, and thus EACRT presents <span class="code-example-span">Strcat8(char8_t*, char8_t*)</span> and <span class="code-example-span">Strcat16(char16_t*, char16_t*)</span>.</p>
|
||||
<p>See EACRT.h for per-function documentation.</p>
|
||||
<pre class="code-example">char_t* Strcat(char_t* pDestination, const char_t* pSource);
|
||||
char_t* Strncat(char_t* pDestination, const char_t* pSource, size_t n);
|
||||
char_t* Strlcat(char_t* pDestination, const char_t* pSource, size_t n);
|
||||
char_t* Strcpy(char_t* pDestination, const char_t* pSource);
|
||||
char_t* Strncpy(char_t* pDestination, const char_t* pSource, size_t n);
|
||||
char_t* Strlcpy(char_t* pDestination, const char_t* pSource, size_t n);
|
||||
size_t Strlen(const char_t* pString);
|
||||
size_t Strxfrm(char_t* pDest, const char_t* pSource, size_t n);
|
||||
char_t* Strdup(const char_t* pString);
|
||||
|
||||
int Isalnum(char_t c);
|
||||
int Isalpha(char_t c);
|
||||
int Isdigit(char_t c);
|
||||
int Isxdigit(char_t c);
|
||||
int Isgraph(char_t c);
|
||||
int Islower(char_t c);
|
||||
int Isprint(char_t c);
|
||||
int Ispunct(char_t c);
|
||||
int Isspace(char_t c);
|
||||
int Iscntrl(char_t c);
|
||||
int Isascii(char_t c);
|
||||
int Toupper(char_t c);
|
||||
int Tolower(char_t c);
|
||||
|
||||
char_t* Strlwr(char_t* pString);
|
||||
char_t* Strupr(char_t* pString);
|
||||
char_t* Strchr(const char_t* pString, char_t c);
|
||||
size_t Strcspn(const char_t* pString1, const char_t* pString2);
|
||||
char_t* Strpbrk(const char_t* pString1, const char_t* pString2);
|
||||
char_t* Strrchr(const char_t* pString, char_t c);
|
||||
size_t Strspn(const char_t* pString, const char_t* pSubString);
|
||||
char_t* Strstr(const char_t* pString, const char_t* pSubString);
|
||||
char_t* Stristr(const char_t* pString, const char_t* pSubString);
|
||||
char_t* Strtok(char_t* pString, const char_t* pTokens, char_t** pContext);
|
||||
char_t* Strset(char_t* pString, char_t c);
|
||||
char_t* Strnset(char_t* pString, char_t c, size_t n);
|
||||
char_t* Strrev(char_t* pString);
|
||||
int Strcmp(const char_t* pString1, const char_t* pString2);
|
||||
int Strncmp(const char_t* pString1, const char_t* pString2, size_t n);
|
||||
int Stricmp(const char_t* pString1, const char_t* pString2);
|
||||
int Strnicmp(const char_t* pString1, const char_t* pString2, size_t n);
|
||||
int Strcoll(const char_t* pString1, const char_t* pString2);
|
||||
int Strncoll(const char_t* pString1, const char_t* pString2, size_t n);
|
||||
int Stricoll(const char_t* pString1, const char_t* pString2);
|
||||
int Strnicoll(const char_t* pString1, const char_t* pString1, size_t n);
|
||||
|
||||
char_t* EcvtBuf(double dValue, int nDigitCount, int* decimalPos, int* sign, char_t* buffer);
|
||||
char_t* FcvtBuf(double dValue, int nDigitCountAfterDecimal, int* decimalPos, int* sign, char_t* buffer);
|
||||
|
||||
char_t* I32toa(int32_t nValue, char_t* pResult, int nBase);
|
||||
char_t* U32toa(uint32_t nValue, char_t* pResult, int nBase);
|
||||
char_t* I64toa(int64_t nValue, char_t* pBuffer, int nBase);
|
||||
char_t* U64toa(uint64_t nValue, char_t* pBuffer, int nBase);
|
||||
double Strtod(const char_t* pString, char_t** ppStringEnd);
|
||||
double StrtodEnglish(const char_t* pString, char_t** ppStringEnd);
|
||||
int64_t StrtoI64(const char_t* pString, char_t** ppStringEnd, int nBase);
|
||||
uint64_t StrtoU64(const char_t* pString, char_t** ppStringEnd, int nBase);
|
||||
int32_t StrtoI32(const char_t* pString, char_t** ppStringEnd, int nBase);
|
||||
uint32_t StrtoU32(const char_t* pString, char_t** ppStringEnd, int nBase);
|
||||
int32_t AtoI32(const char_t* pString);
|
||||
uint32_t AtoU32(const char_t* pString);
|
||||
int64_t AtoI64(const char_t* pString);
|
||||
uint64_t AtoU64(const char_t* pString);
|
||||
double Atof(const char_t* pString);
|
||||
double AtofEnglish(const char_t* pString);
|
||||
char_t* Ftoa(double dValue, char_t* pResult, int nInputLength, int nPrecision, bool bExponentEnabled);
|
||||
char_t* FtoaEnglish(double dValue, char_t* pResult, int nInputLength, int nPrecision, bool bExponentEnabled);
|
||||
|
||||
uint8_t* Memset8 (void* pDestination, uint8_t c, size_t count);
|
||||
uint16_t* Memset16(void* pDestination, uint16_t c, size_t count);
|
||||
uint32_t* Memset32(void* pDestination, uint32_t c, size_t count);
|
||||
uint64_t* Memset64(void* pDestination, uint64_t c, size_t count);
|
||||
void* MemsetN (void* pDestination, const void* pSource, size_t sourceBytes, size_t count);
|
||||
const char_t* Memchr(const char_t* pString, char_t c, size_t n);
|
||||
int Memcmp(const char_t* pString1, const char_t* pString2, size_t n);
|
||||
char_t* Memcpy(char_t* pDestination, const char_t* pSource, size_t n);
|
||||
char_t* Memmove(char_t* pDestination, const char_t* pSource, size_t n);
|
||||
char_t* Memset(char_t* pString, char_t c, size_t n);
|
||||
</pre>
|
||||
<hr>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
</body></html>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,353 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
|
||||
|
||||
<title>EADateTime</title>
|
||||
<link type="text/css" rel="stylesheet" href="UTFDoc.css">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF">
|
||||
<h1>EADateTime</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
<p>EADateTime provides a unified implementation of date, time, and calendar functionality.
|
||||
The DateTime class represents date and time in a single class. Unlike other
|
||||
date/time systems, this class doesn't have a strictly limited resolution, due
|
||||
to its use of 64 bits (instead of 32 bits) of storage for the date/time value.
|
||||
</p>
|
||||
<p> EADateTime supports the modern Gregorian calendar correctly, including such
|
||||
concepts as leap years. You can, for example, use EADateTime to implement proper
|
||||
calendar functionality for your application.</p>
|
||||
<p>The C standard library provides some time and date functionality, but it is
|
||||
slow, has some limitations, is not very easy to use, and isn't supported by
|
||||
all C/C++ compilers. Writing a calendar application with the C time and date
|
||||
functions would be possible, but would be tedious and error-prone.</p>
|
||||
<p>EADateTime does not support the formatting of date and time strings for display
|
||||
to a users. Such functionality is outside the scope of this class, primarily
|
||||
due to the issue of multiple string encodings (e.g. ASCII and Unicode) and due
|
||||
to the existence of multiple locales (e.g. English and French) which use different
|
||||
formats for time and date strings. A separate module -- EALocale -- exists which
|
||||
implements string formatting of dates and times. You can use that module and
|
||||
EADateTime together to implement locale-savvy times, dates, and calendars.</p>
|
||||
<h2>Example usage </h2>
|
||||
<p>All examples presume a <font face="Courier New, Courier, mono" size="-1">#include
|
||||
"Foundation/EADateTime.h"</font> and assume the using of <font face="Courier New, Courier, mono" size="-1">namespace
|
||||
EA</font>.</p>
|
||||
<p>Basic usage of class DateTime:</p>
|
||||
<pre class="code-example">DateTime dt; // Sets dt to the current date and time.
|
||||
|
||||
uint32_t year = dt.GetParameter(kParameterYear); // Get the current year.
|
||||
|
||||
dt.SetParameter(kParameterMonth, kMonthAugust); // Set month to August.
|
||||
dt.AddTime(kParameterDayOfYear, 77); // Add 77 days.</pre>
|
||||
<p>Comparison of DateTime instances:</p>
|
||||
<pre class="code-example">DateTime dtD(2008, kMonthDecember, 25); // Sets dt to Christmas 2008.
|
||||
DateTime dtH(2008, kMonthOctober, 31); // Sets dt to Halloween 2008.
|
||||
|
||||
if(dtH < dtD)
|
||||
printf("Halloween occurs before Christmas.");
|
||||
else
|
||||
printf("Christmas occurs before Halloween.");</pre>
|
||||
<blockquote></blockquote>
|
||||
<p>How to save and restore a DateTime to and from disk:</p>
|
||||
<pre><span class="code-example">DateTime dt;
|
||||
|
||||
uint64_t n = dt.GetSeconds(); // Get the absolute time in seconds. This alone fully represents a DateTime.
|
||||
|
||||
WriteToDisk64(ToBigEndian(n)); // Hypthetical disk writing function and endian conversion function.
|
||||
|
||||
n = FromBigEndian(ReadFromDisk64()); // Hypothetical disk reading function and endian conversion function.
|
||||
|
||||
dt = DateTime(n); // Restore the saved value to a DateTime instance.</span></pre>
|
||||
<p>Usage of standalone EADateTime utility functions, which are independent of
|
||||
class DateTime: </p>
|
||||
<pre class="code-example">bool b = IsLeapYear(2015);
|
||||
|
||||
uint32_t n = GetDaysInYear(1974);
|
||||
|
||||
uint32_t d = GetDaysInMonth(kMonthMarch, 2007);
|
||||
|
||||
int64_t nSeconds = GetDaylightSavingsBias();</pre>
|
||||
<h2></h2>
|
||||
Conversion of C time to DateTime:
|
||||
<pre class="code-example">#include <time.h>
|
||||
|
||||
tm time;
|
||||
asctime(&ascTime); // Get C time.
|
||||
|
||||
DateTime dt;
|
||||
TmToDateTime(time, dt); // Convert to DateTime.</pre>
|
||||
<h2>Interface</h2>
|
||||
<p>The following is defined in EADateTime.h. The latest versions of these definitions
|
||||
can be found in the current version of EADateTime.h</p>
|
||||
<p>Enumerations</p>
|
||||
<pre class="code-example">enum Month
|
||||
{
|
||||
kMonthUnknown = 0,
|
||||
kMonthJanuary = 1,
|
||||
kMonthFebruary = 2,
|
||||
kMonthMarch = 3,
|
||||
kMonthApril = 4,
|
||||
kMonthMay = 5,
|
||||
kMonthJune = 6,
|
||||
kMonthJuly = 7,
|
||||
kMonthAugust = 8,
|
||||
kMonthSeptember = 9,
|
||||
kMonthOctober = 10,
|
||||
kMonthNovember = 11,
|
||||
kMonthDecember = 12
|
||||
};
|
||||
|
||||
enum DayOfMonth
|
||||
{
|
||||
kDayOfMonthUnknown = 0,
|
||||
kDayOfMonthMin = 1,
|
||||
kDayOfMonthMax = 31 <font color="#999999">/// The actual max month is dependent on which month is being referred to.</font>
|
||||
};
|
||||
|
||||
enum DayOfWeek
|
||||
{
|
||||
kDayOfWeekUnknown = 0,
|
||||
kDayOfWeekSunday = 1,
|
||||
kDayOfWeekMonday = 2,
|
||||
kDayOfWeekTuesday = 3,
|
||||
kDayOfWeekWednesday = 4,
|
||||
kDayOfWeekThursday = 5,
|
||||
kDayOfWeekFriday = 6,
|
||||
kDayOfWeekSaturday = 7
|
||||
};
|
||||
|
||||
<span class="code-example-comment">/// TimeFrame
|
||||
</span>enum TimeFrame
|
||||
{
|
||||
kTimeFrameUnknown = 0, <font color="#999999">/// Unspecified time frame.</font>
|
||||
kTimeFrameUTC = 1, <font color="#999999">/// Universal Coordinated Time. This is the time based on the time zone at Greenwich, England.</font>
|
||||
kTimeFrameLocal = 2 <font color="#999999">/// Same time as current machine.</font>
|
||||
};
|
||||
|
||||
<span class="code-example-comment">/// TimeZone
|
||||
/// Standard time zone definitions, with their values corresponding to the nmuber of hours they are
|
||||
/// off relative to UTC (Universal Coordinated Time, which is the time at Greenwich England).
|
||||
/// Note, for example, that kTimeZonePacific is -8 hours relative to Greenwich, England.
|
||||
</span>enum TimeZone
|
||||
{
|
||||
kTimeZoneEniwetok = -12,
|
||||
kTimeZoneSamoa = -11,
|
||||
kTimeZoneHawaii = -10,
|
||||
kTimeZoneAlaska = -9,
|
||||
kTimeZonePacific = -8,
|
||||
kTimeZoneMountain = -7,
|
||||
kTimeZoneCentral = -6,
|
||||
kTimeZoneEastern = -5,
|
||||
kTimeZoneAltantic = -4,
|
||||
kTimeZoneBrazilia = -3,
|
||||
kTimeZoneMidAtlantic = -2,
|
||||
kTimeZoneAzores = -1,
|
||||
kTimeZoneGreenwich = 0,
|
||||
kTimeZoneRome = +1,
|
||||
kTimeZoneIsrael = +2,
|
||||
kTimeZoneMoscow = +3,
|
||||
kTimeZoneBaku = +4,
|
||||
kTimeZoneNewDelhi = +5,
|
||||
kTimeZoneDhakar = +6,
|
||||
kTimeZoneBangkok = +7,
|
||||
kTimeZoneHongKong = +8,
|
||||
kTimeZoneTokyo = +9,
|
||||
kTimeZoneSydney = +10,
|
||||
kTimeZoneMagadan = +11,
|
||||
kTimeZoneWellington = +12
|
||||
};
|
||||
|
||||
<span class="code-example-comment">/// Epoch
|
||||
/// The use of an epoch is to provide a timeframe with which to work.
|
||||
/// Most of the time you don't need to know about this.
|
||||
</span>enum Epoch
|
||||
{
|
||||
kEpochUnknown = 0,
|
||||
kEpochJulian = 1, <font color="#999999">/// Began at noon, January 1, 4712 BC.</font>
|
||||
kEpochModifiedJulian = 2, <font color="#999999">/// Began at midnight, November 17, 1858. Exactly 2,400,000.5 days after Julian epoch began.</font>
|
||||
kEpochGregorian = 3, <font color="#999999">/// Began at midnight, September 14, 1752.</font>
|
||||
kEpoch1900 = 4, <font color="#999999">/// Began at midnight, January 1, 1900.</font>
|
||||
kEpoch1950 = 5, <font color="#999999">/// Began at midnight, January 1, 1950.</font>
|
||||
kEpoch1970 = 6, <font color="#999999">/// Began at midnight, January 1, 1970. Same epoch used by C runtime library and Unix OS.</font>
|
||||
kEpoch2000 = 7 <font color="#999999">/// Began at midnight, January 1, 2000.</font>
|
||||
};
|
||||
|
||||
enum Era
|
||||
{
|
||||
kEraUnknown = 0,
|
||||
kEraBC = 1,
|
||||
kEraAD = 2
|
||||
};
|
||||
|
||||
<span class="code-example-comment">/// Parameter
|
||||
/// Defines a date or time parameter.
|
||||
</span>enum Parameter
|
||||
{
|
||||
kParameterUnknown = 0,
|
||||
kParameterYear = 1, <font color="#999999">/// Refers to full year value, such as 1994, 2006, etc. but not a two digit value such as 94 or 04. The valid range is 0-INT_MAX.</font>
|
||||
kParameterMonth = 2, <font color="#999999">/// Refers to month of year, starting with 1 for January. The valid range is 1-12.</font>
|
||||
kParameterWeekOfYear = 3, <font color="#999999">/// Refers to the week of the year, starting with 1 for the week of January 1. The valid range is 1-52.</font>
|
||||
kParameterWeekOfMonth = 4, <font color="#999999">/// Refers to the week of the month, starting with 1 for the first week. The valid range is 1-5.</font>
|
||||
kParameterDayOfYear = 5, <font color="#999999">/// Refers to a day of the year, starting with 1 for January 1st. The valid range is 1-366.</font>
|
||||
kParameterDayOfMonth = 6, <font color="#999999">/// Refers to the day of the month, starting with 1 for the first of the month. The valid range is 1-31.</font>
|
||||
kParameterDayOfWeek = 7, <font color="#999999">/// Refers to the day of the week, starting with 1 for Sunday. The valid range is 1-7.</font>
|
||||
kParameterHour = 8, <font color="#999999">/// Refers to the hour of a day in 24 hour format, starting with 0 for midnight. The valid range is 0-23.</font>
|
||||
kParameterMinute = 9, <font color="#999999">/// Refers to the minute of the hour, starting with 0 for the first minute. The valid range is 0-59.</font>
|
||||
kParameterSecond = 10, <font color="#999999">/// Refers to the second of the minute, starting with 0 for the first second. The valid range is 0-59.</font>
|
||||
};
|
||||
|
||||
<span class="code-example-comment">/// Conversions
|
||||
/// Defines useful conversion multipliers between seconds, minutes, hours, and days.
|
||||
/// Conversions are not defined for some entities (e.g. days per year) because the
|
||||
/// value changes based on the particular year.
|
||||
</span>enum Conversions
|
||||
{
|
||||
kSecondsPerMinute = 60,
|
||||
kSecondsPerHour = 3600,
|
||||
kSecondsPerDay = 86400,
|
||||
kMinutesPerHour = 60,
|
||||
kMinutesPerDay = 1440,
|
||||
kHoursPerDay = 24,
|
||||
kDaysPerWeek = 7,
|
||||
kWeeksPerYear = 52,
|
||||
kMonthsPerYear = 12
|
||||
};
|
||||
</pre>
|
||||
<p>DateTime</p>
|
||||
<pre class="code-example">class DateTime
|
||||
{
|
||||
public:
|
||||
static const uint32_t kValueDefault = 0xffffffff;
|
||||
static const uint32_t kValueIgnored = 0xffffffff;
|
||||
|
||||
public:
|
||||
DateTime(TimeFrame timeFrame = kTimeFrameLocal);
|
||||
|
||||
DateTime(int64_t nSeconds) : mnSeconds(nSeconds);
|
||||
|
||||
DateTime(const DateTime& dateTime) : mnSeconds(dateTime.mnSeconds);
|
||||
|
||||
<span class="code-example-comment"> /// DateTime
|
||||
/// Constructs a DateTime class object from some standard parameters.
|
||||
/// To construct a DateTime class with a different set of parameter types,
|
||||
/// you'll need to use the Set function or in odd cases do manual calculations.
|
||||
</span> DateTime(uint32_t nYear, uint32_t nMonth, uint32_t nDayOfMonth,
|
||||
uint32_t nHour = 0, uint32_t nMinute = 0, uint32_t nSecond = 0);
|
||||
|
||||
<span class="code-example-comment"> /// operator=
|
||||
</span> DateTime& operator=(const DateTime& dateTime);
|
||||
|
||||
<span class="code-example-comment"> /// Compare
|
||||
/// This function compares this object with another DateTime object and
|
||||
/// returns an integer result.The return value is the same as with the
|
||||
/// strcmp string comparison function. If this object is less than the
|
||||
/// argument dateTime, the return value is < 0. Comparison operators are
|
||||
/// defined outside this class, though they use the Compare function to do their work.
|
||||
</span> int Compare(const DateTime& dateTime, bool bCompareDate = true, bool bCompareTime = true) const;
|
||||
|
||||
<span class="code-example-comment"> /// GetParameter
|
||||
/// Gets the given parameter. If you want to get the year, you would call Get(kParameterYear).
|
||||
</span> uint32_t GetParameter(Parameter parameter) const;
|
||||
|
||||
<span class="code-example-comment"> /// SetParameter
|
||||
/// Sets the given parameter. If you want to set the year to 1999, you would
|
||||
/// call Set(kParameterYear, 1999).
|
||||
</span> void SetParameter(Parameter parameter, uint32_t nValue);
|
||||
|
||||
<span class="code-example-comment"> /// Set
|
||||
/// Sets the time based on the current time. If the timeFrame is kTimeFrameUTC,
|
||||
/// the time is set to what the current UTC time is, which will be a fixed number
|
||||
/// of hours off of what the current local time is.
|
||||
</span> void Set(TimeFrame timeFrame = kTimeFrameLocal);
|
||||
|
||||
<span class="code-example-comment"> /// Set
|
||||
/// Sets the time based on various inputs. If any input is kValueIgnored (uint32_t)-1,
|
||||
/// then the input is ignored and the current value is used. If any of the cyclic
|
||||
/// inputs is beyond its valid range, the modulo of the value is used and the division
|
||||
/// of the value is added to the next higher bracket. For example, if the input nMinute
|
||||
/// is 65, then the minute used is 5 and 1 is added to the current hour value.
|
||||
</span> void Set(uint32_t nYear, uint32_t nMonth, uint32_t nDayOfMonth, uint32_t nHour,
|
||||
uint32_t nMinute, uint32_t nSecond);
|
||||
|
||||
<span class="code-example-comment"> /// AddTime
|
||||
/// Allows you to increment (or decrement) the given parameter by the given amount.
|
||||
</span> void AddTime(Parameter parameter, int32_t nValue);
|
||||
|
||||
<span class="code-example-comment"> /// IsDST
|
||||
/// Returns true if the time is daylight savings time. This function assumes that DST is valid
|
||||
/// for the given current locale; some locales within the United States don't observe DST.
|
||||
</span> bool IsDST() const;
|
||||
|
||||
<span class="code-example-comment"> /// GetSeconds
|
||||
/// Returns the DateTime internal representation.
|
||||
</span> int64_t GetSeconds() const;
|
||||
};</pre>
|
||||
<blockquote></blockquote>
|
||||
<p>Utility</p>
|
||||
<pre class="code-example"><span class="code-example-comment">/// IsLeapYear
|
||||
/// Returns true if the given year is a leap year.
|
||||
</span>bool IsLeapYear(uint32_t nYear);
|
||||
|
||||
<span class="code-example-comment">/// GetDaysInYear
|
||||
/// Returns the number of days in the given year. The value will vary based on whether
|
||||
/// the year is a leap year or not.
|
||||
</span>uint16_t GetDaysInYear(uint32_t nYear);
|
||||
|
||||
<span class="code-example-comment">/// GetDaysInMonth
|
||||
/// Returns the number of days in the given month. The value will vary based on the
|
||||
/// month and based on whether the year is a leap year. The input nMonth takes one
|
||||
/// of enum Month or an integer equivalent.
|
||||
</span>uint8_t GetDaysInMonth(uint32_t nMonth, uint32_t nYear);
|
||||
|
||||
<span class="code-example-comment">/// GetDayOfYear
|
||||
/// The input nMonth takes one of enum Month or an integer equivalent.
|
||||
/// The input nDayOfMonth takes an integer consistent with enum DayOfMonth.
|
||||
</span>uint32_t GetDayOfYear(uint32_t nMonth, uint32_t nDayOfMonth, uint32_t nYear);
|
||||
|
||||
<span class="code-example-comment">/// Convert4DigitTo2DigitYear
|
||||
/// Note that two-digit years bring a number of problems; they are best used for text
|
||||
/// display only and not for any internal processing.
|
||||
</span>inline int Convert4DigitTo2DigitYear(int nYear4);
|
||||
|
||||
<span class="code-example-comment">/// Convert2DigitTo4DigitYear
|
||||
/// This code returns a year in the 1900s if the input year is > 30 but returns
|
||||
/// a year in the 2000s if the year is <= 30. This is merely a guess and in fact there
|
||||
/// really is no good way to reliably convert a two digit year to a four digit year.
|
||||
</span>inline int Convert2DigitTo4DigitYear(int nYear2);
|
||||
|
||||
<span class="code-example-comment">/// GetCurrent
|
||||
/// Returns the current year, month, hour, etc.
|
||||
</span>uint32_t GetCurrent(Parameter parameter);
|
||||
|
||||
<span class="code-example-comment">/// GetDaylightSavingsBias
|
||||
/// Returns the number of seconds that the current time is daylight savings adjusted from
|
||||
/// the conventional time. Adding this value to the conventional time yields the time when
|
||||
/// adjusted for daylight savings.
|
||||
</span>int64_t GetDaylightSavingsBias();
|
||||
|
||||
<span class="code-example-comment">/// GetTimeZoneBias
|
||||
/// Returns the number of seconds that the local time zone is off of UTC.
|
||||
/// Adding this value to the current UTC yields the current local time.
|
||||
</span>int64_t GetTimeZoneBias();
|
||||
|
||||
<span class="code-example-comment">/// DateTimeToTm
|
||||
/// Converts a DateTime to a C tm struct.
|
||||
</span>void DateTimeToTm(const DateTime& dateTime, tm& time);
|
||||
|
||||
<span class="code-example-comment">/// TmToDateTime
|
||||
/// Converts a C tm struct to a DateTime.
|
||||
</span>void TmToDateTime(const tm& time, DateTime& dateTime);</pre>
|
||||
<blockquote></blockquote>
|
||||
<hr>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
</body></html>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,514 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
|
||||
<title>EAFixedPoint</title>
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
<link type="text/css" rel="stylesheet" href="UTFDoc.css">
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF">
|
||||
<h1>EAFixedPoint</h1>
|
||||
<h2> <span style="font-weight: bold;">Introduction</span> </h2>
|
||||
<p>The EAFixedPoint module implements fixed point math via classic C macros and
|
||||
functions and via a more advanced implementation using C++ classes. The C++
|
||||
classes constitute a fairly complete implementation of a fixed point C++ numerical
|
||||
data type that acts much like the built-in float and double data types. </p>
|
||||
<p>The following code freely mixes the SFixed16 (signed 16:16 fixed point) data
|
||||
type with other numerical data types:</p>
|
||||
<pre><span style="font-family: monospace;"><span class="code-example">SFixed16_16 a(1), b(2), c(3);<br>float f(4.5f);<br>double d(3.2);<br>int i(6);
|
||||
<br>a = b * f;<br>a = (c / d) + b + f;<br>a = c / d * (b % i) + f / c;<br>a = i * -c / (b++);<br>a = sin(a) + pow(b, d) * sqrt(a);<br>a = log(a) / log(f);</span></span></pre>
|
||||
<p></p>
|
||||
<p>Fixed point math has a number of uses:</p>
|
||||
<ul>
|
||||
<li>Improved precision over floating point math.</li>
|
||||
<li>Improved speed over floating point math, particularly with respect to division.</li>
|
||||
<li>Consistent behaviour across CPUs, especially during network play when two
|
||||
different machines must behave identically but FPU behaviour may differ.</li>
|
||||
</ul>
|
||||
<p>Information about fixed point can be found on the Internet by simply searching
|
||||
for "fixed point" with your favorite search site.</p>
|
||||
<h2>Fixed point vs. floating point </h2>
|
||||
<p>Fixed point</p>
|
||||
<blockquote>
|
||||
<p>+ Can be very fast. Fixed point
|
||||
math executes at the same speed as integer math. Fixed to int conversions
|
||||
are much faster float to int.<br>
|
||||
+ Executes concurrently with floating point math, due its use of integer math.<br>
|
||||
– Limited range. Fixed point16:16 numbers are between -32767 and +32767.
|
||||
The fractional part is accurate to 1 / 65536. <br>
|
||||
– Harder to code in high-level languages.</p>
|
||||
</blockquote>
|
||||
<p>Floating point</p>
|
||||
<blockquote>
|
||||
<p>+ Large range. The range for floating point numbers is typically in excess
|
||||
of 1e-100 to 1e+100 and have an accuracy of about 13 decimal places. <br>
|
||||
+ Executes concurrently with integer math.<br>
|
||||
– Can be slower. Generally
|
||||
fast for addition and multiplication but may be slower for division and float
|
||||
to int conversions. </p>
|
||||
</blockquote>
|
||||
<h2>Fixed point precision </h2>
|
||||
<p>The C++ fixed point classes provide varying precision via the use of template
|
||||
parameter constants. EAFixedPoint provides the following predefined C++ fixed
|
||||
point types</p>
|
||||
<table width="100%" border="1">
|
||||
<tr>
|
||||
<td><b>Type</b></td>
|
||||
<td><b>Signed</b></td>
|
||||
<td><b>Integral type</b></td>
|
||||
<td><b>Precision</b></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">SFixed24_8</font></td>
|
||||
<td>signed</td>
|
||||
<td>32</td>
|
||||
<td>24 bits of integer, 8 bits of fraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">UFixed24_8</font></td>
|
||||
<td>unsigned</td>
|
||||
<td>32</td>
|
||||
<td>24 bits of integer, 8 bits of fraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">SFixed22_10</font></td>
|
||||
<td>signed</td>
|
||||
<td>32</td>
|
||||
<td>22 bits of integer, 10 bits of fraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">UFixed22_10</font></td>
|
||||
<td>unsigned</td>
|
||||
<td>32</td>
|
||||
<td>22 bits of integer, 10 bits of fraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">SFixed20_12</font></td>
|
||||
<td>signed</td>
|
||||
<td>32</td>
|
||||
<td>20 bits of integer, 12 bits of fraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">UFixed20_12</font></td>
|
||||
<td>unsigned</td>
|
||||
<td>32</td>
|
||||
<td>20 bits of integer, 12 bits of fraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">SFixed18_14</font></td>
|
||||
<td>signed</td>
|
||||
<td>32</td>
|
||||
<td>18 bits of integer, 14 bits of fraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">UFixed18_14</font></td>
|
||||
<td>unsigned</td>
|
||||
<td>32</td>
|
||||
<td>18 bits of integer, 14 bits of fraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">SFixed16_16</font></td>
|
||||
<td>signed</td>
|
||||
<td>32</td>
|
||||
<td>16 bits of integer, 16 bits of fraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">UFixed16_16</font></td>
|
||||
<td>unsigned</td>
|
||||
<td>32</td>
|
||||
<td>16 bits of integer, 16 bits of fraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">SFixed14_18</font></td>
|
||||
<td>signed</td>
|
||||
<td>32</td>
|
||||
<td>14 bits of integer, 18 bits of fraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">UFixed14_18</font></td>
|
||||
<td>unsigned</td>
|
||||
<td>32</td>
|
||||
<td>14 bits of integer, 18 bits of fraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">SFixed12_20</font></td>
|
||||
<td>signed</td>
|
||||
<td>32</td>
|
||||
<td>12 bits of integer, 20 bits of fraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">UFixed12_20</font></td>
|
||||
<td>unsigned</td>
|
||||
<td>32</td>
|
||||
<td>12 bits of integer, 20 bits of fraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">SFixed10_22</font></td>
|
||||
<td>signed</td>
|
||||
<td>32</td>
|
||||
<td>10 bits of integer, 22 bits of fraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">UFixed10_22</font></td>
|
||||
<td>unsigned</td>
|
||||
<td>32</td>
|
||||
<td>10 bits of integer, 22 bits of fraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">SFixed8_24</font></td>
|
||||
<td>signed</td>
|
||||
<td>32</td>
|
||||
<td>8 bits of integer, 24 bits of fraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">UFixed8_24</font></td>
|
||||
<td>unsigned</td>
|
||||
<td>32</td>
|
||||
<td>8 bits of integer, 24 bits of fraction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">SFixed48_16</font></td>
|
||||
<td>signed</td>
|
||||
<td>64</td>
|
||||
<td>48 bits of integer, 16 bits of fraction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">UFixed48_16</font></td>
|
||||
<td>unsigned</td>
|
||||
<td>64</td>
|
||||
<td>48 bits of integer, 16 bits of fraction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">SFixed44_20</font></td>
|
||||
<td>signed</td>
|
||||
<td>64</td>
|
||||
<td>44 bits of integer, 20 bits of fraction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">UFixed44_20</font></td>
|
||||
<td>unsigned</td>
|
||||
<td>64</td>
|
||||
<td>44 bits of integer, 20 bits of fraction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">SFixed40_24</font></td>
|
||||
<td>signed</td>
|
||||
<td>64</td>
|
||||
<td>40 bits of integer, 24 bits of fraction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">UFixed40_24</font></td>
|
||||
<td>unsigned</td>
|
||||
<td>64</td>
|
||||
<td>40 bits of integer, 24 bits of fraction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">SFixed36_28</font></td>
|
||||
<td>signed</td>
|
||||
<td>64</td>
|
||||
<td>36 bits of integer, 28 bits of fraction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">UFixed36_28</font></td>
|
||||
<td>unsigned</td>
|
||||
<td>64</td>
|
||||
<td>36 bits of integer, 28 bits of fraction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">SFixed32_32</font></td>
|
||||
<td>signed</td>
|
||||
<td>64</td>
|
||||
<td>32 bits of integer, 32 bits of fraction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">UFixed32_32</font></td>
|
||||
<td>unsigned</td>
|
||||
<td>64</td>
|
||||
<td>32 bits of integer, 32 bits of fraction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">SFixed28_36</font></td>
|
||||
<td>signed</td>
|
||||
<td>64</td>
|
||||
<td>28 bits of integer, 36 bits of fraction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">UFixed28_36</font></td>
|
||||
<td>unsigned</td>
|
||||
<td>64</td>
|
||||
<td>28 bits of integer, 36 bits of fraction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">SFixed24_40</font></td>
|
||||
<td>signed</td>
|
||||
<td>64</td>
|
||||
<td>24 bits of integer, 40 bits of fraction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">UFixed24_40</font></td>
|
||||
<td>unsigned</td>
|
||||
<td>64</td>
|
||||
<td>24 bits of integer, 40 bits of fraction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">SFixed20_44</font></td>
|
||||
<td>signed</td>
|
||||
<td>64</td>
|
||||
<td>20 bits of integer, 44 bits of fraction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">UFixed20_44</font></td>
|
||||
<td>unsigned</td>
|
||||
<td>64</td>
|
||||
<td>20 bits of integer, 44 bits of fraction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">SFixed16_48</font></td>
|
||||
<td>signed</td>
|
||||
<td>64</td>
|
||||
<td>16 bits of integer, 48 bits of fraction.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><font face="Courier New, Courier, mono" size="-1">UFixed16_48</font></td>
|
||||
<td>unsigned</td>
|
||||
<td>64</td>
|
||||
<td>16 bits of integer, 48 bits of fraction.</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h2>Example usage </h2>
|
||||
<p>To a large degree, you can use fixed point types the same way you would use
|
||||
floating point types. </p>
|
||||
<p>Mixed integer math expressions (same as shown earlier above):</p>
|
||||
<pre class="code-example">SFixed16_16 a(1), b(2), c(3);<br>float f(4.5f);<br>double d(3.2);<br>int i(6);
|
||||
<br>a = b * f;<br>a = (c / d) + b + f;<br>a = c / d * (b % i) + f / c;<br>a = i * -c / (b++);<br>a = sin(a) + pow(b, d) * sqrt(a);<br>a = log(a) / log(f);</pre>
|
||||
<p>printf:</p>
|
||||
<pre class="code-example">SFixed24_8 f = 23.5f;<br><br>printf("%f", f.AsFloat());</pre>
|
||||
<p>Logical expresions:</p>
|
||||
<pre class="code-example">SFixed16_16 a = 20.4;
|
||||
SFixed16_16 b = 130.6;
|
||||
SFixed16_16 c = 223.3;
|
||||
|
||||
if((a < b) || (b >= c) || (a < 23.5))
|
||||
a *= 25;</pre>
|
||||
<h2>Limitations </h2>
|
||||
<p>The primary differences between our fixed point type and a hypothetical built-in
|
||||
version are:</p>
|
||||
<ul>
|
||||
<li>EAFixedPoint doesn't implement cast operators. Instead, provides explicit
|
||||
converters such as AsInt, AsFloat, etc. This is by design, as such casting
|
||||
operators result in ambiguous conversions and would need built-in compiler
|
||||
knowledge to resolve the situation.</li>
|
||||
<li>Standard library functions such as sprintf have no support for such fixed
|
||||
point types. However, most of the time it is sufficient to convert to floating
|
||||
point and use the built-in floating point formatting functions.</li>
|
||||
<li>There is no explicit support for mixing expressions between two different
|
||||
fixed point types, such as SFixed16_16 with SFixed24_8. You can use these
|
||||
together via conversion between built-in types. </li>
|
||||
</ul>
|
||||
<h2>Interface </h2>
|
||||
<p>C interface:</p>
|
||||
<pre class="code-example">typedef int32_t EAFixed16;
|
||||
|
||||
#define EAMAX_FIXED16 0x7fffffff
|
||||
#define EAMIN_FIXED16 0x80000000
|
||||
|
||||
#define EAFixed16ToInt(a) ((int32_t)(a) >> 16)
|
||||
#define EAIntToFixed16(a) ((EAFixed16)((a) << 16))
|
||||
#define EAFixed16ToDouble(a) (((double)a) / 65536.0)
|
||||
#define EADoubleToFixed16(a) ((EAFixed16)((a) * 65536.0))
|
||||
#define EAFixed16ToFloat(a) (((float)a) / 65536.f)
|
||||
#define EAFloatToFixed16(a) ((EAFixed16)((a) * 65536.f))
|
||||
#define EAFixed16Negate(a) (-a)
|
||||
|
||||
EAFixed16 EAFixed16Mul (EAFixed16 a, EAFixed16 b);
|
||||
EAFixed16 EAFixed16Div (EAFixed16 a, EAFixed16 b);
|
||||
EAFixed16 EAFixed16DivSafe (EAFixed16 a, EAFixed16 b);
|
||||
EAFixed16 EAFixed16MulDiv (EAFixed16 a, EAFixed16 b, EAFixed16 c);
|
||||
EAFixed16 EAFixed16MulDivSafe (EAFixed16 a, EAFixed16 b, EAFixed16 c);
|
||||
EAFixed16 EAFixed16Mod (EAFixed16 a, EAFixed16 b);
|
||||
EAFixed16 EAFixed16ModSafe (EAFixed16 a, EAFixed16 b);
|
||||
EAFixed16 EAFixed16Abs (EAFixed16 a);
|
||||
</pre>
|
||||
<p>C++ interface, by example of SFixed16_16. Note that nearly all the functions
|
||||
below are implemented as simple inlines:</p>
|
||||
<pre class="code-example">struct SFixed16_16
|
||||
{
|
||||
SFixed16_16();
|
||||
SFixed16_16(const SFixed16_16& value);
|
||||
SFixed16_16(const int& value);
|
||||
SFixed16_16(const unsigned int& value);
|
||||
SFixed16_16(const long& value);
|
||||
SFixed16_16(const unsigned long& value);
|
||||
SFixed16_16(const float& value);
|
||||
SFixed16_16(const double& value);
|
||||
|
||||
void FromFixed(const int& value);
|
||||
int32_t AsFixed();
|
||||
|
||||
int AsInt() const;
|
||||
unsigned int AsUnsignedInt() const;
|
||||
long AsLong() const;
|
||||
unsigned long AsUnsignedLong()const;
|
||||
float AsFloat() const;
|
||||
double AsDouble() const;
|
||||
|
||||
SFixed16_16& operator=(const SFixed16_16& value);
|
||||
SFixed16_16& operator=(const int& value);
|
||||
SFixed16_16& operator=(const unsigned int& value);
|
||||
SFixed16_16& operator=(const long& value);
|
||||
SFixed16_16& operator=(const unsigned long& value);
|
||||
SFixed16_16& operator=(const float& value);
|
||||
SFixed16_16& operator=(const double& value);
|
||||
|
||||
bool operator< (const SFixed16_16& value) const;
|
||||
bool operator> (const SFixed16_16& value) const;
|
||||
bool operator>=(const SFixed16_16& value) const;
|
||||
bool operator<=(const SFixed16_16& value) const;
|
||||
bool operator==(const SFixed16_16& value) const;
|
||||
bool operator!=(const SFixed16_16& value) const;
|
||||
|
||||
bool operator< (const int& value) const;
|
||||
bool operator> (const int& value) const;
|
||||
bool operator>=(const int& value) const;
|
||||
bool operator<=(const int& value) const;
|
||||
bool operator==(const int& value) const;
|
||||
bool operator!=(const int& value) const;
|
||||
|
||||
bool operator< (const unsigned int& value) const;
|
||||
bool operator> (const unsigned int& value) const;
|
||||
bool operator>=(const unsigned int& value) const;
|
||||
bool operator<=(const unsigned int& value) const;
|
||||
bool operator==(const unsigned int& value) const;
|
||||
bool operator!=(const unsigned int& value) const;
|
||||
|
||||
bool operator< (const long& value) const;
|
||||
bool operator> (const long& value) const;
|
||||
bool operator>=(const long& value) const;
|
||||
bool operator<=(const long& value) const;
|
||||
bool operator==(const long& value) const;
|
||||
bool operator!=(const long& value) const;
|
||||
|
||||
bool operator< (const unsigned long& value) const;
|
||||
bool operator> (const unsigned long& value) const;
|
||||
bool operator>=(const unsigned long& value) const;
|
||||
bool operator<=(const unsigned long& value) const;
|
||||
bool operator==(const unsigned long& value) const;
|
||||
bool operator!=(const unsigned long& value) const;
|
||||
|
||||
bool operator< (const float& value) const;
|
||||
bool operator> (const float& value) const;
|
||||
bool operator>=(const float& value) const;
|
||||
bool operator<=(const float& value) const;
|
||||
bool operator==(const float& value) const;
|
||||
bool operator!=(const float& value) const;
|
||||
|
||||
bool operator< (const double& value) const;
|
||||
bool operator> (const double& value) const;
|
||||
bool operator>=(const double& value) const;
|
||||
bool operator<=(const double& value) const;
|
||||
bool operator==(const double& value) const;
|
||||
bool operator!=(const double& value) const;
|
||||
bool operator! () const;
|
||||
|
||||
SFixed16_16 operator~() const;
|
||||
SFixed16_16 operator-() const;
|
||||
SFixed16_16 operator+() const;
|
||||
|
||||
SFixed16_16& operator+=(const SFixed16_16& value);
|
||||
SFixed16_16& operator+=(const int& value);
|
||||
SFixed16_16& operator+=(const unsigned int& value);
|
||||
SFixed16_16& operator+=(const long & value);
|
||||
SFixed16_16& operator+=(const unsigned long& value);
|
||||
SFixed16_16& operator+=(const float& value);
|
||||
SFixed16_16& operator+=(const double& value);
|
||||
|
||||
SFixed16_16& operator-=(const SFixed16_16& value);
|
||||
SFixed16_16& operator-=(const int& value);
|
||||
SFixed16_16& operator-=(const unsigned int& value);
|
||||
SFixed16_16& operator-=(const long& value);
|
||||
SFixed16_16& operator-=(const unsigned long& value);
|
||||
SFixed16_16& operator-=(const float& value);
|
||||
SFixed16_16& operator-=(const double& value);
|
||||
|
||||
SFixed16_16& operator*=(const SFixed16_16& value);
|
||||
SFixed16_16& operator*=(const int& value)
|
||||
SFixed16_16& operator*=(const unsigned int& value)
|
||||
SFixed16_16& operator*=(const long& value)
|
||||
SFixed16_16& operator*=(const unsigned long& value);
|
||||
SFixed16_16& operator*=(const float& value);
|
||||
SFixed16_16& operator*=(const double& value);
|
||||
|
||||
SFixed16_16& operator/=(const SFixed16_16& value);
|
||||
SFixed16_16& operator/=(const int& value);
|
||||
SFixed16_16& operator/=(const unsigned int& value);
|
||||
SFixed16_16& operator/=(const long& value);
|
||||
SFixed16_16& operator/=(const unsigned long& value);
|
||||
SFixed16_16& operator/=(const float& value);
|
||||
SFixed16_16& operator/=(const double& value);
|
||||
|
||||
SFixed16_16& operator%=(const SFixed16_16& value);
|
||||
SFixed16_16& operator%=(const int& value);
|
||||
SFixed16_16& operator%=(const unsigned int& value);
|
||||
SFixed16_16& operator%=(const long& value);
|
||||
SFixed16_16& operator%=(const unsigned long& value);
|
||||
SFixed16_16& operator%=(const float& value);
|
||||
SFixed16_16& operator%=(const double& value);
|
||||
|
||||
SFixed16_16& operator|=(const SFixed16_16& value);
|
||||
SFixed16_16& operator|=(const int& value);
|
||||
|
||||
SFixed16_16& operator&=(const SFixed16_16& value);
|
||||
SFixed16_16& operator&=(const int& value);
|
||||
|
||||
SFixed16_16& operator^=(const SFixed16_16& value);
|
||||
SFixed16_16& operator^=(const int& value);
|
||||
|
||||
SFixed16_16 operator<<(int numBits) const;
|
||||
SFixed16_16 operator>>(int numBits) const;
|
||||
|
||||
SFixed16_16& operator<<=(int numBits);
|
||||
SFixed16_16& operator>>=(int numBits);
|
||||
|
||||
SFixed16_16& operator++();
|
||||
SFixed16_16& operator--();
|
||||
SFixed16_16 operator++(int);
|
||||
SFixed16_16 operator--(int);
|
||||
|
||||
SFixed16_16 Abs();
|
||||
SFixed16_16 DivSafe(const SFixed16_16& denominator);
|
||||
SFixed16_16& DivSafeAssign(const SFixed16_16& denominator);
|
||||
}<font color="#000099">;</font>
|
||||
</pre>
|
||||
<hr>
|
||||
<p><br>
|
||||
<br>
|
||||
<br>
|
||||
<span style="font-family: monospace;"> </span><br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
</p>
|
||||
</body></html>
|
||||
@@ -0,0 +1,157 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
|
||||
<title>EAGlobal</title>
|
||||
<link type="text/css" rel="stylesheet" href="UTFDoc.css">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF">
|
||||
<h1>EAGlobal</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
<p>EAGlobal provides the GlobalPtr class. GlobalPtr acts as a reference to a pointer which is global throughout the process (includes the application and any loaded DLLs). The object pointed to must define a unique 32-bit kGlobalID if one is not given. The GlobalPtr class works in a way similar to a smart pointer, but note that it is not the same as your typical auto_ptr or anything else provided by C++ library vendors. The pointer is set to NULL on creation.<br>
|
||||
<br>
|
||||
Global pointers may be used from multiple threads once initialized to point to an object, but are _not_ thread-safe when being set. If you have a situation where two threads may attempt to set a global pointer at the same time, you should use OS globals (See EAOSGlobal.h) instead to serialize the creators on the OS global lock and prevent race conditions.<br>
|
||||
<br>
|
||||
A GlobalPtr is not the same thing as simply declaring a pointer at
|
||||
a globally accessible scope, especially on platforms with dynamic libraries such as Windows with its DLLs. A GlobalPtr allows multiple pieces of code to declare independent pointers to an object, even if the pieced of code are in independent DLLs.<br>
|
||||
<br>
|
||||
The pointer assigned to a GlobalPointer need not be a pointer allocated
|
||||
dynamically on the heap. It can just as well be the address of some static or local variable.</p>
|
||||
<h2>Example usage </h2>
|
||||
<p>Here we provide some basic example usage.</p>
|
||||
<pre class="code-example">GlobalPtr<int, 0x11111111> pInteger;
|
||||
GlobalPtr<int, 0x11111111> pInteger2;
|
||||
|
||||
assert(pInteger == NULL);
|
||||
|
||||
pInteger = new int[2];
|
||||
pInteger[0] = 10;
|
||||
pInteger[1] = 20;
|
||||
assert(pInteger2 == pInteger);
|
||||
assert(pInteger2[0] == pInteger[0]);
|
||||
|
||||
delete[] pInteger;
|
||||
pInteger = NULL;
|
||||
assert(pInteger2 == NULL);
|
||||
</pre>
|
||||
<h2>Interface</h2>
|
||||
<p>The GlobalPtr class works like a smart pointer, but note that it is not the same as your typical auto_ptr or anything else provided by C++ library vendors. </p>
|
||||
<pre class="code-example">template<class t, uint32_t kGlobalId = T::kGlobalId>
|
||||
class GlobalPtr
|
||||
{
|
||||
public:
|
||||
<span class="code-example-comment"> /// this_type
|
||||
/// This is an alias for this class.
|
||||
</span> typedef GlobalPtr<T, kGlobalId> this_type;
|
||||
|
||||
<span class="code-example-comment"> /// GlobalPtr
|
||||
///
|
||||
/// Default constructor. Sets member pointer to whatever the
|
||||
/// shared version is. If this is the first usage of the shared
|
||||
/// version, the pointer will be set to NULL.
|
||||
///
|
||||
/// Example usage:
|
||||
/// GlobalPtr<SomeClass, 0x12345678> pSomeClass;
|
||||
///
|
||||
</span> GlobalPtr();
|
||||
|
||||
<span class="code-example-comment"> /// GlobalPtr (copy constructor)
|
||||
///
|
||||
/// Default constructor. Sets member pointer to whatever the
|
||||
/// shared version is. If this is the first usage of the shared
|
||||
/// version, the pointer will be set to NULL.
|
||||
///
|
||||
/// Example usage:
|
||||
/// GlobalPtr<SomeClass, 0x12345678> pSomeClass1;
|
||||
/// pSomeClass1 = new pSomeClass;
|
||||
/// GlobalPtr<SomeClass, 0x12345678> pSomeClass2(pSomeClass1);
|
||||
/// pSomeClass2->DoSomething();
|
||||
///
|
||||
</span> explicit GlobalPtr(const this_type& globalPtr);
|
||||
|
||||
<span class="code-example-comment"> /// operator =
|
||||
///
|
||||
/// Example usage:
|
||||
/// GlobalPtr<SomeClass, 0x12345678> pSomeClass1;
|
||||
/// pSomeClass1 = new pSomeClass;
|
||||
/// GlobalPtr<SomeClass, 0x12345678> pSomeClass2(pSomeClass1);
|
||||
/// pSomeClass2->DoSomething();
|
||||
///
|
||||
</span> this_type& operator=(const this_type& /*globalPtr*/);
|
||||
|
||||
<span class="code-example-comment"> /// operator =
|
||||
///
|
||||
/// Example usage:
|
||||
/// GlobalPtr<SomeClass, 0x12345678> pSomeClass1;
|
||||
/// pSomeClass1 = new pSomeClass;
|
||||
/// delete pSomeClass1;
|
||||
/// pSomeClass1 = new pSomeClass;
|
||||
///
|
||||
</span> this_type& operator=(T* p);
|
||||
|
||||
<span class="code-example-comment"> /// operator T*
|
||||
///
|
||||
/// Example usage:
|
||||
/// GlobalPtrlt;SomeClass, 0x12345678> pSomeClass;
|
||||
/// FunctionWhichUsesSomeClassPtr(pSomeClass);
|
||||
///
|
||||
</span> operator T*() const;
|
||||
|
||||
<span class="code-example-comment"> /// operator T*
|
||||
///
|
||||
/// Example usage:
|
||||
/// GlobalPtr<SomeClass, 0x12345678> pSomeClass;
|
||||
/// CallFunctionWhichUsesSomeClassPtr(pSomeClass);
|
||||
///
|
||||
</span> T& operator*() const;
|
||||
|
||||
<span class="code-example-comment"> /// operator ->
|
||||
///
|
||||
/// Example usage:
|
||||
/// GlobalPtr<SomeClass, 0x12345678> pSomeClass;
|
||||
/// pSomeClass->DoSomething();
|
||||
///
|
||||
</span> T* operator->() const;
|
||||
|
||||
<span class="code-example-comment"> /// operator !
|
||||
///
|
||||
/// Example usage:
|
||||
/// GlobalPtr<SomeClass, 0x12345678> pSomeClass;
|
||||
/// if(!pSomeClass)
|
||||
/// pSomeClass = new SomeClass;
|
||||
///
|
||||
</span> bool operator!() const;
|
||||
|
||||
<span class="code-example-comment"> /// get
|
||||
///
|
||||
/// Returns the owned pointer.
|
||||
///
|
||||
/// Example usage:
|
||||
/// GlobalPtr<SomeClass, 0x12345678> pSomeClass = new SomeClass;
|
||||
/// SomeClass* pSC = pSomeClass.get();
|
||||
/// pSC->DoSomething();
|
||||
///
|
||||
</span> T* get() const;
|
||||
};</pre>
|
||||
<p></p>
|
||||
<hr>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
</body></html>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
|
||||
<title>EAHash</title>
|
||||
<link type="text/css" rel="stylesheet" href="UTFDoc.css">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF">
|
||||
<h1>EAHash</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
<p>EAHash is a family of hashing functions. There are string hashes, binary hashes, cryptographic hashes, checksums, and CRCs; each has its applications. If you are looking for hash tables, they are present in the EASTL library, which provides a suite of hash table containers.</p>
|
||||
<p>Hash functions are functions which take input data and produce a hash value, which is usually an integer or some short fixed-size data. This is useful for implementing hash-tables, cryptographic security, and error checking. A good hash function produces a unique hash value for the large majority of unique input. A cryptographic hash goes further and has a level of mathematical security built into it so that it is difficult or impossible to guess the original input from a given hash value output. You can read more about hash functions at Wikipedia at <a href="http://en.wikipedia.org/wiki/Hash_function">http://en.wikipedia.org/wiki/Hash_function</a>.</p>
|
||||
<p>EAStdC provides the following hash submodules:</p>
|
||||
<ul><li>EAHashString (string hashing) </li>
|
||||
<li>EAHashCRC (cyclical redundancy check)</li>
|
||||
</ul>
|
||||
<p>EAHash provides these hashes in forms that read from blocks in memory. </p>
|
||||
<h2>EAHashString</h2>
|
||||
<p>String hashes are probably the most common hashes used in game development. There is a particular interest in having string hashes that are fast but reasonably collision-free in practice. Cryptographical security is not of interest to string hashes. However, being able to do a case-insensitive hash often is. </p>
|
||||
<p>String hashes are different from binary hashes in that they hash characters and not bytes. Thus, the hash for the 8 bit string "hello" will be the same as the hash for a 16 bit char string L"hello" even though the latter uses twice as many bytes and would hash to a different value via a binary hash function. String hashes are also different in that they sometimes have the option to act with case insensitivity. In such cases the hash for "Hello" is the same as for "hello". </p>
|
||||
<p>The primary string hash provided by EAHashString is the FNV1 hash, though the DJB2 hash is also provided. The FNV1 hash appears to be the best string hash for most users' needs, as it is very fast and yet generates surprisingly few collisions with typical text input. </p>
|
||||
<p>The FNV1 hash functions provided by EAHashString are:</p>
|
||||
<pre class="code-example">uint32_t FNV1 (const void* pData, size_t nLength, uint32_t nInitialValue = kFNV1InitialValue);<br>uint32_t FNV1_String8 (const char8_t* pData, uint32_t nInitialValue = kFNV1InitialValue, CharCase charCase = kCharCaseAny);<br>uint32_t FNV1_String16(const char16_t* pData, uint32_t nInitialValue = kFNV1InitialValue, CharCase charCase = kCharCaseAny);</pre>
|
||||
<p>Example usage: </p>
|
||||
<pre class="code-example">const char16_t fileName[IO::kMaxFileNameLength];
|
||||
|
||||
const uint32_t fileNameHash = FNV1_string16(filePath, kFNV1InitialValue, kCharCaseLower);
|
||||
|
||||
printf("Case-insensitive hash for file %ls is 0x%08x.\n", filePath, fileNameHash);</pre>
|
||||
<h2>EAHashCRC</h2>
|
||||
<p>A CRCs (cyclical redundancy check) is a form of hash which is good at detecting uniqueness of input yet is fairly simple to implement. CRCs are most often used to detect errors during data transmission in a non-security-sensitive environment. If a recieved file has a different checksum than the original file, there was a transmission error. A cryptographic hash could also be used to do what a CRC hash does, but it would have more overhead, particularly when implemented in hardware. </p>
|
||||
<p>There are many standards and variations of CRC algorithms, and trying to understand them can be a tedious frustrating experience. EAHashCRC provides a single CRC implementation for each of various bit sizes and doesn't try to cater to the myriad of variations that exist. Unless you need a CRC function which interacts with some specific third party CRC convention, the version in EAHashCRC is probably fine. You can read more about CRCs on Wikipedia at <a href="http://en.wikipedia.org/wiki/Cyclic_redundancy_check">http://en.wikipedia.org/wiki/Cyclic_redundancy_check</a>.</p>
|
||||
<p>The CRC functions have a 'bFinalize' parameter, which enables the inversion of the bits upon completion. This is a common practice in standardized CRC calculations. When doing iterative CRC calculations, you need to make sure you set bFinalize to false for all but the last call. See the example code below.</p>
|
||||
<p>EAHashCRC provides the following block functions: </p>
|
||||
<pre class="code-example">uint16_t CRC16(const void* pData, size_t nLength, uint16_t nInitialValue = kCRC16InitialValue, bool bFinalize = true);
|
||||
uint32_t CRC24(const void* pData, size_t nLength, uint32_t nInitialValue = kCRC24InitialValue, bool bFinalize = true);
|
||||
uint32_t CRC32(const void* pData, size_t nLength, uint32_t nInitialValue = kCRC32InitialValue, bool bFinalize = true);
|
||||
uint64_t CRC64(const void* pData, size_t nLength, uint64_t nInitialValue = kCRC64InitialValue, bool bFinalize = true);
|
||||
|
||||
uint32_t CRC32Reverse(const void* pData, size_t nLength, uint32_t nInitialValue = kCRC32InitialValue, bool bFinalize = true);</pre>
|
||||
<p>Example basic usage:</p>
|
||||
<pre class="code-example">char* fileData;
|
||||
size_t fileLength;
|
||||
|
||||
ReadFile(pData, fileLength);
|
||||
|
||||
uint16_t crc = CRC16(fileData, fileLength);</pre>
|
||||
<p>Example usage of incremental CRC calculation, which is useful when you don't have the data in a single block:</p>
|
||||
<pre class="code-example">char pDataArray[1000];<br>uint64_t crc = kCRC64InitialValue;<br><br>for(int i = 0; i < 10; i++)<span class="code-example-comment"> // Calculate the CRC for the data array incrementally.</span><br> crc = EA::Hash::CRC64(pDataArray[i * 100], 100, crc, i == 9);<br>
|
||||
</pre>
|
||||
<hr>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
</body></html>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
|
||||
<Title>EAMathHelp</title>
|
||||
|
||||
<link type="text/css" rel="stylesheet" href="UTFDoc.css">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF">
|
||||
<h1>EAMathHelp</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
<p>EAMathHelp provides fast floating point math primitives. It is not a vector/matrix math library such as those in use around Electronic Arts, but rather is a base
|
||||
for doing floating point characterizations and for doing fast floating point conversions. The former often serve to help implement the latter.</p>
|
||||
<p>The constants listed below may look odd if you aren't familiar with the standardized IEEE floating point format. A description of this format is outside the scope
|
||||
of this document, but you can find plenty of documentation about it by looking it up on the Internet. Suffice it to say the floating point numbers are essentially
|
||||
bitfields that specify a sign, an integer value (mantissa), and an exponent to raise the integer value by.</p>
|
||||
<h2>Constants</h2>
|
||||
<pre class="code-example"><span class="code-example-comment">// 32 bit float bits
|
||||
</span>const uint32_t kFloat32SignMask = UINT32_C(0x80000000);
|
||||
const uint32_t kFloat32ExponentMask = UINT32_C(0x7F800000);
|
||||
const uint32_t kFloat32MantissaMask = UINT32_C(0x007FFFFF);
|
||||
const uint32_t kFloat32SignAndExponentMask = UINT32_C(0xFF800000);
|
||||
const uint32_t kFloat32SignAndMantissaMask = UINT32_C(0x807FFFFF);
|
||||
const uint32_t kFloat32ExponentAndMantissaMask = UINT32_C(0x7FFFFFFF);
|
||||
const uint32_t kFloat32PositiveInfinityBits = UINT32_C(0x7F800000);
|
||||
const unsigned kFloat32SignBits = 1;
|
||||
const unsigned kFloat32ExponentBits = 8;
|
||||
const unsigned kFloat32MantissaBits = 23;
|
||||
const unsigned kFloat32BiasValue = 127;
|
||||
|
||||
<span class="code-example-comment">// 64 bit float bits
|
||||
</span>const uint64_t kFloat64SignMask = UINT64_C(0x8000000000000000);
|
||||
const uint64_t kFloat64ExponentMask = UINT64_C(0x7FF0000000000000);
|
||||
const uint64_t kFloat64MantissaMask = UINT64_C(0x000FFFFFFFFFFFFF);
|
||||
const uint64_t kFloat64SignAndExponentMask = UINT64_C(0xFFF0000000000000);
|
||||
const uint64_t kFloat64SignAndMantissaMask = UINT64_C(0x800FFFFFFFFFFFFF);
|
||||
const uint64_t kFloat64ExponentAndMantissaMask = UINT64_C(0x7FFFFFFFFFFFFFFF);
|
||||
const uint64_t kFloat64PositiveInfinityBits = UINT64_C(0x7FF0000000000000);
|
||||
const unsigned kFloat64SignBits = 1;
|
||||
const unsigned kFloat64ExponentBits = 11;
|
||||
const unsigned kFloat64MantissaBits = 52;
|
||||
const unsigned kFloat64BiasValue = 1023;
|
||||
|
||||
const float32_t kFloat32Infinity = kFloat32PositiveInfinityBits;
|
||||
const float64_t kFloat64Infinity = kFloat64PositiveInfinityBits;
|
||||
|
||||
<span class="code-example-comment">// bias to integer
|
||||
</span>const float32_t kFToIBiasF32 = uint32_t(3) << 22;
|
||||
const int32_t kFToIBiasS32 = 0x4B400000; <span class="code-example-comment">// Same as ((int32_t&) kFToIBiasF32), but known to optimizer at compile time.</span>
|
||||
const float64_t kFToIBiasF64 = uint64_t(3) << 52;
|
||||
|
||||
<span class="code-example-comment">// bias to 8-bit fraction
|
||||
</span>const float32_t kFToI8BiasF32 = uint32_t(3) << 14;
|
||||
const int32_t kFToI8BiasS32 = 0x47400000; <span class="code-example-comment">// Same as ((int32_t&) kFToI8BiasF32), but known to optimizer at compile time.</span>
|
||||
|
||||
<span class="code-example-comment">// bias to 16-bit fraction
|
||||
</span>const float32_t kFToI16BiasF32 = uint32_t(3) << 6;
|
||||
const int32_t kFToI16BiasS32 = 0x43400000; <span class="code-example-comment">// Same as ((int32_t&) kFToI16BiasF32), but known to optimizer at compile time.</span>
|
||||
</pre>
|
||||
<h2>Functions</h2>
|
||||
<p>Float conversion functions</p>
|
||||
<pre class="code-example"><span class="code-example-comment">///////////////////////////////////////////////////////////////////////
|
||||
// Full range conversion functions
|
||||
//
|
||||
// These are good for floats within the full range of a float. Remember
|
||||
// that a single-precision float only has a 24-bit significand so
|
||||
// most integers |x| > 2^24 cannot be represented exactly.
|
||||
//
|
||||
// The result of converting an out-of-range number, infinity, or NaN
|
||||
// is undefined.
|
||||
//
|
||||
</span>inline uint32_t RoundToUint32(float fValue);
|
||||
inline int32_t RoundToInt32(float fValue);
|
||||
inline int32_t FloorToInt32(float fValue);
|
||||
inline int32_t CeilToInt32(float fValue);
|
||||
inline int32_t TruncateToInt32(float fValue);
|
||||
|
||||
<span class="code-example-comment">///////////////////////////////////////////////////////////////////////
|
||||
// Partial range conversion functions.
|
||||
//
|
||||
// These are only good for |x| <= 2^23. The result of converting an
|
||||
// out-of-range number, infinity, or NaN is undefined.
|
||||
//
|
||||
</span>inline int32_t FastRoundToInt23(float fValue);
|
||||
|
||||
|
||||
<span class="code-example-comment">///////////////////////////////////////////////////////////////////////
|
||||
// Unit-to-byte functions.
|
||||
//
|
||||
// Converts real values in the range |x| <= 1 to unsigned 8-bit values
|
||||
// [0, 255]. The result of calling UnitFloatToUint8() with |x|>1 is
|
||||
// undefined.
|
||||
//
|
||||
</span>inline uint8_t UnitFloatToUint8(float fValue);
|
||||
inline uint8_t ClampUnitFloatToUint8(float fValue);
|
||||
|
||||
</pre>
|
||||
<p>Float characterization functions</p>
|
||||
<pre class="code-example"><span class="code-example-comment">///////////////////////////////////////////////////////////////////////
|
||||
// IsInvalid
|
||||
//
|
||||
// Returns true if a value does not obey normal arithmetic rules;
|
||||
// specifically, x != x. In the case of Visual C++ 2003, this is true
|
||||
// for NaNs and indefinites, and not for normalized finite values,
|
||||
// denormals, and infinities. Other compilers may return different
|
||||
// results or even false for all values.
|
||||
//
|
||||
// IsInvalid() is useful as a fast assert check that floats are
|
||||
// sane and won't poison computations as NaNs can with masked
|
||||
// exceptions.
|
||||
//
|
||||
</span>inline bool IsInvalid(float32_t fValue);
|
||||
inline bool IsInvalid(float64_t fValue);
|
||||
|
||||
<span class="code-example-comment">///////////////////////////////////////////////////////////////////////////////
|
||||
// IsNormal
|
||||
//
|
||||
// Returns true if the value is a normalized finite number. That is, it is neither
|
||||
// an infinite, nor a NaN (including indefinite NaN), nor a denormalized number.
|
||||
// You generally want to write math operation checking code that asserts for
|
||||
// IsNormal() as opposed to checking specifically for IsNaN, etc.
|
||||
//
|
||||
// Normal values are defined as any floating point value with an exponent in
|
||||
// the range of [1, 254], as 0 is reserved for denormalized (underflow) values
|
||||
// and 255 is reserved for infinite (overflow) and NaN values.
|
||||
//
|
||||
</span>inline bool IsNormal(float32_t fValue);
|
||||
inline bool IsNormal(float64_t fValue);
|
||||
|
||||
<span class="code-example-comment">///////////////////////////////////////////////////////////////////////////////
|
||||
// IsNAN
|
||||
//
|
||||
// A NaN is a special kind of number that is neither finite nor infinite.
|
||||
// It is the result of doing things like the following:
|
||||
// float x = 1 * NaN;
|
||||
// float x = NaN + NaN;
|
||||
// float x = 0 / 0;
|
||||
// float x = 0 / infinite;
|
||||
// float x = infinite - infinite
|
||||
// float x = sqrt(-1);
|
||||
// float x = cos(infinite);
|
||||
// Under the VC++ debugger, x will be displayed as 1.#QNAN00 or 1.#IND00 and
|
||||
// the bit representation of x will be 0x7fc00001 (in the case of 1 * NaN).
|
||||
// The 'Q' in front of NAN stands for "quiet" and means that use of that value
|
||||
// in expressions won't generate exceptions. A signaling NaN (SNAN) means that
|
||||
// use of the value would generate exceptions.
|
||||
//
|
||||
// NaNs are frequently generated in physics simulations and similar mathematical
|
||||
// situations when you are simulating an object moving or turning over time but
|
||||
// the time or distance differential in the calculation is very small.
|
||||
// Also, floating point roundoff error can generate NaNs if you do things
|
||||
// like call acos(x) where you didn't take care to clamp x to <= 1. You can
|
||||
// also get a NaN when memory used to store a floating point value is written
|
||||
// with random data.
|
||||
//
|
||||
// A curious property of NaNs is that all comparisons between NaNs return
|
||||
// false except the expression: NaN != NaN. This is so even if the bit
|
||||
// representation of the two compared NaNs are identical. Thus, with NaNs,
|
||||
// the following holds:
|
||||
// x == x is always false
|
||||
// x < y is always false
|
||||
// x > y is always false
|
||||
//
|
||||
// As a result, one simple way to test for a NaN without fiddling with bits is
|
||||
// to simply test for x == x. If this returns false, then you have a NaN.
|
||||
// Unfortunately, many C and C++ compilers don't obey this, so you are usually
|
||||
// stuck fiddling with bits.
|
||||
//
|
||||
// With a NaN, all exponent bits are 1 and the mantissa is not zero.
|
||||
// If the highest fraction bit is 1, the NAN is "quiet" -- it represents
|
||||
// and indeterminant operation rather than an invalid one.
|
||||
//</span>
|
||||
inline bool IsNAN(float32_t fValue);
|
||||
inline bool IsNAN(float64_t fValue);
|
||||
|
||||
<span class="code-example-comment">///////////////////////////////////////////////////////////////////////////////
|
||||
// IsInfinite
|
||||
//
|
||||
// A value is infinity if the exponent bits are all 1 and all the bits of the
|
||||
// mantissa (significand) are 0. The sign bit indicates positive or negative
|
||||
// infinity. Thus, for Float32, 0x7f800000 is positive infinity and 0xff800000
|
||||
// is negative infinity.
|
||||
//
|
||||
</span>inline bool IsInfinite(float32_t fValue);
|
||||
inline bool IsInfinite(float64_t fValue);
|
||||
|
||||
<span class="code-example-comment">///////////////////////////////////////////////////////////////////////////////
|
||||
// IsIndefinite
|
||||
//
|
||||
// An indefinite is a special kind of NaN that is used to signify that an
|
||||
// operation between non-NaNs generated a NaN. Other than that, it really is
|
||||
// simply another NaN.
|
||||
//
|
||||
</span>inline bool IsIndefinite(float32_t fValue);
|
||||
inline bool IsIndefinite(float64_t fValue);
|
||||
|
||||
<span class="code-example-comment">///////////////////////////////////////////////////////////////////////////////
|
||||
// IsDenormalized
|
||||
//
|
||||
// Much in the same way that infinite numbers represent an overflow,
|
||||
// denormalized numbers represent an underflow. A denormalized number is
|
||||
// indicated by an exponent with a value of zero. You get a denormalized
|
||||
// number when you do operations such as this:
|
||||
// float x = 1e-10 / 1e35;
|
||||
// Under the VC++ debugger, x will be displayed as 1.4e-045#DEN and the
|
||||
// bit representation of x will be 0x00000001. Unlike infinites and NaNs,
|
||||
// you can still do math with denormalized numbers. However, the results
|
||||
// of your math will likely have a lot of imprecision. You can also get a
|
||||
// denormalized value when memory used to store a floating point value is
|
||||
// written with random data.
|
||||
//
|
||||
</span>inline bool IsDenormalized(float32_t fValue);
|
||||
inline bool IsDenormalized(float64_t fValue);</pre>
|
||||
|
||||
<hr>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
</body></html>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
|
||||
|
||||
<title>EAMemory</title>
|
||||
<link type="text/css" rel="stylesheet" href="UTFDoc.css">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
<style type="text/css">
|
||||
<!--
|
||||
.style1 {font-size: smaller}
|
||||
-->
|
||||
</style>
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF">
|
||||
<h1>EAMemory</h1>
|
||||
|
||||
<p>EAMemory provides functions related to copying and filling memory. </p>
|
||||
<p>Note the presence of "C" functions below such as MemcpyC. These refer to memory functions that operate only on cacheable memory, but are faster than otherwise. Cacheable memory is standard system RAM used by applications and is the memory you work with 98% of the time. However, on some hardware systems (e.g. gaming console machines) there is uncacheable memory, such as memory that is mapped to video addresses. This memory is typically called write-through or write-combined memory and is useful for writing data in one direction from system RAM to video memory. The "C" functions do not work on this kind of memory and you can instead use the regular functions such as Memcpy for uncacheable memory. The C here has nothing to do with the C vs. C++ language.</p>
|
||||
<table border="1">
|
||||
<tr>
|
||||
<td colspan="2" valign="top" scope="col"><h3>Memcpy</h3></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="527" valign="top"><span class="style1">char8_t* Memcpy (void* pDest, const void* pSource, size_t n)</span></td>
|
||||
<td rowspan="5" valign="top"><p>Copies nByteCount bytes from pSource to pDestination. The source and destination memory ranges must not overlap. Returns pDestination. There are no restrictions in the way of size, alignment, or memory type, though the source memory must be readable and the destination memory must be writable. </p>
|
||||
<p>The MemcpyS function copies memory from source to destination without filling the cache with the memory. This is useful for when you want to write memory that will not be read by the processor used to write it, such as when the CPU writes to memory used by the GPU. </p>
|
||||
<p>The Memcpy128 function is useful for higher performance memory copies when the requirements can be met. The address pointed to by pDestination must be aligned on a 128-byte boundary, and uint8Count must be a multiple of 128.</p></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">char8_t* MemcpyC (void* pDest, const void* pSource, size_t n)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">char8_t* MemcpyS (void* pDest, const void* pSource, size_t n)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">char8_t* Memcpy128 (void* pDest, const void* pSource, size_t n)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">char8_t* Memcpy128C (void* pDest, const void* pSource, size_t n)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" valign="top"><h3>Memmove</h3></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">char8_t* Memmove (void* pDest, const void* pSource, size_t n)</span></td>
|
||||
<td rowspan="2" valign="top">Copies nByteCount bytes from pSource to pDestination. The source and destination memory ranges may overlap. Returns pDestination. There are no restrictions in the way of size, alignment, or memory type, though the source memory must be readable and the destination memory must be writable. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">char8_t* MemmoveC (void* pDest, const void* pSource, size_t n)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" valign="top"><h3>Memset</h3></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">uint8_t* Memset8 (void* pDest, uint8_t c, size_t uint8Count)</span></td>
|
||||
<td rowspan="10" valign="top"><p> The standard memset function replicates a given 8 bit value into a memory block. However, we might want to replicate a 16 bit, 32 bit, or 64 bit value into a block. That's what these functions do. The MemsetN function is a generic version which can copy unusual sizes such as 24 bits (e.g. RGB fills). The count values for each of these is the count of uint16_t, count of uint32_t, count of pointers, etc.<br>
|
||||
<br>
|
||||
Memset8 is the same as the memset function. We provide additional variations of memset which set uint16_t values, uint32_t value, etc. instead of uint8_t values like Memset8. MemsetN writes a generic type of any size. In each case pDestination must point to enough memory to hold full values. Thus pDestination for Memset32 must have a capacity for at least (uint32Count * sizeof(uint32_t)) bytes. The destination is required to be aligned to its type. Thus the destination of Memset32 must be 32 bit aligned. There are no restrictions about the type of memory pDestination refers to except that it be writable.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">uint8_t* Memset8C (void* pDest, uint8_t c, size_t uint8Count)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">uint8_t* Memset8_128 (void* pDest, uint8_t c, size_t uint8Count)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">uint8_t* Memset8_128C (void* pDest, uint8_t c, size_t uint8Count)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">uint16_t* Memset16 (void* pDest, uint16_t c, size_t uint16Count)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">uint32_t* Memset32 (void* pDest, uint32_t c, size_t uint32Count)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">uint64_t* Memset64 (void* pDest, uint64_t c, size_t uint64Count)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">void* MemsetN (void* pDest, const void* pSource, size_t sourceBytes, size_t nCount)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">void Memclear (void* pDest, size_t n)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">void MemclearC (void* pDest, size_t n)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" valign="top"><h3>Memfill</h3></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">void Memfill16 (void* pDest, uint16_t c, size_t byteCount)</span></td>
|
||||
<td rowspan="5" valign="top">Memfill is the same as memset except that the count parameter is a count of bytes and not (for example) a count of uint32_t values. Memfill supports byte counts that aren't an even multiple the value size. Thus a call to Memfill32(p, 0x00112233, 3) is valid and does what you would expect. MemFill8 is not defined because it is the same thing as Memset8. MemfillSpecific fills (and potentially repeats) any source pattern into any destination space. There are no restrictions about the type of memory pDest refers to except that it be writable.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">void Memfill24 (void* pDest, uint32_t c, size_t byteCount)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">void Memfill32 (void* pDest, uint32_t c, size_t byteCount)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">void Memfill64 (void* pDest, uint64_t c, size_t byteCount)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">void MemfillSpecific(void* pDest, const void* pSource, size_t destByteCount, size_t sourceByteCount)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" valign="top"><h3>Memcheck</h3></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">uint8_t* Memcheck8 (void* pDest, uint8_t c, size_t byteCount)</span></td>
|
||||
<td rowspan="4" valign="top">This family of functions is like Memfill except it verifies that the memory is filled as per the value and byte count. Returns a pointer to the first mis-matching byte if there's a mismatch. Returns NULL if there are no mismatches. There are no restrictions about the type of memory pDest refers to except that it be readable.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">uint16_t* Memcheck16 (void* pDest, uint16_t c, size_t byteCount)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">uint32_t* Memcheck32 (void* pDest, uint32_t c, size_t byteCount)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">uint64_t* Memcheck64 (void* pDest, uint64_t c, size_t byteCount)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2" valign="top"><h3>Misc</h3></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">const void* Memchr(const void* p, char8_t c, size_t n)</span></td>
|
||||
<td valign="top">This is the same as memchr and wmemchr. Searches the first n characters (not necessarily bytes) of the memory block pointed to by pString for character c. Returns a pointer to the character or NULL if not found. There are no restrictions about the type of memory p refers to except that it be readable.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">int Memcmp(const void* p1, const void* p2, size_t n)</span></td>
|
||||
<td valign="top">Same as memcmp and wmemcmp. Compares the first n bytes of two memory blocks pointed by p1 and p2. The comparison is a bytewise compare and thus for strings it is case-sensitive. For a case-insensitive string comparison, use the Stricmp function. Bytes are treated as uint8_t for comparison purposes. Returns 0 if the memory is equal, < 0 if p1 < p2, and > 0 if p1 > p2. There are no restrictions about the type of memory p1 and p2 refer to except that they be readable.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td valign="top"><span class="style1">void* EAAlloca(size_t n)</span></td>
|
||||
<td valign="top"><p>EAAlloca is a portable declaration for the alloca function. </p>
|
||||
<p>The alloca function allocates space in the stack frame of the caller, and returns a pointer to the allocated block. This temporary space is automatically freed when the function from which alloca is called returns.</p></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
</body></html>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
|
||||
<title>EAOSGlobal</title>
|
||||
<link type="text/css" rel="stylesheet" href="UTFDoc.css">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF">
|
||||
<h1>EAOSGlobal</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
<p>OS globals are process-wide globals (singletons, actually) and are shared between an EXE and DLLs, though you can use them on platforms that don't support DLLs. The Windows OS does not directly support this concept of global object sharing, as the only way to accomplish this under Windows is to sequester the global object in its own DLL of which the EXE and all DLLs explicitly reference. OS Globals allow you to have the global object anywhere (including the EXE) and does so without requiring explicit linking. The OS global system works at the operating system level and has auto-discovery logic so that no pointers or init calls need to be made between modules for them to link their OS global systems together. The OS global system consists of EAOSGlobal and <a href="EAGlobal.html">EAGlobal</a>. The latter provides simpler functionality but has less overhead.</p>
|
||||
<p>A primary use of OS globals is in the creation of application singletons such as the main heap, messaging servers, asset managers, etc. <br>
|
||||
<br>
|
||||
Note that the implementation behind OS globals (EAOSGlobal.cpp) may seem a bit convoluted; this is because it needs to be thread-safe, cross-module, and independent of application-level memory allocators. For objects for which order of initialization is clearer and you don't need to reference singletons across DLLs, EASingleton is probably a better choice, as it is simpler and has lower overhead. Indeed, another way of looking at OS globals is to view them as process-wide singletons. </p>
|
||||
<p>The easiest way to use OS globals is via their auto pointers, which make OS globals just about trivial to use. We will cover the major components of EAOSGlobal below, starting with the auto pointers. </p>
|
||||
<p><strong>Caveats</strong></p>
|
||||
<p>OS globals have the potential for resulting in code that's duplicated within each DLL and thus increasing code memory usage. It might be useful to use an OS global to store a pointer to an interface rather than an instance of an interface, and have just a single entity within the application provide the implementation. With this approach you still get the benefit of users of the global not having to know ahead of time where the implementation is as you otherwise need to do with standard DLL linking via "dllexport."</p>
|
||||
<p>OS globals probably aren't needed in cases where you can simply use dllexport (and other platforms' equivalents).</p>
|
||||
<h2>AutoOSGlobalPtr</h2>
|
||||
<p> Holds a reference to an OS global of the specified type and Id. If the OS global does not exist, a new one is created in the shared heap. The Id parameter is an arbitrary guid and allows the user to have multiple OSGlobalPtrs of the same stored type T.<br>
|
||||
<br>
|
||||
OS global lookup is not very fast so the preferred usage of this class is to wrap it in an accessor. This also ensures that the OS global stays around while created.</p>
|
||||
<p>Example usage: </p>
|
||||
<pre class="code-example">AutoOSGlobalPtr<Widget, 0x11111111> gpWidget1A; <span class="code-example-comment">// Declare a global pointer.</span><br>AutoOSGlobalPtr<Widget, 0x11111111> gpWidget1B; <span class="code-example-comment">// Points to the same global Widget as gpWidget1A.</span><br>AutoOSGlobalPtr<Widget, 0x22222222> gpWidget2; <span class="code-example-comment">// Points to a different Widget, as it has the 0x22222222 id.</span><br><br>void Foo()
|
||||
{<br> assert(gpWidget1A == gpWidget1B);<br> assert(gpWidget1A != gpWidget2);<br><br> gpWidget1A->DoSomething();<br> gpWidget2->DoSomething();<br>}</pre>
|
||||
<h2>AutoStaticOSGlobalPtr</h2>
|
||||
<p> Holds a reference to a OS global of the specified type and ID. If the OS global does not exist, a new one is created using static memory.<br>
|
||||
The Id parameter is an arbitrary guid and allows the user to have multiple OSGlobalPtrs of the same stored type T.<br>
|
||||
<br>
|
||||
The advantage of this class is that it uses static memory, so it does not contribute to heap usage and it always succeeds in allocating the object. The disadvantage is that if multiple DLLs are involved each will have its own static space reserved for the OS global.</p>
|
||||
<p>AutoStaticOSGlobalPtrs and AutoOSGlobalPtrs should not be mixed when referring to a OS global. You should reference an OSGlobal via either one or more AutoOSGlobalPtrs, one or more AutoStaticOSGlobalPtrs, but not both at the same time.</p>
|
||||
<p>Example usage (note that it is virtually identical to the AutoOSGlobalPtr example): </p>
|
||||
<pre class="code-example">AutoStaticOSGlobalPtr<Widget, 0x11111111> gpWidget1A; <span class="code-example-comment">// Declare a global pointer.</span><br>AutoStaticOSGlobalPtr<Widget, 0x11111111> gpWidget1B; <span class="code-example-comment">// Points to the same global Widget as gpWidget1A.</span><br>AutoStaticOSGlobalPtr<Widget, 0x22222222> gpWidget2; <span class="code-example-comment">// Points to a different Widget, as it has the 0x22222222 id.</span><br><br>void Foo()
|
||||
{<br> assert(gpWidget1A == gpWidget1B);<br> assert(gpWidget1A != gpWidget2);<br><br> gpWidget1A->DoSomething();<br> gpWidget2->DoSomething();<br>}</pre>
|
||||
<h2>Low level functionality </h2>
|
||||
<p>The above auto pointer classes are really just wrappers around the low level OS global API. Most of the time you want to use the auto pointers. We provide a description of the lowel level API here for those who need to access OS globals in a custom way.</p>
|
||||
<p>The low level system is comprised of the following four entities: </p>
|
||||
<pre class="code-example">struct OSGlobalNode : public eastl::intrusive_list_node { };
|
||||
|
||||
typedef OSGlobalNode* (*OSGlobalFactoryPtr)();
|
||||
|
||||
OSGlobalNode* GetOSGlobal(uint32_t id, OSGlobalFactoryPtr pFactory);
|
||||
|
||||
bool ReleaseOSGlobal(OSGlobalNode* pOSGlobalNode);
|
||||
</pre>
|
||||
<p>Example usage:</p>
|
||||
<pre class="code-example">struct Widget : public OSGlobalNode
|
||||
{
|
||||
<span class="code-example-comment">// User data here.</span>
|
||||
};
|
||||
|
||||
Widget* WidgetFactory()
|
||||
{
|
||||
return new Widget;
|
||||
}
|
||||
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
Widget* pWidget = GetOSGlobal(0x12345678, WidgetFactory);
|
||||
|
||||
pWidget->DoSomething();
|
||||
|
||||
if(ReleaseOSGlobal(pWidget))
|
||||
delete pWidget;
|
||||
|
||||
return 0;
|
||||
}</pre>
|
||||
<p>The above example looks like a basic singleton pattern, and it is such a thing. The difference between this and your typical singleton system is that the OS global system solves the potentially tricky problems of cross-DLL access, thread safety, and memory allocation. </p>
|
||||
<p>For additional example usage, see the source code to AutoOSGlobalPtr in EAOSGlobal.h.</p>
|
||||
<hr>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p></p>
|
||||
</body></html>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,374 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
|
||||
|
||||
<title>EARandom</title>
|
||||
<link type="text/css" rel="stylesheet" href="UTFDoc.css">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
</head>
|
||||
<body bgcolor="#FFFFFF">
|
||||
<h1>EARandom</h1>
|
||||
|
||||
<h2>Introduction</h2>
|
||||
<p>EARandom provides pseudo-random number generation suitable for most kinds of
|
||||
professional game development. Functionality is divided into two modules:</p>
|
||||
<ul>
|
||||
<li>Core random number generation (e.g. random integer, random float)</li>
|
||||
<li>Variable distribution generation (e.g. Gaussian distribution, triangle distribution)</li>
|
||||
</ul>
|
||||
<p>EARandom provides two core generators which address a speed/randomness tradeoff:</p>
|
||||
<ul>
|
||||
<li> RandomLinearCongruential (very fast, also known as RandomFast, but still good randomness)</li>
|
||||
<li>RandomMersenneTwister (very random, also known as RandomQuality)</li>
|
||||
</ul>
|
||||
<p>EARandom provides a number of distribution generators, each of which uses the
|
||||
above core generators underneath:</p>
|
||||
<ul>
|
||||
<li>RandomBool</li>
|
||||
<li>Random2, Random4, Random8, ... Random256</li>
|
||||
<li>RandomInt32UniformRange</li>
|
||||
<li>RandomDoubleUniformRange</li>
|
||||
<li>RandomUint32WeightedChoice</li>
|
||||
<li>RandomUint32Gaussian</li>
|
||||
<li>RandomUint32Triangle</li>
|
||||
</ul>
|
||||
<p><i>Note: EARandom is not certified nor suitable for use in certified gambling
|
||||
software. There are strict standards regarding such software which EARandom
|
||||
does not try to comply with. Similarly, EARandom is not suitable for use in security-related entropy collection (at least not by itself). EARandom's goal is to provide good random number
|
||||
generation with high efficiency.</i></p>
|
||||
<h2>Don't use the C rand() function!</h2>
|
||||
<p> The C library rand function does an OK job as a basic random number generator
|
||||
for testing and hobby purposes. However, the rand function is generally not
|
||||
suitable for professional game software. This is because the rand function:</p>
|
||||
<ul>
|
||||
<li>Generates only numbers between 0 and RAND_MAX, which is usually 32767.</li>
|
||||
<li>Doesn't generate random numbers within a prescribed range. Using the % operator
|
||||
to rectify this is slow (requires integer division) and produces a lopsided
|
||||
distribution unless the divisor is evenly divisible into RAND_MAX.</li>
|
||||
<li>Generates rather poor random numbers. In particular, they tend to have obvious
|
||||
patterns in the low bits. In some cases this can result in users taking advantage
|
||||
of the number generator at the expense of other players or your game franchise
|
||||
itself.</li>
|
||||
<li>Exists only as a single instance of a generator which is shared with the
|
||||
entire application. There is no way to make another instance.</li>
|
||||
<li>Is slow. Generating a random number via rand() was measured as 70% slower
|
||||
than the EARandom generator on modern hardware.</li>
|
||||
<li>Doesn't generate floating point numbers.</li>
|
||||
</ul>
|
||||
<h2>How random is EARandom?</h2>
|
||||
<p>Both RandomLinearCongruential (i.e. RandomFast) and RandomMersenneTwister (RandomQuality) provide randomness that is likely good enough for most convential game uses. Don't be fooled by the "linear congruential" name; it's not the bad generator that you might think based on what you've read about old C rand implementations. </p>
|
||||
<p>A good way to test randomness is with the DieHard randomness tests. See http://en.wikipedia.org/wiki/Diehard_tests for information about DieHard. We have a copy of the <a href="http://eaos.rws.ad.ea.com:8080/@md=d&cd=//EAOS/UTF/DL/UTFResearch/DieHard%20Random%20Number%20Tester/&c=2lr@//EAOS/UTF/DL/UTFResearch/DieHard%20Random%20Number%20Tester/bin/?ac=83">DieHard tester in EAOS</a> which is used to test EARandom and could test any other random number generator. EARandom produces DieHard scores which are pretty good. A number of home-grown random number generators have shown much worse results. </p>
|
||||
<h2>Common misuses</h2>
|
||||
<p>It is worth mentioning that it is surprisingly common for users of random number
|
||||
generators (including EARandom) to come to the belief that the generator is
|
||||
broken when in fact they are misusing the generator. Common misuses of generators
|
||||
include:</p>
|
||||
<ul>
|
||||
<li>Seeding a generator with the same seed every time it's used.</li>
|
||||
<li>Seeding two generators at the same time via the system clock and finding
|
||||
that they produce idential values.</li>
|
||||
<li>Using 'RandomUint32Uniform() % 5000' instead of 'RandomUint32Uniform(5000)'.</li>
|
||||
<li>Inventing flawed distribution generators.</li>
|
||||
<li>Misusing the results of a generator but assuming the generator is yielding
|
||||
bad values.</li>
|
||||
<li>Creating a random number generator for a single use right when it is needed.
|
||||
This is usually bad because the first generated value is no more random than
|
||||
the seed used to generate the number.</li>
|
||||
</ul>
|
||||
<h2>Example usage </h2>
|
||||
<p>EARandom is fairly straightforward to use. Just avoid the above common mistakes
|
||||
and things should work well.</p>
|
||||
<p>Mixed integer math expressions.</p>
|
||||
<pre class="code-example">EA::RandomFast rng(GetCPUTick()); <span class="code-example-comment">// Seed with a hypthetical CPU tick function.</span>
|
||||
|
||||
uint32_t n = rng.RandomUint32Uniform(); <span class="code-example-comment">// Generate value in the range of [0, 0xffffffff] (all bit patterns).</span>
|
||||
uint32_t i = rng.RandomUint32Uniform(200); <span class="code-example-comment">// Generate value in the range of [0, 200).</span>
|
||||
double d = rng.RandomDoubleUniform(); <span class="code-example-comment">// Generate value in the range of [0, 1).</span>
|
||||
double f = rng.RandomDoubleUniform(37); <span class="code-example-comment">// Generate value in the range of [0, 37).</span></pre>
|
||||
How to use EARandom with STL (including EASTL).
|
||||
<pre class="code-example">#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
std::vector v;
|
||||
EA::RandomFast rng;
|
||||
|
||||
std::random_shuffle(v.begin(), v.end(), rng);</pre>
|
||||
How to use basic random distributions. Note that these functions take a random number generator as an argument.
|
||||
<pre class="code-example">EA::RandomQuality rng;
|
||||
|
||||
bool b = EA::RandomBool(rng);
|
||||
int32_t n = EA::Random256(rng);
|
||||
double d = EA::RandomDoubleGaussian(rng, 15.0, 30.0);</pre>
|
||||
<p>How to use RandomUint32WeightedChoice. This function is useful for generating
|
||||
a custom distribution.</p>
|
||||
<pre class="code-example">EA::RandomQuality rng;
|
||||
const float weights[10] = { 1, 2, 3, 4, 5, 5, 4, 3, 2, 1 }; // Create a triangle distribution
|
||||
|
||||
uint32_t i = EA::RandomUint32WeightedChoice(rng, 10, weights); </pre>
|
||||
<h2>Interface</h2>
|
||||
<h3>RandomLinearCongruential</h3>
|
||||
<p>This algorithm generates good enough pseudorandom numbers for most simulationuses.
|
||||
Its biggest weakness is that there are some patterns that occur in the lower
|
||||
bits. However, it is still far better than the C rand function. </p>
|
||||
<pre class="code-example">class RandomLinearCongruential
|
||||
{
|
||||
public:
|
||||
typedef uint32_t result_type;
|
||||
|
||||
|
||||
<span class="code-example-comment"> /// RandomLinearCongruential
|
||||
/// Constructs the random number generator with a given initial state (seed).
|
||||
/// If the seed is 0xffffffff (MAX_UINT32), then the seed is generated automatically
|
||||
/// by a semi-random internal mechanism such as reading the system clock. Note that
|
||||
/// seeding by this mechanism can yield unexpected poor results if you create multiple
|
||||
/// instances of this class within a short period of time, as they will all get the
|
||||
/// same seed due to the system clock having not advanced.
|
||||
</span> RandomLinearCongruential(uint32_t nSeed = 0xffffffff);
|
||||
|
||||
<span class="code-example-comment"> /// RandomLinearCongruential
|
||||
/// Copy constructor
|
||||
</span> RandomLinearCongruential(const RandomLinearCongruential& randomLC);
|
||||
|
||||
<span class="code-example-comment"> /// operator =
|
||||
</span> RandomLinearCongruential& operator=(const RandomLinearCongruential& randomLC);
|
||||
|
||||
<span class="code-example-comment"> /// GetSeed
|
||||
/// Gets the state of the random number generator, which can be entirely
|
||||
/// defined by a single uint32_t.
|
||||
</span> uint32_t GetSeed() const;
|
||||
|
||||
<span class="code-example-comment"> /// SetSeed
|
||||
/// Sets the current state of the random number generator, which can be
|
||||
/// entirely defined by a single uint32_t.
|
||||
</span> void SetSeed(uint32_t nSeed = 0xffffffff);
|
||||
|
||||
<span class="code-example-comment"> /// operator ()
|
||||
/// Generates a random uint32 with an optional limit. Acts the same as the
|
||||
/// RandomUint32Uniform(uint32_t nLimit) function. This function is useful for
|
||||
/// some templated uses whereby you want the class to act as a function object.
|
||||
/// If the input nLimit is 0, then the return value is from 0 to MAX_UINT32 inclusively.
|
||||
</span> uint32_t operator()(uint32_t nLimit = 0);
|
||||
|
||||
<span class="code-example-comment"> /// RandomUint32Uniform
|
||||
/// Return value is from 0 to MAX_UINT32 inclusively, with uniform probability.
|
||||
/// This is the most basic random integer generator for this class; it has no
|
||||
/// extra options but is also the fastest. Note that if you want a random
|
||||
/// integer between 0 and some value, you should use RandomUint32Uniform(nLimit)
|
||||
/// and not use RandomUint32Uniform() % nLimit. The former is both faster and
|
||||
/// more random; using % to achieve a truly random distribution fails unless
|
||||
/// nLimit is evenly divisible into MAX_UINT32.
|
||||
</span> uint32_t RandomUint32Uniform();
|
||||
|
||||
<span class="code-example-comment"> /// RandomUint32Uniform (with limit)
|
||||
/// Return value is from 0 to nLimit-1 inclusively, with uniform probability.
|
||||
</span> uint32_t RandomUint32Uniform(uint32_t nLimit);
|
||||
|
||||
<span class="code-example-comment"> /// RandomDoubleUniform
|
||||
/// Output is in range of [0, 1) with uniform distribution.
|
||||
</span> double RandomDoubleUniform();
|
||||
|
||||
<span class="code-example-comment"> /// RandomDoubleUniform (with limit)
|
||||
/// Output is in range of [0, limit) with uniform distribution.
|
||||
</span> double RandomDoubleUniform(double limit);
|
||||
};
|
||||
</pre>
|
||||
<h3>RandomTaus</h3>
|
||||
<p> RandomTaus is slower than the other EARandom generators but has only 12 bytes of state data. RandomLinearCongruental has only 4 bytes of data but is not as random as RandomTaus. RandomMersenneTwister is more random than RandomTaus but has about 2500 bytes of state data. Thus RandomTaus is a tradeoff. This generator optimizes randomness and and to some degree size at the cost of speed.</p>
|
||||
<pre class="code-example">class RandomTaus
|
||||
{
|
||||
public:
|
||||
typedef uint32_t result_type;
|
||||
|
||||
|
||||
RandomTaus(uint32_t nSeed = 0xffffffff);
|
||||
RandomTaus(const uint32_t* pSeedArray); <span class="code-example-comment">// Array of 3 uint32_t values.</span>
|
||||
|
||||
RandomTaus(const RandomTaus& randomT);
|
||||
RandomTaus& operator=(const RandomTaus& randomT);
|
||||
|
||||
<span class="code-example-comment"> // Single uint32_t version, for compatibility.
|
||||
// Use the seed array version for best behavior.
|
||||
// Not guaranteed to return the uint32_t set by SetSeed(uint32_t).
|
||||
</span> uint32_t GetSeed() const;
|
||||
void SetSeed(uint32_t nSeed = 0xffffffff);
|
||||
|
||||
void GetSeed(uint32_t* pSeedArray) const; <span class="code-example-comment">// Array of 3 uint32_t values.</span>
|
||||
void SetSeed(const uint32_t* pSeedArray); <span class="code-example-comment">// Array of 3 uint32_t values.</span>
|
||||
|
||||
<span class="code-example-comment"> /// Output is in range of [0, nLimit) with uniform distribution.
|
||||
</span> uint32_t operator()(uint32_t nLimit = 0);
|
||||
|
||||
<span class="code-example-comment"> /// Output is in range of [0, UINT32_MAX] with uniform distribution.
|
||||
</span> uint32_t RandomUint32Uniform();
|
||||
|
||||
<span class="code-example-comment"> /// Output is in range of [0, nLimit) with uniform distribution.
|
||||
</span> uint32_t RandomUint32Uniform(uint32_t nLimit);
|
||||
|
||||
<span class="code-example-comment"> /// Output is in range of [0, 1) with uniform numeric (not bit) distribution.
|
||||
</span> double RandomDoubleUniform();
|
||||
|
||||
<span class="code-example-comment"> /// Output is in range of [0, limit) with uniform numeric (not bit) distribution.
|
||||
/// limit is a value > 0.
|
||||
</span> double RandomDoubleUniform(double limit);<br><span class="code-example-comment"></span>};</pre>
|
||||
<h3>RandomMersenneTwister</h3>
|
||||
<p>This algorithm implements a random number generator via the Mersenne Twister
|
||||
algorithm. This algorithm is popular for its very high degree of randomness
|
||||
(period of 2^19937-1 with 623-dimensional equidistribution) while achieving
|
||||
good speed.</p>
|
||||
<pre class="code-example">class RandomMersenneTwister
|
||||
{
|
||||
public:
|
||||
typedef uint32_t result_type;
|
||||
|
||||
<span class="code-example-comment"> /// enum SeedArray
|
||||
/// This enum is public because it allows the user to know how much
|
||||
/// data or space to provide for the GetSeed and SetSeed functions.
|
||||
</span> enum SeedArray { kSeedArrayCount = 624 };
|
||||
|
||||
RandomMersenneTwister(uint32_t nSeed = 0xffffffff);
|
||||
RandomMersenneTwister(const uint32_t seedArray[], unsigned nSeedArraySize);
|
||||
RandomMersenneTwister(const RandomMersenneTwister& randomMT);
|
||||
|
||||
RandomMersenneTwister& operator=(const RandomMersenneTwister& randomMT);
|
||||
|
||||
void GetSeed(uint32_t seedArray[], unsigned nSeedArraySize) const;
|
||||
void SetSeed(const uint32_t seedArray[], unsigned nSeedArraySize);
|
||||
void SetSeed(uint32_t nSeed = 0xffffffff);
|
||||
|
||||
uint32_t operator()(uint32_t nLimit = 0);
|
||||
|
||||
uint32_t RandomUint32Uniform();
|
||||
uint32_t RandomUint32Uniform(uint32_t nLimit);
|
||||
|
||||
double RandomDoubleUniform();
|
||||
double RandomDoubleUniform(double limit);
|
||||
};</pre>
|
||||
<h3>Random distributions</h3>
|
||||
<p>Here is a list of the currently provided distribution functions.</p>
|
||||
<pre class="code-example"><span class="code-example-comment">/// RandomBool
|
||||
/// Returns true or false.
|
||||
</span>template <typename Random>
|
||||
bool RandomBool(Random& r);
|
||||
|
||||
<span class="code-example-comment">/// Random2
|
||||
/// Returns a value between 0 and 1, inclusively.
|
||||
</span>template <typename Random>
|
||||
int32_t Random2(Random& r);
|
||||
|
||||
<span class="code-example-comment">/// Random4
|
||||
/// Returns a value between 0 and 3, inclusively.
|
||||
</span>template <typename Random>
|
||||
int32_t Random4(Random& r);
|
||||
|
||||
<span class="code-example-comment">/// Random8
|
||||
/// Returns a value between 0 and 7, inclusively.
|
||||
</span>template <typename Random>
|
||||
int32_t Random8(Random& r);
|
||||
|
||||
<span class="code-example-comment">/// Random16
|
||||
/// Returns a value between 0 and 15, inclusively.
|
||||
</span>template <typename Random>
|
||||
int32_t Random16(Random& r);
|
||||
|
||||
<span class="code-example-comment">/// Random32
|
||||
/// Returns a value between 0 and 31, inclusively.
|
||||
</span>template <typename Random>
|
||||
int32_t Random32(Random& r);
|
||||
|
||||
<span class="code-example-comment">/// Random64
|
||||
/// Returns a value between 0 and 63, inclusively.
|
||||
</span>template <typename Random>
|
||||
int32_t Random64(Random& r);
|
||||
|
||||
<span class="code-example-comment">/// Random128
|
||||
/// Returns a value between 0 and 127, inclusively.
|
||||
</span>template <typename Random>
|
||||
int32_t Random128(Random& r);
|
||||
|
||||
<span class="code-example-comment">/// Random256
|
||||
/// Returns a value between 0 and 255, inclusively.
|
||||
</span>template <typename Random>
|
||||
int32_t Random256(Random& r);
|
||||
|
||||
<span class="code-example-comment">/// RandomPowerOfTwo
|
||||
/// Returns a value between 0 and 2 ^ nPowerOfTwo - 1, inclusively.
|
||||
/// This is a generalized form of the RandomN set of functions.
|
||||
</span>template <typename Random>
|
||||
int32_t RandomPowerOfTwo(Random& r, unsigned nPowerOfTwo);
|
||||
|
||||
<span class="code-example-comment">/// RandomInt32UniformRange
|
||||
/// Return value is from nBegin to nEnd-1 inclusively, with uniform probability.
|
||||
</span>template <typename Random>
|
||||
int32_t RandomInt32UniformRange(Random& r, int32_t nBegin, int32_t nEnd);
|
||||
|
||||
<span class="code-example-comment">/// RandomDoubleUniformRange
|
||||
/// Return value is in range of [nBegin, nEnd) with uniform probability.
|
||||
</span>template <class Random><class Random><typename Random>
|
||||
double RandomDoubleUniformRange(Random& r, double begin, double end);
|
||||
|
||||
<span class="code-example-comment">/// RandomUint32WeightedChoice
|
||||
/// Return value is from 0 to nLimit-1 inclusively, with probabilities proportional to weights.
|
||||
/// The input array weights must be of length <nlimit>. These values are used to
|
||||
/// determine the probability of each choice. That is, weight[i] is proportional
|
||||
/// to the probability that this function will return i. Negative values are ignored.
|
||||
/// This function is useful in generating a custom distribution.
|
||||
</span>template <typename Random>
|
||||
uint32_t RandomUint32WeightedChoice(Random& r, uint32_t nLimit, float weights[]);
|
||||
|
||||
<span class="code-example-comment">/// RandomUint32Gaussian
|
||||
/// Return value is in the range [0, nLimit) with Gaussian (a.k.a 'normal') distribution.
|
||||
</span>template <typename Random>
|
||||
uint32_t RandomUint32Gaussian(Random& r, int32_t nBegin, int32_t nEnd);
|
||||
|
||||
<span class="code-example-comment">/// RandomDoubleGaussian
|
||||
/// Return value is in the range [0, nLimit) with Gaussian (a.k.a 'normal') distribution.
|
||||
</span>template <typename Random>
|
||||
double RandomDoubleGaussian(Random& r, double nBegin, double nEnd);
|
||||
|
||||
<span class="code-example-comment">/// RandomUint32Triangle
|
||||
/// Return value is in the range [0, nLimit) with triangular distribution.
|
||||
</span>template <typename Random>
|
||||
uint32_t RandomUint32Triangle(Random& r, int32_t nBegin, int32_t nEnd);
|
||||
|
||||
<span class="code-example-comment">/// RandomDoubleTriangle
|
||||
/// Return value is in the range [0, nLimit) with triangular distribution.
|
||||
</span>template <typename Random>
|
||||
double RandomDoubleTriangle(Random& r, double nBegin, double nEnd);
|
||||
|
||||
</pre>
|
||||
<h3>Random fills and shuffles</h3>
|
||||
<p>How to fill a container or sequence with random uint32_t values:</p>
|
||||
<pre class="code-example">#include <eastl/algorithm.h> <span class="code-example-comment"> // or #include <algorithm> to use std STL.</span>
|
||||
|
||||
EA::StdC::Random rand(someSeedValue); <span class="code-example-comment">// We can just use EA::StdC::Random directly because</span> <br>eastl::generate(myVector.begin(), myVector.end(), rand); <span class="code-example-comment">// it has an operator() that returns uint32_t.</span></pre>
|
||||
<p>How to randomize (shuffle) an existing container or sequence of uint32_t values:</p>
|
||||
<pre class="code-example">#include <eastl/algorithm.h> <span class="code-example-comment"> // or #include <algorithm> to use std STL.</span>
|
||||
|
||||
EA::StdC::Random rand(someSeedValue);
|
||||
eastl::random_shuffle(myVector.begin(), myVector.end(), rand);</pre>
|
||||
<p>How to fill a container or sequence with random double:</p>
|
||||
<pre class="code-example">#include <eastl/algorithm.h> <span class="code-example-comment"> // or #include <algorithm> to use std STL.</span>
|
||||
|
||||
struct GenerateDouble
|
||||
{ <br> EA::StdC::Random mRand; <span class="code-example-comment">// We need to make a tiny class that simply has</span> <br> <span class="code-example-comment">// an operator() member function that returns double.</span>
|
||||
GenerateDouble(uint32_t seed) : mRand(seed){} <br>
|
||||
double operator(){ mRand.RandomDoubleUniform(); }
|
||||
};<br>
|
||||
GenerateDouble randDouble(someSeedValue);<br>eastl::generate(myVector.begin(), myVector.end(), randDouble);</pre>
|
||||
<hr>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
</body></html>
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type"
|
||||
content="text/html; charset=ISO-8859-1">
|
||||
<title>EAScanf</title>
|
||||
<link type="text/css" rel="stylesheet"
|
||||
href="UTFDoc.css">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
</head>
|
||||
<body style="background-color: rgb(255, 255, 255);">
|
||||
<h1>EAScanf</h1>
|
||||
<h2>Introduction</h2>
|
||||
<p>EAScanf provides a portable
|
||||
version of the C scanf family of functions which improves on
|
||||
the C family in the following ways:</p>
|
||||
<ul>
|
||||
<li>Behaves identically on all
|
||||
platforms</li>
|
||||
<li>Provides the full gamut of
|
||||
scanf functions, including vsscanf</li>
|
||||
<li>Is more efficient</li>
|
||||
<li>Never allocates memory</li>
|
||||
<li>Provides both 8 and 16 bit
|
||||
versions for all platforms</li>
|
||||
<li>Provides useful
|
||||
extended functionality</li>
|
||||
<li>Complies with the C99
|
||||
standard (except for the %a format, as of this writing)</li>
|
||||
<li>Is readable enough to be
|
||||
traced/debugged by non-experts</li>
|
||||
<li>Is savvy to UTF8 Unicode</li>
|
||||
</ul>
|
||||
<p>The primary disadvantages of
|
||||
EAScanf are:</p>
|
||||
<ul>
|
||||
<li>It doesn't use
|
||||
locale-specific formatting</li>
|
||||
<li>It isn't part of the C/C++
|
||||
standard library</li>
|
||||
</ul>
|
||||
<p>EAScanf doesn't attempt to
|
||||
solve the locale formatting problem because users really are better off
|
||||
using serious locale libraries for such things rather than using the
|
||||
meager support provided by the C standard library. The EALocale library
|
||||
attempts to provide such functionality.</p>
|
||||
<p>EAScanf provides the
|
||||
following functions in 8 and 16 bit versions:
|
||||
</p>
|
||||
<pre><span class="code-example">int Cscanf(ReadFunction8 pReadFunction8, void* pContext, const char8_t* pFormat, ...);
|
||||
int Fscanf(FILE* pFile, const char8_t* pFormat, ...);
|
||||
int Scanf(const char8_t* pFormat, ...);
|
||||
int Sscanf(const char8_t* pTextBuffer, const char8_t* pFormat, ...);
|
||||
|
||||
int Cscanf(ReadFunction16 pReadFunction16, void* pContext, const char16_t* pFormat, ...);
|
||||
int Fscanf(FILE* pFile, const char16_t* pFormat, ...);
|
||||
int Scanf(const char16_t* pFormat, ...);
|
||||
int Sscanf(const char16_t* pTextBuffer, const char16_t* pFormat, ...);
|
||||
|
||||
int Vcscanf(ReadFunction8 pReadFunction8, void* pContext, const char8_t* pFormat, va_list arguments);
|
||||
int Vfscanf(FILE* pFile, const char8_t* pFormat, va_list arguments);
|
||||
int Vscanf(const char8_t* pFormat, va_list arguments);
|
||||
int Vsscanf(const char8_t* pTextBuffer, const char8_t* pFormat, va_list arguments);
|
||||
|
||||
int Vcscanf(ReadFunction16 pReadFunction16, void* pContext, const char16_t* pFormat, va_list arguments);
|
||||
int Vfscanf(FILE* pFile, const char16_t* pFormat, va_list arguments);
|
||||
int Vscanf(const char16_t* pFormat, va_list arguments);
|
||||
int Vsscanf(const char16_t* pTextBuffer, const char16_t* pFormat, va_list arguments);</span></pre>
|
||||
<blockquote> </blockquote>
|
||||
<h2>Extended Functionality</h2>
|
||||
<p> EAPrintf provides extended
|
||||
format functionality not found in the C99 standard but which is useful
|
||||
nevertheless:</p>
|
||||
<table style="text-align: left; width: 100%;" border="1" cellpadding="2"
|
||||
cellspacing="2">
|
||||
<tbody>
|
||||
<tr style="font-weight: bold;">
|
||||
<td>Format</td>
|
||||
<td>Description</td>
|
||||
<td>Example</td>
|
||||
<td>Example output</td>
|
||||
</tr>
|
||||
<tr style="font-weight: bold;">
|
||||
<td><span style="font-weight: normal;">b</span></td>
|
||||
<td style="font-weight: normal;">Binary
|
||||
output field type (joins d, i, x, o, etc.).</td>
|
||||
<td><span style="font-weight: normal;">sscanf("11111111", "%b", &integer);</span></td>
|
||||
<td><span style="font-weight: normal;">integer == 0xff </span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>I8</td>
|
||||
<td>8 bit integer field
|
||||
modifier.</td>
|
||||
<td><span style="font-weight: normal;">sscanf</span>("0xff", "%I8d"<span style="font-weight: normal;">, &int8</span>);</td>
|
||||
<td><span style="font-weight: normal;"><span style="font-weight: normal;">int8</span> == <span style="font-weight: normal;">0xff </span></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>I16</td>
|
||||
<td>16 bit integer field
|
||||
modifier.</td>
|
||||
<td><span style="font-weight: normal;">sscanf</span>("0xffff", "%I16u"<span style="font-weight: normal;">, &uint16</span>);</td>
|
||||
<td><span style="font-weight: normal;"><span style="font-weight: normal;">uint16</span> == <span style="font-weight: normal;">0xffff</span></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>I32</td>
|
||||
<td>32 bit integer field
|
||||
modifier.</td>
|
||||
<td><span style="font-weight: normal;">sscanf</span>("0xffffffff", "%I32d"<span style="font-weight: normal;">, &int32</span>);</td>
|
||||
<td><span style="font-weight: normal;"><span style="font-weight: normal;">int32</span> == <span style="font-weight: normal;">0xffff</span></span>ffff</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>I64</td>
|
||||
<td>64 bit integer field
|
||||
modifier.</td>
|
||||
<td><span style="font-weight: normal;">sscanf</span>("0xffffffffffffffff", "%I64u"<span style="font-weight: normal;">, &int64</span>);</td>
|
||||
<td><span style="font-weight: normal;">int64</span> == -1 </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>I128</td>
|
||||
<td>128 bit integer field
|
||||
modifier.</td>
|
||||
<td><span style="font-weight: normal;">sscanf</span>("0xffffffffffffffffffffffffffffffff", "%I128d"<span style="font-weight: normal;">, &int128</span>);</td>
|
||||
<td><span style="font-weight: normal;">int128</span> = -1</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>Example usage</h2>
|
||||
<p>To do.<br>
|
||||
</p>
|
||||
<hr>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,298 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="content-type"
|
||||
content="text/html; charset=ISO-8859-1">
|
||||
<title>EASprintf</title>
|
||||
<link type="text/css" rel="stylesheet"
|
||||
href="UTFDoc.css">
|
||||
<meta name="author" content="Paul Pedriana">
|
||||
</head>
|
||||
<body style="background-color: rgb(255, 255, 255);">
|
||||
<h1>EASprintf</h1>
|
||||
<h2>Introduction</h2>
|
||||
<p>EAStdC provides a portable
|
||||
version of the C printf family of functions which improves on
|
||||
the C family in the following ways:</p>
|
||||
<ul>
|
||||
<li>Behaves identically on all
|
||||
platforms</li>
|
||||
<li>Provides the full gamut of
|
||||
printf functions, including vsnprintf</li>
|
||||
<li>Is more efficient; executes 20-80% faster. </li>
|
||||
<li>Never allocates memory</li>
|
||||
<li>Provides both 8 and 16 bit
|
||||
versions for all platforms</li>
|
||||
<li>Provides useful
|
||||
extended functionality</li>
|
||||
<li>Complies with the C99
|
||||
standard (except for the %a format, as of this writing)</li>
|
||||
<li>Is readable enough to be
|
||||
traced/debugged by non-experts</li>
|
||||
<li>Is savvy to UTF8 Unicode</li>
|
||||
</ul>
|
||||
<p>The primary disadvantages of
|
||||
EAStdC's printf are:</p>
|
||||
<ul>
|
||||
<li>It doesn't use
|
||||
locale-specific formatting</li>
|
||||
<li>It isn't part of the C/C++
|
||||
standard library</li>
|
||||
</ul>
|
||||
<p>EAStdC doesn't attempt to
|
||||
solve the locale formatting problem because users really are better off
|
||||
using serious locale libraries for such things rather than using the
|
||||
meager support provided by the C standard library. The EALocale library
|
||||
attempts to provide such functionality.</p>
|
||||
<p>EAStdC provides the
|
||||
following functions in 8, 16, and 32 bit versions:
|
||||
</p>
|
||||
<pre><span class="code-example">int Cprintf(WriteFunction8 pWriteFunction, void* pContext, const char8_t* pFormat, ...);
|
||||
int Fprintf(FILE* pFile, const char8_t* pFormat, ...);
|
||||
int Printf(const char8_t* pFormat, ...);
|
||||
int Sprintf(char8_t* pDestination, const char8_t* pFormat, ...);
|
||||
int Snprintf(char8_t* pDestination, size_t n, const char8_t* pFormat, ...);
|
||||
|
||||
int Vcprintf(WriteFunction8 pWriteFunction8, void* pContext, const char8_t* pFormat, va_list arguments);
|
||||
int Vfprintf(FILE* pFile, const char8_t* pFormat, va_list arguments);
|
||||
int Vprintf(const char8_t* pFormat, va_list arguments);
|
||||
int Vsprintf(char8_t* pDestination, const char8_t* pFormat, va_list arguments);
|
||||
int Vsnprintf(char8_t* pDestination, size_t n, const char8_t* pFormat, va_list arguments);<br>int Vscprintf(const char8_t* EA_RESTRICT pFormat, va_list arguments);</span></pre>
|
||||
<p>Also there are:</p>
|
||||
<pre class="code-example">template <typename String>
|
||||
int StringPrintf(String& s, const typename String::value_type* EA_RESTRICT pFormat, ...);</pre>
|
||||
<pre class="code-example">template <typename String>
|
||||
int StringVcprintf(String& s, const typename String::value_type* EA_RESTRICT pFormat, va_list arguments);</pre>
|
||||
<blockquote></blockquote>
|
||||
<h2>Snprintf uses C99 behavior</h2>
|
||||
<p> The EASprintf 'n' functions (Snprintf and Vsnprintf) follow the C99 standard
|
||||
for return value, which is different from some C standard library implementations
|
||||
such as VC++. These functions return the number of characters that would have
|
||||
been written had n been sufficiently large, not counting the terminating null
|
||||
character, or a negative value if an encoding error occurred. Thus, the null-terminated
|
||||
output has been completely written if and only if the returned value is nonnegative
|
||||
and less than n. Another way of saying it is that the return value equal to
|
||||
the strlen of the intended output. See the examples below.</p>
|
||||
<h2>Watch out for common mistakes and security problems</h2>
|
||||
<p> The sprintf family of functions are very convenient but offer numerous opportunities
|
||||
for incorrect usage and security problems. Here is a list of some of the most
|
||||
common issues.</p>
|
||||
<ul>
|
||||
<li>Don't use sprintf unless you are absolutely certain the result will fit
|
||||
into the output buffer. Instead use snprintf.</li>
|
||||
<li>When printing a string, always use <font face="Courier New, Courier, mono" size="-1">printf("%s",
|
||||
pStr)</font> and never <font face="Courier New, Courier, mono" size="-1">printf(pStr)</font>,
|
||||
as the latter may have formatting characters in it.</li>
|
||||
<li>Watch out for platform differences between format types. For example, %u
|
||||
means unsigned int, and you can't use a size_t argument with it on 64 bit
|
||||
platforms. Instead, explicitly cast your arguments to the expected type or
|
||||
use the EASprintf extended format types (see below).</li>
|
||||
<li>Similarly, watch out when passing int8_t and int16_t arguments to EAPrintf
|
||||
(and regular printf), as the compiler will promote them to int and they might
|
||||
not print as you expected, depending on your output format.</li>
|
||||
<li>Watch out for EASprintf's C99 behaviour. C99 behaviour is standard C and
|
||||
is superior to previous C library behaviour, but the previous behaviour exists
|
||||
in the C library today with compilers such as VC++. This behaviour affects
|
||||
the return value of Snprintf/Vsnprintf, and affects the way some format specifiers
|
||||
are rendered.</li>
|
||||
</ul>
|
||||
<h2>Extended Functionality</h2>
|
||||
<p> Printf provides extended
|
||||
format functionality not found in the C99 standard but which is useful
|
||||
nevertheless:</p>
|
||||
<table style="text-align: left; width: 100%;" border="1" cellpadding="2"
|
||||
cellspacing="2">
|
||||
<tbody>
|
||||
<tr style="font-weight: bold;">
|
||||
<td>Format/modifier</td>
|
||||
<td>Description</td>
|
||||
<td>Example</td>
|
||||
<td>Example output</td>
|
||||
</tr>
|
||||
<tr style="font-weight: bold;">
|
||||
<td><span style="font-weight: normal;">b</span></td>
|
||||
<td style="font-weight: normal;">Binary
|
||||
output field type (joins d, i, x, o, etc.).</td>
|
||||
<td><span class="code-example-span">printf("0b%b", 255);<br>
|
||||
printf<span style="font-weight: normal;">("%<span style="font-weight: normal;"><span style="font-weight: normal;">#</span></span>b", 255);</span></span> <span class="code-example-span"><br>
|
||||
<span style="font-weight: normal;">printf<span style="font-weight: normal;">("%<span style="font-weight: normal;"><span style="font-weight: normal;">#</span></span>B", 255);</span> </span></span> </td>
|
||||
<td><span class="code-example-span">0b11111111<br>
|
||||
<span style="font-weight: normal;">0b11111111</span></span> <span class="code-example-span"><br>
|
||||
<span style="font-weight: normal;"><span style="font-weight: normal;">0B11111111</span> </span></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>I8</td>
|
||||
<td>8 bit integer field
|
||||
modifier.</td>
|
||||
<td class="code-example-span">printf("%I8d", 0xff);</td>
|
||||
<td class="code-example-span">-1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>I16</td>
|
||||
<td>16 bit integer field
|
||||
modifier.</td>
|
||||
<td class="code-example-span">printf("%I16u", 0xffff);</td>
|
||||
<td class="code-example-span">65535</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>I32</td>
|
||||
<td>32 bit integer field
|
||||
modifier.</td>
|
||||
<td class="code-example-span">printf("%I32d",
|
||||
0xffffffff);</td>
|
||||
<td class="code-example-span">-1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>I64</td>
|
||||
<td>64 bit integer field
|
||||
modifier.</td>
|
||||
<td class="code-example-span">printf("%I64u",
|
||||
0xffffffffffffffff);</td>
|
||||
<td class="code-example-span">18446744073709551615</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>I128</td>
|
||||
<td>128 bit integer field
|
||||
modifier.</td>
|
||||
<td class="code-example-span">printf("%I128d",
|
||||
0xffffffffffffffffffffffffffffffff);</td>
|
||||
<td class="code-example-span">-1</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>'</td>
|
||||
<td>Display a thousands separator.</td>
|
||||
<td class="code-example-span">printf("%'I16u", 0xffff);</td>
|
||||
<td class="code-example-span">65,535</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>SprintfOrdered</h2>
|
||||
<p>EAStdC also provides an ordered sprintf</p>
|
||||
<p>Ordered printf is like printf except it works on "ordered" printf specifiers. This means that instead of using "%4d %f" we give an order to the arguments via an index and colon, as with "%1:4d %2:f". The point, however, is that you can reorder the indexes, as with "%2:f %1:4d". This is particularly useful for formatted string localization, as different locales use subjects and verbs in different orders.<br>
|
||||
<br>
|
||||
User indexes can start at either 0 or 1. Oprintf detects which is in use as it goes. So the following have identical effect:</p>
|
||||
<pre class="code-example">OPrintf("%1:s" %0:f", 3.0, "hello");
|
||||
OPrintf("%2:s" %1:f", 3.0, "hello");</pre>
|
||||
<p> // User indexes must be contiguous and the behaviour of Oprintf is undefined<br>
|
||||
// if the ordering is non-contiguous. There are debug checks to validate <br>
|
||||
// contiguity, so debug tests should catch mistakes. The following is an <br>
|
||||
// example of non-contiguous ordering, as it is missing a "3:" format:<br>
|
||||
// OPrintf("%1:d" %0:d %3:d", 17, 18, 19, 20);<br>
|
||||
</p>
|
||||
<p>Example usage:</p>
|
||||
<pre><span class="code-example">char16_t buffer[80];</span></pre>
|
||||
<p>// The module provides ordered versions of the printf family of functions:<br>
|
||||
// int OCprintf(WriteFunction pFunction, void* pContext, const char_t* pFormat, ...);<br>
|
||||
// int OFprintf(FILE* pFile, const char_t* pFormat, ...);<br>
|
||||
// int OPrintf(cconst char_t* pFormat, ...);<br>
|
||||
// int OSprintf(char_t* pDestination, const char_t* pFormat, ...);<br>
|
||||
// int OSnprintf(char_t* pDestination, size_t n, const char_t* pFormat, ...);<br>
|
||||
//<br>
|
||||
// int OVcprintf(WriteFunction pFunction, void* pContext, const char_t* pFormat, va_list arguments);<br>
|
||||
// int OVfprintf(FILE* pFile, const char_t* pFormat, va_list arguments);<br>
|
||||
// int OVprintf(const char_t* pFormat, va_list arguments);<br>
|
||||
// int OVsprintf(char_t* pDestination, const char_t* pFormat, va_list arguments);<br>
|
||||
// int OVsnprintf(char_t* pDestination, size_t n, const char_t* pFormat, va_list arguments);<br>
|
||||
// int OVscprintf(const char* pFormat, va_list arguments);<br>
|
||||
//<br>
|
||||
// Ordered printf is like printf except it works on "ordered" printf specifiers.<br>
|
||||
// This means that instead of using "%4d %f" we give an order to the arguments via <br>
|
||||
// an index and colon, as with "%1:4d %2:f". The point, however, is that you can <br>
|
||||
// reorder the indexes, as with "%2:f %1:4d". This is particularly useful for <br>
|
||||
// formatted string localization, as different locales use subjects and verbs<br>
|
||||
// in different orders.<br>
|
||||
//<br>
|
||||
// User indexes can start at either 0 or 1. Oprintf detects which is in use as <br>
|
||||
// it goes. So the following have identical effect:<br>
|
||||
// OPrintf("%1:s" %0:f", 3.0, "hello");<br>
|
||||
// OPrintf("%2:s" %1:f", 3.0, "hello");<br>
|
||||
//<br>
|
||||
// User indexes must be contiguous and the behaviour of Oprintf is undefined<br>
|
||||
// if the ordering is non-contiguous. There are debug checks to validate <br>
|
||||
// contiguity, so debug tests should catch mistakes. The following is an <br>
|
||||
// example of non-contiguous ordering, as it is missing a "3:" format:<br>
|
||||
// OPrintf("%1:d" %0:d %3:d", 17, 18, 19, 20);<br>
|
||||
/////////////////////////////////////////////////////////////////////////////<br>
|
||||
</p>
|
||||
<h2>Example usage</h2>
|
||||
<p>All examples presume the #include of EASprintf.h.</p>
|
||||
<p>Snprintf usage:</p>
|
||||
<pre><span class="code-example">char16_t buffer[80];
|
||||
int nStrlen = Snprintf16(buffer, 80, "Columbus arrived in %d.", 1492);
|
||||
|
||||
if((unsigned)nStrlen < 80) // Cast to unsigned in order to make any negative values be positive and > 80.
|
||||
puts("success");</span></pre>
|
||||
<p>How to write a function that takes variable arguments (e.g. ...) and passes
|
||||
them to EASprintf:</p>
|
||||
<pre><span class="code-example">#include <stdarg.h>
|
||||
|
||||
void CustomFormattedOutput(const char* pFormat, ...)
|
||||
{
|
||||
va_list arguments;
|
||||
va_start(arguments, pFormat);
|
||||
Vprintf8(pFormat, arguments);
|
||||
va_end(arguments);
|
||||
}</span></pre>
|
||||
<p>How to write a function that does custom formatted output to a buffer that
|
||||
is resized as needed for it. This is useful for the implementation of fail-safe
|
||||
utility functions and for debug tracing systems, among other things.</p>
|
||||
<pre><span class="code-example">#include <stdarg.h>
|
||||
#include <string>
|
||||
|
||||
<span class="code-example-comment">// This is a generic function for doing a sprintf into a C++ std::string object.
|
||||
// If the string object lacks enough space for the output, then the string will
|
||||
// be resized to exactly fit the output.
|
||||
</span>size_t StringSprintf(std::string& s, const char* pFormat, ...)
|
||||
{
|
||||
va_list arguments;
|
||||
va_start(arguments, pFormat);
|
||||
|
||||
if(s.size() < s.capacity())
|
||||
s.resize(s.capacity());
|
||||
|
||||
const int nStrlen = Vsnprintf8(const_cast<char*>(s.data()), s.capacity() + 1, pFormat, arguments);
|
||||
|
||||
va_end(arguments);
|
||||
|
||||
if(nStrlen > (int)s.size())
|
||||
{
|
||||
s.resize(nStrlen);
|
||||
Vsnprintf8(const_cast<char*>(s.data()), s.capacity() + 1, pFormat, arguments);
|
||||
|
||||
return (size_t)nStrlen;
|
||||
}</span></pre>
|
||||
<p>Write to the C stderr stream:</p>
|
||||
<pre><span class="code-example">#include <stdio.h>
|
||||
|
||||
Fprintf8(stderr, "Columbus arrived in %d.", 1492);</span></pre>
|
||||
<p>Vsscanf usage. A complete discussion of the ins and outs of vsscanf are currently
|
||||
beyond the scope of this document. The scanf found in EAPrintf acts the same
|
||||
as with the C++ standard, so you can read about that elsewhere for the time
|
||||
being.</p>
|
||||
<pre><span class="code-example">char16_t buffer[64] = EAText16("Columbus arrived in 1492");
|
||||
int year;
|
||||
|
||||
Vsscanf16(buffer, "Columbus arrived in %d.", &year);</span></pre>
|
||||
<h2>Interface</h2>
|
||||
<p>Printf family</p>
|
||||
<pre><span class="code-example">int Fprintf8(FILE* pFile, const char8_t* pFormat, ...);<br>int Printf8(const char8_t* pFormat, ...);<br>int Sprintf8(char8_t* pDestination, const char8_t* pFormat, ...);<br>int Snprintf8(char8_t* pDestination, size_t n, const char8_t* pFormat, ...);<br><br>int Fprintf16(FILE* pFile, const char16_t* pFormat, ...);<br>int Printf16(const char16_t* pFormat, ...);<br>int Sprintf16(char16_t* pDestination, const char16_t* pFormat, ...);<br>int Snprintf16(char16_t* pDestination, size_t n, const char16_t* pFormat, ...);<br></span></pre>
|
||||
<p>Vprintf family</p>
|
||||
<pre><span class="code-example"><span class="code-example-comment">/// Note that vsnprintf was not added to the C standard until C99.<br>/// Here we follow the C99 standard and have the return value of vsnprintf <br>/// return the number of required characters to complete the formatted string.<br>/// This is more useful than the way some libraries implement vsnprintf by <br>/// returning -1 if there isn't enough space. The return value is -1 if there <br>/// was an "encoding error" or the implementation was unable to return a <br>/// value > n upon lack of sufficient space as per the C99 standard.<br>///<br>/// Specification:<br>/// The vsnprintf function is equivalent to snprintf, with the variable <br>/// argument list replaced by arguments, which shall have been initialized <br>/// by the va_start macro (and possibly subsequent va_arg calls). <br>/// The vsnprintf function does not invoke the va_end macro. If copying <br>/// takes place between objects that overlap, the behavior is undefined.<br>///<br>/// The vsnprintf function returns the number of characters that would <br>/// have been written had n been sufficiently large, not counting the <br>/// terminating null character, or a neg ative value if an encoding error <br>/// occurred. Thus, the null-terminated output has been completely written <br>/// if and only if the returned value is nonnegative and less than n.<br>///<br></span>int Vfprintf8(FILE* pFile, const char8_t* pFormat, va_list arguments);<br>int Vprintf8(const char8_t* pFormat, va_list arguments);<br>int Vsprintf8(char8_t* pDestination, const char8_t* pFormat, va_list arguments);<br>int Vsnprintf8(char8_t* pDestination, size_t n, const char8_t* pFormat, va_list arguments);<br><br>int Vfprintf16(FILE* pFile, const char16_t* pFormat, va_list arguments);<br>int Vprintf16(const char16_t* pFormat, va_list arguments);<br>int Vsprintf16(char16_t* pDestination, const char16_t* pFormat, va_list arguments);<br>int Vsnprintf16(char16_t* pDestination, size_t n, const char16_t* pFormat, va_list arguments);<br></span><br>
|
||||
</pre>
|
||||
<hr>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
</body>
|
||||
</html>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user