mirror of
https://github.com/yuzu-emu/FasTC.git
synced 2025-01-03 00:45:40 +00:00
FasTC: Remove everything except what is required for ASTC support.
This commit is contained in:
parent
6171a48b6a
commit
9c4cd7abde
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -1,3 +0,0 @@
|
|||
[submodule "Windows"]
|
||||
path = Windows
|
||||
url = https://github.com/Mokosha/FasTC-MSVCLibs.git
|
|
@ -1,162 +0,0 @@
|
|||
# Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
# <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
IF(NOT "" STREQUAL "${AVPCLLIB_ROOT}")
|
||||
INCLUDE_DIRECTORIES(${AVPCLLIB_INCLUDE_DIR})
|
||||
SET(FOUND_NVTT_BPTC_EXPORT TRUE)
|
||||
ENDIF()
|
||||
|
||||
INCLUDE(CheckCXXSourceRuns)
|
||||
|
||||
IF( NOT HAS_INLINE_ASSEMBLY AND NOT HAS_INLINE_ASSEMBLY_WITH_FLAGS )
|
||||
SET( NO_INLINE_ASSEMBLY true )
|
||||
ENDIF()
|
||||
|
||||
# Check to see whether or not our compiler supports atomic operations
|
||||
IF( ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR
|
||||
${CMAKE_C_COMPILER_ID} STREQUAL "Clang" )
|
||||
SET( COMPILER_CLANG True )
|
||||
ELSEIF( ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" OR
|
||||
${CMAKE_C_COMPILER_ID} STREQUAL "GNU" )
|
||||
SET( COMPILER_GNU True )
|
||||
ENDIF()
|
||||
|
||||
IF( COMPILER_CLANG OR COMPILER_GNU )
|
||||
|
||||
CHECK_CXX_SOURCE_RUNS("
|
||||
int main() {
|
||||
int x = 0;
|
||||
__sync_fetch_and_add(&x, 1);
|
||||
return !x;
|
||||
}"
|
||||
HAS_GCC_ATOMICS
|
||||
)
|
||||
|
||||
ELSEIF( MSVC )
|
||||
|
||||
CHECK_CXX_SOURCE_RUNS("
|
||||
#include <Windows.h>
|
||||
int main() {
|
||||
unsigned int val;
|
||||
unsigned int *x = (unsigned int *)_aligned_malloc(sizeof(int), 32);
|
||||
*x = 0;
|
||||
val = InterlockedIncrement(x);
|
||||
_aligned_free(x);
|
||||
return !val;
|
||||
}"
|
||||
HAS_MSVC_ATOMICS
|
||||
)
|
||||
|
||||
ENDIF()
|
||||
|
||||
IF( HAS_MSVC_ATOMICS OR HAS_GCC_ATOMICS )
|
||||
SET(HAS_ATOMICS true)
|
||||
ENDIF()
|
||||
|
||||
CONFIGURE_FILE(
|
||||
"config/BPTCConfig.h.in"
|
||||
"include/FasTC/BPTCConfig.h"
|
||||
)
|
||||
|
||||
SET(LIBRARY_HEADERS
|
||||
"include/FasTC/BPTCCompressor.h"
|
||||
"include/FasTC/Shapes.h"
|
||||
)
|
||||
|
||||
SET( HEADERS
|
||||
config/BPTCConfig.h.in
|
||||
src/AnchorTables.h
|
||||
src/CompressionMode.h
|
||||
src/RGBAEndpoints.h
|
||||
src/ParallelStage.h
|
||||
${LIBRARY_HEADERS}
|
||||
)
|
||||
|
||||
SET( SOURCES
|
||||
src/Compressor.cpp
|
||||
src/Decompressor.cpp
|
||||
src/RGBAEndpoints.cpp
|
||||
src/ParallelStage.cpp
|
||||
)
|
||||
|
||||
IF( HAS_SSE_41 )
|
||||
|
||||
IF ( HAS_SSE_POPCNT )
|
||||
IF( MSVC )
|
||||
ADD_DEFINITIONS( /arch:SSE4.2 )
|
||||
ELSE() #Assume GCC
|
||||
ADD_DEFINITIONS( -msse4.2 )
|
||||
ENDIF()
|
||||
ELSE()
|
||||
IF( MSVC )
|
||||
ADD_DEFINITIONS( /arch:SSE4.1 )
|
||||
ELSE() #Assume GCC
|
||||
ADD_DEFINITIONS( -msse4.1 )
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
SET( HEADERS
|
||||
${HEADERS}
|
||||
src/RGBAEndpointsSIMD.h
|
||||
src/CompressionModeSIMD.h
|
||||
)
|
||||
|
||||
SET( SOURCES
|
||||
${SOURCES}
|
||||
src/CompressorSIMD.cpp
|
||||
src/RGBAEndpointsSIMD.cpp
|
||||
)
|
||||
ENDIF( HAS_SSE_41 )
|
||||
|
||||
IF( HAS_INLINE_ASSEMBLY_WITH_FLAGS )
|
||||
IF( MSVC )
|
||||
# !FIXME!
|
||||
ELSE()
|
||||
ADD_DEFINITIONS( -fasm-blocks )
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF(NOT "" STREQUAL "${AVPCLLIB_ROOT}")
|
||||
SET( SOURCES
|
||||
${SOURCES}
|
||||
src/CompressNVTT.cpp
|
||||
)
|
||||
ENDIF()
|
||||
|
||||
SET(BPTC_INCLUDES_DIR ${FasTC_BINARY_DIR}/BPTCEncoder/include/FasTC)
|
||||
|
||||
INCLUDE_DIRECTORIES(${FasTC_SOURCE_DIR}/Base/include)
|
||||
INCLUDE_DIRECTORIES(${FasTC_BINARY_DIR}/Base/include)
|
||||
INCLUDE_DIRECTORIES(${FasTC_SOURCE_DIR}/BPTCEncoder/include)
|
||||
INCLUDE_DIRECTORIES(${FasTC_BINARY_DIR}/BPTCEncoder/include)
|
||||
|
||||
ADD_LIBRARY( BPTCEncoder
|
||||
${HEADERS}
|
||||
${SOURCES}
|
||||
)
|
||||
|
||||
INSTALL(TARGETS BPTCEncoder EXPORT FasTCTargets ARCHIVE DESTINATION lib COMPONENT lib)
|
||||
INSTALL(
|
||||
FILES ${LIBRARY_HEADERS} "${BPTC_INCLUDES_DIR}/BPTCConfig.h"
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/FasTC
|
||||
COMPONENT dev)
|
||||
|
||||
TARGET_LINK_LIBRARIES( BPTCEncoder FasTCBase )
|
||||
|
||||
IF(NOT "" STREQUAL "${AVPCLLIB_ROOT}")
|
||||
TARGET_LINK_LIBRARIES( BPTCEncoder avpcl )
|
||||
ENDIF()
|
|
@ -1,30 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
// BPTCConfig.h.in -- This file contains variables that are introduced
|
||||
// explicitly by the CMake build process.
|
||||
|
||||
// Do we have the proper popcnt instruction defined?
|
||||
#cmakedefine NO_INLINE_ASSEMBLY
|
||||
#cmakedefine HAS_SSE_POPCNT
|
||||
#cmakedefine HAS_SSE_41
|
||||
|
||||
#cmakedefine HAS_ATOMICS
|
||||
#cmakedefine HAS_GCC_ATOMICS
|
||||
#cmakedefine HAS_MSVC_ATOMICS
|
||||
|
||||
#cmakedefine FOUND_NVTT_BPTC_EXPORT
|
|
@ -1,219 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
// The original lisence from the code available at the following location:
|
||||
// http://software.intel.com/en-us/vcsource/samples/fast-texture-compression
|
||||
//
|
||||
// This code has been modified significantly from the original.
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright 2011 Intel Corporation
|
||||
// All Rights Reserved
|
||||
//
|
||||
// Permission is granted to use, copy, distribute and prepare derivative works
|
||||
// of this software for any purpose and without fee, provided, that the above
|
||||
// copyright notice and this statement appear in all copies. Intel makes no
|
||||
// representations about the suitability of this software for any purpose. THIS
|
||||
// SOFTWARE IS PROVIDED "AS IS." INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES,
|
||||
// EXPRESS OR IMPLIED, AND ALL LIABILITY, INCLUDING CONSEQUENTIAL AND OTHER
|
||||
// INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE, INCLUDING LIABILITY FOR
|
||||
// INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not assume
|
||||
// any responsibility for any errors which may appear in this software nor any
|
||||
// responsibility to update it.
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef BPTCENCODER_INCLUDE_BPTCCOMPRESSOR_H_
|
||||
#define BPTCENCODER_INCLUDE_BPTCCOMPRESSOR_H_
|
||||
|
||||
#include "FasTC/CompressionJob.h"
|
||||
#include "FasTC/Pixel.h"
|
||||
|
||||
#include "FasTC/BPTCConfig.h"
|
||||
|
||||
#include <iosfwd>
|
||||
#include <vector>
|
||||
|
||||
namespace BPTCC {
|
||||
// The various available block modes that a BPTC compressor can choose from.
|
||||
// The enum is specialized to be power-of-two values so that an EBlockMode
|
||||
// variable can be used as a bit mask.
|
||||
enum EBlockMode {
|
||||
eBlockMode_Zero = 1,
|
||||
eBlockMode_One = 2,
|
||||
eBlockMode_Two = 4,
|
||||
eBlockMode_Three = 8,
|
||||
eBlockMode_Four = 16,
|
||||
eBlockMode_Five = 32,
|
||||
eBlockMode_Six = 64,
|
||||
eBlockMode_Seven = 128
|
||||
};
|
||||
|
||||
// This is the error metric that is applied to our error measurement algorithm
|
||||
// in order to bias calculation towards results that are more in-line with
|
||||
// how the Human Visual System works. Uniform error means that each color
|
||||
// channel is treated equally. For a while, the widely accepted non-uniform
|
||||
// metric has been to give red 30%, green 59% and blue 11% weight when
|
||||
// computing the error between two pixels.
|
||||
enum ErrorMetric {
|
||||
eErrorMetric_Uniform, // Treats r, g, and b channels equally
|
||||
eErrorMetric_Nonuniform, // { 0.3, 0.59, 0.11 }
|
||||
|
||||
kNumErrorMetrics
|
||||
};
|
||||
|
||||
// A shape consists of an index into the table of shapes and the number
|
||||
// of partitions that the index corresponds to. Different BPTC modes
|
||||
// interpret the shape differently and some are even illegal (such as
|
||||
// having an index >= 16 on mode 0). Hence, each shape corresponds to
|
||||
// these two variables.
|
||||
struct Shape {
|
||||
uint32 m_NumPartitions;
|
||||
uint32 m_Index;
|
||||
};
|
||||
|
||||
// A shape selection can influence the results of the compressor by choosing
|
||||
// different modes to compress or not compress. The shape index is a value
|
||||
// between zero and sixty-four that corresponds to one of the available
|
||||
// partitioning schemes defined by the BPTC format.
|
||||
struct ShapeSelection {
|
||||
// This is the number of valid shapes in m_Shapes
|
||||
uint32 m_NumShapesToSearch;
|
||||
|
||||
// These are the shape indices to use when evaluating shapes.
|
||||
// I.e. the shapes that the compressor will try to optimize.
|
||||
Shape m_Shapes[10];
|
||||
|
||||
// This is the additional mask to prevent modes once shape selection
|
||||
// is done. This value is &-ed with m_BlockModes from CompressionSettings
|
||||
// to determine what the final considered blocks are.
|
||||
uint32 m_SelectedModes;
|
||||
|
||||
// Defaults
|
||||
ShapeSelection()
|
||||
: m_NumShapesToSearch(0)
|
||||
, m_SelectedModes(static_cast<EBlockMode>(0xFF))
|
||||
{ }
|
||||
};
|
||||
|
||||
// A shape selection function is one that selects a BPTC shape from a given
|
||||
// block position and pixel array.
|
||||
typedef ShapeSelection (*ShapeSelectionFn)
|
||||
(uint32 x, uint32 y, const uint32 pixels[16], const void *userData);
|
||||
|
||||
// Compression parameters used to control the BPTC compressor. Each of the
|
||||
// values has a default, so this is not strictly required to perform
|
||||
// compression, but some aspects of the compressor can be user-defined or
|
||||
// overridden.
|
||||
struct CompressionSettings {
|
||||
// The shape selection function to use during compression. The default (when
|
||||
// this variable is set to NULL) is to use the diagonal of the axis-aligned
|
||||
// bounding box of every partition to estimate the error using that
|
||||
// partition would accrue. The shape with the least error is then chosen.
|
||||
// This procedure is done for both two and three partition shapes, and then
|
||||
// every block mode is still available.
|
||||
ShapeSelectionFn m_ShapeSelectionFn;
|
||||
|
||||
// The user data passed to the shape selection function.
|
||||
const void *m_ShapeSelectionUserData;
|
||||
|
||||
// The block modes that the compressor will consider during compression.
|
||||
// This variable is a bit mask of EBlockMode values and by default contains
|
||||
// every mode. This setting can be used to further restrict the search space
|
||||
// and increase compression times.
|
||||
uint32 m_BlockModes;
|
||||
|
||||
// See the description for ErrorMetric.
|
||||
ErrorMetric m_ErrorMetric;
|
||||
|
||||
// The number of simulated annealing steps to perform per refinement
|
||||
// iteration. In general, a larger number produces better results. The
|
||||
// default is set to 50. This metric works on a logarithmic scale -- twice
|
||||
// the value will double the compute time, but only decrease the error by
|
||||
// two times a factor.
|
||||
uint32 m_NumSimulatedAnnealingSteps;
|
||||
|
||||
CompressionSettings()
|
||||
: m_ShapeSelectionFn(NULL)
|
||||
, m_ShapeSelectionUserData(NULL)
|
||||
, m_BlockModes(static_cast<EBlockMode>(0xFF))
|
||||
, m_ErrorMetric(eErrorMetric_Uniform)
|
||||
, m_NumSimulatedAnnealingSteps(50)
|
||||
{ }
|
||||
};
|
||||
|
||||
// Retreives a float4 pointer for the r, g, b, a weights for each color
|
||||
// channel, in that order.
|
||||
const float *GetErrorMetric(ErrorMetric e);
|
||||
|
||||
// Compress the image given as RGBA data to BPTC format. Width and Height are
|
||||
// the dimensions of the image in pixels.
|
||||
void Compress(const FasTC::CompressionJob &,
|
||||
CompressionSettings settings = CompressionSettings());
|
||||
|
||||
// Perform a compression while recording all of the choices the compressor
|
||||
// made into a list of statistics. We can use this to see whether or not
|
||||
// certain heuristics are working, such as whether or not certain modes are
|
||||
// being chosen more often than others, etc.
|
||||
void CompressWithStats(const FasTC::CompressionJob &, std::ostream *logStream,
|
||||
CompressionSettings settings = CompressionSettings());
|
||||
|
||||
#ifdef HAS_SSE_41
|
||||
// Compress the image given as RGBA data to BPTC format using an algorithm
|
||||
// optimized for SIMD enabled platforms. Width and Height are the dimensions
|
||||
// of the image in pixels.
|
||||
void CompressImageBPTCSIMD(const unsigned char* inBuf, unsigned char* outBuf,
|
||||
unsigned int width, unsigned int height);
|
||||
#endif
|
||||
|
||||
#ifdef HAS_ATOMICS
|
||||
// This is a threadsafe version of the compression function that is designed
|
||||
// to compress a list of textures. If this function is called with the same
|
||||
// argument from multiple threads, they will work together to compress all of
|
||||
// the images in the list.
|
||||
void CompressAtomic(FasTC::CompressionJobList &);
|
||||
#endif
|
||||
|
||||
#ifdef FOUND_NVTT_BPTC_EXPORT
|
||||
// These functions take the same arguments as Compress and CompressWithStats,
|
||||
// but they use the NVTT compressor if it was supplied to CMake.
|
||||
void CompressNVTT(const FasTC::CompressionJob &);
|
||||
void CompressNVTTWithStats(const FasTC::CompressionJob &,
|
||||
std::ostream *logStream);
|
||||
#endif
|
||||
|
||||
// A logical BPTC block. Each block has a mode, up to three
|
||||
// endpoint pairs, a shape, and a per-pixel index to choose
|
||||
// the proper endpoints.
|
||||
struct LogicalBlock {
|
||||
EBlockMode m_Mode;
|
||||
Shape m_Shape;
|
||||
FasTC::Pixel m_Endpoints[3][2];
|
||||
uint32 m_Indices[16];
|
||||
uint32 m_AlphaIndices[16];
|
||||
};
|
||||
|
||||
// Decompress the data stored into logical blocks
|
||||
void DecompressLogical(const FasTC::DecompressionJob &,
|
||||
std::vector<LogicalBlock> *out);
|
||||
|
||||
// Decompress the image given as BPTC data to R8G8B8A8 format.
|
||||
void Decompress(const FasTC::DecompressionJob &);
|
||||
} // namespace BPTCC
|
||||
|
||||
#endif // BPTCENCODER_INCLUDE_BPTCCOMPRESSOR_H_
|
|
@ -1,83 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#ifndef BPTCENCODER_INCLUDE_SHAPES_H_
|
||||
#define BPTCENCODER_INCLUDE_SHAPES_H_
|
||||
|
||||
namespace BPTCC {
|
||||
|
||||
static const uint32 kNumShapes2 = 64;
|
||||
static const uint16 kShapeMask2[kNumShapes2] = {
|
||||
0xcccc, 0x8888, 0xeeee, 0xecc8, 0xc880, 0xfeec, 0xfec8, 0xec80,
|
||||
0xc800, 0xffec, 0xfe80, 0xe800, 0xffe8, 0xff00, 0xfff0, 0xf000,
|
||||
0xf710, 0x008e, 0x7100, 0x08ce, 0x008c, 0x7310, 0x3100, 0x8cce,
|
||||
0x088c, 0x3110, 0x6666, 0x366c, 0x17e8, 0x0ff0, 0x718e, 0x399c,
|
||||
0xaaaa, 0xf0f0, 0x5a5a, 0x33cc, 0x3c3c, 0x55aa, 0x9696, 0xa55a,
|
||||
0x73ce, 0x13c8, 0x324c, 0x3bdc, 0x6996, 0xc33c, 0x9966, 0x0660,
|
||||
0x0272, 0x04e4, 0x4e40, 0x2720, 0xc936, 0x936c, 0x39c6, 0x639c,
|
||||
0x9336, 0x9cc6, 0x817e, 0xe718, 0xccf0, 0x0fcc, 0x7744, 0xee22
|
||||
};
|
||||
|
||||
static const uint32 kNumShapes3 = 64;
|
||||
static const uint16 kShapeMask3[kNumShapes3][2] = {
|
||||
{0xfecc, 0xf600}, {0xffc8, 0x7300}, {0xff90, 0x3310}, {0xecce, 0x00ce},
|
||||
{0xff00, 0xcc00}, {0xcccc, 0xcc00}, {0xffcc, 0x00cc}, {0xffcc, 0x3300},
|
||||
{0xff00, 0xf000}, {0xfff0, 0xf000}, {0xfff0, 0xff00}, {0xcccc, 0x8888},
|
||||
{0xeeee, 0x8888}, {0xeeee, 0xcccc}, {0xffec, 0xec80}, {0x739c, 0x7310},
|
||||
{0xfec8, 0xc800}, {0x39ce, 0x3100}, {0xfff0, 0xccc0}, {0xfccc, 0x0ccc},
|
||||
{0xeeee, 0xee00}, {0xff88, 0x7700}, {0xeec0, 0xcc00}, {0x7730, 0x3300},
|
||||
{0x0cee, 0x00cc}, {0xffcc, 0xfc88}, {0x6ff6, 0x0660}, {0xff60, 0x6600},
|
||||
{0xcbbc, 0xc88c}, {0xf966, 0xf900}, {0xceec, 0x0cc0}, {0xff10, 0x7310},
|
||||
{0xff80, 0xec80}, {0xccce, 0x08ce}, {0xeccc, 0xec80}, {0x6666, 0x4444},
|
||||
{0x0ff0, 0x0f00}, {0x6db6, 0x4924}, {0x6bd6, 0x4294}, {0xcf3c, 0x0c30},
|
||||
{0xc3fc, 0x03c0}, {0xffaa, 0xff00}, {0xff00, 0x5500}, {0xfcfc, 0xcccc},
|
||||
{0xcccc, 0x0c0c}, {0xf6f6, 0x6666}, {0xaffa, 0x0ff0}, {0xfff0, 0x5550},
|
||||
{0xfaaa, 0xf000}, {0xeeee, 0x0e0e}, {0xf8f8, 0x8888}, {0xfff0, 0x9990},
|
||||
{0xeeee, 0xe00e}, {0x8ff8, 0x8888}, {0xf666, 0xf000}, {0xff00, 0x9900},
|
||||
{0xff66, 0xff00}, {0xcccc, 0xc00c}, {0xcffc, 0xcccc}, {0xf000, 0x9000},
|
||||
{0x8888, 0x0808}, {0xfefe, 0xeeee}, {0xfffa, 0xfff0}, {0x7bde, 0x7310}
|
||||
};
|
||||
|
||||
static uint8 GetSubsetForIndex(int idx, const int shapeIdx, const int nSubs) {
|
||||
int subset = 0;
|
||||
|
||||
switch(nSubs) {
|
||||
case 2:
|
||||
{
|
||||
subset = !!((1 << idx) & kShapeMask2[shapeIdx]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
{
|
||||
if(1 << idx & kShapeMask3[shapeIdx][0])
|
||||
subset = 1 + !!((1 << idx) & kShapeMask3[shapeIdx][1]);
|
||||
else
|
||||
subset = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return subset;
|
||||
}
|
||||
|
||||
} // namespace BPTCC
|
||||
|
||||
#endif // BPTCENCODER_INCLUDE_SHAPES_H_
|
|
@ -1,85 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "FasTC/Shapes.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
static const int kAnchorIdx2[BPTCC::kNumShapes2] = {
|
||||
15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 15, 15, 15, 15, 15, 15, 15,
|
||||
15, 2, 8, 2, 2, 8, 8, 15,
|
||||
2 , 8, 2, 2, 8, 8, 2, 2,
|
||||
15, 15, 6, 8, 2, 8, 15, 15,
|
||||
2 , 8, 2, 2, 2, 15, 15, 6,
|
||||
6 , 2, 6, 8, 15, 15, 2, 2,
|
||||
15, 15, 15, 15, 15, 2, 2, 15
|
||||
};
|
||||
|
||||
static const int kAnchorIdx3[2][BPTCC::kNumShapes3] = {
|
||||
{3, 3, 15, 15, 8, 3, 15, 15,
|
||||
8 , 8, 6, 6, 6, 5, 3, 3,
|
||||
3 , 3, 8, 15, 3, 3, 6, 10,
|
||||
5 , 8, 8, 6, 8, 5, 15, 15,
|
||||
8 , 15, 3, 5, 6, 10, 8, 15,
|
||||
15, 3, 15, 5, 15, 15, 15, 15,
|
||||
3 , 15, 5, 5, 5, 8, 5, 10,
|
||||
5 , 10, 8, 13, 15, 12, 3, 3 },
|
||||
|
||||
{15, 8, 8, 3, 15, 15, 3, 8,
|
||||
15 , 15, 15, 15, 15, 15, 15, 8,
|
||||
15 , 8, 15, 3, 15, 8, 15, 8,
|
||||
3 , 15, 6, 10, 15, 15, 10, 8,
|
||||
15 , 3, 15, 10, 10, 8, 9, 10,
|
||||
6 , 15, 8, 15, 3, 6, 6, 8,
|
||||
15 , 3, 15, 15, 15, 15, 15, 15,
|
||||
15 , 15, 15, 15, 3, 15, 15, 8 }
|
||||
};
|
||||
|
||||
namespace BPTCC {
|
||||
|
||||
static uint32 GetAnchorIndexForSubset(
|
||||
int subset, const int shapeIdx, const int nSubsets
|
||||
) {
|
||||
|
||||
int anchorIdx = 0;
|
||||
switch(subset) {
|
||||
case 1:
|
||||
{
|
||||
if(nSubsets == 2) {
|
||||
anchorIdx = kAnchorIdx2[shapeIdx];
|
||||
} else {
|
||||
anchorIdx = kAnchorIdx3[0][shapeIdx];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
assert(nSubsets == 3);
|
||||
anchorIdx = kAnchorIdx3[1][shapeIdx];
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return anchorIdx;
|
||||
}
|
||||
|
||||
} // namespace BPTCC
|
|
@ -1,967 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
// The original lisence from the code available at the following location:
|
||||
// http://software.intel.com/en-us/vcsource/samples/fast-texture-compression
|
||||
//
|
||||
// This code has been modified significantly from the original.
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Copyright 2011 Intel Corporation
|
||||
// All Rights Reserved
|
||||
//
|
||||
// Permission is granted to use, copy, distribute and prepare derivative works of this
|
||||
// software for any purpose and without fee, provided, that the above copyright notice
|
||||
// and this statement appear in all copies. Intel makes no representations about the
|
||||
// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS."
|
||||
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
|
||||
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
|
||||
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not
|
||||
// assume any responsibility for any errors which may appear in this software nor any
|
||||
// responsibility to update it.
|
||||
//
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
// Each value from 0 to 255 can be exactly interpolated between two other values
|
||||
// with 7 bit precision. BC7 Mode 5 gives us this precision, so we can use look-up
|
||||
// tables to speed up this precision by allowing every value to be 1/3 of the way
|
||||
// between the two colors specified.
|
||||
/*
|
||||
UINT nbits = 7;
|
||||
UINT lastNum = -1;
|
||||
UINT vals[255];
|
||||
UINT valIdx = 0;
|
||||
for(UINT i = 0; i < 256; i++) {
|
||||
UINT num = (i >> (8 - nbits));
|
||||
num <<= (8-nbits);
|
||||
num |= i >> nbits;
|
||||
|
||||
if(num != lastNum) {
|
||||
lastNum = num;
|
||||
vals[valIdx++] = num;
|
||||
}
|
||||
}
|
||||
|
||||
for(UINT i = 0; i < 256; i++) {
|
||||
|
||||
UINT mindist = 0xFFFFFFFF;
|
||||
UINT minj = 0, mink = 0;
|
||||
|
||||
UINT tableEntry[2] = { 0, 0 };
|
||||
|
||||
mindist = 0xFFFFFFFF;
|
||||
minj = 0, mink = 0;
|
||||
|
||||
for(UINT j = 0; j < valIdx; j++) {
|
||||
for(UINT k = 0; k < valIdx ; k++) {
|
||||
|
||||
UINT combo = (43 * vals[j] + 21 * vals[k] + 32) >> 6;
|
||||
UINT dist = ((i > combo) ? i - combo : combo - i);
|
||||
if( dist < mindist )
|
||||
{
|
||||
mindist = dist;
|
||||
minj = j;
|
||||
mink = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(mindist == 0);
|
||||
|
||||
tableEntry[0] = vals[minj];
|
||||
tableEntry[1] = vals[mink];
|
||||
|
||||
wchar_t tableEntryStr[256];
|
||||
swprintf(tableEntryStr, 256, L"{ 0x%02x, 0x%02x },\n",
|
||||
tableEntry[0] >> (8 - nbits),
|
||||
tableEntry[1] >> (8 - nbits)
|
||||
);
|
||||
OutputDebugString(tableEntryStr);
|
||||
}
|
||||
*/
|
||||
static unsigned char Optimal7CompressBC7Mode5[256][2] = {
|
||||
{ 0x00, 0x00 },
|
||||
{ 0x00, 0x01 },
|
||||
{ 0x00, 0x03 },
|
||||
{ 0x00, 0x04 },
|
||||
{ 0x00, 0x06 },
|
||||
{ 0x00, 0x07 },
|
||||
{ 0x00, 0x09 },
|
||||
{ 0x00, 0x0a },
|
||||
{ 0x00, 0x0c },
|
||||
{ 0x00, 0x0d },
|
||||
{ 0x00, 0x0f },
|
||||
{ 0x00, 0x10 },
|
||||
{ 0x00, 0x12 },
|
||||
{ 0x00, 0x14 },
|
||||
{ 0x00, 0x15 },
|
||||
{ 0x00, 0x17 },
|
||||
{ 0x00, 0x18 },
|
||||
{ 0x00, 0x1a },
|
||||
{ 0x00, 0x1b },
|
||||
{ 0x00, 0x1d },
|
||||
{ 0x00, 0x1e },
|
||||
{ 0x00, 0x20 },
|
||||
{ 0x00, 0x21 },
|
||||
{ 0x00, 0x23 },
|
||||
{ 0x00, 0x24 },
|
||||
{ 0x00, 0x26 },
|
||||
{ 0x00, 0x27 },
|
||||
{ 0x00, 0x29 },
|
||||
{ 0x00, 0x2a },
|
||||
{ 0x00, 0x2c },
|
||||
{ 0x00, 0x2d },
|
||||
{ 0x00, 0x2f },
|
||||
{ 0x00, 0x30 },
|
||||
{ 0x00, 0x32 },
|
||||
{ 0x00, 0x34 },
|
||||
{ 0x00, 0x35 },
|
||||
{ 0x00, 0x37 },
|
||||
{ 0x00, 0x38 },
|
||||
{ 0x00, 0x3a },
|
||||
{ 0x00, 0x3b },
|
||||
{ 0x00, 0x3d },
|
||||
{ 0x00, 0x3e },
|
||||
{ 0x00, 0x40 },
|
||||
{ 0x00, 0x41 },
|
||||
{ 0x00, 0x42 },
|
||||
{ 0x00, 0x44 },
|
||||
{ 0x00, 0x45 },
|
||||
{ 0x00, 0x47 },
|
||||
{ 0x00, 0x48 },
|
||||
{ 0x00, 0x4a },
|
||||
{ 0x00, 0x4b },
|
||||
{ 0x00, 0x4d },
|
||||
{ 0x00, 0x4e },
|
||||
{ 0x00, 0x50 },
|
||||
{ 0x00, 0x52 },
|
||||
{ 0x00, 0x53 },
|
||||
{ 0x00, 0x55 },
|
||||
{ 0x00, 0x56 },
|
||||
{ 0x00, 0x58 },
|
||||
{ 0x00, 0x59 },
|
||||
{ 0x00, 0x5b },
|
||||
{ 0x00, 0x5c },
|
||||
{ 0x00, 0x5e },
|
||||
{ 0x00, 0x5f },
|
||||
{ 0x00, 0x61 },
|
||||
{ 0x00, 0x62 },
|
||||
{ 0x00, 0x64 },
|
||||
{ 0x00, 0x65 },
|
||||
{ 0x00, 0x67 },
|
||||
{ 0x00, 0x68 },
|
||||
{ 0x00, 0x6a },
|
||||
{ 0x00, 0x6b },
|
||||
{ 0x00, 0x6d },
|
||||
{ 0x00, 0x6e },
|
||||
{ 0x00, 0x70 },
|
||||
{ 0x00, 0x72 },
|
||||
{ 0x00, 0x73 },
|
||||
{ 0x00, 0x75 },
|
||||
{ 0x00, 0x76 },
|
||||
{ 0x00, 0x78 },
|
||||
{ 0x00, 0x79 },
|
||||
{ 0x00, 0x7b },
|
||||
{ 0x00, 0x7c },
|
||||
{ 0x00, 0x7e },
|
||||
{ 0x00, 0x7f },
|
||||
{ 0x01, 0x7f },
|
||||
{ 0x02, 0x7e },
|
||||
{ 0x03, 0x7e },
|
||||
{ 0x03, 0x7f },
|
||||
{ 0x04, 0x7f },
|
||||
{ 0x05, 0x7e },
|
||||
{ 0x06, 0x7e },
|
||||
{ 0x06, 0x7f },
|
||||
{ 0x07, 0x7f },
|
||||
{ 0x08, 0x7e },
|
||||
{ 0x09, 0x7e },
|
||||
{ 0x09, 0x7f },
|
||||
{ 0x0a, 0x7f },
|
||||
{ 0x0b, 0x7e },
|
||||
{ 0x0c, 0x7e },
|
||||
{ 0x0c, 0x7f },
|
||||
{ 0x0d, 0x7f },
|
||||
{ 0x0e, 0x7e },
|
||||
{ 0x0f, 0x7d },
|
||||
{ 0x0f, 0x7f },
|
||||
{ 0x10, 0x7e },
|
||||
{ 0x11, 0x7e },
|
||||
{ 0x11, 0x7f },
|
||||
{ 0x12, 0x7f },
|
||||
{ 0x13, 0x7e },
|
||||
{ 0x14, 0x7e },
|
||||
{ 0x14, 0x7f },
|
||||
{ 0x15, 0x7f },
|
||||
{ 0x16, 0x7e },
|
||||
{ 0x17, 0x7e },
|
||||
{ 0x17, 0x7f },
|
||||
{ 0x18, 0x7f },
|
||||
{ 0x19, 0x7e },
|
||||
{ 0x1a, 0x7e },
|
||||
{ 0x1a, 0x7f },
|
||||
{ 0x1b, 0x7f },
|
||||
{ 0x1c, 0x7e },
|
||||
{ 0x1d, 0x7e },
|
||||
{ 0x1d, 0x7f },
|
||||
{ 0x1e, 0x7f },
|
||||
{ 0x1f, 0x7e },
|
||||
{ 0x20, 0x7e },
|
||||
{ 0x20, 0x7f },
|
||||
{ 0x21, 0x7f },
|
||||
{ 0x22, 0x7e },
|
||||
{ 0x23, 0x7e },
|
||||
{ 0x23, 0x7f },
|
||||
{ 0x24, 0x7f },
|
||||
{ 0x25, 0x7e },
|
||||
{ 0x26, 0x7e },
|
||||
{ 0x26, 0x7f },
|
||||
{ 0x27, 0x7f },
|
||||
{ 0x28, 0x7e },
|
||||
{ 0x29, 0x7e },
|
||||
{ 0x29, 0x7f },
|
||||
{ 0x2a, 0x7f },
|
||||
{ 0x2b, 0x7e },
|
||||
{ 0x2c, 0x7e },
|
||||
{ 0x2c, 0x7f },
|
||||
{ 0x2d, 0x7f },
|
||||
{ 0x2e, 0x7e },
|
||||
{ 0x2f, 0x7d },
|
||||
{ 0x2f, 0x7f },
|
||||
{ 0x30, 0x7e },
|
||||
{ 0x31, 0x7e },
|
||||
{ 0x31, 0x7f },
|
||||
{ 0x32, 0x7f },
|
||||
{ 0x33, 0x7e },
|
||||
{ 0x34, 0x7e },
|
||||
{ 0x34, 0x7f },
|
||||
{ 0x35, 0x7f },
|
||||
{ 0x36, 0x7e },
|
||||
{ 0x37, 0x7e },
|
||||
{ 0x37, 0x7f },
|
||||
{ 0x38, 0x7f },
|
||||
{ 0x39, 0x7e },
|
||||
{ 0x3a, 0x7e },
|
||||
{ 0x3a, 0x7f },
|
||||
{ 0x3b, 0x7f },
|
||||
{ 0x3c, 0x7e },
|
||||
{ 0x3d, 0x7e },
|
||||
{ 0x3d, 0x7f },
|
||||
{ 0x3e, 0x7f },
|
||||
{ 0x3f, 0x7e },
|
||||
{ 0x40, 0x7d },
|
||||
{ 0x40, 0x7e },
|
||||
{ 0x41, 0x7e },
|
||||
{ 0x41, 0x7f },
|
||||
{ 0x42, 0x7f },
|
||||
{ 0x43, 0x7e },
|
||||
{ 0x44, 0x7e },
|
||||
{ 0x44, 0x7f },
|
||||
{ 0x45, 0x7f },
|
||||
{ 0x46, 0x7e },
|
||||
{ 0x47, 0x7e },
|
||||
{ 0x47, 0x7f },
|
||||
{ 0x48, 0x7f },
|
||||
{ 0x49, 0x7e },
|
||||
{ 0x4a, 0x7e },
|
||||
{ 0x4a, 0x7f },
|
||||
{ 0x4b, 0x7f },
|
||||
{ 0x4c, 0x7e },
|
||||
{ 0x4d, 0x7d },
|
||||
{ 0x4d, 0x7f },
|
||||
{ 0x4e, 0x7e },
|
||||
{ 0x4f, 0x7e },
|
||||
{ 0x4f, 0x7f },
|
||||
{ 0x50, 0x7f },
|
||||
{ 0x51, 0x7e },
|
||||
{ 0x52, 0x7e },
|
||||
{ 0x52, 0x7f },
|
||||
{ 0x53, 0x7f },
|
||||
{ 0x54, 0x7e },
|
||||
{ 0x55, 0x7e },
|
||||
{ 0x55, 0x7f },
|
||||
{ 0x56, 0x7f },
|
||||
{ 0x57, 0x7e },
|
||||
{ 0x58, 0x7e },
|
||||
{ 0x58, 0x7f },
|
||||
{ 0x59, 0x7f },
|
||||
{ 0x5a, 0x7e },
|
||||
{ 0x5b, 0x7e },
|
||||
{ 0x5b, 0x7f },
|
||||
{ 0x5c, 0x7f },
|
||||
{ 0x5d, 0x7e },
|
||||
{ 0x5e, 0x7e },
|
||||
{ 0x5e, 0x7f },
|
||||
{ 0x5f, 0x7f },
|
||||
{ 0x60, 0x7e },
|
||||
{ 0x61, 0x7e },
|
||||
{ 0x61, 0x7f },
|
||||
{ 0x62, 0x7f },
|
||||
{ 0x63, 0x7e },
|
||||
{ 0x64, 0x7e },
|
||||
{ 0x64, 0x7f },
|
||||
{ 0x65, 0x7f },
|
||||
{ 0x66, 0x7e },
|
||||
{ 0x67, 0x7e },
|
||||
{ 0x67, 0x7f },
|
||||
{ 0x68, 0x7f },
|
||||
{ 0x69, 0x7e },
|
||||
{ 0x6a, 0x7e },
|
||||
{ 0x6a, 0x7f },
|
||||
{ 0x6b, 0x7f },
|
||||
{ 0x6c, 0x7e },
|
||||
{ 0x6d, 0x7d },
|
||||
{ 0x6d, 0x7f },
|
||||
{ 0x6e, 0x7e },
|
||||
{ 0x6f, 0x7e },
|
||||
{ 0x6f, 0x7f },
|
||||
{ 0x70, 0x7f },
|
||||
{ 0x71, 0x7e },
|
||||
{ 0x72, 0x7e },
|
||||
{ 0x72, 0x7f },
|
||||
{ 0x73, 0x7f },
|
||||
{ 0x74, 0x7e },
|
||||
{ 0x75, 0x7e },
|
||||
{ 0x75, 0x7f },
|
||||
{ 0x76, 0x7f },
|
||||
{ 0x77, 0x7e },
|
||||
{ 0x78, 0x7e },
|
||||
{ 0x78, 0x7f },
|
||||
{ 0x79, 0x7f },
|
||||
{ 0x7a, 0x7e },
|
||||
{ 0x7b, 0x7e },
|
||||
{ 0x7b, 0x7f },
|
||||
{ 0x7c, 0x7f },
|
||||
{ 0x7d, 0x7e },
|
||||
{ 0x7e, 0x7e },
|
||||
{ 0x7e, 0x7f },
|
||||
{ 0x7f, 0x7f }
|
||||
};
|
||||
|
||||
// For each value, we give the best possible compression range for that value with 5 bits.
|
||||
// The first value says whether or not it's
|
||||
// 1 - the midpoint of two other values, or
|
||||
// 0 - 1/3 of the way in between two other values.
|
||||
// If the first value is 1 or 2 then the last two values are the range between which the
|
||||
// value should be interpolated. If the first value is 2, then it should be interpolated
|
||||
// one third of the way from the second to third value...
|
||||
//
|
||||
// The following tables were generated with the following program:
|
||||
/*
|
||||
UINT nbits = 5;
|
||||
UINT lastNum = -1;
|
||||
UINT vals[255];
|
||||
UINT valIdx = 0;
|
||||
for(UINT i = 0; i < 256; i++) {
|
||||
UINT num = (i >> (8 - nbits));
|
||||
num <<= (8-nbits);
|
||||
num |= i >> nbits;
|
||||
|
||||
if(num != lastNum) {
|
||||
lastNum = num;
|
||||
vals[valIdx++] = num;
|
||||
}
|
||||
}
|
||||
|
||||
for(UINT i = 0; i < 256; i++) {
|
||||
|
||||
UINT mindist = 0xFFFFFFFF;
|
||||
UINT minj = 0, mink = 0;
|
||||
|
||||
UINT tableEntry[2][4] = { {1, 0, 0, 0xFFFFFFFF}, {0, 0, 0, 0xFFFFFFFF} };
|
||||
|
||||
for(UINT j = 0; j < valIdx; j++) {
|
||||
for(UINT k = j; k < valIdx ; k++) {
|
||||
|
||||
UINT combo = (vals[j] + vals[k]) / 2;
|
||||
UINT dist = ((i > combo) ? i - combo : combo - i);
|
||||
if( dist < mindist )
|
||||
{
|
||||
mindist = dist;
|
||||
minj = j;
|
||||
mink = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tableEntry[0][1] = vals[minj];
|
||||
tableEntry[0][2] = vals[mink];
|
||||
tableEntry[0][3] = mindist;
|
||||
|
||||
mindist = 0xFFFFFFFF;
|
||||
minj = 0, mink = 0;
|
||||
|
||||
for(UINT j = 0; j < valIdx; j++) {
|
||||
for(UINT k = j; k < valIdx ; k++) {
|
||||
|
||||
UINT combo = (2 * vals[j] + vals[k]) / 3;
|
||||
UINT dist = ((i > combo) ? i - combo : combo - i);
|
||||
if( dist < mindist )
|
||||
{
|
||||
mindist = dist;
|
||||
minj = j;
|
||||
mink = k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tableEntry[1][1] = vals[minj];
|
||||
tableEntry[1][2] = vals[mink];
|
||||
tableEntry[1][3] = mindist;
|
||||
|
||||
wchar_t tableEntryStr[256];
|
||||
if(tableEntry[1][3] > tableEntry[0][3]) {
|
||||
swprintf(tableEntryStr, 256, L"{ { %d, 0x%02x, 0x%02x }, { %d, 0x%02x, 0x%02x } },\n",
|
||||
tableEntry[0][0],
|
||||
tableEntry[0][1] >> (8 - nbits),
|
||||
tableEntry[0][2] >> (8 - nbits),
|
||||
tableEntry[1][0],
|
||||
tableEntry[1][1] >> (8 - nbits),
|
||||
tableEntry[1][2] >> (8 - nbits)
|
||||
);
|
||||
}
|
||||
else {
|
||||
swprintf(tableEntryStr, 256, L"{ { %d, 0x%02x, 0x%02x }, { %d, 0x%02x, 0x%02x } },\n",
|
||||
tableEntry[1][0],
|
||||
tableEntry[1][1] >> (8 - nbits),
|
||||
tableEntry[1][2] >> (8 - nbits),
|
||||
tableEntry[0][0],
|
||||
tableEntry[0][1] >> (8 - nbits),
|
||||
tableEntry[0][2] >> (8 - nbits)
|
||||
);
|
||||
}
|
||||
OutputDebugString(tableEntryStr);
|
||||
}
|
||||
static unsigned char Optimal5CompressDXT1[256][2][3] = {
|
||||
{ { 0, 0x00, 0x00 }, { 1, 0x00, 0x00 } },
|
||||
{ { 0, 0x00, 0x00 }, { 1, 0x00, 0x00 } },
|
||||
{ { 0, 0x00, 0x01 }, { 1, 0x00, 0x00 } },
|
||||
{ { 0, 0x00, 0x01 }, { 1, 0x00, 0x01 } },
|
||||
{ { 1, 0x00, 0x01 }, { 0, 0x00, 0x02 } },
|
||||
{ { 0, 0x00, 0x02 }, { 1, 0x00, 0x01 } },
|
||||
{ { 0, 0x00, 0x02 }, { 1, 0x00, 0x01 } },
|
||||
{ { 0, 0x00, 0x03 }, { 1, 0x00, 0x02 } },
|
||||
{ { 0, 0x00, 0x03 }, { 1, 0x00, 0x02 } },
|
||||
{ { 0, 0x00, 0x03 }, { 1, 0x00, 0x02 } },
|
||||
{ { 0, 0x01, 0x02 }, { 1, 0x00, 0x02 } },
|
||||
{ { 0, 0x00, 0x04 }, { 1, 0x00, 0x03 } },
|
||||
{ { 1, 0x00, 0x03 }, { 0, 0x00, 0x04 } },
|
||||
{ { 0, 0x00, 0x05 }, { 1, 0x00, 0x03 } },
|
||||
{ { 0, 0x00, 0x05 }, { 1, 0x00, 0x03 } },
|
||||
{ { 0, 0x00, 0x06 }, { 1, 0x00, 0x04 } },
|
||||
{ { 0, 0x00, 0x06 }, { 1, 0x00, 0x04 } },
|
||||
{ { 0, 0x00, 0x06 }, { 1, 0x00, 0x04 } },
|
||||
{ { 0, 0x02, 0x03 }, { 1, 0x00, 0x04 } },
|
||||
{ { 0, 0x00, 0x07 }, { 1, 0x00, 0x05 } },
|
||||
{ { 1, 0x00, 0x05 }, { 0, 0x00, 0x07 } },
|
||||
{ { 0, 0x01, 0x06 }, { 1, 0x00, 0x05 } },
|
||||
{ { 0, 0x00, 0x08 }, { 1, 0x00, 0x05 } },
|
||||
{ { 0, 0x00, 0x08 }, { 1, 0x00, 0x06 } },
|
||||
{ { 0, 0x00, 0x09 }, { 1, 0x00, 0x06 } },
|
||||
{ { 0, 0x00, 0x09 }, { 1, 0x00, 0x06 } },
|
||||
{ { 0, 0x00, 0x0a }, { 1, 0x00, 0x06 } },
|
||||
{ { 0, 0x00, 0x0a }, { 1, 0x00, 0x07 } },
|
||||
{ { 1, 0x00, 0x07 }, { 0, 0x00, 0x0a } },
|
||||
{ { 0, 0x02, 0x07 }, { 1, 0x00, 0x07 } },
|
||||
{ { 0, 0x00, 0x0b }, { 1, 0x00, 0x07 } },
|
||||
{ { 0, 0x00, 0x0b }, { 1, 0x01, 0x07 } },
|
||||
{ { 0, 0x01, 0x0a }, { 1, 0x01, 0x07 } },
|
||||
{ { 0, 0x00, 0x0c }, { 1, 0x00, 0x08 } },
|
||||
{ { 0, 0x00, 0x0c }, { 1, 0x00, 0x08 } },
|
||||
{ { 0, 0x00, 0x0d }, { 1, 0x02, 0x07 } },
|
||||
{ { 1, 0x02, 0x07 }, { 0, 0x00, 0x0d } },
|
||||
{ { 1, 0x00, 0x09 }, { 0, 0x00, 0x0e } },
|
||||
{ { 0, 0x00, 0x0e }, { 1, 0x00, 0x09 } },
|
||||
{ { 0, 0x00, 0x0e }, { 1, 0x03, 0x07 } },
|
||||
{ { 0, 0x02, 0x0b }, { 1, 0x03, 0x07 } },
|
||||
{ { 0, 0x00, 0x0f }, { 1, 0x00, 0x0a } },
|
||||
{ { 0, 0x00, 0x0f }, { 1, 0x00, 0x0a } },
|
||||
{ { 0, 0x01, 0x0e }, { 1, 0x00, 0x0a } },
|
||||
{ { 0, 0x00, 0x10 }, { 1, 0x00, 0x0b } },
|
||||
{ { 1, 0x00, 0x0b }, { 0, 0x00, 0x10 } },
|
||||
{ { 0, 0x00, 0x11 }, { 1, 0x00, 0x0b } },
|
||||
{ { 0, 0x00, 0x11 }, { 1, 0x00, 0x0b } },
|
||||
{ { 0, 0x00, 0x12 }, { 1, 0x00, 0x0c } },
|
||||
{ { 0, 0x00, 0x12 }, { 1, 0x00, 0x0c } },
|
||||
{ { 0, 0x00, 0x12 }, { 1, 0x00, 0x0c } },
|
||||
{ { 0, 0x02, 0x0f }, { 1, 0x00, 0x0c } },
|
||||
{ { 0, 0x00, 0x13 }, { 1, 0x00, 0x0d } },
|
||||
{ { 1, 0x00, 0x0d }, { 0, 0x00, 0x13 } },
|
||||
{ { 0, 0x01, 0x12 }, { 1, 0x00, 0x0d } },
|
||||
{ { 0, 0x00, 0x14 }, { 1, 0x00, 0x0d } },
|
||||
{ { 0, 0x00, 0x14 }, { 1, 0x00, 0x0e } },
|
||||
{ { 0, 0x00, 0x15 }, { 1, 0x00, 0x0e } },
|
||||
{ { 0, 0x00, 0x15 }, { 1, 0x00, 0x0e } },
|
||||
{ { 0, 0x00, 0x16 }, { 1, 0x00, 0x0e } },
|
||||
{ { 0, 0x00, 0x16 }, { 1, 0x00, 0x0f } },
|
||||
{ { 1, 0x00, 0x0f }, { 0, 0x00, 0x16 } },
|
||||
{ { 0, 0x02, 0x13 }, { 1, 0x00, 0x0f } },
|
||||
{ { 0, 0x00, 0x17 }, { 1, 0x00, 0x0f } },
|
||||
{ { 0, 0x00, 0x17 }, { 1, 0x01, 0x0f } },
|
||||
{ { 0, 0x01, 0x16 }, { 1, 0x01, 0x0f } },
|
||||
{ { 0, 0x00, 0x18 }, { 1, 0x00, 0x10 } },
|
||||
{ { 0, 0x00, 0x18 }, { 1, 0x00, 0x10 } },
|
||||
{ { 0, 0x00, 0x19 }, { 1, 0x02, 0x0f } },
|
||||
{ { 1, 0x02, 0x0f }, { 0, 0x00, 0x19 } },
|
||||
{ { 1, 0x00, 0x11 }, { 0, 0x00, 0x1a } },
|
||||
{ { 0, 0x00, 0x1a }, { 1, 0x00, 0x11 } },
|
||||
{ { 0, 0x00, 0x1a }, { 1, 0x03, 0x0f } },
|
||||
{ { 0, 0x02, 0x17 }, { 1, 0x03, 0x0f } },
|
||||
{ { 0, 0x00, 0x1b }, { 1, 0x00, 0x12 } },
|
||||
{ { 0, 0x00, 0x1b }, { 1, 0x00, 0x12 } },
|
||||
{ { 0, 0x01, 0x1a }, { 1, 0x00, 0x12 } },
|
||||
{ { 0, 0x00, 0x1c }, { 1, 0x00, 0x13 } },
|
||||
{ { 1, 0x00, 0x13 }, { 0, 0x00, 0x1c } },
|
||||
{ { 0, 0x00, 0x1d }, { 1, 0x00, 0x13 } },
|
||||
{ { 0, 0x00, 0x1d }, { 1, 0x00, 0x13 } },
|
||||
{ { 0, 0x00, 0x1e }, { 1, 0x00, 0x14 } },
|
||||
{ { 0, 0x00, 0x1e }, { 1, 0x00, 0x14 } },
|
||||
{ { 0, 0x00, 0x1e }, { 1, 0x00, 0x14 } },
|
||||
{ { 0, 0x02, 0x1b }, { 1, 0x00, 0x14 } },
|
||||
{ { 0, 0x00, 0x1f }, { 1, 0x00, 0x15 } },
|
||||
{ { 1, 0x00, 0x15 }, { 0, 0x00, 0x1f } },
|
||||
{ { 0, 0x01, 0x1e }, { 1, 0x00, 0x15 } },
|
||||
{ { 0, 0x04, 0x18 }, { 1, 0x00, 0x15 } },
|
||||
{ { 0, 0x01, 0x1f }, { 1, 0x00, 0x16 } },
|
||||
{ { 0, 0x01, 0x1f }, { 1, 0x00, 0x16 } },
|
||||
{ { 0, 0x01, 0x1f }, { 1, 0x00, 0x16 } },
|
||||
{ { 0, 0x02, 0x1e }, { 1, 0x00, 0x16 } },
|
||||
{ { 0, 0x02, 0x1e }, { 1, 0x00, 0x17 } },
|
||||
{ { 1, 0x00, 0x17 }, { 0, 0x02, 0x1e } },
|
||||
{ { 0, 0x02, 0x1f }, { 1, 0x00, 0x17 } },
|
||||
{ { 0, 0x04, 0x1b }, { 1, 0x00, 0x17 } },
|
||||
{ { 0, 0x03, 0x1e }, { 1, 0x01, 0x17 } },
|
||||
{ { 0, 0x03, 0x1e }, { 1, 0x01, 0x17 } },
|
||||
{ { 0, 0x04, 0x1c }, { 1, 0x00, 0x18 } },
|
||||
{ { 0, 0x03, 0x1f }, { 1, 0x00, 0x18 } },
|
||||
{ { 0, 0x03, 0x1f }, { 1, 0x02, 0x17 } },
|
||||
{ { 1, 0x02, 0x17 }, { 0, 0x03, 0x1f } },
|
||||
{ { 1, 0x00, 0x19 }, { 0, 0x04, 0x1e } },
|
||||
{ { 0, 0x04, 0x1e }, { 1, 0x00, 0x19 } },
|
||||
{ { 0, 0x04, 0x1e }, { 1, 0x03, 0x17 } },
|
||||
{ { 0, 0x06, 0x1b }, { 1, 0x03, 0x17 } },
|
||||
{ { 0, 0x04, 0x1f }, { 1, 0x00, 0x1a } },
|
||||
{ { 0, 0x04, 0x1f }, { 1, 0x00, 0x1a } },
|
||||
{ { 0, 0x05, 0x1e }, { 1, 0x00, 0x1a } },
|
||||
{ { 0, 0x08, 0x18 }, { 1, 0x00, 0x1b } },
|
||||
{ { 1, 0x00, 0x1b }, { 0, 0x05, 0x1f } },
|
||||
{ { 0, 0x05, 0x1f }, { 1, 0x00, 0x1b } },
|
||||
{ { 0, 0x05, 0x1f }, { 1, 0x00, 0x1b } },
|
||||
{ { 0, 0x06, 0x1e }, { 1, 0x00, 0x1c } },
|
||||
{ { 0, 0x06, 0x1e }, { 1, 0x00, 0x1c } },
|
||||
{ { 0, 0x06, 0x1e }, { 1, 0x00, 0x1c } },
|
||||
{ { 0, 0x06, 0x1f }, { 1, 0x00, 0x1c } },
|
||||
{ { 0, 0x08, 0x1b }, { 1, 0x00, 0x1d } },
|
||||
{ { 1, 0x00, 0x1d }, { 0, 0x07, 0x1e } },
|
||||
{ { 0, 0x07, 0x1e }, { 1, 0x00, 0x1d } },
|
||||
{ { 0, 0x08, 0x1c }, { 1, 0x00, 0x1d } },
|
||||
{ { 0, 0x07, 0x1f }, { 1, 0x00, 0x1e } },
|
||||
{ { 0, 0x07, 0x1f }, { 1, 0x00, 0x1e } },
|
||||
{ { 0, 0x07, 0x1f }, { 1, 0x00, 0x1e } },
|
||||
{ { 0, 0x08, 0x1e }, { 1, 0x00, 0x1e } },
|
||||
{ { 0, 0x08, 0x1e }, { 1, 0x00, 0x1f } },
|
||||
{ { 1, 0x00, 0x1f }, { 0, 0x08, 0x1e } },
|
||||
{ { 0, 0x0a, 0x1b }, { 1, 0x00, 0x1f } },
|
||||
{ { 0, 0x08, 0x1f }, { 1, 0x00, 0x1f } },
|
||||
{ { 0, 0x08, 0x1f }, { 1, 0x01, 0x1f } },
|
||||
{ { 0, 0x09, 0x1e }, { 1, 0x01, 0x1f } },
|
||||
{ { 0, 0x0c, 0x18 }, { 1, 0x04, 0x1c } },
|
||||
{ { 0, 0x09, 0x1f }, { 1, 0x04, 0x1c } },
|
||||
{ { 0, 0x09, 0x1f }, { 1, 0x02, 0x1f } },
|
||||
{ { 1, 0x02, 0x1f }, { 0, 0x09, 0x1f } },
|
||||
{ { 1, 0x04, 0x1d }, { 0, 0x0a, 0x1e } },
|
||||
{ { 0, 0x0a, 0x1e }, { 1, 0x04, 0x1d } },
|
||||
{ { 0, 0x0a, 0x1e }, { 1, 0x03, 0x1f } },
|
||||
{ { 0, 0x0a, 0x1f }, { 1, 0x03, 0x1f } },
|
||||
{ { 0, 0x0c, 0x1b }, { 1, 0x04, 0x1e } },
|
||||
{ { 0, 0x0b, 0x1e }, { 1, 0x04, 0x1e } },
|
||||
{ { 0, 0x0b, 0x1e }, { 1, 0x04, 0x1e } },
|
||||
{ { 0, 0x0c, 0x1c }, { 1, 0x04, 0x1f } },
|
||||
{ { 1, 0x04, 0x1f }, { 0, 0x0b, 0x1f } },
|
||||
{ { 0, 0x0b, 0x1f }, { 1, 0x04, 0x1f } },
|
||||
{ { 0, 0x0b, 0x1f }, { 1, 0x04, 0x1f } },
|
||||
{ { 0, 0x0c, 0x1e }, { 1, 0x05, 0x1f } },
|
||||
{ { 0, 0x0c, 0x1e }, { 1, 0x05, 0x1f } },
|
||||
{ { 0, 0x0c, 0x1e }, { 1, 0x05, 0x1f } },
|
||||
{ { 0, 0x0e, 0x1b }, { 1, 0x05, 0x1f } },
|
||||
{ { 0, 0x0c, 0x1f }, { 1, 0x06, 0x1f } },
|
||||
{ { 1, 0x06, 0x1f }, { 0, 0x0c, 0x1f } },
|
||||
{ { 0, 0x0d, 0x1e }, { 1, 0x06, 0x1f } },
|
||||
{ { 0, 0x10, 0x18 }, { 1, 0x06, 0x1f } },
|
||||
{ { 0, 0x0d, 0x1f }, { 1, 0x07, 0x1f } },
|
||||
{ { 0, 0x0d, 0x1f }, { 1, 0x07, 0x1f } },
|
||||
{ { 0, 0x0d, 0x1f }, { 1, 0x07, 0x1f } },
|
||||
{ { 0, 0x0e, 0x1e }, { 1, 0x07, 0x1f } },
|
||||
{ { 0, 0x0e, 0x1e }, { 1, 0x08, 0x1f } },
|
||||
{ { 1, 0x08, 0x1f }, { 0, 0x0e, 0x1e } },
|
||||
{ { 0, 0x0e, 0x1f }, { 1, 0x08, 0x1f } },
|
||||
{ { 0, 0x10, 0x1b }, { 1, 0x08, 0x1f } },
|
||||
{ { 0, 0x0f, 0x1e }, { 1, 0x09, 0x1f } },
|
||||
{ { 0, 0x0f, 0x1e }, { 1, 0x09, 0x1f } },
|
||||
{ { 0, 0x10, 0x1c }, { 1, 0x0c, 0x1c } },
|
||||
{ { 0, 0x0f, 0x1f }, { 1, 0x0c, 0x1c } },
|
||||
{ { 0, 0x0f, 0x1f }, { 1, 0x0a, 0x1f } },
|
||||
{ { 1, 0x0a, 0x1f }, { 0, 0x0f, 0x1f } },
|
||||
{ { 1, 0x0c, 0x1d }, { 0, 0x10, 0x1e } },
|
||||
{ { 0, 0x10, 0x1e }, { 1, 0x0c, 0x1d } },
|
||||
{ { 0, 0x10, 0x1e }, { 1, 0x0b, 0x1f } },
|
||||
{ { 0, 0x12, 0x1b }, { 1, 0x0b, 0x1f } },
|
||||
{ { 0, 0x10, 0x1f }, { 1, 0x0c, 0x1e } },
|
||||
{ { 0, 0x10, 0x1f }, { 1, 0x0c, 0x1e } },
|
||||
{ { 0, 0x11, 0x1e }, { 1, 0x0c, 0x1e } },
|
||||
{ { 0, 0x14, 0x18 }, { 1, 0x0c, 0x1f } },
|
||||
{ { 1, 0x0c, 0x1f }, { 0, 0x11, 0x1f } },
|
||||
{ { 0, 0x11, 0x1f }, { 1, 0x0c, 0x1f } },
|
||||
{ { 0, 0x11, 0x1f }, { 1, 0x0c, 0x1f } },
|
||||
{ { 0, 0x12, 0x1e }, { 1, 0x0d, 0x1f } },
|
||||
{ { 0, 0x12, 0x1e }, { 1, 0x0d, 0x1f } },
|
||||
{ { 0, 0x12, 0x1e }, { 1, 0x0d, 0x1f } },
|
||||
{ { 0, 0x12, 0x1f }, { 1, 0x0d, 0x1f } },
|
||||
{ { 0, 0x14, 0x1b }, { 1, 0x0e, 0x1f } },
|
||||
{ { 1, 0x0e, 0x1f }, { 0, 0x13, 0x1e } },
|
||||
{ { 0, 0x13, 0x1e }, { 1, 0x0e, 0x1f } },
|
||||
{ { 0, 0x14, 0x1c }, { 1, 0x0e, 0x1f } },
|
||||
{ { 0, 0x13, 0x1f }, { 1, 0x0f, 0x1f } },
|
||||
{ { 0, 0x13, 0x1f }, { 1, 0x0f, 0x1f } },
|
||||
{ { 0, 0x13, 0x1f }, { 1, 0x0f, 0x1f } },
|
||||
{ { 0, 0x14, 0x1e }, { 1, 0x0f, 0x1f } },
|
||||
{ { 0, 0x14, 0x1e }, { 1, 0x10, 0x1f } },
|
||||
{ { 1, 0x10, 0x1f }, { 0, 0x14, 0x1e } },
|
||||
{ { 0, 0x16, 0x1b }, { 1, 0x10, 0x1f } },
|
||||
{ { 0, 0x14, 0x1f }, { 1, 0x10, 0x1f } },
|
||||
{ { 0, 0x14, 0x1f }, { 1, 0x11, 0x1f } },
|
||||
{ { 0, 0x15, 0x1e }, { 1, 0x11, 0x1f } },
|
||||
{ { 0, 0x18, 0x18 }, { 1, 0x14, 0x1c } },
|
||||
{ { 0, 0x15, 0x1f }, { 1, 0x14, 0x1c } },
|
||||
{ { 0, 0x15, 0x1f }, { 1, 0x12, 0x1f } },
|
||||
{ { 1, 0x12, 0x1f }, { 0, 0x15, 0x1f } },
|
||||
{ { 1, 0x14, 0x1d }, { 0, 0x16, 0x1e } },
|
||||
{ { 0, 0x16, 0x1e }, { 1, 0x14, 0x1d } },
|
||||
{ { 0, 0x16, 0x1e }, { 1, 0x13, 0x1f } },
|
||||
{ { 0, 0x16, 0x1f }, { 1, 0x13, 0x1f } },
|
||||
{ { 0, 0x18, 0x1b }, { 1, 0x14, 0x1e } },
|
||||
{ { 0, 0x17, 0x1e }, { 1, 0x14, 0x1e } },
|
||||
{ { 0, 0x17, 0x1e }, { 1, 0x14, 0x1e } },
|
||||
{ { 0, 0x18, 0x1c }, { 1, 0x14, 0x1f } },
|
||||
{ { 1, 0x14, 0x1f }, { 0, 0x17, 0x1f } },
|
||||
{ { 0, 0x17, 0x1f }, { 1, 0x14, 0x1f } },
|
||||
{ { 0, 0x17, 0x1f }, { 1, 0x14, 0x1f } },
|
||||
{ { 0, 0x18, 0x1e }, { 1, 0x15, 0x1f } },
|
||||
{ { 0, 0x18, 0x1e }, { 1, 0x15, 0x1f } },
|
||||
{ { 0, 0x18, 0x1e }, { 1, 0x15, 0x1f } },
|
||||
{ { 0, 0x1a, 0x1b }, { 1, 0x15, 0x1f } },
|
||||
{ { 0, 0x18, 0x1f }, { 1, 0x16, 0x1f } },
|
||||
{ { 1, 0x16, 0x1f }, { 0, 0x18, 0x1f } },
|
||||
{ { 0, 0x19, 0x1e }, { 1, 0x16, 0x1f } },
|
||||
{ { 0, 0x19, 0x1e }, { 1, 0x16, 0x1f } },
|
||||
{ { 0, 0x19, 0x1f }, { 1, 0x17, 0x1f } },
|
||||
{ { 0, 0x19, 0x1f }, { 1, 0x17, 0x1f } },
|
||||
{ { 0, 0x19, 0x1f }, { 1, 0x17, 0x1f } },
|
||||
{ { 0, 0x1a, 0x1e }, { 1, 0x17, 0x1f } },
|
||||
{ { 0, 0x1a, 0x1e }, { 1, 0x18, 0x1f } },
|
||||
{ { 1, 0x18, 0x1f }, { 0, 0x1a, 0x1e } },
|
||||
{ { 0, 0x1a, 0x1f }, { 1, 0x18, 0x1f } },
|
||||
{ { 0, 0x1a, 0x1f }, { 1, 0x18, 0x1f } },
|
||||
{ { 0, 0x1b, 0x1e }, { 1, 0x19, 0x1f } },
|
||||
{ { 0, 0x1b, 0x1e }, { 1, 0x19, 0x1f } },
|
||||
{ { 0, 0x1c, 0x1c }, { 1, 0x1c, 0x1c } },
|
||||
{ { 0, 0x1b, 0x1f }, { 1, 0x1c, 0x1c } },
|
||||
{ { 0, 0x1b, 0x1f }, { 1, 0x1a, 0x1f } },
|
||||
{ { 1, 0x1a, 0x1f }, { 0, 0x1b, 0x1f } },
|
||||
{ { 1, 0x1c, 0x1d }, { 0, 0x1c, 0x1e } },
|
||||
{ { 0, 0x1c, 0x1e }, { 1, 0x1c, 0x1d } },
|
||||
{ { 0, 0x1c, 0x1e }, { 1, 0x1b, 0x1f } },
|
||||
{ { 1, 0x1b, 0x1f }, { 0, 0x1c, 0x1f } },
|
||||
{ { 0, 0x1c, 0x1f }, { 1, 0x1c, 0x1e } },
|
||||
{ { 0, 0x1c, 0x1f }, { 1, 0x1c, 0x1e } },
|
||||
{ { 0, 0x1d, 0x1e }, { 1, 0x1c, 0x1e } },
|
||||
{ { 0, 0x1d, 0x1e }, { 1, 0x1c, 0x1f } },
|
||||
{ { 1, 0x1c, 0x1f }, { 0, 0x1d, 0x1f } },
|
||||
{ { 0, 0x1d, 0x1f }, { 1, 0x1c, 0x1f } },
|
||||
{ { 0, 0x1d, 0x1f }, { 1, 0x1c, 0x1f } },
|
||||
{ { 0, 0x1e, 0x1e }, { 1, 0x1d, 0x1f } },
|
||||
{ { 0, 0x1e, 0x1e }, { 1, 0x1d, 0x1f } },
|
||||
{ { 0, 0x1e, 0x1e }, { 1, 0x1d, 0x1f } },
|
||||
{ { 0, 0x1e, 0x1f }, { 1, 0x1d, 0x1f } },
|
||||
{ { 0, 0x1e, 0x1f }, { 1, 0x1e, 0x1f } },
|
||||
{ { 1, 0x1e, 0x1f }, { 0, 0x1e, 0x1f } },
|
||||
{ { 1, 0x1e, 0x1f }, { 0, 0x1e, 0x1f } },
|
||||
{ { 0, 0x1f, 0x1f }, { 1, 0x1e, 0x1f } },
|
||||
{ { 0, 0x1f, 0x1f }, { 1, 0x1f, 0x1f } },
|
||||
{ { 0, 0x1f, 0x1f }, { 1, 0x1f, 0x1f } }
|
||||
};
|
||||
*/
|
||||
|
||||
static unsigned char Optimal6CompressDXT1[256][2][3] = {
|
||||
{ { 0, 0x00, 0x00 }, { 1, 0x00, 0x00 } },
|
||||
{ { 0, 0x00, 0x01 }, { 1, 0x00, 0x00 } },
|
||||
{ { 0, 0x00, 0x02 }, { 1, 0x00, 0x01 } },
|
||||
{ { 0, 0x00, 0x02 }, { 1, 0x00, 0x01 } },
|
||||
{ { 0, 0x00, 0x03 }, { 1, 0x00, 0x02 } },
|
||||
{ { 0, 0x00, 0x04 }, { 1, 0x00, 0x02 } },
|
||||
{ { 0, 0x00, 0x05 }, { 1, 0x00, 0x03 } },
|
||||
{ { 0, 0x00, 0x05 }, { 1, 0x00, 0x03 } },
|
||||
{ { 0, 0x00, 0x06 }, { 1, 0x00, 0x04 } },
|
||||
{ { 0, 0x00, 0x07 }, { 1, 0x00, 0x04 } },
|
||||
{ { 0, 0x00, 0x08 }, { 1, 0x00, 0x05 } },
|
||||
{ { 0, 0x00, 0x08 }, { 1, 0x00, 0x05 } },
|
||||
{ { 0, 0x00, 0x09 }, { 1, 0x00, 0x06 } },
|
||||
{ { 0, 0x00, 0x0a }, { 1, 0x00, 0x06 } },
|
||||
{ { 0, 0x00, 0x0b }, { 1, 0x00, 0x07 } },
|
||||
{ { 0, 0x00, 0x0b }, { 1, 0x00, 0x07 } },
|
||||
{ { 0, 0x00, 0x0c }, { 1, 0x00, 0x08 } },
|
||||
{ { 0, 0x00, 0x0d }, { 1, 0x00, 0x08 } },
|
||||
{ { 0, 0x00, 0x0e }, { 1, 0x00, 0x09 } },
|
||||
{ { 0, 0x00, 0x0e }, { 1, 0x00, 0x09 } },
|
||||
{ { 0, 0x00, 0x0f }, { 1, 0x00, 0x0a } },
|
||||
{ { 0, 0x00, 0x10 }, { 1, 0x00, 0x0a } },
|
||||
{ { 0, 0x01, 0x0f }, { 1, 0x00, 0x0b } },
|
||||
{ { 0, 0x00, 0x11 }, { 1, 0x00, 0x0b } },
|
||||
{ { 0, 0x00, 0x12 }, { 1, 0x00, 0x0c } },
|
||||
{ { 0, 0x00, 0x13 }, { 1, 0x00, 0x0c } },
|
||||
{ { 0, 0x03, 0x0e }, { 1, 0x00, 0x0d } },
|
||||
{ { 0, 0x00, 0x14 }, { 1, 0x00, 0x0d } },
|
||||
{ { 0, 0x00, 0x15 }, { 1, 0x00, 0x0e } },
|
||||
{ { 0, 0x00, 0x16 }, { 1, 0x00, 0x0e } },
|
||||
{ { 0, 0x04, 0x0f }, { 1, 0x00, 0x0f } },
|
||||
{ { 0, 0x00, 0x17 }, { 1, 0x00, 0x0f } },
|
||||
{ { 0, 0x00, 0x18 }, { 1, 0x00, 0x10 } },
|
||||
{ { 0, 0x00, 0x19 }, { 1, 0x00, 0x10 } },
|
||||
{ { 0, 0x06, 0x0e }, { 1, 0x00, 0x11 } },
|
||||
{ { 0, 0x00, 0x1a }, { 1, 0x00, 0x11 } },
|
||||
{ { 0, 0x00, 0x1b }, { 1, 0x00, 0x12 } },
|
||||
{ { 0, 0x00, 0x1c }, { 1, 0x00, 0x12 } },
|
||||
{ { 0, 0x07, 0x0f }, { 1, 0x00, 0x13 } },
|
||||
{ { 0, 0x00, 0x1d }, { 1, 0x00, 0x13 } },
|
||||
{ { 0, 0x00, 0x1e }, { 1, 0x00, 0x14 } },
|
||||
{ { 0, 0x00, 0x1f }, { 1, 0x00, 0x14 } },
|
||||
{ { 0, 0x09, 0x0e }, { 1, 0x00, 0x15 } },
|
||||
{ { 0, 0x00, 0x20 }, { 1, 0x00, 0x15 } },
|
||||
{ { 0, 0x00, 0x21 }, { 1, 0x00, 0x16 } },
|
||||
{ { 0, 0x02, 0x1e }, { 1, 0x00, 0x16 } },
|
||||
{ { 0, 0x00, 0x22 }, { 1, 0x00, 0x17 } },
|
||||
{ { 0, 0x00, 0x23 }, { 1, 0x00, 0x17 } },
|
||||
{ { 0, 0x00, 0x24 }, { 1, 0x00, 0x18 } },
|
||||
{ { 0, 0x03, 0x1f }, { 1, 0x00, 0x18 } },
|
||||
{ { 0, 0x00, 0x25 }, { 1, 0x00, 0x19 } },
|
||||
{ { 0, 0x00, 0x26 }, { 1, 0x00, 0x19 } },
|
||||
{ { 0, 0x00, 0x27 }, { 1, 0x00, 0x1a } },
|
||||
{ { 0, 0x05, 0x1e }, { 1, 0x00, 0x1a } },
|
||||
{ { 0, 0x00, 0x28 }, { 1, 0x00, 0x1b } },
|
||||
{ { 0, 0x00, 0x29 }, { 1, 0x00, 0x1b } },
|
||||
{ { 0, 0x00, 0x2a }, { 1, 0x00, 0x1c } },
|
||||
{ { 0, 0x06, 0x1f }, { 1, 0x00, 0x1c } },
|
||||
{ { 0, 0x00, 0x2b }, { 1, 0x00, 0x1d } },
|
||||
{ { 0, 0x00, 0x2c }, { 1, 0x00, 0x1d } },
|
||||
{ { 0, 0x00, 0x2d }, { 1, 0x00, 0x1e } },
|
||||
{ { 0, 0x08, 0x1e }, { 1, 0x00, 0x1e } },
|
||||
{ { 0, 0x00, 0x2e }, { 1, 0x00, 0x1f } },
|
||||
{ { 0, 0x00, 0x2f }, { 1, 0x00, 0x1f } },
|
||||
{ { 0, 0x01, 0x2e }, { 1, 0x01, 0x1f } },
|
||||
{ { 0, 0x00, 0x30 }, { 1, 0x00, 0x20 } },
|
||||
{ { 0, 0x00, 0x31 }, { 1, 0x02, 0x1f } },
|
||||
{ { 0, 0x00, 0x32 }, { 1, 0x00, 0x21 } },
|
||||
{ { 0, 0x02, 0x2f }, { 1, 0x03, 0x1f } },
|
||||
{ { 0, 0x00, 0x33 }, { 1, 0x00, 0x22 } },
|
||||
{ { 0, 0x00, 0x34 }, { 1, 0x04, 0x1f } },
|
||||
{ { 0, 0x00, 0x35 }, { 1, 0x00, 0x23 } },
|
||||
{ { 0, 0x04, 0x2e }, { 1, 0x05, 0x1f } },
|
||||
{ { 0, 0x00, 0x36 }, { 1, 0x00, 0x24 } },
|
||||
{ { 0, 0x00, 0x37 }, { 1, 0x06, 0x1f } },
|
||||
{ { 0, 0x00, 0x38 }, { 1, 0x00, 0x25 } },
|
||||
{ { 0, 0x05, 0x2f }, { 1, 0x07, 0x1f } },
|
||||
{ { 0, 0x00, 0x39 }, { 1, 0x00, 0x26 } },
|
||||
{ { 0, 0x00, 0x3a }, { 1, 0x08, 0x1f } },
|
||||
{ { 0, 0x00, 0x3b }, { 1, 0x00, 0x27 } },
|
||||
{ { 0, 0x07, 0x2e }, { 1, 0x09, 0x1f } },
|
||||
{ { 0, 0x00, 0x3c }, { 1, 0x00, 0x28 } },
|
||||
{ { 0, 0x00, 0x3d }, { 1, 0x0a, 0x1f } },
|
||||
{ { 0, 0x00, 0x3e }, { 1, 0x00, 0x29 } },
|
||||
{ { 0, 0x08, 0x2f }, { 1, 0x0b, 0x1f } },
|
||||
{ { 0, 0x00, 0x3f }, { 1, 0x00, 0x2a } },
|
||||
{ { 0, 0x01, 0x3e }, { 1, 0x0c, 0x1f } },
|
||||
{ { 0, 0x01, 0x3f }, { 1, 0x00, 0x2b } },
|
||||
{ { 0, 0x0a, 0x2e }, { 1, 0x0d, 0x1f } },
|
||||
{ { 0, 0x02, 0x3e }, { 1, 0x00, 0x2c } },
|
||||
{ { 0, 0x02, 0x3f }, { 1, 0x0e, 0x1f } },
|
||||
{ { 0, 0x03, 0x3e }, { 1, 0x00, 0x2d } },
|
||||
{ { 0, 0x0b, 0x2f }, { 1, 0x0f, 0x1f } },
|
||||
{ { 0, 0x03, 0x3f }, { 1, 0x00, 0x2e } },
|
||||
{ { 0, 0x04, 0x3e }, { 1, 0x00, 0x2e } },
|
||||
{ { 0, 0x04, 0x3f }, { 1, 0x00, 0x2f } },
|
||||
{ { 0, 0x0d, 0x2e }, { 1, 0x00, 0x2f } },
|
||||
{ { 0, 0x05, 0x3e }, { 1, 0x00, 0x30 } },
|
||||
{ { 0, 0x05, 0x3f }, { 1, 0x00, 0x30 } },
|
||||
{ { 0, 0x06, 0x3e }, { 1, 0x00, 0x31 } },
|
||||
{ { 0, 0x0e, 0x2f }, { 1, 0x00, 0x31 } },
|
||||
{ { 0, 0x06, 0x3f }, { 1, 0x00, 0x32 } },
|
||||
{ { 0, 0x07, 0x3e }, { 1, 0x00, 0x32 } },
|
||||
{ { 0, 0x07, 0x3f }, { 1, 0x00, 0x33 } },
|
||||
{ { 0, 0x10, 0x2d }, { 1, 0x00, 0x33 } },
|
||||
{ { 0, 0x08, 0x3e }, { 1, 0x00, 0x34 } },
|
||||
{ { 0, 0x08, 0x3f }, { 1, 0x00, 0x34 } },
|
||||
{ { 0, 0x09, 0x3e }, { 1, 0x00, 0x35 } },
|
||||
{ { 0, 0x10, 0x30 }, { 1, 0x00, 0x35 } },
|
||||
{ { 0, 0x09, 0x3f }, { 1, 0x00, 0x36 } },
|
||||
{ { 0, 0x0a, 0x3e }, { 1, 0x00, 0x36 } },
|
||||
{ { 0, 0x0a, 0x3f }, { 1, 0x00, 0x37 } },
|
||||
{ { 0, 0x10, 0x33 }, { 1, 0x00, 0x37 } },
|
||||
{ { 0, 0x0b, 0x3e }, { 1, 0x00, 0x38 } },
|
||||
{ { 0, 0x0b, 0x3f }, { 1, 0x00, 0x38 } },
|
||||
{ { 0, 0x0c, 0x3e }, { 1, 0x00, 0x39 } },
|
||||
{ { 0, 0x10, 0x36 }, { 1, 0x00, 0x39 } },
|
||||
{ { 0, 0x0c, 0x3f }, { 1, 0x00, 0x3a } },
|
||||
{ { 0, 0x0d, 0x3e }, { 1, 0x00, 0x3a } },
|
||||
{ { 0, 0x0d, 0x3f }, { 1, 0x00, 0x3b } },
|
||||
{ { 0, 0x10, 0x39 }, { 1, 0x00, 0x3b } },
|
||||
{ { 0, 0x0e, 0x3e }, { 1, 0x00, 0x3c } },
|
||||
{ { 0, 0x0e, 0x3f }, { 1, 0x00, 0x3c } },
|
||||
{ { 0, 0x0f, 0x3e }, { 1, 0x00, 0x3d } },
|
||||
{ { 0, 0x10, 0x3c }, { 1, 0x00, 0x3d } },
|
||||
{ { 0, 0x0f, 0x3f }, { 1, 0x00, 0x3e } },
|
||||
{ { 0, 0x18, 0x2e }, { 1, 0x00, 0x3e } },
|
||||
{ { 0, 0x10, 0x3e }, { 1, 0x00, 0x3f } },
|
||||
{ { 0, 0x10, 0x3f }, { 1, 0x00, 0x3f } },
|
||||
{ { 0, 0x11, 0x3e }, { 1, 0x01, 0x3f } },
|
||||
{ { 0, 0x19, 0x2f }, { 1, 0x10, 0x30 } },
|
||||
{ { 0, 0x11, 0x3f }, { 1, 0x02, 0x3f } },
|
||||
{ { 0, 0x12, 0x3e }, { 1, 0x10, 0x31 } },
|
||||
{ { 0, 0x12, 0x3f }, { 1, 0x03, 0x3f } },
|
||||
{ { 0, 0x1b, 0x2e }, { 1, 0x10, 0x32 } },
|
||||
{ { 0, 0x13, 0x3e }, { 1, 0x04, 0x3f } },
|
||||
{ { 0, 0x13, 0x3f }, { 1, 0x10, 0x33 } },
|
||||
{ { 0, 0x14, 0x3e }, { 1, 0x05, 0x3f } },
|
||||
{ { 0, 0x1c, 0x2f }, { 1, 0x10, 0x34 } },
|
||||
{ { 0, 0x14, 0x3f }, { 1, 0x06, 0x3f } },
|
||||
{ { 0, 0x15, 0x3e }, { 1, 0x10, 0x35 } },
|
||||
{ { 0, 0x15, 0x3f }, { 1, 0x07, 0x3f } },
|
||||
{ { 0, 0x1e, 0x2e }, { 1, 0x10, 0x36 } },
|
||||
{ { 0, 0x16, 0x3e }, { 1, 0x08, 0x3f } },
|
||||
{ { 0, 0x16, 0x3f }, { 1, 0x10, 0x37 } },
|
||||
{ { 0, 0x17, 0x3e }, { 1, 0x09, 0x3f } },
|
||||
{ { 0, 0x1f, 0x2f }, { 1, 0x10, 0x38 } },
|
||||
{ { 0, 0x17, 0x3f }, { 1, 0x0a, 0x3f } },
|
||||
{ { 0, 0x18, 0x3e }, { 1, 0x10, 0x39 } },
|
||||
{ { 0, 0x18, 0x3f }, { 1, 0x0b, 0x3f } },
|
||||
{ { 0, 0x20, 0x2f }, { 1, 0x10, 0x3a } },
|
||||
{ { 0, 0x19, 0x3e }, { 1, 0x0c, 0x3f } },
|
||||
{ { 0, 0x19, 0x3f }, { 1, 0x10, 0x3b } },
|
||||
{ { 0, 0x1a, 0x3e }, { 1, 0x0d, 0x3f } },
|
||||
{ { 0, 0x20, 0x32 }, { 1, 0x10, 0x3c } },
|
||||
{ { 0, 0x1a, 0x3f }, { 1, 0x0e, 0x3f } },
|
||||
{ { 0, 0x1b, 0x3e }, { 1, 0x10, 0x3d } },
|
||||
{ { 0, 0x1b, 0x3f }, { 1, 0x0f, 0x3f } },
|
||||
{ { 0, 0x20, 0x35 }, { 1, 0x10, 0x3e } },
|
||||
{ { 0, 0x1c, 0x3e }, { 1, 0x10, 0x3e } },
|
||||
{ { 0, 0x1c, 0x3f }, { 1, 0x10, 0x3f } },
|
||||
{ { 0, 0x1d, 0x3e }, { 1, 0x10, 0x3f } },
|
||||
{ { 0, 0x20, 0x38 }, { 1, 0x11, 0x3f } },
|
||||
{ { 0, 0x1d, 0x3f }, { 1, 0x11, 0x3f } },
|
||||
{ { 0, 0x1e, 0x3e }, { 1, 0x12, 0x3f } },
|
||||
{ { 0, 0x1e, 0x3f }, { 1, 0x12, 0x3f } },
|
||||
{ { 0, 0x20, 0x3b }, { 1, 0x13, 0x3f } },
|
||||
{ { 0, 0x1f, 0x3e }, { 1, 0x13, 0x3f } },
|
||||
{ { 0, 0x1f, 0x3f }, { 1, 0x14, 0x3f } },
|
||||
{ { 0, 0x20, 0x3d }, { 1, 0x14, 0x3f } },
|
||||
{ { 0, 0x20, 0x3e }, { 1, 0x15, 0x3f } },
|
||||
{ { 0, 0x20, 0x3f }, { 1, 0x15, 0x3f } },
|
||||
{ { 0, 0x29, 0x2e }, { 1, 0x16, 0x3f } },
|
||||
{ { 0, 0x21, 0x3e }, { 1, 0x16, 0x3f } },
|
||||
{ { 0, 0x21, 0x3f }, { 1, 0x17, 0x3f } },
|
||||
{ { 0, 0x22, 0x3e }, { 1, 0x17, 0x3f } },
|
||||
{ { 0, 0x2a, 0x2f }, { 1, 0x18, 0x3f } },
|
||||
{ { 0, 0x22, 0x3f }, { 1, 0x18, 0x3f } },
|
||||
{ { 0, 0x23, 0x3e }, { 1, 0x19, 0x3f } },
|
||||
{ { 0, 0x23, 0x3f }, { 1, 0x19, 0x3f } },
|
||||
{ { 0, 0x2c, 0x2e }, { 1, 0x1a, 0x3f } },
|
||||
{ { 0, 0x24, 0x3e }, { 1, 0x1a, 0x3f } },
|
||||
{ { 0, 0x24, 0x3f }, { 1, 0x1b, 0x3f } },
|
||||
{ { 0, 0x25, 0x3e }, { 1, 0x1b, 0x3f } },
|
||||
{ { 0, 0x2d, 0x2f }, { 1, 0x1c, 0x3f } },
|
||||
{ { 0, 0x25, 0x3f }, { 1, 0x1c, 0x3f } },
|
||||
{ { 0, 0x26, 0x3e }, { 1, 0x1d, 0x3f } },
|
||||
{ { 0, 0x26, 0x3f }, { 1, 0x1d, 0x3f } },
|
||||
{ { 1, 0x1e, 0x3f }, { 0, 0x26, 0x3f } },
|
||||
{ { 0, 0x27, 0x3e }, { 1, 0x1e, 0x3f } },
|
||||
{ { 0, 0x27, 0x3f }, { 1, 0x1f, 0x3f } },
|
||||
{ { 0, 0x28, 0x3e }, { 1, 0x1f, 0x3f } },
|
||||
{ { 1, 0x20, 0x3f }, { 0, 0x28, 0x3e } },
|
||||
{ { 0, 0x28, 0x3f }, { 1, 0x20, 0x3f } },
|
||||
{ { 0, 0x29, 0x3e }, { 1, 0x21, 0x3f } },
|
||||
{ { 0, 0x29, 0x3f }, { 1, 0x30, 0x30 } },
|
||||
{ { 0, 0x30, 0x31 }, { 1, 0x22, 0x3f } },
|
||||
{ { 0, 0x2a, 0x3e }, { 1, 0x30, 0x31 } },
|
||||
{ { 0, 0x2a, 0x3f }, { 1, 0x23, 0x3f } },
|
||||
{ { 0, 0x2b, 0x3e }, { 1, 0x30, 0x32 } },
|
||||
{ { 0, 0x30, 0x34 }, { 1, 0x24, 0x3f } },
|
||||
{ { 0, 0x2b, 0x3f }, { 1, 0x30, 0x33 } },
|
||||
{ { 0, 0x2c, 0x3e }, { 1, 0x25, 0x3f } },
|
||||
{ { 0, 0x2c, 0x3f }, { 1, 0x30, 0x34 } },
|
||||
{ { 0, 0x30, 0x37 }, { 1, 0x26, 0x3f } },
|
||||
{ { 0, 0x2d, 0x3e }, { 1, 0x30, 0x35 } },
|
||||
{ { 0, 0x2d, 0x3f }, { 1, 0x27, 0x3f } },
|
||||
{ { 0, 0x2e, 0x3e }, { 1, 0x30, 0x36 } },
|
||||
{ { 0, 0x30, 0x3a }, { 1, 0x28, 0x3f } },
|
||||
{ { 0, 0x2e, 0x3f }, { 1, 0x30, 0x37 } },
|
||||
{ { 0, 0x2f, 0x3e }, { 1, 0x29, 0x3f } },
|
||||
{ { 0, 0x2f, 0x3f }, { 1, 0x30, 0x38 } },
|
||||
{ { 0, 0x30, 0x3d }, { 1, 0x2a, 0x3f } },
|
||||
{ { 0, 0x30, 0x3e }, { 1, 0x30, 0x39 } },
|
||||
{ { 1, 0x2b, 0x3f }, { 0, 0x30, 0x3e } },
|
||||
{ { 0, 0x30, 0x3f }, { 1, 0x30, 0x3a } },
|
||||
{ { 0, 0x31, 0x3e }, { 1, 0x2c, 0x3f } },
|
||||
{ { 0, 0x31, 0x3f }, { 1, 0x30, 0x3b } },
|
||||
{ { 1, 0x2d, 0x3f }, { 0, 0x31, 0x3f } },
|
||||
{ { 0, 0x32, 0x3e }, { 1, 0x30, 0x3c } },
|
||||
{ { 0, 0x32, 0x3f }, { 1, 0x2e, 0x3f } },
|
||||
{ { 0, 0x33, 0x3e }, { 1, 0x30, 0x3d } },
|
||||
{ { 1, 0x2f, 0x3f }, { 0, 0x33, 0x3e } },
|
||||
{ { 0, 0x33, 0x3f }, { 1, 0x30, 0x3e } },
|
||||
{ { 0, 0x34, 0x3e }, { 1, 0x30, 0x3e } },
|
||||
{ { 0, 0x34, 0x3f }, { 1, 0x30, 0x3f } },
|
||||
{ { 0, 0x34, 0x3f }, { 1, 0x30, 0x3f } },
|
||||
{ { 0, 0x35, 0x3e }, { 1, 0x31, 0x3f } },
|
||||
{ { 0, 0x35, 0x3f }, { 1, 0x31, 0x3f } },
|
||||
{ { 0, 0x36, 0x3e }, { 1, 0x32, 0x3f } },
|
||||
{ { 0, 0x36, 0x3e }, { 1, 0x32, 0x3f } },
|
||||
{ { 0, 0x36, 0x3f }, { 1, 0x33, 0x3f } },
|
||||
{ { 0, 0x37, 0x3e }, { 1, 0x33, 0x3f } },
|
||||
{ { 0, 0x37, 0x3f }, { 1, 0x34, 0x3f } },
|
||||
{ { 0, 0x37, 0x3f }, { 1, 0x34, 0x3f } },
|
||||
{ { 0, 0x38, 0x3e }, { 1, 0x35, 0x3f } },
|
||||
{ { 0, 0x38, 0x3f }, { 1, 0x35, 0x3f } },
|
||||
{ { 0, 0x39, 0x3e }, { 1, 0x36, 0x3f } },
|
||||
{ { 0, 0x39, 0x3e }, { 1, 0x36, 0x3f } },
|
||||
{ { 0, 0x39, 0x3f }, { 1, 0x37, 0x3f } },
|
||||
{ { 0, 0x3a, 0x3e }, { 1, 0x37, 0x3f } },
|
||||
{ { 0, 0x3a, 0x3f }, { 1, 0x38, 0x3f } },
|
||||
{ { 0, 0x3a, 0x3f }, { 1, 0x38, 0x3f } },
|
||||
{ { 0, 0x3b, 0x3e }, { 1, 0x39, 0x3f } },
|
||||
{ { 0, 0x3b, 0x3f }, { 1, 0x39, 0x3f } },
|
||||
{ { 0, 0x3c, 0x3e }, { 1, 0x3a, 0x3f } },
|
||||
{ { 0, 0x3c, 0x3e }, { 1, 0x3a, 0x3f } },
|
||||
{ { 0, 0x3c, 0x3f }, { 1, 0x3b, 0x3f } },
|
||||
{ { 0, 0x3d, 0x3e }, { 1, 0x3b, 0x3f } },
|
||||
{ { 0, 0x3d, 0x3f }, { 1, 0x3c, 0x3f } },
|
||||
{ { 0, 0x3d, 0x3f }, { 1, 0x3c, 0x3f } },
|
||||
{ { 0, 0x3e, 0x3e }, { 1, 0x3d, 0x3f } },
|
||||
{ { 0, 0x3e, 0x3f }, { 1, 0x3d, 0x3f } },
|
||||
{ { 1, 0x3e, 0x3f }, { 0, 0x3e, 0x3f } },
|
||||
{ { 0, 0x3f, 0x3f }, { 1, 0x3e, 0x3f } },
|
||||
{ { 0, 0x3f, 0x3f }, { 1, 0x3f, 0x3f } }
|
||||
};
|
|
@ -1,172 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "FasTC/BPTCCompressor.h"
|
||||
|
||||
#include "CompressionMode.h"
|
||||
#undef DBL_MAX
|
||||
#include "FasTC/BitStream.h"
|
||||
#include "FasTC/TexCompTypes.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <cstring>
|
||||
|
||||
#include "avpcl.h"
|
||||
|
||||
namespace BPTCC {
|
||||
|
||||
void GetBlock(uint32 x, uint32 y, uint32 width, const uint32 *pixels, Tile &t) {
|
||||
for(uint32 j = 0; j < 4; j++)
|
||||
for(uint32 i = 0; i < 4; i++) {
|
||||
uint32 pixel = pixels[(y+j)*width + (x+i)];
|
||||
t.data[j][i].X() = pixel & 0xFF;
|
||||
t.data[j][i].Y() = (pixel >> 8) & 0xFF;
|
||||
t.data[j][i].Z() = (pixel >> 16) & 0xFF;
|
||||
t.data[j][i].W() = (pixel >> 24) & 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
class BlockLogger {
|
||||
public:
|
||||
BlockLogger(uint64 blockIdx, std::ostream &os)
|
||||
: m_BlockIdx(blockIdx), m_Stream(os) { }
|
||||
|
||||
template<typename T>
|
||||
friend std::ostream &operator<<(const BlockLogger &bl, const T &v);
|
||||
|
||||
uint64 m_BlockIdx;
|
||||
std::ostream &m_Stream;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
std::ostream &operator<<(const BlockLogger &bl, const T &v) {
|
||||
std::stringstream ss;
|
||||
ss << bl.m_BlockIdx << ": " << v;
|
||||
return bl.m_Stream << ss.str();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void PrintStat(const BlockLogger &lgr, const char *stat, const T &v) {
|
||||
std::stringstream ss;
|
||||
ss << stat << " -- " << v << std::endl;
|
||||
lgr << ss.str();
|
||||
}
|
||||
|
||||
// Compress an image using BC7 compression. Use the inBuf parameter to point
|
||||
// to an image in 4-byte RGBA format. The width and height parameters specify
|
||||
// the size of the image in pixels. The buffer pointed to by outBuf should be
|
||||
// large enough to store the compressed image. This implementation has an 4:1
|
||||
// compression ratio.
|
||||
void CompressNVTT(const FasTC::CompressionJob &cj) {
|
||||
const uint32 *inPixels = reinterpret_cast<const uint32 *>(cj.InBuf());
|
||||
const uint32 kBlockSz = GetBlockSize(FasTC::eCompressionFormat_BPTC);
|
||||
uint8 *outBuf = cj.OutBuf() + cj.CoordsToBlockIdx(cj.XStart(), cj.YStart()) * kBlockSz;
|
||||
|
||||
uint32 startX = cj.XStart();
|
||||
const uint32 endY = std::min(cj.YEnd(), cj.Height() - 4);
|
||||
for(uint32 j = cj.YStart(); j <= endY; j += 4) {
|
||||
const uint32 endX = j == cj.YEnd()? cj.XEnd() : cj.Width();
|
||||
for(uint32 i = startX; i < endX; i += 4) {
|
||||
|
||||
Tile block(4, 4);
|
||||
GetBlock(i, j, cj.Width(), inPixels, block);
|
||||
AVPCL::compress(block, reinterpret_cast<char *>(outBuf), NULL);
|
||||
|
||||
outBuf += kBlockSz;
|
||||
}
|
||||
startX = 0;
|
||||
}
|
||||
}
|
||||
|
||||
typedef double (*ModeCompressFunc)(const Tile &, char* out);
|
||||
static ModeCompressFunc kModeFuncs[8] = {
|
||||
AVPCL::compress_mode0,
|
||||
AVPCL::compress_mode1,
|
||||
AVPCL::compress_mode2,
|
||||
AVPCL::compress_mode3,
|
||||
AVPCL::compress_mode4,
|
||||
AVPCL::compress_mode5,
|
||||
AVPCL::compress_mode6,
|
||||
AVPCL::compress_mode7
|
||||
};
|
||||
|
||||
double CompressMode(uint32 mode, const Tile &t, char *out, BlockLogger &log) {
|
||||
std::stringstream ss;
|
||||
ss << "Mode_" << mode << "_error";
|
||||
double mse = kModeFuncs[mode](t, out);
|
||||
PrintStat(log, ss.str().c_str(), mse);
|
||||
|
||||
FasTC::BitStreamReadOnly strm(reinterpret_cast<uint8 *>(out));
|
||||
while(!strm.ReadBit());
|
||||
|
||||
const CompressionMode::Attributes *attrs =
|
||||
CompressionMode::GetAttributesForMode(mode);
|
||||
const uint32 nSubsets = attrs->numSubsets;
|
||||
|
||||
ss.str("");
|
||||
ss << "Mode_" << mode << "_shape";
|
||||
|
||||
uint32 shapeIdx = 0;
|
||||
if ( nSubsets > 1 ) {
|
||||
shapeIdx = strm.ReadBits(mode == 0? 4 : 6);
|
||||
PrintStat(log, ss.str().c_str(), shapeIdx);
|
||||
} else {
|
||||
PrintStat(log, ss.str().c_str(), -1);
|
||||
}
|
||||
|
||||
return mse;
|
||||
}
|
||||
|
||||
void CompressNVTTWithStats(const FasTC::CompressionJob &cj, std::ostream *logStream) {
|
||||
const uint32 *inPixels = reinterpret_cast<const uint32 *>(cj.InBuf());
|
||||
const uint32 kBlockSz = GetBlockSize(FasTC::eCompressionFormat_BPTC);
|
||||
uint8 *outBuf = cj.OutBuf() + cj.CoordsToBlockIdx(cj.XStart(), cj.YStart()) * kBlockSz;
|
||||
|
||||
uint32 startX = cj.XStart();
|
||||
const uint32 endY = std::min(cj.YEnd(), cj.Height() - 4);
|
||||
for(uint32 j = cj.YStart(); j <= endY; j += 4) {
|
||||
const uint32 endX = j == cj.YEnd()? cj.XEnd() : cj.Width();
|
||||
for(uint32 i = startX; i < endX; i += 4) {
|
||||
|
||||
Tile block(4, 4);
|
||||
GetBlock(i, j, cj.Width(), inPixels, block);
|
||||
|
||||
if(logStream) {
|
||||
BlockLogger logger(cj.CoordsToBlockIdx(i, j), *logStream);
|
||||
|
||||
char tempblock[16];
|
||||
double msebest = 1e30;
|
||||
for(uint32 mode = 0; mode < 8; mode++) {
|
||||
double mse_mode = CompressMode(mode, block, tempblock, logger);
|
||||
if(mse_mode < msebest) {
|
||||
msebest = mse_mode;
|
||||
memcpy(outBuf, tempblock, AVPCL::BLOCKSIZE);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
AVPCL::compress(block, reinterpret_cast<char *>(outBuf), NULL);
|
||||
}
|
||||
|
||||
outBuf += 16;
|
||||
}
|
||||
|
||||
startX = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace BC7C
|
|
@ -1,312 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
// The original lisence from the code available at the following location:
|
||||
// http://software.intel.com/en-us/vcsource/samples/fast-texture-compression
|
||||
//
|
||||
// This code has been modified significantly from the original.
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright 2011 Intel Corporation
|
||||
// All Rights Reserved
|
||||
//
|
||||
// Permission is granted to use, copy, distribute and prepare derivative works
|
||||
// of this software for any purpose and without fee, provided, that the above
|
||||
// copyright notice and this statement appear in all copies. Intel makes no
|
||||
// representations about the suitability of this software for any purpose. THIS
|
||||
// SOFTWARE IS PROVIDED "AS IS." INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES,
|
||||
// EXPRESS OR IMPLIED, AND ALL LIABILITY, INCLUDING CONSEQUENTIAL AND OTHER
|
||||
// INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE, INCLUDING LIABILITY FOR
|
||||
// INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not assume
|
||||
// any responsibility for any errors which may appear in this software nor any
|
||||
// responsibility to update it.
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef BPTCENCODER_SRC_BPTCCOMPRESSIONMODE_H_
|
||||
#define BPTCENCODER_SRC_BPTCCOMPRESSIONMODE_H_
|
||||
|
||||
#include "RGBAEndpoints.h"
|
||||
|
||||
namespace FasTC {
|
||||
class BitStream;
|
||||
} // namespace FasTC
|
||||
|
||||
namespace BPTCC {
|
||||
|
||||
// Forward Declarations
|
||||
struct VisitedState;
|
||||
const int kMaxEndpoints = 3;
|
||||
|
||||
static const int kPBits[4][2] = {
|
||||
{ 0, 0 },
|
||||
{ 0, 1 },
|
||||
{ 1, 0 },
|
||||
{ 1, 1 }
|
||||
};
|
||||
|
||||
class CompressionMode {
|
||||
|
||||
public:
|
||||
|
||||
static const uint32 kMaxNumSubsets = 3;
|
||||
static const uint32 kNumModes = 8;
|
||||
|
||||
// This initializes the compression variables used in order to compress a list
|
||||
// of clusters. We can increase the speed a tad by specifying whether or not
|
||||
// the block is opaque or not.
|
||||
explicit CompressionMode(int mode, const CompressionSettings &settings)
|
||||
: m_IsOpaque(mode < 4)
|
||||
, m_Attributes(&(kModeAttributes[mode]))
|
||||
, m_SASteps(settings.m_NumSimulatedAnnealingSteps)
|
||||
, m_ErrorMetric(settings.m_ErrorMetric)
|
||||
, m_RotateMode(0)
|
||||
, m_IndexMode(0)
|
||||
{ }
|
||||
~CompressionMode() { }
|
||||
|
||||
// These are all of the parameters required to define the data in a compressed
|
||||
// BPTC block. The mode determines how these parameters will be translated
|
||||
// into actual bits.
|
||||
struct Params {
|
||||
RGBAVector m_P1[kMaxNumSubsets], m_P2[kMaxNumSubsets];
|
||||
uint8 m_Indices[kMaxNumSubsets][kMaxNumDataPoints];
|
||||
uint8 m_AlphaIndices[kMaxNumDataPoints];
|
||||
uint8 m_PbitCombo[kMaxNumSubsets];
|
||||
int8 m_RotationMode;
|
||||
int8 m_IndexMode;
|
||||
uint16 m_ShapeIdx;
|
||||
Params() { }
|
||||
explicit Params(uint32 shape)
|
||||
: m_RotationMode(-1), m_IndexMode(-1), m_ShapeIdx(shape) {
|
||||
memset(m_Indices, 0xFF, sizeof(m_Indices));
|
||||
memset(m_AlphaIndices, 0xFF, sizeof(m_AlphaIndices));
|
||||
memset(m_PbitCombo, 0xFF, sizeof(m_PbitCombo));
|
||||
}
|
||||
};
|
||||
|
||||
// This outputs the parameters to the given bitstream based on the current
|
||||
// compression mode. The first argument is not const because the mode and
|
||||
// the value of the first index determines whether or not the indices need to
|
||||
// be swapped. The final output bits will always be a valid BPTC block.
|
||||
void Pack(Params ¶ms, FasTC::BitStream &stream) const;
|
||||
|
||||
// This function compresses a group of clusters into the passed bitstream.
|
||||
double Compress(Params ¶ms, const int shapeIdx,
|
||||
RGBACluster &cluster);
|
||||
|
||||
// This switch controls the quality of the simulated annealing optimizer. We
|
||||
// will not make more than this many steps regardless of how bad the error is.
|
||||
// Higher values will produce better quality results but will run slower.
|
||||
// Default is 20.
|
||||
static int MaxAnnealingIterations; // This is a setting
|
||||
static const int kMaxAnnealingIterations = 256; // This is a limit
|
||||
|
||||
// P-bits are low-order bits that are shared across color channels. This enum
|
||||
// says whether or not both endpoints share a p-bit or whether or not they
|
||||
// even have a p-bit.
|
||||
enum EPBitType {
|
||||
ePBitType_Shared,
|
||||
ePBitType_NotShared,
|
||||
ePBitType_None
|
||||
};
|
||||
|
||||
// These are all the per-mode attributes that can be set. They are specified
|
||||
// in a table and we access them through the private m_Attributes variable.
|
||||
static struct Attributes {
|
||||
int modeNumber;
|
||||
int numPartitionBits;
|
||||
int numSubsets;
|
||||
int numBitsPerIndex;
|
||||
int numBitsPerAlpha;
|
||||
int colorChannelPrecision;
|
||||
int alphaChannelPrecision;
|
||||
bool hasRotation;
|
||||
bool hasIdxMode;
|
||||
EPBitType pbitType;
|
||||
} kModeAttributes[kNumModes];
|
||||
|
||||
// This returns the above attributes structure for the given mode.
|
||||
static const Attributes *GetAttributesForMode(int mode) {
|
||||
if(mode < 0 || mode >= 8) return NULL;
|
||||
return &kModeAttributes[mode];
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
const double m_IsOpaque;
|
||||
const Attributes *const m_Attributes;
|
||||
|
||||
int m_SASteps;
|
||||
ErrorMetric m_ErrorMetric;
|
||||
int m_RotateMode;
|
||||
int m_IndexMode;
|
||||
|
||||
void SetIndexMode(int mode) { m_IndexMode = mode; }
|
||||
void SetRotationMode(int mode) { m_RotateMode = mode; }
|
||||
|
||||
int GetRotationMode() const {
|
||||
return m_Attributes->hasRotation? m_RotateMode : 0;
|
||||
}
|
||||
int GetModeNumber() const { return m_Attributes->modeNumber; }
|
||||
|
||||
int GetNumberOfPartitionBits() const {
|
||||
return m_Attributes->numPartitionBits;
|
||||
}
|
||||
int GetNumberOfSubsets() const { return m_Attributes->numSubsets; }
|
||||
|
||||
int GetNumberOfBitsPerIndex(int8 indexMode = -1) const {
|
||||
if(indexMode < 0) indexMode = m_IndexMode;
|
||||
if(indexMode == 0)
|
||||
return m_Attributes->numBitsPerIndex;
|
||||
else
|
||||
return m_Attributes->numBitsPerAlpha;
|
||||
}
|
||||
|
||||
int GetNumberOfBitsPerAlpha(int8 indexMode = -1) const {
|
||||
if(indexMode < 0) indexMode = m_IndexMode;
|
||||
if(indexMode == 0)
|
||||
return m_Attributes->numBitsPerAlpha;
|
||||
else
|
||||
return m_Attributes->numBitsPerIndex;
|
||||
}
|
||||
|
||||
// If we handle alpha separately, then we will consider the alpha channel
|
||||
// to be not used whenever we do any calculations...
|
||||
int GetAlphaChannelPrecision() const {
|
||||
return m_Attributes->alphaChannelPrecision;
|
||||
}
|
||||
|
||||
// This returns the proper error metric even if we have rotation bits set
|
||||
RGBAVector GetErrorMetric() const {
|
||||
const float *w = BPTCC::GetErrorMetric(m_ErrorMetric);
|
||||
switch(GetRotationMode()) {
|
||||
default:
|
||||
case 0: return RGBAVector(w[0], w[1], w[2], w[3]);
|
||||
case 1: return RGBAVector(w[3], w[1], w[2], w[0]);
|
||||
case 2: return RGBAVector(w[0], w[3], w[2], w[1]);
|
||||
case 3: return RGBAVector(w[0], w[1], w[3], w[2]);
|
||||
}
|
||||
}
|
||||
|
||||
EPBitType GetPBitType() const { return m_Attributes->pbitType; }
|
||||
|
||||
// This function creates an integer that represents the maximum values in each
|
||||
// channel. We can use this to figure out the proper endpoint values for a
|
||||
// given mode.
|
||||
unsigned int GetQuantizationMask() const {
|
||||
const int maskSeed = 0x80000000;
|
||||
const uint32 alphaPrec = GetAlphaChannelPrecision();
|
||||
const uint32 cbits = m_Attributes->colorChannelPrecision - 1;
|
||||
const uint32 abits = GetAlphaChannelPrecision() - 1;
|
||||
if(alphaPrec > 0) {
|
||||
return (
|
||||
(maskSeed >> (24 + cbits) & 0xFF) |
|
||||
(maskSeed >> (16 + cbits) & 0xFF00) |
|
||||
(maskSeed >> (8 + cbits) & 0xFF0000) |
|
||||
(maskSeed >> abits & 0xFF000000)
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
((maskSeed >> (24 + cbits) & 0xFF) |
|
||||
(maskSeed >> (16 + cbits) & 0xFF00) |
|
||||
(maskSeed >> (8 + cbits) & 0xFF0000)) &
|
||||
(0x00FFFFFF)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
int GetNumPbitCombos() const {
|
||||
switch(GetPBitType()) {
|
||||
case ePBitType_Shared: return 2;
|
||||
case ePBitType_NotShared: return 4;
|
||||
default:
|
||||
case ePBitType_None: return 1;
|
||||
}
|
||||
}
|
||||
|
||||
const int *GetPBitCombo(int idx) const {
|
||||
switch(GetPBitType()) {
|
||||
case ePBitType_Shared: return (idx)? kPBits[3] : kPBits[0];
|
||||
case ePBitType_NotShared: return kPBits[idx % 4];
|
||||
default:
|
||||
case ePBitType_None: return kPBits[0];
|
||||
}
|
||||
}
|
||||
|
||||
// This performs simulated annealing on the endpoints p1 and p2 based on the
|
||||
// current MaxAnnealingIterations. This is set by calling the function
|
||||
// SetQualityLevel
|
||||
double OptimizeEndpointsForCluster(
|
||||
const RGBACluster &cluster,
|
||||
RGBAVector &p1, RGBAVector &p2,
|
||||
uint8 *bestIndices,
|
||||
uint8 &bestPbitCombo
|
||||
) const;
|
||||
|
||||
// This function performs the heuristic to choose the "best" neighboring
|
||||
// endpoints to p1 and p2 based on the compression mode (index precision,
|
||||
// endpoint precision etc)
|
||||
void PickBestNeighboringEndpoints(
|
||||
const RGBACluster &cluster,
|
||||
const RGBAVector &p1, const RGBAVector &p2,
|
||||
const int curPbitCombo,
|
||||
RGBAVector &np1, RGBAVector &np2,
|
||||
int &nPbitCombo,
|
||||
const VisitedState *visitedStates,
|
||||
int nVisited,
|
||||
float stepSz = 1.0f
|
||||
) const;
|
||||
|
||||
// This is used by simulated annealing to determine whether or not the
|
||||
// newError (from the neighboring endpoints) is sufficient to continue the
|
||||
// annealing process from these new endpoints based on how good the oldError
|
||||
// was, and how long we've been annealing (t)
|
||||
bool AcceptNewEndpointError(double newError, double oldError, float t) const;
|
||||
|
||||
// This function figures out the best compression for the single color p, and
|
||||
// places the endpoints in p1 and p2. If the compression mode supports p-bits,
|
||||
// then we choose the best p-bit combo and return it as well.
|
||||
double CompressSingleColor(const RGBAVector &p,
|
||||
RGBAVector &p1, RGBAVector &p2,
|
||||
uint8 &bestPbitCombo) const;
|
||||
|
||||
// Compress the cluster using a generalized cluster fit. This figures out the
|
||||
// proper endpoints assuming that we have no alpha.
|
||||
double CompressCluster(const RGBACluster &cluster,
|
||||
RGBAVector &p1, RGBAVector &p2,
|
||||
uint8 *bestIndices, uint8 &bestPbitCombo) const;
|
||||
|
||||
// Compress the non-opaque cluster using a generalized cluster fit, and place
|
||||
// the endpoints within p1 and p2. The color indices and alpha indices are
|
||||
// computed as well.
|
||||
double CompressCluster(const RGBACluster &cluster,
|
||||
RGBAVector &p1, RGBAVector &p2,
|
||||
uint8 *bestIndices, uint8 *alphaIndices) const;
|
||||
|
||||
// This function takes two endpoints in the continuous domain (as floats) and
|
||||
// clamps them to the nearest grid points based on the compression mode (and
|
||||
// possible pbit values)
|
||||
void ClampEndpointsToGrid(RGBAVector &p1, RGBAVector &p2,
|
||||
uint8 &bestPBitCombo) const;
|
||||
};
|
||||
|
||||
extern const uint32 kInterpolationValues[4][16][2];
|
||||
|
||||
} // namespace BPTCC {
|
||||
#endif // BPTCENCODER_SRC_BPTCCOMPRESSIONMODE_H_
|
|
@ -1,205 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
// The original lisence from the code available at the following location:
|
||||
// http://software.intel.com/en-us/vcsource/samples/fast-texture-compression
|
||||
//
|
||||
// This code has been modified significantly from the original.
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright 2011 Intel Corporation
|
||||
// All Rights Reserved
|
||||
//
|
||||
// Permission is granted to use, copy, distribute and prepare derivative works
|
||||
// of this software for any purpose and without fee, provided, that the above
|
||||
// copyright notice and this statement appear in all copies. Intel makes no
|
||||
// representations about the suitability of this software for any purpose. THIS
|
||||
// SOFTWARE IS PROVIDED "AS IS." INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES,
|
||||
// EXPRESS OR IMPLIED, AND ALL LIABILITY, INCLUDING CONSEQUENTIAL AND OTHER
|
||||
// INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE, INCLUDING LIABILITY FOR
|
||||
// INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not assume
|
||||
// any responsibility for any errors which may appear in this software nor any
|
||||
// responsibility to update it.
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#ifndef BPTCENCODER_SRC_BC7COMPRESSIONMODESIMD_H_
|
||||
#define BPTCENCODER_SRC_BC7COMPRESSIONMODESIMD_H_
|
||||
|
||||
#include "TexCompTypes.h"
|
||||
#include "RGBAEndpointsSIMD.h"
|
||||
|
||||
// Forward Declarations
|
||||
class BitStream;
|
||||
|
||||
static const int kPBits[4][2] = {
|
||||
{ 0, 0 },
|
||||
{ 0, 1 },
|
||||
{ 1, 0 },
|
||||
{ 1, 1 }
|
||||
};
|
||||
|
||||
class BC7CompressionModeSIMD {
|
||||
public:
|
||||
|
||||
static const int kMaxNumSubsets = 3;
|
||||
static const int kNumModes = 8;
|
||||
|
||||
enum EPBitType {
|
||||
ePBitType_Shared,
|
||||
ePBitType_NotShared,
|
||||
ePBitType_None
|
||||
};
|
||||
|
||||
BC7CompressionModeSIMD(int mode, double err)
|
||||
: m_EstimatedError(err)
|
||||
, m_Attributes(&(kModeAttributes[mode]))
|
||||
{ }
|
||||
~BC7CompressionModeSIMD() { }
|
||||
|
||||
static int NumUses[8];
|
||||
static void ResetNumUses() { memset(NumUses, 0, sizeof(NumUses)); }
|
||||
|
||||
double Compress(BitStream &stream, const int shapeIdx,
|
||||
const RGBAClusterSIMD *clusters) const;
|
||||
|
||||
// This switch controls the quality of the simulated annealing optimizer. We
|
||||
// will not make more than this many steps regardless of how bad the error is.
|
||||
// Higher values will produce better quality results but will run slower.
|
||||
// Default is 50.
|
||||
static int MaxAnnealingIterations; // This is a setting
|
||||
|
||||
private:
|
||||
|
||||
static struct Attributes {
|
||||
int modeNumber;
|
||||
int numPartitionBits;
|
||||
int numSubsets;
|
||||
int numBitsPerIndex;
|
||||
int redChannelPrecision;
|
||||
int greenChannelPrecision;
|
||||
int blueChannelPrecision;
|
||||
int alphaChannelPrecision;
|
||||
EPBitType pbitType;
|
||||
} kModeAttributes[kNumModes];
|
||||
|
||||
protected:
|
||||
const Attributes *const m_Attributes;
|
||||
|
||||
int GetModeNumber() const { return m_Attributes->modeNumber; }
|
||||
int GetNumberOfPartitionBits() const {
|
||||
return m_Attributes->numPartitionBits;
|
||||
}
|
||||
int GetNumberOfSubsets() const { return m_Attributes->numSubsets; }
|
||||
int GetNumberOfBitsPerIndex() const { return m_Attributes->numBitsPerIndex; }
|
||||
|
||||
int GetRedChannelPrecision() const {
|
||||
return m_Attributes->redChannelPrecision;
|
||||
}
|
||||
|
||||
int GetGreenChannelPrecision() const {
|
||||
return m_Attributes->greenChannelPrecision;
|
||||
}
|
||||
|
||||
int GetBlueChannelPrecision() const {
|
||||
return m_Attributes->blueChannelPrecision;
|
||||
}
|
||||
|
||||
int GetAlphaChannelPrecision() const {
|
||||
return m_Attributes->alphaChannelPrecision;
|
||||
}
|
||||
|
||||
EPBitType GetPBitType() const { return m_Attributes->pbitType; }
|
||||
|
||||
// !SPEED! Add this to the attributes lookup table
|
||||
void GetQuantizationMask(__m128i &mask) const {
|
||||
const int maskSeed = 0x80000000;
|
||||
const uint32 abits = 24 + GetAlphaChannelPrecision() - 1;
|
||||
const uint32 rbits = 24 + GetRedChannelPrecision() - 1;
|
||||
const uint32 gbits = 24 + GetGreenChannelPrecision() - 1;
|
||||
const uint32 bbits = 24 + GetBlueChannelPrecision() - 1;
|
||||
mask = _mm_set_epi32(
|
||||
(GetAlphaChannelPrecision() > 0)? (maskSeed >> abits & 0xFF) : 0xFF,
|
||||
(maskSeed >> rbits & 0xFF),
|
||||
(maskSeed >> gbits & 0xFF),
|
||||
(maskSeed >> bbits & 0xFF)
|
||||
);
|
||||
}
|
||||
|
||||
int GetNumPbitCombos() const {
|
||||
switch(GetPBitType()) {
|
||||
case ePBitType_Shared: return 2;
|
||||
case ePBitType_NotShared: return 4;
|
||||
default:
|
||||
case ePBitType_None: return 1;
|
||||
}
|
||||
}
|
||||
|
||||
const int *GetPBitCombo(int idx) const {
|
||||
switch(GetPBitType()) {
|
||||
case ePBitType_Shared: return (idx)? kPBits[3] : kPBits[0];
|
||||
case ePBitType_NotShared: return kPBits[idx % 4];
|
||||
default:
|
||||
case ePBitType_None: return kPBits[0];
|
||||
}
|
||||
}
|
||||
|
||||
double OptimizeEndpointsForCluster(const RGBAClusterSIMD &cluster,
|
||||
RGBAVectorSIMD &p1, RGBAVectorSIMD &p2,
|
||||
__m128i *bestIndices,
|
||||
int &bestPbitCombo) const;
|
||||
|
||||
struct VisitedState {
|
||||
RGBAVectorSIMD p1;
|
||||
RGBAVectorSIMD p2;
|
||||
int pBitCombo;
|
||||
};
|
||||
|
||||
void PickBestNeighboringEndpoints(
|
||||
const RGBAClusterSIMD &cluster,
|
||||
const RGBAVectorSIMD &p1, const RGBAVectorSIMD &p2,
|
||||
const int curPbitCombo,
|
||||
RGBAVectorSIMD &np1, RGBAVectorSIMD &np2,
|
||||
int &nPbitCombo,
|
||||
const __m128 &stepVec
|
||||
) const;
|
||||
|
||||
bool AcceptNewEndpointError(float newError, float oldError, float temp) const;
|
||||
|
||||
double CompressSingleColor(const RGBAVectorSIMD &p,
|
||||
RGBAVectorSIMD &p1, RGBAVectorSIMD &p2,
|
||||
int &bestPbitCombo) const;
|
||||
double CompressCluster(const RGBAClusterSIMD &cluster,
|
||||
RGBAVectorSIMD &p1, RGBAVectorSIMD &p2,
|
||||
__m128i *bestIndices,
|
||||
int &bestPbitCombo) const;
|
||||
|
||||
void ClampEndpointsToGrid(RGBAVectorSIMD &p1, RGBAVectorSIMD &p2,
|
||||
int &bestPBitCombo) const;
|
||||
|
||||
int GetSubsetForIndex(int idx, const int shapeIdx) const;
|
||||
int GetAnchorIndexForSubset(int subset, const int shapeIdx) const;
|
||||
|
||||
double GetEstimatedError() const { return m_EstimatedError; }
|
||||
const double m_EstimatedError;
|
||||
};
|
||||
|
||||
extern const __m128i kBC7InterpolationValuesSIMD[4][16][2];
|
||||
extern const uint32 kBC7InterpolationValuesScalar[4][16][2];
|
||||
|
||||
#endif // BPTCENCODER_SRC_BC7COMPRESSIONMODESIMD_H_
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,369 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "FasTC/BPTCCompressor.h"
|
||||
#include "FasTC/Shapes.h"
|
||||
|
||||
#include "FasTC/TexCompTypes.h"
|
||||
#include "FasTC/BitStream.h"
|
||||
|
||||
using FasTC::BitStream;
|
||||
using FasTC::BitStreamReadOnly;
|
||||
|
||||
#include "AnchorTables.h"
|
||||
#include "CompressionMode.h"
|
||||
|
||||
using BPTCC::CompressionMode;
|
||||
|
||||
static int UnpackParams(const uint8 block[16], CompressionMode::Params ¶ms) {
|
||||
BitStreamReadOnly strm(block);
|
||||
|
||||
uint32 mode = 0;
|
||||
while(!strm.ReadBit()) {
|
||||
mode++;
|
||||
}
|
||||
|
||||
const CompressionMode::Attributes *attrs =
|
||||
CompressionMode::GetAttributesForMode(mode);
|
||||
const uint32 nSubsets = attrs->numSubsets;
|
||||
|
||||
params.m_IndexMode = 0;
|
||||
params.m_RotationMode = 0;
|
||||
params.m_ShapeIdx = 0;
|
||||
|
||||
if ( nSubsets > 1 ) {
|
||||
params.m_ShapeIdx = strm.ReadBits(mode == 0? 4 : 6);
|
||||
} else if( attrs->hasRotation ) {
|
||||
params.m_RotationMode = strm.ReadBits(2);
|
||||
if( attrs->hasIdxMode ) {
|
||||
params.m_IndexMode = strm.ReadBit();
|
||||
}
|
||||
}
|
||||
|
||||
assert(params.m_IndexMode < 2);
|
||||
assert(params.m_RotationMode < 4);
|
||||
assert(params.m_ShapeIdx < ((mode == 0)? 16U : 64U));
|
||||
|
||||
uint32 cp = attrs->colorChannelPrecision;
|
||||
const uint32 shift = 8 - cp;
|
||||
|
||||
uint8 eps[3][2][4];
|
||||
for(uint32 ch = 0; ch < 3; ch++)
|
||||
for(uint32 i = 0; i < nSubsets; i++)
|
||||
for(uint32 ep = 0; ep < 2; ep++)
|
||||
eps[i][ep][ch] = strm.ReadBits(cp) << shift;
|
||||
|
||||
uint32 ap = attrs->alphaChannelPrecision;
|
||||
const uint32 ash = 8 - ap;
|
||||
|
||||
if(ap == 0) {
|
||||
for(uint32 i = 0; i < nSubsets; i++)
|
||||
for(uint32 ep = 0; ep < 2; ep++)
|
||||
eps[i][ep][3] = 0xFF;
|
||||
} else {
|
||||
for(uint32 i = 0; i < nSubsets; i++)
|
||||
for(uint32 ep = 0; ep < 2; ep++)
|
||||
eps[i][ep][3] = strm.ReadBits(ap) << ash;
|
||||
}
|
||||
|
||||
// Handle pbits
|
||||
switch(attrs->pbitType) {
|
||||
case CompressionMode::ePBitType_None:
|
||||
// Do nothing.
|
||||
break;
|
||||
|
||||
case CompressionMode::ePBitType_Shared:
|
||||
|
||||
cp += 1;
|
||||
ap += 1;
|
||||
|
||||
for(uint32 i = 0; i < nSubsets; i++) {
|
||||
|
||||
uint32 pbit = strm.ReadBit();
|
||||
|
||||
for(uint32 j = 0; j < 2; j++)
|
||||
for(uint32 ch = 0; ch < kNumColorChannels; ch++) {
|
||||
const uint32 prec = ch == 3? ap : cp;
|
||||
eps[i][j][ch] |= pbit << (8-prec);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CompressionMode::ePBitType_NotShared:
|
||||
|
||||
cp += 1;
|
||||
ap += 1;
|
||||
|
||||
for(uint32 i = 0; i < nSubsets; i++)
|
||||
for(uint32 j = 0; j < 2; j++) {
|
||||
|
||||
uint32 pbit = strm.ReadBit();
|
||||
|
||||
for(uint32 ch = 0; ch < kNumColorChannels; ch++) {
|
||||
const uint32 prec = ch == 3? ap : cp;
|
||||
eps[i][j][ch] |= pbit << (8-prec);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Quantize endpoints...
|
||||
for(uint32 i = 0; i < nSubsets; i++)
|
||||
for(uint32 j = 0; j < 2; j++)
|
||||
for(uint32 ch = 0; ch < kNumColorChannels; ch++) {
|
||||
const uint32 prec = ch == 3? ap : cp;
|
||||
eps[i][j][ch] |= eps[i][j][ch] >> prec;
|
||||
}
|
||||
|
||||
for(uint32 i = 0; i < nSubsets; i++) {
|
||||
params.m_P1[i] = RGBAVector(eps[i][0][0], eps[i][0][1], eps[i][0][2], eps[i][0][3]);
|
||||
params.m_P2[i] = RGBAVector(eps[i][1][0], eps[i][1][1], eps[i][1][2], eps[i][1][3]);
|
||||
}
|
||||
|
||||
// Figure out indices...
|
||||
uint32 alphaIndices[kMaxNumDataPoints];
|
||||
uint32 colorIndices[kMaxNumDataPoints];
|
||||
|
||||
int nBitsPerAlpha = attrs->numBitsPerAlpha;
|
||||
int nBitsPerColor = attrs->numBitsPerIndex;
|
||||
|
||||
uint32 idxPrec = attrs->numBitsPerIndex;
|
||||
for(uint32 i = 0; i < kMaxNumDataPoints; i++) {
|
||||
uint32 subset = BPTCC::GetSubsetForIndex(i, params.m_ShapeIdx, nSubsets);
|
||||
|
||||
int idx = 0;
|
||||
if(BPTCC::GetAnchorIndexForSubset(subset, params.m_ShapeIdx, nSubsets) == i) {
|
||||
idx = strm.ReadBits(idxPrec - 1);
|
||||
} else {
|
||||
idx = strm.ReadBits(idxPrec);
|
||||
}
|
||||
colorIndices[i] = idx;
|
||||
}
|
||||
|
||||
idxPrec = attrs->numBitsPerAlpha;
|
||||
if(idxPrec == 0) {
|
||||
memcpy(alphaIndices, colorIndices, sizeof(alphaIndices));
|
||||
} else {
|
||||
for(uint32 i = 0; i < kMaxNumDataPoints; i++) {
|
||||
uint32 subset = BPTCC::GetSubsetForIndex(i, params.m_ShapeIdx, nSubsets);
|
||||
|
||||
int idx = 0;
|
||||
if(BPTCC::GetAnchorIndexForSubset(subset, params.m_ShapeIdx, nSubsets) == i) {
|
||||
idx = strm.ReadBits(idxPrec - 1);
|
||||
} else {
|
||||
idx = strm.ReadBits(idxPrec);
|
||||
}
|
||||
alphaIndices[i] = idx;
|
||||
}
|
||||
|
||||
if(params.m_IndexMode) {
|
||||
for(uint32 i = 0; i < kMaxNumDataPoints; i++) {
|
||||
std::swap(alphaIndices[i], colorIndices[i]);
|
||||
}
|
||||
|
||||
std::swap(nBitsPerAlpha, nBitsPerColor);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < kMaxNumDataPoints; ++i) {
|
||||
params.m_Indices[0][i] = static_cast<uint8>(colorIndices[i]);
|
||||
params.m_AlphaIndices[i] = static_cast<uint8>(alphaIndices[i]);
|
||||
}
|
||||
|
||||
assert(strm.GetBitsRead() == 128);
|
||||
|
||||
return mode;
|
||||
}
|
||||
|
||||
static FasTC::Pixel ConvertEndpoint(const int mode, const RGBAVector &ep) {
|
||||
|
||||
const CompressionMode::Attributes *attrs =
|
||||
BPTCC::CompressionMode::GetAttributesForMode(mode);
|
||||
|
||||
uint8 depth[4];
|
||||
memset(depth, 0, sizeof(depth));
|
||||
|
||||
depth[0] = attrs->colorChannelPrecision;
|
||||
depth[1] = attrs->colorChannelPrecision;
|
||||
depth[2] = attrs->colorChannelPrecision;
|
||||
depth[3] = attrs->alphaChannelPrecision;
|
||||
|
||||
if (attrs->pbitType != CompressionMode::ePBitType_None) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (depth[i] != 0) {
|
||||
depth[i] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
assert(depth[i] <= 8);
|
||||
}
|
||||
|
||||
FasTC::Pixel p;
|
||||
p.ChangeBitDepth(depth);
|
||||
|
||||
p.R() = static_cast<int16>(ep.R()) >> (8 - depth[0]);
|
||||
p.G() = static_cast<int16>(ep.G()) >> (8 - depth[1]);
|
||||
p.B() = static_cast<int16>(ep.B()) >> (8 - depth[2]);
|
||||
if (depth[3] == 0) {
|
||||
p.A() = 0xFF;
|
||||
} else {
|
||||
p.A() = static_cast<int16>(ep.A()) >> (8 - depth[3]);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
static void DecompressBC7Block(const uint8 block[16], BPTCC::LogicalBlock *out) {
|
||||
CompressionMode::Params params;
|
||||
int mode = UnpackParams(block, params);
|
||||
|
||||
const CompressionMode::Attributes *attrs =
|
||||
BPTCC::CompressionMode::GetAttributesForMode(mode);
|
||||
|
||||
BPTCC::Shape shape;
|
||||
shape.m_NumPartitions = attrs->numSubsets;
|
||||
shape.m_Index = params.m_ShapeIdx;
|
||||
|
||||
out->m_Mode = static_cast<BPTCC::EBlockMode>(1 << mode);
|
||||
out->m_Shape = shape;
|
||||
for (int i = 0; i < attrs->numSubsets; ++i) {
|
||||
out->m_Endpoints[i][0] = ConvertEndpoint(mode, params.m_P1[i]);
|
||||
out->m_Endpoints[i][1] = ConvertEndpoint(mode, params.m_P2[i]);
|
||||
}
|
||||
|
||||
for (uint32 i = 0; i < kMaxNumDataPoints; ++i) {
|
||||
out->m_Indices[i] = static_cast<uint32>(params.m_Indices[0][i]);
|
||||
out->m_AlphaIndices[i] = static_cast<uint32>(params.m_AlphaIndices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void DecompressBC7Block(const uint8 block[16], uint32 outBuf[16]) {
|
||||
|
||||
CompressionMode::Params params;
|
||||
int mode = UnpackParams(block, params);
|
||||
|
||||
const CompressionMode::Attributes *attrs =
|
||||
BPTCC::CompressionMode::GetAttributesForMode(mode);
|
||||
|
||||
const int nBitsPerAlpha = attrs->numBitsPerAlpha;
|
||||
const int nBitsPerColor = attrs->numBitsPerIndex;
|
||||
|
||||
// Get final colors by interpolating...
|
||||
for(uint32 i = 0; i < kMaxNumDataPoints; i++) {
|
||||
|
||||
const uint32 subset = BPTCC::GetSubsetForIndex(i, params.m_ShapeIdx, attrs->numSubsets);
|
||||
uint32 &pixel = outBuf[i];
|
||||
|
||||
pixel = 0;
|
||||
for(int ch = 0; ch < 4; ch++) {
|
||||
if(ch == 3 && nBitsPerAlpha > 0) {
|
||||
uint32 i0 =
|
||||
BPTCC::kInterpolationValues[nBitsPerAlpha - 1][params.m_AlphaIndices[i]][0];
|
||||
uint32 i1 =
|
||||
BPTCC::kInterpolationValues[nBitsPerAlpha - 1][params.m_AlphaIndices[i]][1];
|
||||
|
||||
const uint32 ep1 = static_cast<uint32>(params.m_P1[subset].A());
|
||||
const uint32 ep2 = static_cast<uint32>(params.m_P2[subset].A());
|
||||
const uint8 ip = (((ep1 * i0 + ep2 * i1) + 32) >> 6) & 0xFF;
|
||||
pixel |= ip << 24;
|
||||
|
||||
} else {
|
||||
uint32 i0 =
|
||||
BPTCC::kInterpolationValues[nBitsPerColor - 1][params.m_Indices[0][i]][0];
|
||||
uint32 i1 =
|
||||
BPTCC::kInterpolationValues[nBitsPerColor - 1][params.m_Indices[0][i]][1];
|
||||
|
||||
const uint32 ep1 = static_cast<uint32>(params.m_P1[subset][ch]);
|
||||
const uint32 ep2 = static_cast<uint32>(params.m_P2[subset][ch]);
|
||||
const uint8 ip = (((ep1 * i0 + ep2 * i1) + 32) >> 6) & 0xFF;
|
||||
pixel |= ip << (8*ch);
|
||||
}
|
||||
}
|
||||
|
||||
// Swap colors if necessary...
|
||||
uint8 *pb = reinterpret_cast<uint8 *>(&pixel);
|
||||
switch(params.m_RotationMode) {
|
||||
default:
|
||||
case 0:
|
||||
// Do nothing
|
||||
break;
|
||||
|
||||
case 1:
|
||||
std::swap(pb[0], pb[3]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
std::swap(pb[1], pb[3]);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
std::swap(pb[2], pb[3]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace BPTCC {
|
||||
|
||||
// Convert the image from a BC7 buffer to a RGBA8 buffer
|
||||
void DecompressLogical(const FasTC::DecompressionJob &dj,
|
||||
std::vector<LogicalBlock> *out) {
|
||||
|
||||
if (!out) { return; }
|
||||
|
||||
out->clear();
|
||||
out->resize(dj.Height() * dj.Width() / 16);
|
||||
|
||||
const uint8 *inBuf = dj.InBuf();
|
||||
|
||||
int blockIdx = 0;
|
||||
for(unsigned int j = 0; j < dj.Height(); j += 4) {
|
||||
for(unsigned int i = 0; i < dj.Width(); i += 4) {
|
||||
DecompressBC7Block(inBuf, &(out->at(blockIdx++)));
|
||||
inBuf += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the image from a BC7 buffer to a RGBA8 buffer
|
||||
void Decompress(const FasTC::DecompressionJob &dj) {
|
||||
|
||||
const uint8 *inBuf = dj.InBuf();
|
||||
uint32 *outBuf = reinterpret_cast<uint32 *>(dj.OutBuf());
|
||||
|
||||
for(unsigned int j = 0; j < dj.Height(); j += 4) {
|
||||
for(unsigned int i = 0; i < dj.Width(); i += 4) {
|
||||
|
||||
uint32 pixels[16];
|
||||
DecompressBC7Block(inBuf, pixels);
|
||||
|
||||
uint32 decompWidth = std::min(4U, dj.Width() - i);
|
||||
uint32 decompHeight = std::min(4U, dj.Height() - j);
|
||||
|
||||
uint32 *outRow = outBuf + j * dj.Width() + i;
|
||||
for (uint32 jj = 0; jj < decompHeight; ++jj) {
|
||||
memcpy(outRow + jj*dj.Width(), pixels + 4 * jj, decompWidth * sizeof(pixels[0]));
|
||||
}
|
||||
|
||||
inBuf += 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace BPTCC
|
|
@ -1,134 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "ParallelStage.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
const BPTCParallelStage stage;
|
||||
|
||||
// This is the stream of data that will be used to read the block data.
|
||||
const unsigned char *const m_InBuf;
|
||||
|
||||
// This is the destination buffer to which the block data will be written to.
|
||||
unsigned char *const m_OutBuf;
|
||||
|
||||
// This is the array of block offsets that belong to this stage.
|
||||
uint32 *m_Blocks;
|
||||
|
||||
// This is the total number of blocks in the given image.
|
||||
const uint32 m_TotalNumBlocks;
|
||||
|
||||
// This is the total number of blocks in this particular stage.
|
||||
uint32 m_NumBlocks;
|
||||
*/
|
||||
ParallelStage::ParallelStage(
|
||||
BPTCParallelStage stage,
|
||||
const unsigned char *inbuf,
|
||||
unsigned char *outbuf,
|
||||
uint32 numBlocks,
|
||||
uint32 outBlockSz,
|
||||
uint32 inBlockSz
|
||||
)
|
||||
: m_Stage(stage)
|
||||
, m_InBuf(inbuf)
|
||||
, m_OutBuf(outbuf)
|
||||
, m_Blocks(new uint32[numBlocks])
|
||||
, m_TotalNumBlocks(numBlocks)
|
||||
, m_NumBlocks(0)
|
||||
, m_OutBlockSz(outBlockSz)
|
||||
, m_InBlockSz(inBlockSz)
|
||||
{
|
||||
assert(numBlocks > 0);
|
||||
}
|
||||
|
||||
ParallelStage::ParallelStage(const ParallelStage &other)
|
||||
: m_Stage(other.m_Stage)
|
||||
, m_InBuf(other.m_InBuf)
|
||||
, m_OutBuf(other.m_OutBuf)
|
||||
, m_Blocks(new uint32[other.m_NumBlocks])
|
||||
, m_TotalNumBlocks(other.m_TotalNumBlocks)
|
||||
, m_NumBlocks(other.m_NumBlocks)
|
||||
, m_OutBlockSz(other.m_OutBlockSz)
|
||||
, m_InBlockSz(other.m_InBlockSz)
|
||||
{
|
||||
memcpy(m_Blocks, other.m_Blocks, m_NumBlocks * sizeof(m_Blocks[0]));
|
||||
}
|
||||
|
||||
ParallelStage &ParallelStage::operator=(const ParallelStage &other) {
|
||||
assert(m_Stage == other.m_Stage);
|
||||
assert(m_InBuf == other.m_InBuf);
|
||||
assert(m_OutBuf == other.m_OutBuf);
|
||||
assert(m_TotalNumBlocks == other.m_TotalNumBlocks);
|
||||
assert(m_NumBlocks == other.m_NumBlocks);
|
||||
assert(m_OutBlockSz == other.m_OutBlockSz);
|
||||
assert(m_InBlockSz == other.m_InBlockSz);
|
||||
|
||||
memcpy(m_Blocks, other.m_Blocks, m_NumBlocks * sizeof(m_Blocks[0]));
|
||||
return *this;
|
||||
}
|
||||
|
||||
ParallelStage::~ParallelStage() {
|
||||
if(m_Blocks) {
|
||||
delete [] m_Blocks;
|
||||
m_Blocks = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void ParallelStage::AddBlock(uint32 blockNum) {
|
||||
assert(m_NumBlocks < m_TotalNumBlocks);
|
||||
|
||||
m_Blocks[m_NumBlocks++] = blockNum;
|
||||
}
|
||||
|
||||
uint32 ParallelStage::LoadBlocks(uint32 blockOffset, uint32 numBlocks, unsigned char *dst) {
|
||||
|
||||
if(!dst)
|
||||
return 0;
|
||||
|
||||
if(blockOffset + numBlocks > m_NumBlocks)
|
||||
return 0;
|
||||
|
||||
int lastBlock = blockOffset + numBlocks;
|
||||
for(int i = blockOffset; i < lastBlock; i++)
|
||||
{
|
||||
uint32 block = m_Blocks[i];
|
||||
uint32 bOffset = block * m_InBlockSz;
|
||||
memcpy(dst + ((i - blockOffset) * m_InBlockSz), m_InBuf + bOffset, m_InBlockSz);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ParallelStage::WriteBlocks(uint32 blockOffset, uint32 numBlocks, const unsigned char *src) {
|
||||
if(!src)
|
||||
return false;
|
||||
|
||||
if(blockOffset + numBlocks > m_NumBlocks)
|
||||
return false;
|
||||
|
||||
int lastBlock = blockOffset + numBlocks;
|
||||
for(int i = blockOffset; i < lastBlock; i++) {
|
||||
uint32 block = m_Blocks[i];
|
||||
uint32 bOffset = block * m_OutBlockSz;
|
||||
memcpy(m_OutBuf + bOffset, src + ((i-blockOffset) * m_OutBlockSz), m_OutBlockSz);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "FasTC/TexCompTypes.h"
|
||||
|
||||
enum BPTCParallelStage {
|
||||
eParallelStage_Uniform,
|
||||
eParallelStage_Partitioned,
|
||||
eParallelStage_Normal,
|
||||
|
||||
kNumParallelStages
|
||||
};
|
||||
|
||||
class ParallelStage {
|
||||
public:
|
||||
ParallelStage(
|
||||
BPTCParallelStage stage,
|
||||
const unsigned char *inbuf,
|
||||
unsigned char *outbuf,
|
||||
uint32 numBlocks,
|
||||
uint32 outBlockSz = 16,
|
||||
uint32 inBlockSz = 64
|
||||
);
|
||||
ParallelStage(const ParallelStage &);
|
||||
ParallelStage &operator=(const ParallelStage &);
|
||||
|
||||
~ParallelStage();
|
||||
|
||||
const BPTCParallelStage m_Stage;
|
||||
|
||||
// Adds the block number to the list of blocks for this parallel stage
|
||||
void AddBlock(uint32 blockNum);
|
||||
|
||||
// Loads the desired number of blocks into the destination buffer. Returns
|
||||
// the number of blocks loaded.
|
||||
uint32 LoadBlocks(uint32 blockOffset, uint32 numBlocks, unsigned char *dst);
|
||||
|
||||
// Writes the block data from src into numBlocks blocks starting from
|
||||
// the block given by blockOffset.
|
||||
bool WriteBlocks(uint32 blockOffset, uint32 numBlocks, const unsigned char *src);
|
||||
|
||||
private:
|
||||
|
||||
// This is the stream of data that will be used to read the block data.
|
||||
const unsigned char *const m_InBuf;
|
||||
|
||||
// This is the destination buffer to which the block data will be written to.
|
||||
unsigned char *const m_OutBuf;
|
||||
|
||||
// This is the array of block offsets that belong to this stage.
|
||||
uint32 *m_Blocks;
|
||||
|
||||
// This is the total number of blocks in the given image.
|
||||
const uint32 m_TotalNumBlocks;
|
||||
|
||||
// This is the total number of blocks in this particular stage.
|
||||
uint32 m_NumBlocks;
|
||||
|
||||
const uint32 m_OutBlockSz;
|
||||
const uint32 m_InBlockSz;
|
||||
};
|
|
@ -1,441 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
// The original lisence from the code available at the following location:
|
||||
// http://software.intel.com/en-us/vcsource/samples/fast-texture-compression
|
||||
//
|
||||
// This code has been modified significantly from the original.
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright 2011 Intel Corporation
|
||||
// All Rights Reserved
|
||||
//
|
||||
// Permission is granted to use, copy, distribute and prepare derivative works
|
||||
// of this software for any purpose and without fee, provided, that the above
|
||||
// copyright notice and this statement appear in all copies. Intel makes no
|
||||
// representations about the suitability of this software for any purpose. THIS
|
||||
// SOFTWARE IS PROVIDED "AS IS." INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES,
|
||||
// EXPRESS OR IMPLIED, AND ALL LIABILITY, INCLUDING CONSEQUENTIAL AND OTHER
|
||||
// INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE, INCLUDING LIABILITY FOR
|
||||
// INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE WARRANTIES OF
|
||||
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not assume
|
||||
// any responsibility for any errors which may appear in this software nor any
|
||||
// responsibility to update it.
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "FasTC/BPTCConfig.h"
|
||||
#include "FasTC/BPTCCompressor.h"
|
||||
|
||||
#include "RGBAEndpoints.h"
|
||||
#include "CompressionMode.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cfloat>
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
|
||||
#ifndef min
|
||||
template <typename T>
|
||||
static T min(const T &a, const T &b) {
|
||||
return (a > b)? b : a;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef max
|
||||
template <typename T>
|
||||
static T max(const T &a, const T &b) {
|
||||
return (a > b)? a : b;
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Static helper functions
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
static inline uint32 CountBitsInMask(uint8 n) {
|
||||
|
||||
#if defined(_WIN64) || defined(__x86_64__) || defined(NO_INLINE_ASSEMBLY)
|
||||
if(!n) return 0; // no bits set
|
||||
if(!(n & (n-1))) return 1; // power of two
|
||||
|
||||
uint32 c;
|
||||
for(c = 0; n; c++) {
|
||||
n &= n - 1;
|
||||
}
|
||||
return c;
|
||||
#else
|
||||
#ifdef _MSC_VER
|
||||
__asm {
|
||||
mov eax, 8
|
||||
movzx ecx, n
|
||||
bsf ecx, ecx
|
||||
sub eax, ecx
|
||||
}
|
||||
#else
|
||||
uint32 ans;
|
||||
__asm__("movl $8, %%eax;"
|
||||
"movzbl %b1, %%ecx;"
|
||||
"bsf %%ecx, %%ecx;"
|
||||
"subl %%ecx, %%eax;"
|
||||
"movl %%eax, %0;"
|
||||
: "=Q"(ans)
|
||||
: "b"(n)
|
||||
: "%eax", "%ecx"
|
||||
);
|
||||
return ans;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename ty>
|
||||
static inline void clamp(ty &x, const ty &min, const ty &max) {
|
||||
x = (x < min)? min : ((x > max)? max : x);
|
||||
}
|
||||
|
||||
// absolute distance. It turns out the compiler does a much
|
||||
// better job of optimizing this than we can, since we can't
|
||||
// translate the values to/from registers
|
||||
template <typename ty>
|
||||
static ty sad(ty a, ty b) {
|
||||
return (a > b)? a - b : b - a;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// RGBAVector implementation
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
uint8 QuantizeChannel(const uint8 val, const uint8 mask, const int pBit) {
|
||||
|
||||
// If the mask is all the bits, then we can just return the value.
|
||||
if(mask == 0xFF) {
|
||||
return val;
|
||||
}
|
||||
|
||||
// Otherwise if the mask is no bits then we'll assume that they want
|
||||
// all the bits ... this is only really relevant for alpha...
|
||||
if(mask == 0x0) {
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
uint32 prec = CountBitsInMask(mask);
|
||||
const uint32 step = 1 << (8 - prec);
|
||||
|
||||
assert(step-1 == uint8(~mask));
|
||||
|
||||
uint32 lval = val & mask;
|
||||
uint32 hval = lval + step;
|
||||
|
||||
if(pBit >= 0) {
|
||||
prec++;
|
||||
lval |= !!(pBit) << (8 - prec);
|
||||
hval |= !!(pBit) << (8 - prec);
|
||||
}
|
||||
|
||||
if(lval > val) {
|
||||
lval -= step;
|
||||
hval -= step;
|
||||
}
|
||||
|
||||
lval |= lval >> prec;
|
||||
hval |= hval >> prec;
|
||||
|
||||
if(sad<uint8>(val, lval) < sad<uint8>(val, hval))
|
||||
return lval;
|
||||
else
|
||||
return hval;
|
||||
}
|
||||
|
||||
uint32 RGBAVector::ToPixel(const uint32 channelMask, const int pBit) const {
|
||||
|
||||
const uint8 pRet0 = QuantizeChannel(uint32(R() + 0.5) & 0xFF, channelMask & 0xFF, pBit);
|
||||
const uint8 pRet1 = QuantizeChannel(uint32(G() + 0.5) & 0xFF, (channelMask >> 8) & 0xFF, pBit);
|
||||
const uint8 pRet2 = QuantizeChannel(uint32(B() + 0.5) & 0xFF, (channelMask >> 16) & 0xFF, pBit);
|
||||
const uint8 pRet3 = QuantizeChannel(uint32(A() + 0.5) & 0xFF, (channelMask >> 24) & 0xFF, pBit);
|
||||
|
||||
const uint32 ret = pRet0 | (pRet1 << 8) | (pRet2 << 16) | (pRet3 << 24);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Cluster implementation
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename T>
|
||||
static inline T Clamp(const T &x, const T &a, const T &b) {
|
||||
return std::max(a, std::min(x, b));
|
||||
}
|
||||
|
||||
template<const uint8 nBuckets>
|
||||
double RGBACluster::QuantizedError(
|
||||
const RGBAVector &p1, const RGBAVector &p2,
|
||||
uint32 bitMask, const RGBAVector &errorMetricVec,
|
||||
const int pbits[2], uint8 *indices
|
||||
) const {
|
||||
|
||||
// nBuckets should be a power of two.
|
||||
const uint8 indexPrec = static_cast<uint8>(log(static_cast<float>(nBuckets))/log(2.0f));
|
||||
assert(!(nBuckets & (nBuckets - 1)));
|
||||
assert(indexPrec >= 2 && indexPrec <= 4);
|
||||
|
||||
typedef uint32 tInterpPair[2];
|
||||
typedef tInterpPair tInterpLevel[16];
|
||||
const tInterpLevel *interpVals = BPTCC::kInterpolationValues + (indexPrec - 1);
|
||||
|
||||
uint32 qp1, qp2;
|
||||
if(pbits) {
|
||||
qp1 = p1.ToPixel(bitMask, pbits[0]);
|
||||
qp2 = p2.ToPixel(bitMask, pbits[1]);
|
||||
} else {
|
||||
qp1 = p1.ToPixel(bitMask);
|
||||
qp2 = p2.ToPixel(bitMask);
|
||||
}
|
||||
|
||||
const RGBAVector uqp1 = RGBAVector(0, qp1);
|
||||
const RGBAVector uqp2 = RGBAVector(0, qp2);
|
||||
const float uqplsq = (uqp1 - uqp2).LengthSq();
|
||||
const RGBAVector uqpdir = uqp2 - uqp1;
|
||||
|
||||
const uint8 *pqp1 = reinterpret_cast<const uint8 *>(&qp1);
|
||||
const uint8 *pqp2 = reinterpret_cast<const uint8 *>(&qp2);
|
||||
|
||||
const RGBAVector metric = errorMetricVec;
|
||||
|
||||
float totalError = 0.0;
|
||||
if(uqplsq == 0) {
|
||||
|
||||
// If both endpoints are the same then the indices don't matter...
|
||||
for(uint32 i = 0; i < GetNumPoints(); i++) {
|
||||
|
||||
const uint32 pixel = GetPixel(i);
|
||||
const uint8 *pb = (const uint8 *)(&pixel);
|
||||
|
||||
uint32 interp0 = (*interpVals)[0][0];
|
||||
uint32 interp1 = (*interpVals)[0][1];
|
||||
|
||||
RGBAVector errorVec (0.0f);
|
||||
for(uint32 k = 0; k < 4; k++) {
|
||||
const uint32 ip = (((pqp1[k] * interp0) + (pqp2[k] * interp1) + 32) >> 6) & 0xFF;
|
||||
const uint8 dist = sad<uint8>(pb[k], ip);
|
||||
errorVec[k] = static_cast<float>(dist) * metric[k];
|
||||
}
|
||||
|
||||
totalError += errorVec * errorVec;
|
||||
|
||||
if(indices)
|
||||
indices[i] = 0;
|
||||
}
|
||||
|
||||
return totalError;
|
||||
}
|
||||
|
||||
for(uint32 i = 0; i < GetNumPoints(); i++) {
|
||||
|
||||
// Project this point unto the direction denoted by uqpdir...
|
||||
const RGBAVector pt = GetPoint(i);
|
||||
#if 0
|
||||
const float pct = Clamp(((pt - uqp1) * uqpdir) / uqplsq, 0.0f, 1.0f);
|
||||
const int32 j1 = static_cast<int32>(pct * static_cast<float>(nBuckets-1));
|
||||
const int32 j2 = static_cast<int32>(pct * static_cast<float>(nBuckets-1) + 0.7);
|
||||
#else
|
||||
const float pct = ((pt - uqp1) * uqpdir) / uqplsq;
|
||||
int32 j1 = static_cast<int32>(floor(pct * static_cast<float>(nBuckets-1)));
|
||||
int32 j2 = static_cast<int32>(ceil(pct * static_cast<float>(nBuckets-1)));
|
||||
j1 = std::min(std::max(0, j1), nBuckets - 1);
|
||||
j2 = std::min(j2, nBuckets - 1);
|
||||
#endif
|
||||
|
||||
assert(j1 >= 0 && j2 <= nBuckets - 1);
|
||||
|
||||
const uint32 pixel = GetPixel(i);
|
||||
const uint8 *pb = (const uint8 *)(&pixel);
|
||||
|
||||
float minError = FLT_MAX;
|
||||
uint8 bestBucket = 0;
|
||||
int32 j = j1;
|
||||
do {
|
||||
|
||||
uint32 interp0 = (*interpVals)[j][0];
|
||||
uint32 interp1 = (*interpVals)[j][1];
|
||||
|
||||
RGBAVector errorVec (0.0f);
|
||||
for(uint32 k = 0; k < 4; k++) {
|
||||
const uint32 ip = (((pqp1[k] * interp0) + (pqp2[k] * interp1) + 32) >> 6) & 0xFF;
|
||||
const uint8 dist = sad<uint8>(pb[k], ip);
|
||||
errorVec[k] = static_cast<float>(dist) * metric[k];
|
||||
}
|
||||
|
||||
float error = errorVec * errorVec;
|
||||
if(error < minError) {
|
||||
minError = error;
|
||||
bestBucket = j;
|
||||
}
|
||||
|
||||
// Conceptually, once the error starts growing, it doesn't stop growing (we're moving
|
||||
// farther away from the reference point along the line). Hence we can early out here.
|
||||
// However, quanitzation artifacts mean that this is not ALWAYS the case, so we do suffer
|
||||
// about 0.01 RMS error.
|
||||
else if(error > minError) {
|
||||
break;
|
||||
}
|
||||
} while(++j <= j2);
|
||||
|
||||
totalError += minError;
|
||||
|
||||
if(indices) indices[i] = bestBucket;
|
||||
}
|
||||
|
||||
return totalError;
|
||||
}
|
||||
|
||||
template double RGBACluster::QuantizedError<4>(
|
||||
const RGBAVector &p1, const RGBAVector &p2,
|
||||
uint32 bitMask, const RGBAVector &errorMetricVec,
|
||||
const int pbits[2], uint8 *indices) const;
|
||||
|
||||
template double RGBACluster::QuantizedError<8>(
|
||||
const RGBAVector &p1, const RGBAVector &p2,
|
||||
uint32 bitMask, const RGBAVector &errorMetricVec,
|
||||
const int pbits[2], uint8 *indices) const;
|
||||
|
||||
template double RGBACluster::QuantizedError<16>(
|
||||
const RGBAVector &p1, const RGBAVector &p2,
|
||||
uint32 bitMask, const RGBAVector &errorMetricVec,
|
||||
const int pbits[2], uint8 *indices) const;
|
||||
|
||||
uint32 RGBACluster::GetPrincipalAxis(RGBADir &axis, float *eigOne, float *eigTwo) const {
|
||||
|
||||
// We use these vectors for calculating the covariance matrix...
|
||||
RGBAVector toPts[kMaxNumDataPoints];
|
||||
RGBAVector toPtsMax(-std::numeric_limits<float>::max());
|
||||
for(uint32 i = 0; i < this->GetNumPoints(); i++) {
|
||||
toPts[i] = this->GetPoint(i) - this->GetAvg();
|
||||
|
||||
for(uint32 j = 0; j < kNumColorChannels; j++) {
|
||||
toPtsMax[j] = max(toPtsMax[j], toPts[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a list of unique points...
|
||||
RGBAVector upts[kMaxNumDataPoints];
|
||||
uint32 uptsIdx = 0;
|
||||
for(uint32 i = 0; i < this->GetNumPoints(); i++) {
|
||||
|
||||
bool hasPt = false;
|
||||
for(uint32 j = 0; j < uptsIdx; j++) {
|
||||
if(upts[j] == this->GetPoint(i))
|
||||
hasPt = true;
|
||||
}
|
||||
|
||||
if(!hasPt) {
|
||||
upts[uptsIdx++] = this->GetPoint(i);
|
||||
}
|
||||
}
|
||||
|
||||
assert(uptsIdx > 0);
|
||||
|
||||
if(uptsIdx == 1) {
|
||||
axis.R() = axis.G() = axis.B() = axis.A() = 0.0f;
|
||||
return 0;
|
||||
|
||||
// Collinear?
|
||||
} else {
|
||||
RGBADir dir (upts[1] - upts[0]);
|
||||
bool collinear = true;
|
||||
for(uint32 i = 2; i < this->GetNumPoints(); i++) {
|
||||
RGBAVector v = (upts[i] - upts[0]);
|
||||
if(fabs(fabs(v*dir) - v.Length()) > 1e-7) {
|
||||
collinear = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(collinear) {
|
||||
axis = dir;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
RGBAMatrix covMatrix;
|
||||
|
||||
// Compute covariance.
|
||||
for(uint32 i = 0; i < kNumColorChannels; i++) {
|
||||
for(uint32 j = 0; j <= i; j++) {
|
||||
|
||||
float sum = 0.0;
|
||||
for(uint32 k = 0; k < this->GetNumPoints(); k++) {
|
||||
sum += toPts[k][i] * toPts[k][j];
|
||||
}
|
||||
|
||||
covMatrix(i, j) = sum / static_cast<float>(kNumColorChannels - 1);
|
||||
covMatrix(j, i) = covMatrix(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
uint32 iters = covMatrix.PowerMethod(axis, eigOne);
|
||||
if(NULL != eigTwo && NULL != eigOne) {
|
||||
if(*eigOne != 0.0) {
|
||||
RGBAMatrix reduced;
|
||||
for(uint32 j = 0; j < 4; j++) {
|
||||
for(uint32 i = 0; i < 4; i++) {
|
||||
reduced(i, j) = axis[j] * axis[i];
|
||||
}
|
||||
}
|
||||
|
||||
reduced = covMatrix - ((*eigOne) * reduced);
|
||||
bool allZero = true;
|
||||
for(uint32 i = 0; i < 16; i++) {
|
||||
if(fabs(reduced[i]) > 0.0005) {
|
||||
allZero = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(allZero) {
|
||||
*eigTwo = 0.0;
|
||||
}
|
||||
else {
|
||||
RGBADir dummyDir;
|
||||
iters += reduced.PowerMethod(dummyDir, eigTwo);
|
||||
}
|
||||
}
|
||||
else {
|
||||
*eigTwo = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
return iters;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Utility function implementation
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ClampEndpoints(RGBAVector &p1, RGBAVector &p2) {
|
||||
for(uint32 i = 0; i < 4; i++) {
|
||||
clamp(p1[i], 0.0f, 255.0f);
|
||||
clamp(p2[i], 0.0f, 255.0f);
|
||||
}
|
||||
}
|
|
@ -1,238 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
// The original lisence from the code available at the following location:
|
||||
// http://software.intel.com/en-us/vcsource/samples/fast-texture-compression
|
||||
//
|
||||
// This code has been modified significantly from the original.
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Copyright 2011 Intel Corporation
|
||||
// All Rights Reserved
|
||||
//
|
||||
// Permission is granted to use, copy, distribute and prepare derivative works of this
|
||||
// software for any purpose and without fee, provided, that the above copyright notice
|
||||
// and this statement appear in all copies. Intel makes no representations about the
|
||||
// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS."
|
||||
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
|
||||
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
|
||||
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not
|
||||
// assume any responsibility for any errors which may appear in this software nor any
|
||||
// responsibility to update it.
|
||||
//
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
#ifndef __RGBA_ENDPOINTS_H__
|
||||
#define __RGBA_ENDPOINTS_H__
|
||||
|
||||
#include "FasTC/TexCompTypes.h"
|
||||
#include "FasTC/Vector4.h"
|
||||
#include "FasTC/Matrix4x4.h"
|
||||
|
||||
#include "FasTC/Shapes.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <cfloat>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
|
||||
static const uint32 kNumColorChannels = 4;
|
||||
static const uint32 kMaxNumDataPoints = 16;
|
||||
|
||||
class RGBAVector : public FasTC::Vector4<float> {
|
||||
typedef FasTC::Vector4<float> BaseVector;
|
||||
public:
|
||||
uint32 GetIdx() const { return m_Idx; }
|
||||
RGBAVector() : BaseVector(-1.0, -1.0, -1.0, -1.0), m_Idx(0) { }
|
||||
RGBAVector(uint32 idx, uint32 pixel) :
|
||||
BaseVector(
|
||||
static_cast<float>(pixel & 0xFF),
|
||||
static_cast<float>((pixel >> 8) & 0xFF),
|
||||
static_cast<float>((pixel >> 16) & 0xFF),
|
||||
static_cast<float>((pixel >> 24) & 0xFF)
|
||||
)
|
||||
, m_Idx(idx)
|
||||
{ }
|
||||
|
||||
RGBAVector(float _r, float _g, float _b, float _a)
|
||||
: BaseVector(_r, _g, _b, _a), m_Idx(0) { }
|
||||
|
||||
explicit RGBAVector(float cc) : BaseVector(cc, cc, cc, cc), m_Idx(0) { }
|
||||
|
||||
const float &R() const { return vec[0]; }
|
||||
float &R() { return vec[0]; }
|
||||
const float &G() const { return vec[1]; }
|
||||
float &G() { return vec[1]; }
|
||||
const float &B() const { return vec[2]; }
|
||||
float &B() { return vec[2]; }
|
||||
const float &A() const { return vec[3]; }
|
||||
float &A() { return vec[3]; }
|
||||
|
||||
// Quantize this point.
|
||||
uint32 ToPixel(const uint32 channelMask = 0xFFFFFFFF, const int pBit = -1) const;
|
||||
|
||||
private:
|
||||
uint32 m_Idx;
|
||||
};
|
||||
typedef FasTC::Matrix4x4<float> RGBAMatrix;
|
||||
|
||||
class RGBADir : public RGBAVector {
|
||||
public:
|
||||
RGBADir() : RGBAVector() { }
|
||||
RGBADir(const RGBAVector &p) : RGBAVector(p) {
|
||||
this->Normalize();
|
||||
}
|
||||
};
|
||||
|
||||
class RGBACluster {
|
||||
// We really don't ever need to do these
|
||||
RGBACluster &operator=(const RGBACluster &) { return *this; }
|
||||
public:
|
||||
explicit RGBACluster(const uint32 pixels[16])
|
||||
: m_NumPoints(0)
|
||||
, m_Avg(0)
|
||||
, m_Min(std::numeric_limits<float>::max())
|
||||
, m_Max(-std::numeric_limits<float>::max())
|
||||
{
|
||||
for(uint32 i = 0; i < 16; i++) {
|
||||
RGBAVector p = RGBAVector(i, pixels[i]);
|
||||
m_Avg += p;
|
||||
m_PointMap[m_NumPoints] = i;
|
||||
m_DataPixels[m_NumPoints] = p.ToPixel();
|
||||
m_DataPoints[m_NumPoints++] = p;
|
||||
|
||||
for(uint32 i = 0; i < kNumColorChannels; i++) {
|
||||
m_Min[i] = std::min(p[i], m_Min[i]);
|
||||
m_Max[i] = std::max(p[i], m_Max[i]);
|
||||
}
|
||||
}
|
||||
m_Avg /= static_cast<float>(m_NumPoints);
|
||||
}
|
||||
|
||||
RGBAVector &Point(int idx) { return m_DataPoints[m_PointMap[idx]]; }
|
||||
const RGBAVector &GetPoint(int idx) const {
|
||||
return m_DataPoints[m_PointMap[idx]];
|
||||
}
|
||||
|
||||
const uint32 &GetPixel(int idx) const {
|
||||
return m_DataPixels[m_PointMap[idx]];
|
||||
}
|
||||
|
||||
uint32 GetNumPoints() const { return m_NumPoints; }
|
||||
RGBAVector GetAvg() const { return m_Avg; }
|
||||
|
||||
void GetBoundingBox(RGBAVector &Min, RGBAVector &Max) const {
|
||||
Min = m_Min, Max = m_Max;
|
||||
}
|
||||
|
||||
// Returns the error if we were to quantize the colors right now with the
|
||||
// given number of buckets and bit mask.
|
||||
double QuantizedError(
|
||||
const RGBAVector &p1, const RGBAVector &p2,
|
||||
uint32 nBuckets, uint32 bitMask, const RGBAVector &errorMetricVec,
|
||||
const int pbits[2] = NULL, uint8 *indices = NULL) const {
|
||||
switch(nBuckets) {
|
||||
case 4: return QuantizedError<4>(p1, p2, bitMask, errorMetricVec, pbits, indices);
|
||||
case 8: return QuantizedError<8>(p1, p2, bitMask, errorMetricVec, pbits, indices);
|
||||
case 16: return QuantizedError<16>(p1, p2, bitMask, errorMetricVec, pbits, indices);
|
||||
}
|
||||
assert(!"Unsupported num buckets");
|
||||
return std::numeric_limits<double>::max();
|
||||
}
|
||||
|
||||
bool AllSamePoint() const { return m_Max == m_Min; }
|
||||
|
||||
// Returns the principal axis for this point cluster.
|
||||
uint32 GetPrincipalAxis(RGBADir &axis, float *eigOne, float *eigTwo) const;
|
||||
|
||||
void SetShapeIndex(uint32 shapeIdx, uint32 nPartitions) {
|
||||
m_NumPartitions = nPartitions;
|
||||
m_ShapeIdx = shapeIdx;
|
||||
}
|
||||
|
||||
void SetShapeIndex(uint32 shapeIdx) {
|
||||
SetShapeIndex(shapeIdx, m_NumPartitions);
|
||||
}
|
||||
|
||||
void SetPartition(uint32 part) {
|
||||
m_SelectedPartition = part;
|
||||
Recalculate();
|
||||
}
|
||||
|
||||
bool IsPointValid(uint32 idx) const {
|
||||
return m_SelectedPartition ==
|
||||
BPTCC::GetSubsetForIndex(idx, m_ShapeIdx, m_NumPartitions);
|
||||
}
|
||||
|
||||
private:
|
||||
// The number of points in the cluster.
|
||||
uint32 m_NumPoints;
|
||||
uint32 m_NumPartitions;
|
||||
uint32 m_SelectedPartition;
|
||||
uint32 m_ShapeIdx;
|
||||
|
||||
RGBAVector m_Avg;
|
||||
|
||||
// The points in the cluster.
|
||||
RGBAVector m_DataPoints[kMaxNumDataPoints];
|
||||
uint32 m_DataPixels[kMaxNumDataPoints];
|
||||
uint8 m_PointMap[kMaxNumDataPoints];
|
||||
RGBAVector m_Min, m_Max;
|
||||
|
||||
template<const uint8 nBuckets>
|
||||
double QuantizedError(
|
||||
const RGBAVector &p1, const RGBAVector &p2,
|
||||
uint32 bitMask, const RGBAVector &errorMetricVec,
|
||||
const int pbits[2] = NULL, uint8 *indices = NULL) const;
|
||||
|
||||
void Recalculate() {
|
||||
m_NumPoints = 0;
|
||||
m_Avg = RGBAVector(0.0f);
|
||||
m_Min = RGBAVector(std::numeric_limits<float>::max());
|
||||
m_Max = RGBAVector(-std::numeric_limits<float>::max());
|
||||
|
||||
uint32 map = 0;
|
||||
for(uint32 idx = 0; idx < 16; idx++) {
|
||||
if(!IsPointValid(idx)) continue;
|
||||
|
||||
m_NumPoints++;
|
||||
m_Avg += m_DataPoints[idx];
|
||||
m_PointMap[map++] = idx;
|
||||
|
||||
for(uint32 i = 0; i < kNumColorChannels; i++) {
|
||||
m_Min[i] = std::min(m_DataPoints[idx][i], m_Min[i]);
|
||||
m_Max[i] = std::max(m_DataPoints[idx][i], m_Max[i]);
|
||||
}
|
||||
}
|
||||
|
||||
m_Avg /= static_cast<float>(m_NumPoints);
|
||||
}
|
||||
};
|
||||
|
||||
// Makes sure that the values of the endpoints lie between 0 and 1.
|
||||
extern void ClampEndpoints(RGBAVector &p1, RGBAVector &p2);
|
||||
extern uint8 QuantizeChannel(const uint8 val, const uint8 mask, const int pBit = -1);
|
||||
|
||||
namespace FasTC {
|
||||
REGISTER_VECTOR_TYPE(RGBAVector);
|
||||
REGISTER_VECTOR_TYPE(RGBADir);
|
||||
}
|
||||
|
||||
#endif //__RGBA_ENDPOINTS_H__
|
|
@ -1,446 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
// The original lisence from the code available at the following location:
|
||||
// http://software.intel.com/en-us/vcsource/samples/fast-texture-compression
|
||||
//
|
||||
// This code has been modified significantly from the original.
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Copyright 2011 Intel Corporation
|
||||
// All Rights Reserved
|
||||
//
|
||||
// Permission is granted to use, copy, distribute and prepare derivative works of this
|
||||
// software for any purpose and without fee, provided, that the above copyright notice
|
||||
// and this statement appear in all copies. Intel makes no representations about the
|
||||
// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS."
|
||||
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
|
||||
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
|
||||
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not
|
||||
// assume any responsibility for any errors which may appear in this software nor any
|
||||
// responsibility to update it.
|
||||
//
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
#include "BC7Config.h"
|
||||
#include "RGBAEndpointsSIMD.h"
|
||||
#include "BC7Compressor.h"
|
||||
#include "BC7CompressionModeSIMD.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cfloat>
|
||||
|
||||
#ifndef HAS_SSE_POPCNT
|
||||
static inline uint32 popcnt32(uint32 x) {
|
||||
uint32 m1 = 0x55555555;
|
||||
uint32 m2 = 0x33333333;
|
||||
uint32 m3 = 0x0f0f0f0f;
|
||||
x -= (x>>1) & 1;
|
||||
x = (x&m2) + ((x>>2)&m2);
|
||||
x = (x+(x>>4))&m3;
|
||||
x += x>>8;
|
||||
return (x+(x>>16)) & 0x3f;
|
||||
}
|
||||
#endif
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// RGBAVectorSIMD implementation
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/* Original scalar implementation:
|
||||
|
||||
// If the mask is all the bits, then we can just return the value.
|
||||
if(mask == 0xFF) {
|
||||
return val;
|
||||
}
|
||||
|
||||
uint32 prec = CountBitsInMask(mask);
|
||||
const uint32 step = 1 << (8 - prec);
|
||||
|
||||
assert(step-1 == uint8(~mask));
|
||||
|
||||
uint32 lval = val & mask;
|
||||
uint32 hval = lval + step;
|
||||
|
||||
if(pBit >= 0) {
|
||||
prec++;
|
||||
lval |= !!(pBit) << (8 - prec);
|
||||
hval |= !!(pBit) << (8 - prec);
|
||||
}
|
||||
|
||||
if(lval > val) {
|
||||
lval -= step;
|
||||
hval -= step;
|
||||
}
|
||||
|
||||
lval |= lval >> prec;
|
||||
hval |= hval >> prec;
|
||||
|
||||
if(sad(val, lval) < sad(val, hval))
|
||||
return lval;
|
||||
else
|
||||
return hval;
|
||||
*/
|
||||
|
||||
// !TODO! AVX2 supports an instruction known as vsllv, which shifts a vector
|
||||
// by the values stored in another vector. I.e. you can do something like this:
|
||||
//
|
||||
// __m128i shiftVals = _mm_set_epi32(1, 2, 3, 4);
|
||||
// __m128i someVector = _mm_set1_epi32(1) ;
|
||||
// __m128i shifted = _mm_srav_epi32 (someVector, shiftVals);
|
||||
//
|
||||
// and the result will be the same as __mm_Set_epi32(1, 4, 8, 16);
|
||||
//
|
||||
// This is useful because our color channels may have different precisions
|
||||
// when we're quantizing them, such as for BC7 modes 4 and 5. Hence, we would
|
||||
// want to do our quantization as accurately as possible, but currently it would
|
||||
// be very hard to vectorize.
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define ALIGN_SSE __declspec ( align(16) )
|
||||
#else
|
||||
#define ALIGN_SSE __attribute__((aligned(16)))
|
||||
#endif
|
||||
|
||||
// Constants. There are two ways to specify them: either by using the _mm_set*
|
||||
// intrinsics, or by defining them as aligned arrays. You want to do the former
|
||||
// when you use them infrequently, and the latter when you use them multiple times
|
||||
// in a short time frame (like in an inner loop)
|
||||
static const __m128 kZero = _mm_set1_ps(0.0f);
|
||||
static const __m128 kByteMax = _mm_set1_ps(255.0f);
|
||||
static const __m128 kHalfVector = _mm_set1_ps(0.5f);
|
||||
static const __m128i kOneVector = _mm_set1_epi32(1);
|
||||
static const __m128i kZeroVector = _mm_set1_epi32(0);
|
||||
static const ALIGN_SSE uint32 kThirtyTwoVector[4] = { 32, 32, 32, 32 };
|
||||
static const __m128i kByteValMask = _mm_set_epi32(0xFF, 0xFF, 0xFF, 0xFF);
|
||||
|
||||
static inline __m128i sad(const __m128i &a, const __m128i &b) {
|
||||
const __m128i maxab = _mm_max_epu8(a, b);
|
||||
const __m128i minab = _mm_min_epu8(a, b);
|
||||
return _mm_and_si128( kByteValMask, _mm_subs_epu8( maxab, minab ) );
|
||||
}
|
||||
|
||||
__m128i RGBAVectorSIMD::ToPixel(const __m128i &qmask) const {
|
||||
|
||||
// !SPEED! We should figure out a way to get rid of these scalar operations.
|
||||
#ifdef HAS_SSE_POPCNT
|
||||
const uint32 prec = _mm_popcnt_u32(((uint32 *)(&qmask))[0]);
|
||||
#else
|
||||
const uint32 prec = popcnt32(((uint32 *)(&qmask))[0]);
|
||||
#endif
|
||||
|
||||
assert(r >= 0.0f && r <= 255.0f);
|
||||
assert(g >= 0.0f && g <= 255.0f);
|
||||
assert(b >= 0.0f && b <= 255.0f);
|
||||
assert(a >= 0.0f && a <= 255.0f);
|
||||
assert(((uint32 *)(&qmask))[3] == 0xFF || ((uint32 *)(&qmask))[3] == ((uint32 *)(&qmask))[0]);
|
||||
assert(((uint32 *)(&qmask))[2] == ((uint32 *)(&qmask))[1] && ((uint32 *)(&qmask))[0] == ((uint32 *)(&qmask))[1]);
|
||||
|
||||
const __m128i val = _mm_cvtps_epi32( _mm_add_ps(kHalfVector, vec) );
|
||||
|
||||
const __m128i step = _mm_slli_epi32( kOneVector, 8 - prec );
|
||||
const __m128i &mask = qmask;
|
||||
|
||||
__m128i lval = _mm_and_si128(val, mask);
|
||||
__m128i hval = _mm_add_epi32(lval, step);
|
||||
|
||||
const __m128i lvalShift = _mm_srli_epi32(lval, prec);
|
||||
const __m128i hvalShift = _mm_srli_epi32(hval, prec);
|
||||
|
||||
lval = _mm_or_si128(lval, lvalShift);
|
||||
hval = _mm_or_si128(hval, hvalShift);
|
||||
|
||||
const __m128i lvald = _mm_sub_epi32( val, lval );
|
||||
const __m128i hvald = _mm_sub_epi32( hval, val );
|
||||
|
||||
const __m128i vd = _mm_cmplt_epi32(lvald, hvald);
|
||||
__m128i ans = _mm_blendv_epi8(hval, lval, vd);
|
||||
|
||||
const __m128i chanExact = _mm_cmpeq_epi32(mask, kByteValMask);
|
||||
ans = _mm_blendv_epi8( ans, val, chanExact );
|
||||
return ans;
|
||||
}
|
||||
|
||||
__m128i RGBAVectorSIMD::ToPixel(const __m128i &qmask, const int pBit) const {
|
||||
|
||||
// !SPEED! We should figure out a way to get rid of these scalar operations.
|
||||
#ifdef HAS_SSE_POPCNT
|
||||
const uint32 prec = _mm_popcnt_u32(((uint32 *)(&qmask))[0]);
|
||||
#else
|
||||
const uint32 prec = popcnt32(((uint32 *)(&qmask))[0]);
|
||||
#endif
|
||||
|
||||
assert(r >= 0.0f && r <= 255.0f);
|
||||
assert(g >= 0.0f && g <= 255.0f);
|
||||
assert(b >= 0.0f && b <= 255.0f);
|
||||
assert(a >= 0.0f && a <= 255.0f);
|
||||
assert(((uint32 *)(&qmask))[3] == 0xFF || ((uint32 *)(&qmask))[3] == ((uint32 *)(&qmask))[0]);
|
||||
assert(((uint32 *)(&qmask))[2] == ((uint32 *)(&qmask))[1] && ((uint32 *)(&qmask))[0] == ((uint32 *)(&qmask))[1]);
|
||||
|
||||
const __m128i val = _mm_cvtps_epi32( _mm_add_ps(kHalfVector, vec) );
|
||||
const __m128i pbit = _mm_set1_epi32(!!pBit);
|
||||
|
||||
const __m128i &mask = qmask; // _mm_set_epi32(alphaMask, channelMask, channelMask, channelMask);
|
||||
const __m128i step = _mm_slli_epi32( kOneVector, 8 - prec );
|
||||
|
||||
__m128i lval = _mm_and_si128( val, mask );
|
||||
__m128i hval = _mm_add_epi32( lval, step );
|
||||
|
||||
const __m128i pBitShifted = _mm_slli_epi32(pbit, 7 - prec);
|
||||
lval = _mm_or_si128(lval, pBitShifted );
|
||||
hval = _mm_or_si128(hval, pBitShifted);
|
||||
|
||||
// These next three lines we make sure that after adding the pbit that val is
|
||||
// still in between lval and hval. If it isn't, then we subtract a
|
||||
// step from both. Now, val should be larger than lval and less than
|
||||
// hval, but certain situations make this not always the case (e.g. val
|
||||
// is 0, precision is 4 bits, and pbit is 1). Hence, we add back the
|
||||
// step if it goes below zero, making it equivalent to hval and so it
|
||||
// doesn't matter which we choose.
|
||||
{
|
||||
__m128i cmp = _mm_cmpgt_epi32(lval, val);
|
||||
cmp = _mm_mullo_epi32(cmp, step);
|
||||
lval = _mm_add_epi32(lval, cmp);
|
||||
hval = _mm_add_epi32(hval, cmp);
|
||||
|
||||
cmp = _mm_cmplt_epi32(lval, kZeroVector);
|
||||
cmp = _mm_mullo_epi32(cmp, step);
|
||||
lval = _mm_sub_epi32(lval, cmp);
|
||||
}
|
||||
|
||||
const __m128i lvalShift = _mm_srli_epi32(lval, prec + 1);
|
||||
const __m128i hvalShift = _mm_srli_epi32(hval, prec + 1);
|
||||
|
||||
lval = _mm_or_si128(lval, lvalShift);
|
||||
hval = _mm_or_si128(hval, hvalShift);
|
||||
|
||||
const __m128i lvald = _mm_sub_epi32( val, lval );
|
||||
const __m128i hvald = _mm_sub_epi32( hval, val );
|
||||
|
||||
const __m128i vd = _mm_cmplt_epi32(lvald, hvald);
|
||||
__m128i ans = _mm_blendv_epi8(hval, lval, vd);
|
||||
|
||||
const __m128i chanExact = _mm_cmpeq_epi32(mask, kByteValMask);
|
||||
ans = _mm_blendv_epi8( ans, val, chanExact );
|
||||
return ans;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// RGBAMatrixSIMD implementation
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RGBAVectorSIMD RGBAMatrixSIMD::operator *(const RGBAVectorSIMD &p) const {
|
||||
|
||||
__m128 xVec = _mm_set1_ps( p.x );
|
||||
__m128 yVec = _mm_set1_ps( p.y );
|
||||
__m128 zVec = _mm_set1_ps( p.z );
|
||||
__m128 wVec = _mm_set1_ps( p.w );
|
||||
|
||||
__m128 vec1 = _mm_mul_ps( xVec, col[0] );
|
||||
__m128 vec2 = _mm_mul_ps( yVec, col[1] );
|
||||
__m128 vec3 = _mm_mul_ps( zVec, col[2] );
|
||||
__m128 vec4 = _mm_mul_ps( wVec, col[3] );
|
||||
|
||||
return RGBAVectorSIMD( _mm_add_ps( _mm_add_ps( vec1, vec2 ), _mm_add_ps( vec3, vec4 ) ) );
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Cluster implementation
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RGBAClusterSIMD::RGBAClusterSIMD(const RGBAClusterSIMD &left, const RGBAClusterSIMD &right) {
|
||||
|
||||
assert(!(left.m_PointBitString & right.m_PointBitString));
|
||||
|
||||
*this = left;
|
||||
for(int i = 0; i < right.m_NumPoints; i++) {
|
||||
|
||||
const RGBAVectorSIMD &p = right.m_DataPoints[i];
|
||||
|
||||
assert(m_NumPoints < kMaxNumDataPoints);
|
||||
m_Total += p;
|
||||
m_DataPoints[m_NumPoints++] = p;
|
||||
|
||||
m_Min.vec = _mm_min_ps(m_Min.vec, p.vec);
|
||||
m_Max.vec = _mm_max_ps(m_Max.vec, p.vec);
|
||||
}
|
||||
|
||||
m_PointBitString = left.m_PointBitString | right.m_PointBitString;
|
||||
m_PrincipalAxisCached = false;
|
||||
}
|
||||
|
||||
void RGBAClusterSIMD::AddPoint(const RGBAVectorSIMD &p, int idx) {
|
||||
assert(m_NumPoints < kMaxNumDataPoints);
|
||||
m_Total += p;
|
||||
m_DataPoints[m_NumPoints++] = p;
|
||||
m_PointBitString |= 1 << idx;
|
||||
|
||||
m_Min.vec = _mm_min_ps(m_Min.vec, p.vec);
|
||||
m_Max.vec = _mm_max_ps(m_Max.vec, p.vec);
|
||||
}
|
||||
|
||||
float RGBAClusterSIMD::QuantizedError(const RGBAVectorSIMD &p1, const RGBAVectorSIMD &p2, const uint8 nBuckets, const __m128i &bitMask, const int pbits[2], __m128i *indices) const {
|
||||
|
||||
// nBuckets should be a power of two.
|
||||
assert(!(nBuckets & (nBuckets - 1)));
|
||||
|
||||
#ifdef HAS_SSE_POPCNT
|
||||
const uint8 indexPrec = 8-_mm_popcnt_u32(~(nBuckets - 1) & 0xFF);
|
||||
#else
|
||||
const uint8 indexPrec = 8-popcnt32(~(nBuckets - 1) & 0xFF);
|
||||
#endif
|
||||
assert(indexPrec >= 2 && indexPrec <= 4);
|
||||
|
||||
typedef __m128i tInterpPair[2];
|
||||
typedef tInterpPair tInterpLevel[16];
|
||||
const tInterpLevel *interpVals = kBC7InterpolationValuesSIMD + (indexPrec - 1);
|
||||
|
||||
__m128i qp1, qp2;
|
||||
if(pbits) {
|
||||
qp1 = p1.ToPixel(bitMask, pbits[0]);
|
||||
qp2 = p2.ToPixel(bitMask, pbits[1]);
|
||||
}
|
||||
else {
|
||||
qp1 = p1.ToPixel(bitMask);
|
||||
qp2 = p2.ToPixel(bitMask);
|
||||
}
|
||||
|
||||
__m128 errorMetricVec = _mm_load_ps( BC7C::GetErrorMetric() );
|
||||
|
||||
__m128 totalError = kZero;
|
||||
for(int i = 0; i < m_NumPoints; i++) {
|
||||
|
||||
const __m128i pixel = m_DataPoints[i].ToPixel( kByteValMask );
|
||||
|
||||
__m128 minError = _mm_set1_ps(FLT_MAX);
|
||||
__m128i bestBucket = _mm_set1_epi32(-1);
|
||||
for(int j = 0; j < nBuckets; j++) {
|
||||
|
||||
const __m128i jVec = _mm_set1_epi32(j);
|
||||
const __m128i interp0 = (*interpVals)[j][0];
|
||||
const __m128i interp1 = (*interpVals)[j][1];
|
||||
|
||||
const __m128i ip0 = _mm_mullo_epi32( qp1, interp0 );
|
||||
const __m128i ip1 = _mm_mullo_epi32( qp2, interp1 );
|
||||
const __m128i ip = _mm_add_epi32( *((const __m128i *)kThirtyTwoVector), _mm_add_epi32( ip0, ip1 ) );
|
||||
const __m128i dist = sad( _mm_and_si128( _mm_srli_epi32( ip, 6 ), kByteValMask ), pixel );
|
||||
__m128 errorVec = _mm_cvtepi32_ps( dist );
|
||||
|
||||
errorVec = _mm_mul_ps( errorVec, errorMetricVec );
|
||||
errorVec = _mm_mul_ps( errorVec, errorVec );
|
||||
errorVec = _mm_hadd_ps( errorVec, errorVec );
|
||||
errorVec = _mm_hadd_ps( errorVec, errorVec );
|
||||
|
||||
const __m128 cmp = _mm_cmple_ps( errorVec, minError );
|
||||
minError = _mm_blendv_ps( minError, errorVec, cmp );
|
||||
bestBucket = _mm_blendv_epi8( bestBucket, jVec, _mm_castps_si128( cmp ) );
|
||||
|
||||
// Conceptually, once the error starts growing, it doesn't stop growing (we're moving
|
||||
// farther away from the reference point along the line). Hence we can early out here.
|
||||
// However, quanitzation artifacts mean that this is not ALWAYS the case, so we do suffer
|
||||
// about 0.01 RMS error.
|
||||
if(!((uint8 *)(&cmp))[0])
|
||||
break;
|
||||
}
|
||||
|
||||
totalError = _mm_add_ps(totalError, minError);
|
||||
if(indices) ((uint32 *)indices)[i] = ((uint32 *)(&bestBucket))[0];
|
||||
}
|
||||
|
||||
return ((float *)(&totalError))[0];
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Utility function implementation
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void ClampEndpoints(RGBAVectorSIMD &p1, RGBAVectorSIMD &p2) {
|
||||
p1.vec = _mm_min_ps( kByteMax, _mm_max_ps( p1.vec, kZero ) );
|
||||
p2.vec = _mm_min_ps( kByteMax, _mm_max_ps( p2.vec, kZero ) );
|
||||
}
|
||||
|
||||
void GetPrincipalAxis(const RGBAClusterSIMD &c, RGBADirSIMD &axis) {
|
||||
|
||||
if(c.GetNumPoints() == 2) {
|
||||
axis = c.GetPoint(1) - c.GetPoint(0);
|
||||
return;
|
||||
}
|
||||
|
||||
RGBAVectorSIMD avg = c.GetTotal();
|
||||
avg /= float(c.GetNumPoints());
|
||||
|
||||
// We use these vectors for calculating the covariance matrix...
|
||||
RGBAVectorSIMD toPts[kMaxNumDataPoints];
|
||||
RGBAVectorSIMD toPtsMax(-FLT_MAX);
|
||||
for(int i = 0; i < c.GetNumPoints(); i++) {
|
||||
toPts[i] = c.GetPoint(i) - avg;
|
||||
toPtsMax.vec = _mm_max_ps(toPtsMax.vec, toPts[i].vec);
|
||||
}
|
||||
|
||||
RGBAMatrixSIMD covMatrix;
|
||||
|
||||
// Compute covariance.
|
||||
const float fNumPoints = float(c.GetNumPoints());
|
||||
for(int i = 0; i < kNumColorChannels; i++) {
|
||||
for(int j = 0; j <= i; j++) {
|
||||
|
||||
float sum = 0.0;
|
||||
for(int k = 0; k < c.GetNumPoints(); k++) {
|
||||
sum += toPts[k].c[i] * toPts[k].c[j];
|
||||
}
|
||||
|
||||
covMatrix(i, j) = sum / fNumPoints;
|
||||
covMatrix(j, i) = covMatrix(i, j);
|
||||
}
|
||||
}
|
||||
|
||||
// !SPEED! Find eigenvectors by using the power method. This is good because the
|
||||
// matrix is only 4x4, which allows us to use SIMD...
|
||||
RGBAVectorSIMD b = toPtsMax;
|
||||
assert(b.Length() > 0);
|
||||
b /= b.Length();
|
||||
|
||||
RGBAVectorSIMD newB = covMatrix * b;
|
||||
|
||||
// !HACK! If the principal eigenvector of the covariance matrix
|
||||
// converges to zero, that means that the points lie equally
|
||||
// spaced on a sphere in this space. In this (extremely rare)
|
||||
// situation, just choose a point and use it as the principal
|
||||
// direction.
|
||||
const float newBlen = newB.Length();
|
||||
if(newBlen < 1e-10) {
|
||||
axis = toPts[0];
|
||||
return;
|
||||
}
|
||||
|
||||
for(int i = 0; i < 8; i++) {
|
||||
newB = covMatrix * b;
|
||||
newB.Normalize();
|
||||
b = newB;
|
||||
}
|
||||
|
||||
axis = b;
|
||||
}
|
|
@ -1,397 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
// The original lisence from the code available at the following location:
|
||||
// http://software.intel.com/en-us/vcsource/samples/fast-texture-compression
|
||||
//
|
||||
// This code has been modified significantly from the original.
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Copyright 2011 Intel Corporation
|
||||
// All Rights Reserved
|
||||
//
|
||||
// Permission is granted to use, copy, distribute and prepare derivative works of this
|
||||
// software for any purpose and without fee, provided, that the above copyright notice
|
||||
// and this statement appear in all copies. Intel makes no representations about the
|
||||
// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS."
|
||||
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
|
||||
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
|
||||
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not
|
||||
// assume any responsibility for any errors which may appear in this software nor any
|
||||
// responsibility to update it.
|
||||
//
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
#ifndef __RGBA_SIMD_ENDPOINTS_H__
|
||||
#define __RGBA_SIMD_ENDPOINTS_H__
|
||||
|
||||
#include "TexCompTypes.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cfloat>
|
||||
#include <cstring>
|
||||
|
||||
#include <smmintrin.h>
|
||||
|
||||
static const int kNumColorChannels = 4;
|
||||
static const int kMaxNumDataPoints = 16;
|
||||
static const __m128 kEpsilonSIMD = _mm_set1_ps(1e-8f);
|
||||
|
||||
class RGBAVectorSIMD {
|
||||
|
||||
public:
|
||||
union {
|
||||
struct { float r, g, b, a; };
|
||||
struct { float x, y, z, w; };
|
||||
float c[4];
|
||||
__m128 vec;
|
||||
};
|
||||
|
||||
RGBAVectorSIMD() : r(-1.0), g(-1.0), b(-1.0), a(-1.0) { }
|
||||
RGBAVectorSIMD(uint32 pixel) :
|
||||
r(float(pixel & 0xFF)),
|
||||
g(float((pixel >> 8) & 0xFF)),
|
||||
b(float((pixel >> 16) & 0xFF)),
|
||||
a(float((pixel >> 24) & 0xFF))
|
||||
{ }
|
||||
|
||||
explicit RGBAVectorSIMD(float _r, float _g, float _b, float _a) :
|
||||
r(_r), g(_g), b(_b), a(_a) { }
|
||||
|
||||
explicit RGBAVectorSIMD(float cc) : r(cc), g(cc), b(cc), a(cc) { }
|
||||
|
||||
RGBAVectorSIMD (const __m128 &newVec) : vec(newVec) { }
|
||||
RGBAVectorSIMD (const RGBAVectorSIMD &other) : vec(other.vec) { }
|
||||
|
||||
RGBAVectorSIMD operator +(const RGBAVectorSIMD &p) const {
|
||||
return RGBAVectorSIMD( _mm_add_ps(this->vec, p.vec) );
|
||||
}
|
||||
|
||||
RGBAVectorSIMD &operator +=(const RGBAVectorSIMD &p) {
|
||||
this->vec = _mm_add_ps(this->vec, p.vec);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RGBAVectorSIMD operator -(const RGBAVectorSIMD &p) const {
|
||||
return RGBAVectorSIMD( _mm_sub_ps(this->vec, p.vec) );
|
||||
}
|
||||
|
||||
RGBAVectorSIMD &operator -=(const RGBAVectorSIMD &p) {
|
||||
this->vec = _mm_sub_ps(this->vec, p.vec);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RGBAVectorSIMD operator /(const float s) const {
|
||||
return RGBAVectorSIMD( _mm_div_ps(this->vec, _mm_set1_ps(s) ) );
|
||||
}
|
||||
|
||||
RGBAVectorSIMD &operator /=(const float s) {
|
||||
this->vec = _mm_div_ps(this->vec, _mm_set1_ps(s) );
|
||||
return *this;
|
||||
}
|
||||
|
||||
float operator *(const RGBAVectorSIMD &p) const {
|
||||
__m128 mul = _mm_mul_ps(this->vec, p.vec);
|
||||
mul = _mm_hadd_ps(mul, mul);
|
||||
mul = _mm_hadd_ps(mul, mul);
|
||||
return ((float *)(&mul))[0];
|
||||
}
|
||||
|
||||
void Normalize() {
|
||||
__m128 rsqrt = _mm_rsqrt_ps( _mm_set1_ps( (*this) * (*this) ) );
|
||||
vec = _mm_mul_ps( vec, rsqrt );
|
||||
}
|
||||
|
||||
float Length() const {
|
||||
return sqrt((*this) * (*this));
|
||||
}
|
||||
|
||||
RGBAVectorSIMD &operator *=(const RGBAVectorSIMD &v) {
|
||||
this->vec = _mm_mul_ps(this->vec, v.vec);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RGBAVectorSIMD operator *(const float s) const {
|
||||
return RGBAVectorSIMD( _mm_mul_ps( this->vec, _mm_set1_ps(s) ) );
|
||||
}
|
||||
|
||||
friend RGBAVectorSIMD operator *(const float s, const RGBAVectorSIMD &p) {
|
||||
return RGBAVectorSIMD( _mm_mul_ps( p.vec, _mm_set1_ps(s) ) );
|
||||
}
|
||||
|
||||
RGBAVectorSIMD &operator *=(const float s) {
|
||||
this->vec = _mm_mul_ps( this->vec, _mm_set1_ps(s) );
|
||||
return *this;
|
||||
}
|
||||
|
||||
float &operator [](const int i) {
|
||||
return c[i];
|
||||
}
|
||||
|
||||
friend bool operator ==(const RGBAVectorSIMD &rhs, const RGBAVectorSIMD &lhs) {
|
||||
__m128 d = _mm_sub_ps(rhs.vec, lhs.vec);
|
||||
d = _mm_mul_ps(d, d);
|
||||
__m128 cmp = _mm_cmpgt_ps(d, kEpsilonSIMD);
|
||||
cmp = _mm_hadd_ps(cmp, cmp);
|
||||
cmp = _mm_hadd_ps(cmp, cmp);
|
||||
return ((float *)(&cmp))[0] == 0.0f;
|
||||
}
|
||||
|
||||
friend bool operator !=(const RGBAVectorSIMD &rhs, const RGBAVectorSIMD &lhs) {
|
||||
return !(rhs == lhs);
|
||||
}
|
||||
|
||||
operator float *() {
|
||||
return c;
|
||||
}
|
||||
|
||||
// Quantize this point.
|
||||
__m128i ToPixel(const __m128i &channelMask, const int pBit) const;
|
||||
__m128i ToPixel(const __m128i &channelMask) const;
|
||||
};
|
||||
|
||||
class RGBAMatrixSIMD {
|
||||
private:
|
||||
union {
|
||||
float m[kNumColorChannels*kNumColorChannels];
|
||||
struct {
|
||||
float m1, m5, m9, m13;
|
||||
float m2, m6, m10, m14;
|
||||
float m3, m7, m11, m15;
|
||||
float m4, m8, m12, m16;
|
||||
};
|
||||
__m128 col[kNumColorChannels];
|
||||
};
|
||||
|
||||
RGBAMatrixSIMD(const float *arr) {
|
||||
memcpy(m, arr, sizeof(m));
|
||||
}
|
||||
|
||||
RGBAMatrixSIMD(const __m128 newcol[kNumColorChannels]) {
|
||||
for(int i = 0; i < kNumColorChannels; i++)
|
||||
col[i] = newcol[i];
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
RGBAMatrixSIMD() :
|
||||
m1(1.0f), m2(0.0f), m3(0.0f), m4(0.0f),
|
||||
m5(0.0f), m6(1.0f), m7(0.0f), m8(0.0f),
|
||||
m9(0.0f), m10(0.0f), m11(1.0f), m12(0.0f),
|
||||
m13(0.0f), m14(0.0f), m15(0.0f), m16(1.0f)
|
||||
{ }
|
||||
|
||||
RGBAMatrixSIMD &operator =(const RGBAMatrixSIMD &other) {
|
||||
memcpy(m, other.m, sizeof(m));
|
||||
return (*this);
|
||||
}
|
||||
|
||||
RGBAMatrixSIMD operator +(const RGBAMatrixSIMD &p) const {
|
||||
RGBAMatrixSIMD newm;
|
||||
for(int i = 0; i < kNumColorChannels; i++) {
|
||||
newm.col[i] = _mm_add_ps(col[i], p.col[i]);
|
||||
}
|
||||
return newm;
|
||||
}
|
||||
|
||||
RGBAMatrixSIMD &operator +=(const RGBAMatrixSIMD &p) {
|
||||
for(int i = 0; i < kNumColorChannels; i++) {
|
||||
col[i] = _mm_add_ps( col[i], p.col[i] );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
RGBAMatrixSIMD operator -(const RGBAMatrixSIMD &p) const {
|
||||
RGBAMatrixSIMD newm;
|
||||
for(int i = 0; i < kNumColorChannels; i++) {
|
||||
newm.col[i] = _mm_sub_ps( col[i], p.col[i] );
|
||||
}
|
||||
return newm;
|
||||
}
|
||||
|
||||
RGBAMatrixSIMD &operator -=(const RGBAMatrixSIMD &p) {
|
||||
for(int i = 0; i < kNumColorChannels; i++) {
|
||||
col[i] = _mm_sub_ps( col[i], p.col[i] );
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
RGBAMatrixSIMD operator /(const float s) const {
|
||||
__m128 f = _mm_set1_ps(s);
|
||||
RGBAMatrixSIMD newm;
|
||||
|
||||
for(int i = 0; i < kNumColorChannels; i++) {
|
||||
newm.col[i] = _mm_div_ps( col[i], f );
|
||||
}
|
||||
|
||||
return newm;
|
||||
}
|
||||
|
||||
RGBAMatrixSIMD &operator /=(const float s) {
|
||||
|
||||
__m128 f = _mm_set1_ps(s);
|
||||
|
||||
for(int i = 0; i < kNumColorChannels; i++) {
|
||||
col[i] = _mm_div_ps(col[i], f);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
RGBAMatrixSIMD operator *(const float s) const {
|
||||
__m128 f = _mm_set1_ps(s);
|
||||
|
||||
RGBAMatrixSIMD newm;
|
||||
for(int i = 0; i < kNumColorChannels; i++) {
|
||||
newm.col[i] = _mm_mul_ps( col[i], f );
|
||||
}
|
||||
return newm;
|
||||
}
|
||||
|
||||
friend RGBAMatrixSIMD operator *(const float s, const RGBAMatrixSIMD &p) {
|
||||
__m128 f = _mm_set1_ps(s);
|
||||
RGBAMatrixSIMD newm;
|
||||
|
||||
for(int i = 0; i < kNumColorChannels; i++) {
|
||||
newm.col[i] = _mm_mul_ps( p.col[i], f );
|
||||
}
|
||||
return newm;
|
||||
}
|
||||
|
||||
RGBAMatrixSIMD &operator *=(const float s) {
|
||||
__m128 f = _mm_set1_ps(s);
|
||||
for(int i = 0; i < kNumColorChannels; i++)
|
||||
col[i] = _mm_mul_ps(col[i], f);
|
||||
return *this;
|
||||
}
|
||||
|
||||
float &operator ()(const int i, const int j) {
|
||||
return (*this)[j*4 + i];
|
||||
}
|
||||
|
||||
float &operator [](const int i) {
|
||||
return m[i];
|
||||
}
|
||||
|
||||
friend bool operator ==(const RGBAMatrixSIMD &rhs, const RGBAMatrixSIMD &lhs) {
|
||||
|
||||
__m128 sum = _mm_set1_ps(0.0f);
|
||||
for(int i = 0; i < kNumColorChannels; i++) {
|
||||
__m128 d = _mm_sub_ps(rhs.col[i], lhs.col[i]);
|
||||
d = _mm_mul_ps(d, d);
|
||||
__m128 cmp = _mm_cmpgt_ps(d, kEpsilonSIMD);
|
||||
cmp = _mm_hadd_ps(cmp, cmp);
|
||||
cmp = _mm_hadd_ps(cmp, cmp);
|
||||
sum = _mm_add_ps(sum, cmp);
|
||||
}
|
||||
|
||||
if(((float *)(&sum))[0] != 0)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
operator float *() {
|
||||
return m;
|
||||
}
|
||||
|
||||
RGBAVectorSIMD operator *(const RGBAVectorSIMD &p) const;
|
||||
};
|
||||
|
||||
class RGBADirSIMD : public RGBAVectorSIMD {
|
||||
public:
|
||||
RGBADirSIMD() : RGBAVectorSIMD() { }
|
||||
RGBADirSIMD(const RGBAVectorSIMD &p) : RGBAVectorSIMD(p) {
|
||||
this->Normalize();
|
||||
}
|
||||
};
|
||||
|
||||
// Makes sure that the values of the endpoints lie between 0 and 1.
|
||||
extern void ClampEndpoints(RGBAVectorSIMD &p1, RGBAVectorSIMD &p2);
|
||||
|
||||
class RGBAClusterSIMD {
|
||||
public:
|
||||
|
||||
RGBAClusterSIMD() :
|
||||
m_NumPoints(0), m_Total(0.0f),
|
||||
m_PointBitString(0),
|
||||
m_Min(FLT_MAX),
|
||||
m_Max(-FLT_MAX),
|
||||
m_PrincipalAxisCached(false)
|
||||
{ }
|
||||
|
||||
RGBAClusterSIMD(const RGBAClusterSIMD &c) :
|
||||
m_NumPoints(c.m_NumPoints),
|
||||
m_Total(c.m_Total),
|
||||
m_PointBitString(c.m_PointBitString),
|
||||
m_Min(c.m_Min),
|
||||
m_Max(c.m_Max),
|
||||
m_PrincipalAxisCached(false)
|
||||
{
|
||||
memcpy(this->m_DataPoints, c.m_DataPoints, m_NumPoints * sizeof(RGBAVectorSIMD));
|
||||
}
|
||||
|
||||
RGBAClusterSIMD(const RGBAClusterSIMD &left, const RGBAClusterSIMD &right);
|
||||
RGBAClusterSIMD(const RGBAVectorSIMD &p, int idx) :
|
||||
m_NumPoints(1),
|
||||
m_Total(p),
|
||||
m_PointBitString(0),
|
||||
m_Min(p), m_Max(p),
|
||||
m_PrincipalAxisCached(false)
|
||||
{
|
||||
m_DataPoints[0] = p;
|
||||
m_PointBitString |= (1 << idx);
|
||||
}
|
||||
|
||||
RGBAVectorSIMD GetTotal() const { return m_Total; }
|
||||
const RGBAVectorSIMD &GetPoint(int idx) const { return m_DataPoints[idx]; }
|
||||
int GetNumPoints() const { return m_NumPoints; }
|
||||
RGBAVectorSIMD GetAvg() const { return m_Total / float(m_NumPoints); }
|
||||
|
||||
void AddPoint(const RGBAVectorSIMD &p, int idx);
|
||||
|
||||
void GetBoundingBox(RGBAVectorSIMD &Min, RGBAVectorSIMD &Max) const {
|
||||
Min = m_Min, Max = m_Max;
|
||||
}
|
||||
|
||||
// Returns the error if we were to quantize the colors right now with the given number of buckets and bit mask.
|
||||
float QuantizedError(const RGBAVectorSIMD &p1, const RGBAVectorSIMD &p2, const uint8 nBuckets, const __m128i &bitMask, const int pbits[2] = NULL, __m128i *indices = NULL) const;
|
||||
|
||||
bool AllSamePoint() const { return m_Max == m_Min; }
|
||||
int GetPointBitString() const { return m_PointBitString; }
|
||||
|
||||
private:
|
||||
|
||||
// The number of points in the cluster.
|
||||
int m_NumPoints;
|
||||
|
||||
RGBAVectorSIMD m_Total;
|
||||
|
||||
// The points in the cluster.
|
||||
RGBAVectorSIMD m_DataPoints[kMaxNumDataPoints];
|
||||
|
||||
RGBAVectorSIMD m_Min, m_Max;
|
||||
int m_PointBitString;
|
||||
|
||||
RGBADirSIMD m_PrincipalAxis;
|
||||
bool m_PrincipalAxisCached;
|
||||
};
|
||||
|
||||
extern void GetPrincipalAxis(const RGBAClusterSIMD &c, RGBADirSIMD &axis);
|
||||
|
||||
#endif //__RGBA_SIMD_ENDPOINTS_H__
|
|
@ -1,58 +0,0 @@
|
|||
# Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
# <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR}/Base/include )
|
||||
INCLUDE_DIRECTORIES( ${FasTC_BINARY_DIR}/Base/include )
|
||||
|
||||
INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR}/Core/include )
|
||||
INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR}/IO/include )
|
||||
|
||||
ADD_EXECUTABLE(
|
||||
tc
|
||||
"src/tc.cpp"
|
||||
)
|
||||
|
||||
ADD_EXECUTABLE(
|
||||
compare
|
||||
"src/compare.cpp"
|
||||
)
|
||||
|
||||
ADD_EXECUTABLE(
|
||||
decomp
|
||||
"src/decomp.cpp"
|
||||
)
|
||||
|
||||
# Add flag for link time code generation. This was used to build the libpng
|
||||
# libraries, so we should probably also include it for this project as well...
|
||||
IF( MSVC )
|
||||
SET_TARGET_PROPERTIES(tc PROPERTIES LINK_FLAGS "/LTCG")
|
||||
SET_TARGET_PROPERTIES(compare PROPERTIES LINK_FLAGS "/LTCG")
|
||||
SET_TARGET_PROPERTIES(decomp PROPERTIES LINK_FLAGS "/LTCG")
|
||||
ENDIF()
|
||||
|
||||
TARGET_LINK_LIBRARIES( tc FasTCBase )
|
||||
TARGET_LINK_LIBRARIES( tc FasTCIO )
|
||||
TARGET_LINK_LIBRARIES( tc FasTCCore )
|
||||
|
||||
TARGET_LINK_LIBRARIES( compare FasTCBase )
|
||||
TARGET_LINK_LIBRARIES( compare FasTCIO )
|
||||
|
||||
TARGET_LINK_LIBRARIES( decomp FasTCBase )
|
||||
TARGET_LINK_LIBRARIES( decomp FasTCIO )
|
||||
|
||||
INSTALL(TARGETS tc compare decomp EXPORT FasTCTargets
|
||||
RUNTIME DESTINATION bin COMPONENT bin)
|
|
@ -1,130 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#ifdef _MSC_VER
|
||||
# include <SDKDDKVer.h>
|
||||
# include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include "FasTC/Image.h"
|
||||
#include "FasTC/ImageFile.h"
|
||||
#include "FasTC/TexComp.h"
|
||||
#include "FasTC/ThreadSafeStreambuf.h"
|
||||
|
||||
static void PrintUsageAndExit() {
|
||||
fprintf(stderr, "Usage: compare [-d] <img1> <img2>\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void gen_random(char *s, const int len) {
|
||||
static const char alphanum[] =
|
||||
"0123456789"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
srand(static_cast<unsigned int>(time(NULL)));
|
||||
for (int i = 0; i < len; ++i) {
|
||||
s[i] = alphanum[rand() % (sizeof(alphanum) - 1)];
|
||||
}
|
||||
|
||||
s[len] = 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if(argc < 3 || argc > 5) {
|
||||
PrintUsageAndExit();
|
||||
}
|
||||
|
||||
bool diff_images = false;
|
||||
float diff_multiplier = 1.0;
|
||||
int arg = 1;
|
||||
if (strncmp(argv[arg], "-d", 2) == 0) {
|
||||
diff_images = true;
|
||||
arg++;
|
||||
|
||||
if (argc == 5) {
|
||||
diff_multiplier = static_cast<float>(atoi(argv[arg]));
|
||||
if (diff_multiplier < 0) {
|
||||
PrintUsageAndExit();
|
||||
}
|
||||
arg++;
|
||||
}
|
||||
}
|
||||
|
||||
ImageFile img1f (argv[arg]);
|
||||
if(!img1f.Load()) {
|
||||
fprintf(stderr, "Error loading file: %s\n", argv[arg]);
|
||||
return 1;
|
||||
}
|
||||
arg++;
|
||||
|
||||
ImageFile img2f (argv[arg]);
|
||||
if(!img2f.Load()) {
|
||||
fprintf(stderr, "Error loading file: %s\n", argv[arg]);
|
||||
return 1;
|
||||
}
|
||||
arg++;
|
||||
|
||||
FasTC::Image<> &img1 = *img1f.GetImage();
|
||||
FasTC::Image<> &img2 = *img2f.GetImage();
|
||||
|
||||
if (img1.GetWidth() != img2.GetWidth() ||
|
||||
img1.GetHeight() != img2.GetHeight()) {
|
||||
std::cerr << "Images differ in dimension!" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (diff_images) {
|
||||
FasTC::Image<> diff = img1.Diff(&img2, diff_multiplier);
|
||||
|
||||
char fname_buf [5 + 16 + 4 + 1]; // "diff-" + hash + ".png" + null
|
||||
memset(fname_buf, 0, sizeof(fname_buf));
|
||||
strncat(fname_buf, "diff-", 5);
|
||||
gen_random(fname_buf + 5, 16);
|
||||
strncat(fname_buf + 5 + 16, ".png", 4);
|
||||
|
||||
EImageFileFormat fmt = ImageFile::DetectFileFormat(fname_buf);
|
||||
ImageFile cImgFile (fname_buf, fmt, diff);
|
||||
cImgFile.Write();
|
||||
}
|
||||
|
||||
double PSNR = img1.ComputePSNR(&img2);
|
||||
if(PSNR > 0.0) {
|
||||
fprintf(stdout, "PSNR: %.3f\n", PSNR);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "Error computing PSNR\n");
|
||||
}
|
||||
|
||||
double SSIM = img1.ComputeSSIM(&img2);
|
||||
if(SSIM > 0.0) {
|
||||
fprintf(stdout, "SSIM: %.9f\n", SSIM);
|
||||
} else {
|
||||
fprintf(stderr, "Error computing MSSIM\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#ifdef _MSC_VER
|
||||
# include <SDKDDKVer.h>
|
||||
# include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include "FasTC/Image.h"
|
||||
#include "FasTC/ImageFile.h"
|
||||
#include "FasTC/TexComp.h"
|
||||
#include "FasTC/ThreadSafeStreambuf.h"
|
||||
|
||||
void PrintUsage() {
|
||||
fprintf(stderr, "Usage: decomp <in_img> <out_img>\n");
|
||||
fprintf(stderr, "\tIf in_img is not a compressed image, then this tool simply copies the image.\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if(argc != 3) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
ImageFile imgf (argv[1]);
|
||||
if(!imgf.Load()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
FasTC::Image<> *img = imgf.GetImage();
|
||||
|
||||
EImageFileFormat fmt = ImageFile::DetectFileFormat(argv[2]);
|
||||
ImageFile cImgFile (argv[2], fmt, *img);
|
||||
cImgFile.Write();
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -1,346 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#ifdef _MSC_VER
|
||||
# include <SDKDDKVer.h>
|
||||
# include <Windows.h>
|
||||
# undef min
|
||||
# undef max
|
||||
#endif
|
||||
|
||||
#include "FasTC/Image.h"
|
||||
#include "FasTC/ImageFile.h"
|
||||
#include "FasTC/TexComp.h"
|
||||
#include "FasTC/ThreadSafeStreambuf.h"
|
||||
|
||||
void PrintUsage() {
|
||||
fprintf(stderr, "Usage: tc [OPTIONS] imagefile\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "\t-h|--help\tPrint this help.\n");
|
||||
fprintf(stderr, "\t-v\t\tVerbose mode: prints out Entropy, Mean Local Entropy, and MSSIM\n");
|
||||
fprintf(stderr, "\t-f <fmt>\tFormat to use. Either \"BPTC\", \"ETC1\", \"DXT1\", \"DXT5\", or \"PVRTC\". Default: BPTC\n");
|
||||
fprintf(stderr, "\t-l\t\tSave an output log.\n");
|
||||
fprintf(stderr, "\t-d <file>\tSpecify decompressed output (default: basename-<fmt>.png)\n");
|
||||
fprintf(stderr, "\t-nd\t\tSuppress decompressed output\n");
|
||||
fprintf(stderr, "\t-q <quality>\tSet compression quality level. Default: 50\n");
|
||||
fprintf(stderr, "\t-n <num>\tCompress the image num times and give the average time and PSNR. Default: 1\n");
|
||||
fprintf(stderr, "\t-simd\t\tUse SIMD compression path\n");
|
||||
fprintf(stderr, "\t-t <num>\tCompress the image using <num> threads. Default: 1\n");
|
||||
fprintf(stderr, "\t-a \t\tCompress the image using synchronization via atomic operations. Default: Off\n");
|
||||
fprintf(stderr, "\t-j <num>\tUse <num> blocks for each work item in a worker queue threading model. Default: (Blocks / Threads)\n");
|
||||
}
|
||||
|
||||
void ExtractBasename(const char *filename, char *buf, size_t bufSz) {
|
||||
size_t len = strlen(filename);
|
||||
const char *end = filename + len;
|
||||
const char *ext = end;
|
||||
const char *base = NULL;
|
||||
while(--end != filename && !base) {
|
||||
if(*end == '.') {
|
||||
ext = end;
|
||||
} else if(*end == '\\' || *end == '/') {
|
||||
base = end + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!base) {
|
||||
base = end;
|
||||
}
|
||||
|
||||
size_t numChars = ext - base + 1;
|
||||
size_t toCopy = ::std::min(numChars, bufSz);
|
||||
memcpy(buf, base, toCopy);
|
||||
buf[toCopy - 1] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
|
||||
int fileArg = 1;
|
||||
if (fileArg == argc) {
|
||||
PrintUsage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char decompressedOutput[256];
|
||||
decompressedOutput[0] = '\0';
|
||||
bool bDecompress = true;
|
||||
int numJobs = 0;
|
||||
int quality = 50;
|
||||
int numThreads = 1;
|
||||
int numCompressions = 1;
|
||||
bool bUseSIMD = false;
|
||||
bool bSaveLog = false;
|
||||
bool bUseAtomics = false;
|
||||
bool bUsePVRTexLib = false;
|
||||
bool bUseNVTT = false;
|
||||
bool bVerbose = false;
|
||||
FasTC::ECompressionFormat format = FasTC::eCompressionFormat_BPTC;
|
||||
|
||||
bool knowArg = false;
|
||||
do {
|
||||
knowArg = false;
|
||||
|
||||
if (strcmp(argv[fileArg], "-n") == 0) {
|
||||
fileArg++;
|
||||
|
||||
if (fileArg == argc || (numCompressions = atoi(argv[fileArg])) < 0) {
|
||||
PrintUsage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fileArg++;
|
||||
knowArg = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(argv[fileArg], "-f") == 0) {
|
||||
fileArg++;
|
||||
|
||||
if (fileArg == argc) {
|
||||
PrintUsage();
|
||||
exit(1);
|
||||
} else {
|
||||
if (!strcmp(argv[fileArg], "PVRTC")) {
|
||||
format = FasTC::eCompressionFormat_PVRTC4;
|
||||
} else if (!strcmp(argv[fileArg], "PVRTCLib")) {
|
||||
format = FasTC::eCompressionFormat_PVRTC4;
|
||||
bUsePVRTexLib = true;
|
||||
} else if (!strcmp(argv[fileArg], "BPTCLib")) {
|
||||
format = FasTC::eCompressionFormat_BPTC;
|
||||
bUseNVTT = true;
|
||||
} else if (!strcmp(argv[fileArg], "ETC1")) {
|
||||
format = FasTC::eCompressionFormat_ETC1;
|
||||
} else if (!strcmp(argv[fileArg], "DXT1")) {
|
||||
format = FasTC::eCompressionFormat_DXT1;
|
||||
} else if (!strcmp(argv[fileArg], "DXT5")) {
|
||||
format = FasTC::eCompressionFormat_DXT5;
|
||||
}
|
||||
}
|
||||
|
||||
fileArg++;
|
||||
knowArg = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(argv[fileArg], "-h") == 0 || strcmp(argv[fileArg], "--help") == 0) {
|
||||
PrintUsage();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (strcmp(argv[fileArg], "-d") == 0) {
|
||||
fileArg++;
|
||||
|
||||
if (fileArg == argc) {
|
||||
PrintUsage();
|
||||
exit(1);
|
||||
} else {
|
||||
size_t sz = 255;
|
||||
sz = ::std::min(sz, static_cast<size_t>(strlen(argv[fileArg])));
|
||||
memcpy(decompressedOutput, argv[fileArg], sz + 1);
|
||||
}
|
||||
|
||||
fileArg++;
|
||||
knowArg = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(argv[fileArg], "-nd") == 0) {
|
||||
fileArg++;
|
||||
bDecompress = false;
|
||||
knowArg = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(argv[fileArg], "-l") == 0) {
|
||||
fileArg++;
|
||||
bSaveLog = true;
|
||||
knowArg = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(argv[fileArg], "-v") == 0) {
|
||||
fileArg++;
|
||||
bVerbose = true;
|
||||
knowArg = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(argv[fileArg], "-simd") == 0) {
|
||||
fileArg++;
|
||||
bUseSIMD = true;
|
||||
knowArg = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(argv[fileArg], "-t") == 0) {
|
||||
fileArg++;
|
||||
|
||||
if (fileArg == argc || (numThreads = atoi(argv[fileArg])) < 1) {
|
||||
PrintUsage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fileArg++;
|
||||
knowArg = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(argv[fileArg], "-q") == 0) {
|
||||
fileArg++;
|
||||
|
||||
if (fileArg == argc || (quality = atoi(argv[fileArg])) < 0) {
|
||||
PrintUsage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fileArg++;
|
||||
knowArg = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(argv[fileArg], "-j") == 0) {
|
||||
fileArg++;
|
||||
|
||||
if (fileArg == argc || (numJobs = atoi(argv[fileArg])) < 0) {
|
||||
PrintUsage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fileArg++;
|
||||
knowArg = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strcmp(argv[fileArg], "-a") == 0) {
|
||||
fileArg++;
|
||||
bUseAtomics = true;
|
||||
knowArg = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
} while (knowArg && fileArg < argc);
|
||||
|
||||
if (fileArg == argc) {
|
||||
PrintUsage();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char basename[256];
|
||||
ExtractBasename(argv[fileArg], basename, 256);
|
||||
|
||||
ImageFile file(argv[fileArg]);
|
||||
if (!file.Load()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
FasTC::Image<> img(*file.GetImage());
|
||||
|
||||
if (bVerbose) {
|
||||
fprintf(stdout, "Entropy: %.5f\n", img.ComputeEntropy());
|
||||
fprintf(stdout, "Mean Local Entropy: %.5f\n", img.ComputeMeanLocalEntropy());
|
||||
}
|
||||
|
||||
std::ofstream logFile;
|
||||
ThreadSafeStreambuf streamBuf(logFile);
|
||||
std::ostream logStream(&streamBuf);
|
||||
if (bSaveLog) {
|
||||
char logname[256];
|
||||
sprintf(logname, "%s.log", basename);
|
||||
logFile.open(logname);
|
||||
}
|
||||
|
||||
SCompressionSettings settings;
|
||||
settings.format = format;
|
||||
settings.bUseSIMD = bUseSIMD;
|
||||
settings.bUseAtomics = bUseAtomics;
|
||||
settings.iNumThreads = numThreads;
|
||||
settings.iQuality = quality;
|
||||
settings.iNumCompressions = numCompressions;
|
||||
settings.iJobSize = numJobs;
|
||||
settings.bUsePVRTexLib = bUsePVRTexLib;
|
||||
settings.bUseNVTT = bUseNVTT;
|
||||
if (bSaveLog) {
|
||||
settings.logStream = &logStream;
|
||||
} else {
|
||||
settings.logStream = NULL;
|
||||
}
|
||||
|
||||
CompressedImage *ci = CompressImage(&img, settings);
|
||||
if (NULL == ci) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ci->GetWidth() != img.GetWidth() ||
|
||||
ci->GetHeight() != img.GetHeight()) {
|
||||
fprintf(stderr, "Cannot compute image metrics: compressed and uncompressed dimensions differ.\n");
|
||||
} else {
|
||||
double PSNR = img.ComputePSNR(ci);
|
||||
if(PSNR > 0.0) {
|
||||
fprintf(stdout, "PSNR: %.3f\n", PSNR);
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "Error computing PSNR\n");
|
||||
}
|
||||
|
||||
if(bVerbose) {
|
||||
double SSIM = img.ComputeSSIM(ci);
|
||||
if(SSIM > 0.0) {
|
||||
fprintf(stdout, "SSIM: %.9f\n", SSIM);
|
||||
} else {
|
||||
fprintf(stderr, "Error computing SSIM\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(bDecompress) {
|
||||
if(decompressedOutput[0] != '\0') {
|
||||
memcpy(basename, decompressedOutput, 256);
|
||||
} else if(format == FasTC::eCompressionFormat_BPTC) {
|
||||
strcat(basename, "-bptc.png");
|
||||
} else if(format == FasTC::eCompressionFormat_PVRTC4) {
|
||||
strcat(basename, "-pvrtc-4bpp.png");
|
||||
} else if(format == FasTC::eCompressionFormat_DXT1) {
|
||||
strcat(basename, "-dxt1.png");
|
||||
} else if(format == FasTC::eCompressionFormat_DXT5) {
|
||||
strcat(basename, "-dxt5.png");
|
||||
} else if(format == FasTC::eCompressionFormat_ETC1) {
|
||||
strcat(basename, "-etc1.png");
|
||||
}
|
||||
|
||||
EImageFileFormat fmt = ImageFile::DetectFileFormat(basename);
|
||||
ImageFile cImgFile (basename, fmt, *ci);
|
||||
cImgFile.Write();
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
delete ci;
|
||||
if(bSaveLog) {
|
||||
logFile.close();
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -73,11 +73,6 @@ IF(TREAT_WARNINGS_AS_ERRORS)
|
|||
ENDIF(MSVC)
|
||||
ENDIF(TREAT_WARNINGS_AS_ERRORS)
|
||||
|
||||
SET(CMAKE_MODULE_PATH "${FasTC_SOURCE_DIR}/CMakeModules" ${CMAKE_MODULE_PATH})
|
||||
FIND_PACKAGE(PVRTexLib)
|
||||
FIND_PACKAGE(BC7Export)
|
||||
FIND_PACKAGE(PNG)
|
||||
|
||||
######################################################################
|
||||
##
|
||||
## Package definitions
|
||||
|
@ -89,66 +84,11 @@ SET(LIB_INSTALL_DIR lib CACHE INTERNAL "")
|
|||
SET(BIN_INSTALL_DIR bin CACHE INTERNAL "")
|
||||
|
||||
SET(FASTC_DIRECTORIES
|
||||
Base Core IO BPTCEncoder PVRTCEncoder DXTEncoder ETCEncoder ASTCEncoder
|
||||
Base ASTCEncoder
|
||||
)
|
||||
|
||||
FOREACH(DIR ${FASTC_DIRECTORIES})
|
||||
ADD_SUBDIRECTORY(${DIR})
|
||||
ENDFOREACH()
|
||||
ADD_SUBDIRECTORY(CLTool)
|
||||
|
||||
SET(FasTC_LIBRARIES FasTCBase FasTCIO FasTCCore BPTCEncoder PVRTCEncoder DXTEncoder ETCEncoder ASTCEncoder)
|
||||
SET(FasTC_EXECUTABLES tc compare decomp)
|
||||
|
||||
######################################################################
|
||||
##
|
||||
## Config
|
||||
##
|
||||
######################################################################
|
||||
|
||||
INCLUDE(CMakePackageConfigHelpers)
|
||||
CONFIGURE_PACKAGE_CONFIG_FILE(
|
||||
"${FasTC_SOURCE_DIR}/CMakeModules/FasTCConfig.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/FasTCConfig.cmake"
|
||||
INSTALL_DESTINATION ${LIB_INSTALL_DIR}/cmake/FasTC
|
||||
PATH_VARS INCLUDE_INSTALL_DIR BIN_INSTALL_DIR LIB_INSTALL_DIR)
|
||||
|
||||
WRITE_BASIC_PACKAGE_VERSION_FILE(
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/FasTCConfigVersion.cmake"
|
||||
VERSION ${FasTC_VERSION}
|
||||
COMPATIBILITY SameMajorVersion)
|
||||
|
||||
INSTALL(
|
||||
FILES "${CMAKE_CURRENT_BINARY_DIR}/FasTCConfigVersion.cmake" "${CMAKE_CURRENT_BINARY_DIR}/FasTCConfig.cmake"
|
||||
DESTINATION ${LIB_INSTALL_DIR}/cmake/FasTC
|
||||
COMPONENT dev)
|
||||
|
||||
EXPORT(
|
||||
TARGETS ${FasTC_LIBRARIES} ${FasTC_EXECUTABLES}
|
||||
FILE "${CMAKE_CURRENT_BINARY_DIR}/FasTCTargets.cmake")
|
||||
EXPORT(PACKAGE FasTC)
|
||||
|
||||
INSTALL(
|
||||
EXPORT FasTCTargets
|
||||
FILE FasTCTargets.cmake
|
||||
DESTINATION ${LIB_INSTALL_DIR}/cmake/FasTC)
|
||||
|
||||
######################################################################
|
||||
##
|
||||
## Testing
|
||||
##
|
||||
######################################################################
|
||||
|
||||
ENABLE_TESTING()
|
||||
|
||||
IF(MSVC)
|
||||
SET(gtest_force_shared_crt TRUE CACHE BOOL "Used to properly select MSVC runtime libraries" FORCE)
|
||||
ENDIF(MSVC)
|
||||
|
||||
ADD_SUBDIRECTORY(GTest)
|
||||
FOREACH(DIR ${FASTC_DIRECTORIES})
|
||||
SET(TESTDIR ${FasTC_SOURCE_DIR}/${DIR}/test)
|
||||
IF(IS_DIRECTORY ${TESTDIR})
|
||||
ADD_SUBDIRECTORY(${TESTDIR})
|
||||
ENDIF()
|
||||
ENDFOREACH()
|
||||
SET(FasTC_LIBRARIES FasTCBase ASTCEncoder)
|
|
@ -1,53 +0,0 @@
|
|||
# Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
# <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
SET(FASTC_VERSION @FasTC_VERSION@)
|
||||
|
||||
@PACKAGE_INIT@
|
||||
|
||||
SET(FasTC_LIBRARIES FasTCBase FasTCIO FasTCCore BPTCEncoder PVRTCEncoder DXTEncoder ETCEncoder ASTCEncoder)
|
||||
|
||||
IF(NOT TARGET FasTCBase)
|
||||
# We're coming from a build tree -- include all of the targets
|
||||
# from the project and try to make sure that our includes are set properly
|
||||
INCLUDE("${CMAKE_CURRENT_LIST_DIR}/FasTCTargets.cmake")
|
||||
|
||||
FOREACH(LIB ${FasTC_LIBRARIES})
|
||||
STRING(REPLACE "FasTC" "" DIR "${LIB}")
|
||||
|
||||
SET(CURRENT_DIR "@FasTC_SOURCE_DIR@/${DIR}/include")
|
||||
IF( EXISTS "${CURRENT_DIR}/" )
|
||||
SET(FasTC_INCLUDE_DIRS ${FasTC_INCLUDE_DIRS} ${CURRENT_DIR})
|
||||
ENDIF()
|
||||
|
||||
SET(CURRENT_DIR "@FasTC_BINARY_DIR@/${DIR}/include")
|
||||
IF( EXISTS "${CURRENT_DIR}/" )
|
||||
SET(FasTC_INCLUDE_DIRS ${FasTC_INCLUDE_DIRS} ${CURRENT_DIR})
|
||||
ENDIF()
|
||||
|
||||
ENDFOREACH()
|
||||
|
||||
SET(FasTC_EXECUTABLES tc compare decomp)
|
||||
|
||||
ELSE()
|
||||
|
||||
# This is an install tree -- everything should be a lot easier....
|
||||
SET_AND_CHECK(FasTC_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@/FasTC")
|
||||
SET_AND_CHECK(FasTC_BIN_DIR "@PACKAGE_BIN_INSTALL_DIR@")
|
||||
SET_AND_CHECK(FasTC_LIB_DIR "@PACKAGE_LIB_INSTALL_DIR@")
|
||||
|
||||
ENDIF()
|
|
@ -1,28 +0,0 @@
|
|||
# Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
# <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
SET(PACKAGE_VERSION "@FasTC_VERSION@")
|
||||
|
||||
# Check whether the requested PACKAGE_FIND_VERSION is compatible
|
||||
if("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
else()
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
|
||||
set(PACKAGE_VERSION_EXACT TRUE)
|
||||
endif()
|
||||
endif()
|
|
@ -1,38 +0,0 @@
|
|||
# Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
# <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
# - Try to find libPVRTexLib
|
||||
# Once done this will define
|
||||
# PVRTEXLIB_FOUND - System has PVRTexLib
|
||||
# PVRTEXLIB_INCLUDE_DIRS - The PVRTexLib include directories
|
||||
# PVRTEXLIB_LIBRARIES - The libraries needed to use PVRTexLib
|
||||
|
||||
SET(AVPCLLIB_ROOT "" CACHE STRING "Location of the BC7 Export library from NVTT")
|
||||
|
||||
IF(NOT AVPCLLIB_ROOT STREQUAL "")
|
||||
IF(NOT EXISTS "${AVPCLLIB_ROOT}/src/CMakeLists.txt")
|
||||
CONFIGURE_FILE(
|
||||
"${CMAKE_CURRENT_LIST_DIR}/bc7_export/CMakeLists.txt"
|
||||
"${AVPCLLIB_ROOT}/src"
|
||||
COPYONLY)
|
||||
ENDIF()
|
||||
ADD_SUBDIRECTORY(${AVPCLLIB_ROOT}/src ${CMAKE_CURRENT_BINARY_DIR}/bc7_export)
|
||||
set(AVPCLLIB_INCLUDE_DIR ${AVPCLLIB_ROOT}/src )
|
||||
SET(FOUND_NVTT_BPTC_EXPORT TRUE)
|
||||
ENDIF()
|
||||
|
||||
mark_as_advanced( FORCE AVPCLLIB_ROOT AVPCLLIB_INCLUDE_DIR )
|
|
@ -1,96 +0,0 @@
|
|||
# Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
# <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
# - Try to find libPVRTexLib
|
||||
# Once done this will define
|
||||
# PVRTEXLIB_FOUND - System has PVRTexLib
|
||||
# PVRTEXLIB_INCLUDE_DIRS - The PVRTexLib include directories
|
||||
# PVRTEXLIB_LIBRARIES - The libraries needed to use PVRTexLib
|
||||
|
||||
IF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
SET( PVRTEXLIB_ROOT "/Applications/Imagination/PowerVR/GraphicsSDK/PVRTexTool/Library" )
|
||||
find_path(
|
||||
PVRTEXLIB_INCLUDE_DIR PVRTexture.h
|
||||
PATHS ${PVRTEXLIB_ROOT}/Include
|
||||
)
|
||||
|
||||
find_library(PVRTEXLIB_LIB PVRTexLib
|
||||
PATHS ${PVRTEXLIB_ROOT}/OSX_x86/Static
|
||||
${PVRTEXLIB_ROOT}/OSX_x86/Dynamic
|
||||
)
|
||||
|
||||
SET( USE_PTHREAD TRUE )
|
||||
|
||||
ELSEIF (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
SET( PVRTEXLIB_ROOT "/opt/Imagination/PowerVR/GraphicsSDK/PVRTexTool/Library" )
|
||||
find_path(
|
||||
PVRTEXLIB_INCLUDE_DIR PVRTexture.h
|
||||
PATHS ${PVRTEXLIB_ROOT}/Include
|
||||
)
|
||||
|
||||
IF(${CMAKE_SIZEOF_VOID_P} EQUAL 8)
|
||||
find_library(PVRTEXLIB_LIB PVRTexLib
|
||||
PATHS ${PVRTEXLIB_ROOT}/Linux_x86_64/Static
|
||||
${PVRTEXLIB_ROOT}/Linux_x86_64/Dynamic
|
||||
)
|
||||
ELSE()
|
||||
find_library(PVRTEXLIB_LIB PVRTexLib
|
||||
PATHS ${PVRTEXLIB_ROOT}/Linux_x86_32/Static
|
||||
${PVRTEXLIB_ROOT}/Linux_x86_32/Dynamic
|
||||
)
|
||||
ENDIF()
|
||||
|
||||
SET( USE_PTHREAD TRUE )
|
||||
|
||||
ELSEIF(MSVC)
|
||||
SET( PVRTEXLIB_ROOT "C:/Imagination/PowerVR/GraphicsSDK/PVRTexTool/Library" )
|
||||
find_path(
|
||||
PVRTEXLIB_INCLUDE_DIR PVRTexture.h
|
||||
PATHS ${PVRTEXLIB_ROOT}/Include
|
||||
)
|
||||
|
||||
IF(${CMAKE_GENERATOR} MATCHES Win64)
|
||||
find_library(PVRTEXLIB_LIB PVRTexLib
|
||||
PATHS ${PVRTEXLIB_ROOT}/Windows_x86_64/Static
|
||||
${PVRTEXLIB_ROOT}/Windows_x86_64/Dynamic
|
||||
)
|
||||
ELSE()
|
||||
find_library(PVRTEXLIB_LIB PVRTexLib
|
||||
PATHS ${PVRTEXLIB_ROOT}/Windows_x86_32/Static
|
||||
${PVRTEXLIB_ROOT}/Windows_x86_32/Dynamic
|
||||
)
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
IF( USE_PTHREAD )
|
||||
FIND_PACKAGE( Threads REQUIRED )
|
||||
set(PVRTEXLIB_LIBRARIES
|
||||
${PVRTEXLIB_LIB}
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
ELSE()
|
||||
set(PVRTEXLIB_LIBRARIES ${PVRTEXLIB_LIB})
|
||||
ENDIF()
|
||||
set(PVRTEXLIB_INCLUDE_DIRS ${PVRTEXLIB_INCLUDE_DIR} )
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
# handle the QUIETLY and REQUIRED arguments and set LIBXML2_FOUND to TRUE
|
||||
# if all listed variables are TRUE
|
||||
find_package_handle_standard_args(PVRTexLib DEFAULT_MSG
|
||||
PVRTEXLIB_LIB PVRTEXLIB_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced( PVRTEXLIB_ROOT PVRTEXLIB_INCLUDE_DIR PVRTEXLIB_LIB )
|
|
@ -1,79 +0,0 @@
|
|||
# Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
# <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_LIST_DIR})
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_LIST_DIR}/arvo)
|
||||
|
||||
SET( HEADERS
|
||||
avpcl.h
|
||||
bits.h
|
||||
endpts.h
|
||||
ImfArray.h
|
||||
rgba.h
|
||||
shapes_three.h
|
||||
shapes_two.h
|
||||
targa.h
|
||||
tile.h
|
||||
utils.h
|
||||
arvo/ArvoMath.h
|
||||
arvo/Char.h
|
||||
arvo/Complex.h
|
||||
arvo/form.h
|
||||
arvo/Matrix.h
|
||||
arvo/Perm.h
|
||||
arvo/Rand.h
|
||||
arvo/SI_units.h
|
||||
arvo/SphTri.h
|
||||
arvo/SVD.h
|
||||
arvo/Token.h
|
||||
arvo/Vec2.h
|
||||
arvo/Vec3.h
|
||||
arvo/Vec4.h
|
||||
arvo/Vector.h
|
||||
)
|
||||
|
||||
SET( SOURCES
|
||||
avpcl.cpp
|
||||
avpcl_mode0.cpp
|
||||
avpcl_mode1.cpp
|
||||
avpcl_mode2.cpp
|
||||
avpcl_mode3.cpp
|
||||
avpcl_mode4.cpp
|
||||
avpcl_mode5.cpp
|
||||
avpcl_mode6.cpp
|
||||
avpcl_mode7.cpp
|
||||
targa.cpp
|
||||
utils.cpp
|
||||
arvo/ArvoMath.cpp
|
||||
arvo/Char.cpp
|
||||
arvo/Complex.cpp
|
||||
arvo/Matrix.cpp
|
||||
arvo/Perm.cpp
|
||||
arvo/Rand.cpp
|
||||
arvo/SphTri.cpp
|
||||
arvo/SVD.cpp
|
||||
arvo/Token.cpp
|
||||
arvo/Vec2.cpp
|
||||
arvo/Vec3.cpp
|
||||
arvo/Vec4.cpp
|
||||
arvo/Vector.cpp
|
||||
)
|
||||
|
||||
ADD_LIBRARY( avpcl
|
||||
${HEADERS}
|
||||
${SOURCES}
|
||||
)
|
|
@ -1,118 +0,0 @@
|
|||
# Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
# <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
SET( SOURCES
|
||||
"src/TexComp.cpp"
|
||||
"src/CompressedImage.cpp"
|
||||
)
|
||||
|
||||
SET( LIBRARY_HEADERS
|
||||
"include/FasTC/CompressedImage.h"
|
||||
"include/FasTC/ReferenceCounter.h"
|
||||
"include/FasTC/StopWatch.h"
|
||||
"include/FasTC/TexComp.h"
|
||||
"include/FasTC/ThreadSafeStreambuf.h"
|
||||
)
|
||||
|
||||
SET( HEADERS
|
||||
${LIBRARY_HEADERS}
|
||||
"src/CompressionFuncs.h"
|
||||
)
|
||||
|
||||
# Make sure to add the appropriate stopwatch files...
|
||||
IF( WIN32 )
|
||||
SET( SOURCES ${SOURCES} "src/StopWatchWin32.cpp" )
|
||||
ELSEIF( APPLE )
|
||||
SET( SOURCES ${SOURCES} "src/StopWatchOSX.cpp" )
|
||||
ELSE()
|
||||
SET( SOURCES ${SOURCES} "src/StopWatchUnix.cpp" )
|
||||
|
||||
# Assume compiler is GCC
|
||||
SET( LINK_FLAGS -lrt ${LINK_FLAGS} )
|
||||
ENDIF()
|
||||
|
||||
###### Find Threads....
|
||||
IF( MSVC )
|
||||
SET( SOURCES ${SOURCES} "src/ThreadWin32.cpp" )
|
||||
ELSE()
|
||||
FIND_PACKAGE( Threads )
|
||||
IF( CMAKE_USE_PTHREADS_INIT )
|
||||
SET( SOURCES ${SOURCES} "src/ThreadPThread.cpp" )
|
||||
ELSE()
|
||||
MESSAGE( FATAL_ERROR "Could not find suitable threading library." )
|
||||
ENDIF()
|
||||
ENDIF()
|
||||
|
||||
# Add internal sources
|
||||
SET( HEADERS ${HEADERS} "src/Thread.h" )
|
||||
SET( HEADERS ${HEADERS} "src/ThreadGroup.h" )
|
||||
SET( HEADERS ${HEADERS} "src/WorkerQueue.h" )
|
||||
|
||||
SET( SOURCES ${SOURCES} "src/ThreadSafeStreambuf.cpp" )
|
||||
SET( SOURCES ${SOURCES} "src/Thread.cpp" )
|
||||
SET( SOURCES ${SOURCES} "src/ThreadGroup.cpp" )
|
||||
SET( SOURCES ${SOURCES} "src/WorkerQueue.cpp" )
|
||||
|
||||
# Dependencies...
|
||||
INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR}/Base/include )
|
||||
INCLUDE_DIRECTORIES( ${FasTC_BINARY_DIR}/Base/include )
|
||||
INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR}/Core/include )
|
||||
INCLUDE_DIRECTORIES( ${FasTC_BINARY_DIR}/Core/include )
|
||||
INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR}/IO/include )
|
||||
INCLUDE_DIRECTORIES( ${FasTC_BINARY_DIR}/IO/include )
|
||||
|
||||
INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR}/ASTCEncoder/include )
|
||||
INCLUDE_DIRECTORIES( ${FasTC_BINARY_DIR}/ASTCEncoder/include )
|
||||
INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR}/ETCEncoder/include )
|
||||
INCLUDE_DIRECTORIES( ${FasTC_BINARY_DIR}/ETCEncoder/include )
|
||||
INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR}/DXTEncoder/include )
|
||||
INCLUDE_DIRECTORIES( ${FasTC_BINARY_DIR}/DXTEncoder/include )
|
||||
INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR}/PVRTCEncoder/include)
|
||||
INCLUDE_DIRECTORIES( ${FasTC_BINARY_DIR}/PVRTCEncoder/include)
|
||||
INCLUDE_DIRECTORIES( ${FasTC_SOURCE_DIR}/BPTCEncoder/include )
|
||||
INCLUDE_DIRECTORIES( ${FasTC_BINARY_DIR}/BPTCEncoder/include )
|
||||
|
||||
ADD_LIBRARY( FasTCCore
|
||||
${HEADERS}
|
||||
${SOURCES}
|
||||
)
|
||||
|
||||
INSTALL(
|
||||
TARGETS FasTCCore
|
||||
EXPORT FasTCTargets
|
||||
ARCHIVE DESTINATION lib COMPONENT lib
|
||||
)
|
||||
|
||||
INSTALL(
|
||||
FILES ${LIBRARY_HEADERS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/FasTC COMPONENT dev)
|
||||
|
||||
TARGET_LINK_LIBRARIES( FasTCCore FasTCBase )
|
||||
TARGET_LINK_LIBRARIES( FasTCCore FasTCIO )
|
||||
TARGET_LINK_LIBRARIES( FasTCCore ETCEncoder )
|
||||
TARGET_LINK_LIBRARIES( FasTCCore DXTEncoder )
|
||||
TARGET_LINK_LIBRARIES( FasTCCore BPTCEncoder )
|
||||
TARGET_LINK_LIBRARIES( FasTCCore PVRTCEncoder )
|
||||
TARGET_LINK_LIBRARIES( FasTCCore ASTCEncoder )
|
||||
|
||||
IF( CMAKE_USE_PTHREADS_INIT )
|
||||
TARGET_LINK_LIBRARIES( FasTCCore ${CMAKE_THREAD_LIBS_INIT} )
|
||||
ENDIF()
|
||||
|
||||
IF( NOT WIN32 AND NOT APPLE )
|
||||
TARGET_LINK_LIBRARIES( FasTCCore rt )
|
||||
ENDIF()
|
|
@ -1,74 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#ifndef _COMPRESSED_IMAGE_H_
|
||||
#define _COMPRESSED_IMAGE_H_
|
||||
|
||||
#include "FasTC/TexCompTypes.h"
|
||||
#include "FasTC/CompressionFormat.h"
|
||||
#include "FasTC/Image.h"
|
||||
|
||||
class CompressedImage : public FasTC::Image<FasTC::Pixel> {
|
||||
private:
|
||||
FasTC::ECompressionFormat m_Format;
|
||||
uint8 *m_CompressedData;
|
||||
|
||||
typedef FasTC::Image<FasTC::Pixel> UncompressedImage;
|
||||
|
||||
public:
|
||||
CompressedImage(const CompressedImage &);
|
||||
CompressedImage &operator=(const CompressedImage &);
|
||||
|
||||
// Create a compressed image from the given data according to
|
||||
// the passed format. The size of the data is expected to conform
|
||||
// to the width, height, and format specified.
|
||||
CompressedImage(
|
||||
const uint32 width,
|
||||
const uint32 height,
|
||||
const FasTC::ECompressionFormat format,
|
||||
const uint8 *data
|
||||
);
|
||||
|
||||
virtual ~CompressedImage();
|
||||
|
||||
virtual FasTC::Image<FasTC::Pixel> *Clone() const {
|
||||
return new CompressedImage(*this);
|
||||
}
|
||||
|
||||
virtual void ComputePixels();
|
||||
|
||||
static uint32 GetCompressedSize(uint32 width, uint32 height, FasTC::ECompressionFormat format);
|
||||
|
||||
uint32 GetCompressedSize() const {
|
||||
return GetCompressedSize(GetWidth(), GetHeight(), m_Format);
|
||||
}
|
||||
uint32 GetUncompressedSize() const {
|
||||
return GetWidth() * GetHeight() * sizeof(uint32);
|
||||
}
|
||||
|
||||
// Decompress the compressed image data into outBuf. outBufSz is expected
|
||||
// to be the proper size determined by the width, height, and format.
|
||||
// !FIXME! We should have a function to explicitly return the in/out buf
|
||||
// size for a given compressed image.
|
||||
bool DecompressImage(uint8 *outBuf, uint32 outBufSz) const;
|
||||
|
||||
const uint8 *GetCompressedData() const { return m_CompressedData; }
|
||||
|
||||
FasTC::ECompressionFormat GetFormat() const { return m_Format; }
|
||||
};
|
||||
|
||||
#endif // _COMPRESSED_IMAGE_H_
|
|
@ -1,67 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#ifndef __REFERENCE_COUNTER_H__
|
||||
#define __REFERENCE_COUNTER_H__
|
||||
|
||||
#include "TexCompTypes.h"
|
||||
|
||||
class ReferenceCounter {
|
||||
public:
|
||||
ReferenceCounter() : m_ReferenceCount( new uint32 ) {
|
||||
*m_ReferenceCount = 1;
|
||||
}
|
||||
ReferenceCounter(const ReferenceCounter &other)
|
||||
: m_ReferenceCount(other.m_ReferenceCount) {
|
||||
IncRefCount();
|
||||
}
|
||||
|
||||
ReferenceCounter &operator=(const ReferenceCounter &other) {
|
||||
DecRefCount();
|
||||
m_ReferenceCount = other.m_ReferenceCount;
|
||||
IncRefCount();
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint32 GetRefCount() const {
|
||||
if(m_ReferenceCount)
|
||||
return *m_ReferenceCount;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void DecRefCount() {
|
||||
if(!m_ReferenceCount) return;
|
||||
|
||||
(*m_ReferenceCount)--;
|
||||
|
||||
if(*m_ReferenceCount == 0) {
|
||||
delete m_ReferenceCount;
|
||||
m_ReferenceCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void IncRefCount() {
|
||||
if(!m_ReferenceCount) return;
|
||||
(*m_ReferenceCount)++;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32 *m_ReferenceCount;
|
||||
};
|
||||
|
||||
#endif // __REFERENCE_COUNTER_H__
|
|
@ -1,70 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
// The original lisence from the code available at the following location:
|
||||
// http://software.intel.com/en-us/vcsource/samples/fast-texture-compression
|
||||
//
|
||||
// This code has been modified significantly from the original.
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Copyright 2011 Intel Corporation
|
||||
// All Rights Reserved
|
||||
//
|
||||
// Permission is granted to use, copy, distribute and prepare derivative works of this
|
||||
// software for any purpose and without fee, provided, that the above copyright notice
|
||||
// and this statement appear in all copies. Intel makes no representations about the
|
||||
// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS."
|
||||
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
|
||||
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
|
||||
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not
|
||||
// assume any responsibility for any errors which may appear in this software nor any
|
||||
// responsibility to update it.
|
||||
//
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
#ifndef __TEXCOMP_STOP_WATCH_H__
|
||||
#define __TEXCOMP_STOP_WATCH_H__
|
||||
|
||||
// Forward declare the private implementation of the class that will actually implement
|
||||
// the timing features. This class is defined in each module depending on the platform...
|
||||
class StopWatchImpl;
|
||||
|
||||
// A simple stopwatch class using Windows' high-resolution performance counters.
|
||||
class StopWatch
|
||||
{
|
||||
public:
|
||||
StopWatch();
|
||||
StopWatch(const StopWatch &);
|
||||
|
||||
~StopWatch();
|
||||
|
||||
StopWatch &operator=(const StopWatch &);
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
void Reset();
|
||||
|
||||
double TimeInSeconds() const;
|
||||
double TimeInMilliseconds() const;
|
||||
double TimeInMicroseconds() const;
|
||||
|
||||
private:
|
||||
StopWatchImpl *impl;
|
||||
};
|
||||
|
||||
#endif // __TEXCOMP_STOP_WATCH_H__
|
|
@ -1,98 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#ifndef _TEX_COMP_H_
|
||||
#define _TEX_COMP_H_
|
||||
|
||||
#include "FasTC/CompressedImage.h"
|
||||
#include "FasTC/CompressionJob.h"
|
||||
|
||||
#include <iosfwd>
|
||||
#include "FasTC/ImageFwd.h"
|
||||
|
||||
// Forward declarations
|
||||
class ImageFile;
|
||||
|
||||
struct SCompressionSettings {
|
||||
SCompressionSettings(); // defaults
|
||||
|
||||
// The compression format for the image.
|
||||
FasTC::ECompressionFormat format;
|
||||
|
||||
// The flag that requests us to use SIMD, if it is available
|
||||
bool bUseSIMD;
|
||||
|
||||
// The number of threads to spawn in order to process the data
|
||||
int iNumThreads;
|
||||
|
||||
// Some compression formats take a measurement of quality when
|
||||
// compressing an image. If the format supports it, this value
|
||||
// will be used for quality purposes.
|
||||
int iQuality;
|
||||
|
||||
// The number of compressions to perform. The program will compress
|
||||
// the image this many times, and then take the average of the timing.
|
||||
int iNumCompressions;
|
||||
|
||||
// This setting measures the number of blocks that a thread
|
||||
// will process at any given time. If this value is zero,
|
||||
// which is the default, the work will be divided by the
|
||||
// number of threads, and each thread will do it's job and
|
||||
// exit.
|
||||
int iJobSize;
|
||||
|
||||
// This flags instructs the compression routine to be launched in succession
|
||||
// with many threads at once. Atomic expressions based on the availability
|
||||
// in the platform and compiler will provide synchronization.
|
||||
bool bUseAtomics;
|
||||
|
||||
// This flag instructs the infrastructure to use the compression routine from
|
||||
// PVRTexLib. If no such lib is found during configuration then this flag is
|
||||
// ignored. The quality being used is the fastest compression quality.
|
||||
bool bUsePVRTexLib;
|
||||
|
||||
// This flag instructs the infrastructure to use the compression routine from
|
||||
// NVidia Texture Tools. If no such lib is found during configuration then this
|
||||
// flag is ignored.
|
||||
bool bUseNVTT;
|
||||
|
||||
// This is the output stream with which we should output the logs for the
|
||||
// compression functions.
|
||||
std::ostream *logStream;
|
||||
};
|
||||
|
||||
template<typename PixelType>
|
||||
extern CompressedImage *CompressImage(FasTC::Image<PixelType> *img, const SCompressionSettings &settings);
|
||||
|
||||
extern bool CompressImageData(
|
||||
const unsigned char *data,
|
||||
const unsigned int width,
|
||||
const unsigned int height,
|
||||
unsigned char *cmpData,
|
||||
const unsigned int cmpDataSz,
|
||||
const SCompressionSettings &settings
|
||||
);
|
||||
|
||||
// This function computes the Peak Signal to Noise Ratio between a
|
||||
// compressed image and a raw image.
|
||||
extern double ComputePSNR(const CompressedImage &ci, const ImageFile &file);
|
||||
|
||||
// This is a multi-platform yield function that preempts the current thread
|
||||
// based on the threading library that we're using.
|
||||
extern void YieldThread();
|
||||
|
||||
#endif //_TEX_COMP_H_
|
|
@ -1,42 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#ifndef CORE_INCLUDE_THREADSAFESTREAMBUF_H_
|
||||
#define CORE_INCLUDE_THREADSAFESTREAMBUF_H_
|
||||
|
||||
// Forward Declarations
|
||||
class TCMutex;
|
||||
|
||||
#include <streambuf>
|
||||
#include <iosfwd>
|
||||
|
||||
class ThreadSafeStreambuf : public ::std::streambuf {
|
||||
public:
|
||||
ThreadSafeStreambuf(std::ostream &sink);
|
||||
virtual ~ThreadSafeStreambuf();
|
||||
|
||||
protected:
|
||||
virtual std::streamsize xsputn(const char_type *s, std::streamsize count);
|
||||
private:
|
||||
// Not implemented -- not allowed...
|
||||
ThreadSafeStreambuf(const ThreadSafeStreambuf &);
|
||||
ThreadSafeStreambuf &operator=(const ThreadSafeStreambuf &);
|
||||
std::ostream &m_Sink;
|
||||
TCMutex *m_Mutex;
|
||||
};
|
||||
|
||||
#endif // CORE_INCLUDE_THREADSAFESTREAMBUF_H_
|
|
@ -1,149 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "FasTC/CompressedImage.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "FasTC/Pixel.h"
|
||||
|
||||
#include "FasTC/TexCompTypes.h"
|
||||
#include "FasTC/BPTCCompressor.h"
|
||||
#include "FasTC/PVRTCCompressor.h"
|
||||
#include "FasTC/DXTCompressor.h"
|
||||
#include "FasTC/ETCCompressor.h"
|
||||
#include "FasTC/ASTCCompressor.h"
|
||||
|
||||
using FasTC::CompressionJob;
|
||||
using FasTC::DecompressionJob;
|
||||
using FasTC::ECompressionFormat;
|
||||
|
||||
CompressedImage::CompressedImage( const CompressedImage &other )
|
||||
: UncompressedImage(other)
|
||||
, m_Format(other.m_Format)
|
||||
, m_CompressedData(0)
|
||||
{
|
||||
if(other.m_CompressedData) {
|
||||
uint32 compressedSz = GetCompressedSize();
|
||||
m_CompressedData = new uint8[compressedSz];
|
||||
memcpy(m_CompressedData, other.m_CompressedData, compressedSz);
|
||||
}
|
||||
}
|
||||
|
||||
CompressedImage::CompressedImage(
|
||||
const unsigned int width,
|
||||
const unsigned int height,
|
||||
const ECompressionFormat format,
|
||||
const unsigned char *data
|
||||
)
|
||||
: UncompressedImage(width, height, reinterpret_cast<uint32 *>(NULL))
|
||||
, m_Format(format)
|
||||
, m_CompressedData(0)
|
||||
{
|
||||
uint32 cmpSz = GetCompressedSize();
|
||||
if(cmpSz > 0) {
|
||||
assert(!m_CompressedData);
|
||||
m_CompressedData = new uint8[cmpSz];
|
||||
memcpy(m_CompressedData, data, cmpSz);
|
||||
}
|
||||
}
|
||||
|
||||
CompressedImage &CompressedImage::operator=(const CompressedImage &other) {
|
||||
UncompressedImage::operator=(other);
|
||||
m_Format = other.m_Format;
|
||||
if(other.m_CompressedData) {
|
||||
uint32 cmpSz = GetCompressedSize();
|
||||
m_CompressedData = new uint8[cmpSz];
|
||||
memcpy(m_CompressedData, other.m_CompressedData, cmpSz);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
CompressedImage::~CompressedImage() {
|
||||
if(m_CompressedData) {
|
||||
delete m_CompressedData;
|
||||
m_CompressedData = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool CompressedImage::DecompressImage(unsigned char *outBuf, unsigned int outBufSz) const {
|
||||
|
||||
assert(outBufSz == GetUncompressedSize());
|
||||
|
||||
uint8 *byteData = reinterpret_cast<uint8 *>(m_CompressedData);
|
||||
DecompressionJob dj (m_Format, byteData, outBuf, GetWidth(), GetHeight());
|
||||
if(m_Format == FasTC::eCompressionFormat_DXT1) {
|
||||
DXTC::DecompressDXT1(dj);
|
||||
} else if(m_Format == FasTC::eCompressionFormat_DXT5) {
|
||||
DXTC::DecompressDXT5(dj);
|
||||
} else if (m_Format == FasTC::eCompressionFormat_ETC1) {
|
||||
ETCC::Decompress(dj);
|
||||
} else if(FasTC::COMPRESSION_FORMAT_PVRTC_BEGIN <= m_Format &&
|
||||
FasTC::COMPRESSION_FORMAT_PVRTC_END >= m_Format) {
|
||||
#ifndef NDEBUG
|
||||
PVRTCC::Decompress(dj, PVRTCC::eWrapMode_Wrap, true);
|
||||
#else
|
||||
PVRTCC::Decompress(dj);
|
||||
#endif
|
||||
} else if(m_Format == FasTC::eCompressionFormat_BPTC) {
|
||||
BPTCC::Decompress(dj);
|
||||
} else if(FasTC::COMPRESSION_FORMAT_ASTC_BEGIN <= m_Format &&
|
||||
FasTC::COMPRESSION_FORMAT_ASTC_END >= m_Format) {
|
||||
ASTCC::Decompress(dj);
|
||||
} else {
|
||||
const char *errStr = "Have not implemented decompression method.";
|
||||
fprintf(stderr, "%s\n", errStr);
|
||||
assert(!errStr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CompressedImage::ComputePixels() {
|
||||
|
||||
uint32 unCompSz = GetWidth() * GetHeight() * 4;
|
||||
uint8 *unCompBuf = new uint8[unCompSz];
|
||||
DecompressImage(unCompBuf, unCompSz);
|
||||
|
||||
uint32 * newPixelBuf = reinterpret_cast<uint32 *>(unCompBuf);
|
||||
|
||||
FasTC::Pixel *newPixels = new FasTC::Pixel[GetWidth() * GetHeight()];
|
||||
for(uint32 i = 0; i < GetWidth() * GetHeight(); i++) {
|
||||
newPixels[i].Unpack(newPixelBuf[i]);
|
||||
}
|
||||
|
||||
SetImageData(GetWidth(), GetHeight(), newPixels);
|
||||
}
|
||||
|
||||
uint32 CompressedImage::GetCompressedSize(uint32 width, uint32 height, ECompressionFormat format) {
|
||||
// The compressed size is the block size times the number of blocks
|
||||
uint32 blockDim[2];
|
||||
GetBlockDimensions(format, blockDim);
|
||||
|
||||
const uint32 blocksWide = (width + blockDim[0] - 1) / blockDim[0];
|
||||
const uint32 blocksHigh = (height + blockDim[1] - 1) / blockDim[1];
|
||||
const uint32 uncompBlockSize = blockDim[0] * blockDim[1] * sizeof(uint32);
|
||||
|
||||
const uint32 nBlocks = blocksWide * blocksHigh;
|
||||
const uint32 blockSz = GetBlockSize(format);
|
||||
|
||||
return nBlocks * blockSz;
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#ifndef CORE_SRC_COMPRESSIONFUNCS_H_
|
||||
#define CORE_SRC_COMPRESSIONFUNCS_H_
|
||||
|
||||
#include "FasTC/CompressionJob.h"
|
||||
#include <iosfwd>
|
||||
|
||||
// A compression function format. It takes the raw data and image dimensions and
|
||||
// returns the compressed image data into outData. It is assumed that there is
|
||||
// enough space allocated for outData to store the compressed data. Allocation
|
||||
// is dependent on the compression format.
|
||||
typedef void (* CompressionFunc)(const FasTC::CompressionJob &);
|
||||
|
||||
// A compression function format. It takes the raw data and image dimensions and
|
||||
// returns the compressed image data into outData. It is assumed that there is
|
||||
// enough space allocated for outData to store the compressed data. Allocation
|
||||
// is dependent on the compression format.
|
||||
typedef void (* CompressionFuncWithStats)(const FasTC::CompressionJob &, std::ostream *logStream);
|
||||
|
||||
#endif // CORE_SRC_COMPRESSIONFUNCS_H_
|
|
@ -1,81 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "FasTC/StopWatch.h"
|
||||
#include "FasTC/TexCompTypes.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
class StopWatchImpl {
|
||||
public:
|
||||
uint64 start;
|
||||
uint64 duration;
|
||||
};
|
||||
|
||||
static uint64 Now() {
|
||||
timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return tv.tv_usec + (1e6 * tv.tv_sec);
|
||||
}
|
||||
|
||||
StopWatch::StopWatch(const StopWatch &other) {
|
||||
impl = new StopWatchImpl();
|
||||
memcpy(impl, other.impl, sizeof(StopWatchImpl));
|
||||
}
|
||||
|
||||
StopWatch &StopWatch::operator=(const StopWatch &other) {
|
||||
if(impl) {
|
||||
delete impl;
|
||||
}
|
||||
impl = new StopWatchImpl();
|
||||
memcpy(impl, other.impl, sizeof(StopWatchImpl));
|
||||
return *this;
|
||||
}
|
||||
|
||||
StopWatch::~StopWatch() {
|
||||
delete impl;
|
||||
}
|
||||
|
||||
StopWatch::StopWatch() : impl(new StopWatchImpl) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void StopWatch::Start() {
|
||||
impl->start = Now();
|
||||
}
|
||||
|
||||
void StopWatch::Stop() {
|
||||
impl->duration = Now() - impl->start;
|
||||
}
|
||||
|
||||
void StopWatch::Reset() {
|
||||
impl->start = impl->duration = 0.0;
|
||||
}
|
||||
|
||||
double StopWatch::TimeInSeconds() const {
|
||||
return double(impl->duration) / 1e6;
|
||||
}
|
||||
|
||||
double StopWatch::TimeInMilliseconds() const {
|
||||
return double(impl->duration) / 1e3;
|
||||
}
|
||||
|
||||
double StopWatch::TimeInMicroseconds() const {
|
||||
return double(impl->duration);
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "FasTC/StopWatch.h"
|
||||
#include "FasTC/TexCompTypes.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
class StopWatchImpl {
|
||||
public:
|
||||
timespec ts;
|
||||
|
||||
double timer;
|
||||
double duration;
|
||||
};
|
||||
|
||||
StopWatch::StopWatch(const StopWatch &other) {
|
||||
impl = new StopWatchImpl();
|
||||
memcpy(impl, other.impl, sizeof(StopWatchImpl));
|
||||
}
|
||||
|
||||
StopWatch &StopWatch::operator=(const StopWatch &other) {
|
||||
if(impl) {
|
||||
delete impl;
|
||||
}
|
||||
impl = new StopWatchImpl();
|
||||
memcpy(impl, other.impl, sizeof(StopWatchImpl));
|
||||
return *this;
|
||||
}
|
||||
|
||||
StopWatch::~StopWatch() {
|
||||
delete impl;
|
||||
}
|
||||
|
||||
StopWatch::StopWatch() : impl(new StopWatchImpl) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void StopWatch::Start() {
|
||||
clock_gettime(CLOCK_REALTIME, &(impl->ts));
|
||||
impl->timer = double(impl->ts.tv_sec) + 1e-9 * double(impl->ts.tv_nsec);
|
||||
}
|
||||
|
||||
void StopWatch::Stop() {
|
||||
clock_gettime(CLOCK_REALTIME, &(impl->ts));
|
||||
impl->duration = -(impl->timer) + (double(impl->ts.tv_sec) + 1e-9 * double(impl->ts.tv_nsec));
|
||||
}
|
||||
|
||||
void StopWatch::Reset() {
|
||||
impl->timer = impl->duration = 0.0;
|
||||
memset(&(impl->ts), 0, sizeof(timespec));
|
||||
}
|
||||
|
||||
double StopWatch::TimeInSeconds() const {
|
||||
return impl->duration;
|
||||
}
|
||||
|
||||
double StopWatch::TimeInMilliseconds() const {
|
||||
return impl->duration * 1000;
|
||||
}
|
||||
|
||||
double StopWatch::TimeInMicroseconds() const {
|
||||
return impl->duration * 1000000;
|
||||
}
|
|
@ -1,180 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
// The original lisence from the code available at the following location:
|
||||
// http://software.intel.com/en-us/vcsource/samples/fast-texture-compression
|
||||
//
|
||||
// This code has been modified significantly from the original.
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
// Copyright 2011 Intel Corporation
|
||||
// All Rights Reserved
|
||||
//
|
||||
// Permission is granted to use, copy, distribute and prepare derivative works of this
|
||||
// software for any purpose and without fee, provided, that the above copyright notice
|
||||
// and this statement appear in all copies. Intel makes no representations about the
|
||||
// suitability of this software for any purpose. THIS SOFTWARE IS PROVIDED "AS IS."
|
||||
// INTEL SPECIFICALLY DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, AND ALL LIABILITY,
|
||||
// INCLUDING CONSEQUENTIAL AND OTHER INDIRECT DAMAGES, FOR THE USE OF THIS SOFTWARE,
|
||||
// INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PROPRIETARY RIGHTS, AND INCLUDING THE
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. Intel does not
|
||||
// assume any responsibility for any errors which may appear in this software nor any
|
||||
// responsibility to update it.
|
||||
//
|
||||
//--------------------------------------------------------------------------------------
|
||||
|
||||
#include "FasTC/StopWatch.h"
|
||||
#include "FasTC/TexCompTypes.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <Windows.h>
|
||||
#include <WinBase.h>
|
||||
|
||||
class StopWatchImpl {
|
||||
public:
|
||||
uint64 frequency;
|
||||
uint64 start;
|
||||
uint64 stop;
|
||||
#ifndef __MINGW32__
|
||||
uintptr_t affinityMask;
|
||||
#endif
|
||||
|
||||
StopWatchImpl() :
|
||||
start(0), stop(0)
|
||||
#ifndef __MINGW32__
|
||||
, affinityMask(0)
|
||||
#endif
|
||||
{
|
||||
// Initialize the performance counter frequency.
|
||||
LARGE_INTEGER perfQuery;
|
||||
#ifndef NDEBUG
|
||||
assert(QueryPerformanceFrequency(&perfQuery));
|
||||
#else
|
||||
QueryPerformanceFrequency(&perfQuery);
|
||||
#endif
|
||||
this->frequency = perfQuery.QuadPart;
|
||||
}
|
||||
};
|
||||
|
||||
StopWatch::StopWatch() : impl(new StopWatchImpl) { }
|
||||
|
||||
StopWatch::StopWatch(const StopWatch &other) {
|
||||
impl = new StopWatchImpl();
|
||||
memcpy(impl, other.impl, sizeof(StopWatchImpl));
|
||||
}
|
||||
|
||||
StopWatch &StopWatch::operator=(const StopWatch &other) {
|
||||
if(impl) {
|
||||
delete impl;
|
||||
}
|
||||
impl = new StopWatchImpl();
|
||||
memcpy(impl, other.impl, sizeof(StopWatchImpl));
|
||||
return *this;
|
||||
}
|
||||
|
||||
StopWatch::~StopWatch() {
|
||||
delete impl;
|
||||
}
|
||||
|
||||
// Start the stopwatch.
|
||||
void StopWatch::Start()
|
||||
{
|
||||
#ifndef __MINGW32__
|
||||
// MSDN recommends setting the thread affinity to avoid bugs in the BIOS and HAL.
|
||||
// Create an affinity mask for the current processor.
|
||||
impl->affinityMask = (DWORD_PTR)1 << GetCurrentProcessorNumber();
|
||||
HANDLE currThread = GetCurrentThread();
|
||||
DWORD_PTR prevAffinityMask = SetThreadAffinityMask(currThread, impl->affinityMask);
|
||||
assert(prevAffinityMask != 0);
|
||||
#endif
|
||||
|
||||
// Query the performance counter.
|
||||
LARGE_INTEGER perfQuery;
|
||||
#ifndef NDEBUG
|
||||
assert(QueryPerformanceCounter(&perfQuery));
|
||||
#else
|
||||
QueryPerformanceCounter(&perfQuery);
|
||||
#endif
|
||||
impl->start = perfQuery.QuadPart;
|
||||
|
||||
#ifndef __MINGW32__
|
||||
// Restore the thread's affinity mask.
|
||||
prevAffinityMask = SetThreadAffinityMask(currThread, prevAffinityMask);
|
||||
assert(prevAffinityMask != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Stop the stopwatch.
|
||||
void StopWatch::Stop()
|
||||
{
|
||||
#ifndef __MINGW32__
|
||||
// MSDN recommends setting the thread affinity to avoid bugs in the BIOS and HAL.
|
||||
// Use the affinity mask that was created in the Start function.
|
||||
HANDLE currThread = GetCurrentThread();
|
||||
DWORD_PTR prevAffinityMask = SetThreadAffinityMask(currThread, impl->affinityMask);
|
||||
assert(prevAffinityMask != 0);
|
||||
#endif
|
||||
|
||||
// Query the performance counter.
|
||||
LARGE_INTEGER perfQuery;
|
||||
#ifndef NDEBUG
|
||||
assert(QueryPerformanceCounter(&perfQuery));
|
||||
#else
|
||||
QueryPerformanceCounter(&perfQuery);
|
||||
#endif
|
||||
impl->stop = perfQuery.QuadPart;
|
||||
|
||||
#ifndef __MINGW32__
|
||||
// Restore the thread's affinity mask.
|
||||
prevAffinityMask = SetThreadAffinityMask(currThread, prevAffinityMask);
|
||||
assert(prevAffinityMask != 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Reset the stopwatch.
|
||||
void StopWatch::Reset()
|
||||
{
|
||||
impl->start = 0;
|
||||
impl->stop = 0;
|
||||
#ifndef __MINGW32__
|
||||
impl->affinityMask = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Get the elapsed time in seconds.
|
||||
double StopWatch::TimeInSeconds() const
|
||||
{
|
||||
// Return the elapsed time in seconds.
|
||||
assert((impl->stop - impl->start) > 0);
|
||||
return double(impl->stop - impl->start) / double(impl->frequency);
|
||||
}
|
||||
|
||||
// Get the elapsed time in milliseconds.
|
||||
double StopWatch::TimeInMilliseconds() const
|
||||
{
|
||||
// Return the elapsed time in milliseconds.
|
||||
assert((impl->stop - impl->start) > 0);
|
||||
return double(impl->stop - impl->start) / double(impl->frequency) * 1000.0;
|
||||
}
|
||||
|
||||
// Get the elapsed time in microseconds.
|
||||
double StopWatch::TimeInMicroseconds() const
|
||||
{
|
||||
// Return the elapsed time in microseconds.
|
||||
assert((impl->stop - impl->start) > 0);
|
||||
return double(impl->stop - impl->start) / double(impl->frequency) * 1000000.0;
|
||||
}
|
|
@ -1,529 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "FasTC/TexComp.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <string.h>
|
||||
|
||||
#include "FasTC/BPTCCompressor.h"
|
||||
#include "FasTC/CompressionFormat.h"
|
||||
#include "FasTC/DXTCompressor.h"
|
||||
#include "FasTC/ETCCompressor.h"
|
||||
#include "FasTC/ImageFile.h"
|
||||
#include "FasTC/Pixel.h"
|
||||
#include "FasTC/PVRTCCompressor.h"
|
||||
|
||||
#include "CompressionFuncs.h"
|
||||
#include "Thread.h"
|
||||
#include "ThreadGroup.h"
|
||||
#include "WorkerQueue.h"
|
||||
|
||||
using FasTC::CompressionJob;
|
||||
using FasTC::CompressionJobList;
|
||||
using FasTC::ECompressionFormat;
|
||||
|
||||
template <typename T>
|
||||
static void clamp(T &x, const T &minX, const T &maxX) {
|
||||
x = std::max(std::min(maxX, x), minX);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline T sad(const T &a, const T &b) {
|
||||
return (a > b)? a - b : b - a;
|
||||
}
|
||||
|
||||
static BPTCC::CompressionSettings gBPTCSettings;
|
||||
static void CompressBPTC(const CompressionJob &cj) {
|
||||
BPTCC::Compress(cj, gBPTCSettings);
|
||||
}
|
||||
|
||||
static void CompressBPTCWithStats(const CompressionJob &cj,
|
||||
std::ostream *strm) {
|
||||
BPTCC::CompressWithStats(cj, strm, gBPTCSettings);
|
||||
}
|
||||
|
||||
static void CompressPVRTC(const CompressionJob &cj) {
|
||||
PVRTCC::Compress(cj);
|
||||
}
|
||||
|
||||
static void CompressPVRTCLib(const CompressionJob &cj) {
|
||||
#ifdef PVRTEXLIB_FOUND
|
||||
PVRTCC::CompressPVRLib(cj);
|
||||
#else
|
||||
fprintf(stderr, "WARNING: PVRTexLib not found, defaulting to FasTC implementation.\n");
|
||||
PVRTCC::Compress(cj);
|
||||
#endif
|
||||
}
|
||||
|
||||
SCompressionSettings:: SCompressionSettings()
|
||||
: format(FasTC::eCompressionFormat_BPTC)
|
||||
, bUseSIMD(false)
|
||||
, iNumThreads(1)
|
||||
, iQuality(50)
|
||||
, iNumCompressions(1)
|
||||
{
|
||||
clamp(iQuality, 0, 256);
|
||||
}
|
||||
|
||||
static CompressionFuncWithStats ChooseFuncFromSettingsWithStats(const SCompressionSettings &s) {
|
||||
switch(s.format) {
|
||||
|
||||
case FasTC::eCompressionFormat_BPTC:
|
||||
{
|
||||
#ifdef FOUND_NVTT_BPTC_EXPORT
|
||||
if(s.bUseNVTT)
|
||||
return BPTCC::CompressNVTTWithStats;
|
||||
else
|
||||
#endif
|
||||
return CompressBPTCWithStats;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
assert(!"Not implemented!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static CompressionFunc ChooseFuncFromSettings(const SCompressionSettings &s) {
|
||||
switch(s.format) {
|
||||
case FasTC::eCompressionFormat_BPTC:
|
||||
{
|
||||
gBPTCSettings.m_NumSimulatedAnnealingSteps = s.iQuality;
|
||||
#ifdef HAS_SSE_41
|
||||
if(s.bUseSIMD) {
|
||||
return BPTCC::CompressImageBPTCSIMD;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FOUND_NVTT_BPTC_EXPORT
|
||||
if(s.bUseNVTT)
|
||||
return BPTCC::CompressNVTT;
|
||||
else
|
||||
#endif
|
||||
return CompressBPTC;
|
||||
}
|
||||
break;
|
||||
|
||||
case FasTC::eCompressionFormat_DXT1:
|
||||
return DXTC::CompressImageDXT1;
|
||||
|
||||
case FasTC::eCompressionFormat_DXT5:
|
||||
return DXTC::CompressImageDXT5;
|
||||
|
||||
case FasTC::eCompressionFormat_PVRTC4:
|
||||
{
|
||||
if(s.bUsePVRTexLib) {
|
||||
return CompressPVRTCLib;
|
||||
} else {
|
||||
return CompressPVRTC;
|
||||
}
|
||||
}
|
||||
|
||||
case FasTC::eCompressionFormat_ETC1:
|
||||
return ETCC::Compress_RG;
|
||||
|
||||
default:
|
||||
{
|
||||
assert(!"Not implemented!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ReportError(const char *msg) {
|
||||
fprintf(stderr, "TexComp -- %s\n", msg);
|
||||
}
|
||||
|
||||
static double CompressImageInSerial(
|
||||
const CompressionJob &job,
|
||||
const SCompressionSettings &settings
|
||||
) {
|
||||
CompressionFunc f = ChooseFuncFromSettings(settings);
|
||||
CompressionFuncWithStats fStats = NULL;
|
||||
if (settings.logStream) {
|
||||
fStats = ChooseFuncFromSettingsWithStats(settings);
|
||||
}
|
||||
|
||||
double cmpTimeTotal = 0.0;
|
||||
|
||||
StopWatch stopWatch = StopWatch();
|
||||
for(int i = 0; i < settings.iNumCompressions; i++) {
|
||||
|
||||
stopWatch.Reset();
|
||||
stopWatch.Start();
|
||||
|
||||
if(fStats && settings.logStream) {
|
||||
(*fStats)(job, settings.logStream);
|
||||
} else {
|
||||
(*f)(job);
|
||||
}
|
||||
|
||||
stopWatch.Stop();
|
||||
|
||||
cmpTimeTotal += stopWatch.TimeInMilliseconds();
|
||||
}
|
||||
|
||||
double cmpTime = cmpTimeTotal / double(settings.iNumCompressions);
|
||||
return cmpTime;
|
||||
}
|
||||
|
||||
#ifdef HAS_ATOMICS
|
||||
class AtomicThreadUnit : public TCCallable {
|
||||
CompressionJobList &m_CompressionJobList;
|
||||
TCBarrier *m_Barrier;
|
||||
CompressionFunc m_CmpFnc;
|
||||
|
||||
public:
|
||||
AtomicThreadUnit(
|
||||
CompressionJobList &_cjl,
|
||||
TCBarrier *barrier,
|
||||
CompressionFunc f
|
||||
) : TCCallable(),
|
||||
m_CompressionJobList(_cjl),
|
||||
m_Barrier(barrier),
|
||||
m_CmpFnc(f)
|
||||
{ }
|
||||
|
||||
virtual ~AtomicThreadUnit() { }
|
||||
virtual void operator()() {
|
||||
m_Barrier->Wait();
|
||||
if(m_CmpFnc == CompressBPTC) {
|
||||
BPTCC::CompressAtomic(m_CompressionJobList);
|
||||
}
|
||||
else {
|
||||
assert(!"I don't know what we're compressing...");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static double CompressImageWithAtomics(
|
||||
const CompressionJob &cj,
|
||||
const SCompressionSettings &settings
|
||||
) {
|
||||
CompressionFunc f = ChooseFuncFromSettings(settings);
|
||||
|
||||
// Setup compression list...
|
||||
const int nTimes = settings.iNumCompressions;
|
||||
CompressionJobList cjl (nTimes);
|
||||
for(int i = 0; i < nTimes; i++) {
|
||||
if(!cjl.AddJob(cj)) {
|
||||
assert(!"Error adding compression job to job list!");
|
||||
}
|
||||
}
|
||||
|
||||
const int nThreads = settings.iNumThreads;
|
||||
|
||||
// Allocate resources...
|
||||
TCBarrier barrier (nThreads+1);
|
||||
TCThread **threads = (TCThread **)malloc(nThreads * sizeof(TCThread *));
|
||||
AtomicThreadUnit **units = (AtomicThreadUnit **)malloc(nThreads * sizeof(AtomicThreadUnit *));
|
||||
|
||||
// Launch threads...
|
||||
for(int i = 0; i < nThreads; i++) {
|
||||
AtomicThreadUnit *u = new AtomicThreadUnit(cjl, &barrier, f);
|
||||
threads[i] = new TCThread(*u);
|
||||
units[i] = u;
|
||||
}
|
||||
|
||||
// Wait here to make sure that our timer is correct...
|
||||
barrier.Wait();
|
||||
|
||||
StopWatch sw;
|
||||
sw.Start();
|
||||
|
||||
// Wait for threads to finish
|
||||
for(int i = 0; i < nThreads; i++) {
|
||||
threads[i]->Join();
|
||||
}
|
||||
sw.Stop();
|
||||
|
||||
// Cleanup
|
||||
for(int i = 0; i < nThreads; i++)
|
||||
delete threads[i];
|
||||
free(threads);
|
||||
for(int i = 0; i < nThreads; i++)
|
||||
delete units[i];
|
||||
free(units);
|
||||
|
||||
// Compression time
|
||||
double cmpTimeTotal = sw.TimeInMilliseconds();
|
||||
return cmpTimeTotal / double(settings.iNumCompressions);
|
||||
}
|
||||
#else // HAS_ATOMICS
|
||||
static double CompressImageWithAtomics(
|
||||
const CompressionJob &cj,
|
||||
const SCompressionSettings &settings
|
||||
) {
|
||||
fprintf(stderr, "Compiler does not support atomic operations!");
|
||||
}
|
||||
#endif
|
||||
|
||||
static double CompressThreadGroup(ThreadGroup &tgrp, const SCompressionSettings &settings) {
|
||||
if(!(tgrp.PrepareThreads())) {
|
||||
assert(!"Thread group failed to prepare threads?!");
|
||||
return -1.0f;
|
||||
}
|
||||
|
||||
double cmpTimeTotal = 0.0;
|
||||
for(int i = 0; i < settings.iNumCompressions; i++) {
|
||||
if(i > 0)
|
||||
tgrp.PrepareThreads();
|
||||
|
||||
tgrp.Start();
|
||||
tgrp.Join();
|
||||
|
||||
StopWatch stopWatch = tgrp.GetStopWatch();
|
||||
cmpTimeTotal += tgrp.GetStopWatch().TimeInMilliseconds();
|
||||
}
|
||||
|
||||
tgrp.CleanUpThreads();
|
||||
return cmpTimeTotal;
|
||||
}
|
||||
|
||||
static double CompressImageWithThreads(
|
||||
const CompressionJob &job,
|
||||
const SCompressionSettings &settings
|
||||
) {
|
||||
|
||||
CompressionFunc f = ChooseFuncFromSettings(settings);
|
||||
CompressionFuncWithStats fStats = ChooseFuncFromSettingsWithStats(settings);
|
||||
|
||||
double cmpTimeTotal = 0.0;
|
||||
if(fStats && settings.logStream) {
|
||||
ThreadGroup tgrp (settings.iNumThreads, job, fStats, settings.logStream);
|
||||
cmpTimeTotal = CompressThreadGroup(tgrp, settings);
|
||||
}
|
||||
else {
|
||||
ThreadGroup tgrp (settings.iNumThreads, job, f);
|
||||
cmpTimeTotal = CompressThreadGroup(tgrp, settings);
|
||||
}
|
||||
|
||||
double cmpTime = cmpTimeTotal / double(settings.iNumCompressions);
|
||||
return cmpTime;
|
||||
}
|
||||
|
||||
static double RunWorkerQueue(WorkerQueue &wq) {
|
||||
wq.Run();
|
||||
return wq.GetStopWatch().TimeInMilliseconds();
|
||||
}
|
||||
|
||||
static double CompressImageWithWorkerQueue(
|
||||
const CompressionJob &job,
|
||||
const SCompressionSettings &settings
|
||||
) {
|
||||
CompressionFunc f = ChooseFuncFromSettings(settings);
|
||||
CompressionFuncWithStats fStats = ChooseFuncFromSettingsWithStats(settings);
|
||||
|
||||
double cmpTimeTotal = 0.0;
|
||||
if(fStats && settings.logStream) {
|
||||
WorkerQueue wq (
|
||||
settings.iNumCompressions,
|
||||
settings.iNumThreads,
|
||||
settings.iJobSize,
|
||||
job,
|
||||
fStats,
|
||||
settings.logStream
|
||||
);
|
||||
cmpTimeTotal = RunWorkerQueue(wq);
|
||||
}
|
||||
else {
|
||||
WorkerQueue wq (
|
||||
settings.iNumCompressions,
|
||||
settings.iNumThreads,
|
||||
settings.iJobSize,
|
||||
job,
|
||||
f
|
||||
);
|
||||
cmpTimeTotal = RunWorkerQueue(wq);
|
||||
}
|
||||
|
||||
return cmpTimeTotal / double(settings.iNumCompressions);
|
||||
}
|
||||
|
||||
template<typename PixelType>
|
||||
CompressedImage *CompressImage(
|
||||
FasTC::Image<PixelType> *img, const SCompressionSettings &settings
|
||||
) {
|
||||
if(!img) return NULL;
|
||||
|
||||
uint32 width = img->GetWidth();
|
||||
uint32 height = img->GetHeight();
|
||||
assert(width > 0);
|
||||
assert(height > 0);
|
||||
|
||||
// Make sure that the width and height of the image is a multiple of
|
||||
// the block size of the format
|
||||
uint32 blockDims[2];
|
||||
FasTC::GetBlockDimensions(settings.format, blockDims);
|
||||
if ((width % blockDims[0]) != 0 || (height % blockDims[1]) != 0) {
|
||||
ReportError("WARNING - Image size is not a multiple of block size. Padding with zeros...");
|
||||
uint32 newWidth = ((width + (blockDims[0] - 1)) / blockDims[0]) * blockDims[0];
|
||||
uint32 newHeight = ((height + (blockDims[1] - 1)) / blockDims[1]) * blockDims[1];
|
||||
|
||||
assert(newWidth > width || newHeight > height);
|
||||
assert(newWidth % blockDims[0] == 0);
|
||||
assert(newHeight % blockDims[1] == 0);
|
||||
|
||||
width = newWidth;
|
||||
height = newHeight;
|
||||
}
|
||||
|
||||
uint32 *data = new uint32[width * height];
|
||||
memset(data, 0, width * height * sizeof(data[0]));
|
||||
|
||||
CompressedImage *outImg = NULL;
|
||||
|
||||
// Allocate data based on the compression method
|
||||
uint32 cmpDataSz = CompressedImage::GetCompressedSize(width, height, settings.format);
|
||||
|
||||
// Make sure that we have RGBA data...
|
||||
img->ComputePixels();
|
||||
for(uint32 j = 0; j < img->GetHeight(); j++) {
|
||||
for(uint32 i = 0; i < img->GetWidth(); i++) {
|
||||
data[j * width + i] = (*img)(i, j).Pack();
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char *cmpData = new unsigned char[cmpDataSz];
|
||||
uint8 *dataPtr = reinterpret_cast<uint8 *>(data);
|
||||
if (CompressImageData(dataPtr, width, height, cmpData, cmpDataSz, settings)) {
|
||||
outImg = new CompressedImage(width, height, settings.format, cmpData);
|
||||
}
|
||||
|
||||
delete [] data;
|
||||
delete [] cmpData;
|
||||
return outImg;
|
||||
}
|
||||
|
||||
// !FIXME! Ideally, we wouldn't have to do this because there would be a way to instantiate this
|
||||
// function in the header or using some fancy template metaprogramming. I can't think of the way
|
||||
// at the moment.
|
||||
template CompressedImage *CompressImage(FasTC::Image<FasTC::Pixel> *, const SCompressionSettings &settings);
|
||||
|
||||
bool CompressImageData(
|
||||
const uint8 *data,
|
||||
const uint32 width,
|
||||
const uint32 height,
|
||||
uint8 *compressedData,
|
||||
const uint32 cmpDataSz,
|
||||
const SCompressionSettings &settings
|
||||
) {
|
||||
|
||||
uint32 dataSz = width * height * 4;
|
||||
|
||||
// Make sure that platform supports SSE if they chose this
|
||||
// option...
|
||||
#ifndef HAS_SSE_41
|
||||
if(settings.bUseSIMD) {
|
||||
ReportError("Platform does not support SIMD!\n");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef HAS_ATOMICS
|
||||
if(settings.bUseAtomics) {
|
||||
ReportError("Compiler's atomic operations are not supported!\n");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(dataSz <= 0) {
|
||||
ReportError("No data sent to compress!");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 numThreads = settings.iNumThreads;
|
||||
if(settings.format == FasTC::eCompressionFormat_PVRTC4 &&
|
||||
(settings.iNumThreads > 1 || settings.logStream)) {
|
||||
if(settings.iNumThreads > 1) {
|
||||
ReportError("WARNING - PVRTC compressor does not support multithreading.");
|
||||
numThreads = 1;
|
||||
}
|
||||
|
||||
if(settings.logStream) {
|
||||
ReportError("WARNING - PVRTC compressor does not support stat collection.");
|
||||
}
|
||||
}
|
||||
|
||||
uint32 blockDims[2];
|
||||
FasTC::GetBlockDimensions(settings.format, blockDims);
|
||||
if ((width % blockDims[0]) != 0 || (height % blockDims[1]) != 0) {
|
||||
ReportError("ERROR - CompressImageData: width or height is not multiple of block dimension");
|
||||
return false;
|
||||
} else if (settings.format == FasTC::eCompressionFormat_PVRTC4 &&
|
||||
((width & (width - 1)) != 0 ||
|
||||
(height & (height - 1)) != 0 ||
|
||||
width != height)) {
|
||||
ReportError("ERROR - CompressImageData: PVRTC4 images must be square and power-of-two.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Allocate data based on the compression method
|
||||
uint32 compressedDataSzNeeded =
|
||||
CompressedImage::GetCompressedSize(width, height, settings.format);
|
||||
|
||||
if(compressedDataSzNeeded == 0) {
|
||||
ReportError("Unknown compression format");
|
||||
return false;
|
||||
}
|
||||
else if(compressedDataSzNeeded > cmpDataSz) {
|
||||
ReportError("Not enough space for compressed data!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(ChooseFuncFromSettings(settings)) {
|
||||
|
||||
CompressionJob cj(settings.format, data, compressedData, width, height);
|
||||
|
||||
double cmpMSTime = 0.0;
|
||||
if(numThreads > 1) {
|
||||
if(settings.bUseAtomics) {
|
||||
cmpMSTime = CompressImageWithAtomics(cj, settings);
|
||||
} else if(settings.iJobSize > 0) {
|
||||
cmpMSTime = CompressImageWithWorkerQueue(cj, settings);
|
||||
} else {
|
||||
cmpMSTime = CompressImageWithThreads(cj, settings);
|
||||
}
|
||||
}
|
||||
else {
|
||||
cmpMSTime = CompressImageInSerial(cj, settings);
|
||||
}
|
||||
|
||||
// Report compression time
|
||||
fprintf(stdout, "Compression time: %0.3f ms\n", cmpMSTime);
|
||||
}
|
||||
else {
|
||||
ReportError("Could not find adequate compression function for specified settings");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void YieldThread() {
|
||||
TCThread::Yield();
|
||||
}
|
|
@ -1,138 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "Thread.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Base Implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TCThreadBase::TCThreadBase(const TCThreadBaseImplFactory &factory)
|
||||
: m_Impl(factory.CreateImpl())
|
||||
{ }
|
||||
|
||||
TCThreadBase::TCThreadBase(const TCThreadBase &other)
|
||||
: m_Impl(other.m_Impl)
|
||||
{
|
||||
assert(m_Impl->GetReferenceCount() > 0);
|
||||
m_Impl->IncreaseReferenceCount();
|
||||
}
|
||||
|
||||
TCThreadBase &TCThreadBase::operator=(const TCThreadBase &other) {
|
||||
assert(m_Impl->GetReferenceCount() > 0);
|
||||
|
||||
// We are no longer referencing this implementation...
|
||||
m_Impl->DecreaseReferenceCount();
|
||||
|
||||
// If we're the last ones to reference it, then it should be destroyed.
|
||||
if(m_Impl->GetReferenceCount() <= 0) {
|
||||
delete m_Impl;
|
||||
m_Impl = 0;
|
||||
}
|
||||
|
||||
// Our implementation is now the same as the other.
|
||||
m_Impl = other.m_Impl;
|
||||
m_Impl->IncreaseReferenceCount();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TCThreadBase::~TCThreadBase() {
|
||||
|
||||
// We are no longer referencing this implementation...
|
||||
m_Impl->DecreaseReferenceCount();
|
||||
|
||||
// If we're the last ones to reference it, then it should be destroyed.
|
||||
if(m_Impl->GetReferenceCount() <= 0) {
|
||||
assert(m_Impl->GetReferenceCount() == 0);
|
||||
delete m_Impl;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void TCThreadBase::CheckReferenceCount() {
|
||||
assert(m_Impl->GetReferenceCount() > 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Barrier Implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class TCBarrierImpl : public TCThreadBaseImpl {
|
||||
private:
|
||||
unsigned int m_ThreadLimit;
|
||||
unsigned int m_ThreadCount;
|
||||
unsigned int m_Times;
|
||||
|
||||
TCMutex m_Mutex;
|
||||
TCConditionVariable m_CV;
|
||||
|
||||
public:
|
||||
TCBarrierImpl(int threads)
|
||||
: TCThreadBaseImpl()
|
||||
, m_ThreadLimit(threads)
|
||||
, m_ThreadCount(threads)
|
||||
, m_Times(0)
|
||||
{
|
||||
assert(threads > 0);
|
||||
}
|
||||
|
||||
virtual ~TCBarrierImpl() { }
|
||||
|
||||
bool Wait() {
|
||||
TCLock lock(m_Mutex);
|
||||
unsigned int times = m_Times;
|
||||
|
||||
if(--m_ThreadCount == 0) {
|
||||
m_Times++;
|
||||
m_ThreadCount = m_ThreadLimit;
|
||||
m_CV.NotifyAll();
|
||||
return true;
|
||||
}
|
||||
|
||||
while(times == m_Times) {
|
||||
m_CV.Wait(lock);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
class TCBarrierImplFactory : public TCThreadBaseImplFactory {
|
||||
private:
|
||||
int m_NumThreads;
|
||||
public:
|
||||
TCBarrierImplFactory(int threads) : TCThreadBaseImplFactory(), m_NumThreads(threads) { }
|
||||
virtual ~TCBarrierImplFactory() { }
|
||||
virtual TCThreadBaseImpl *CreateImpl() const {
|
||||
return new TCBarrierImpl(m_NumThreads);
|
||||
}
|
||||
};
|
||||
|
||||
TCBarrier::TCBarrier(int threads)
|
||||
: TCThreadBase(TCBarrierImplFactory(threads))
|
||||
{ }
|
||||
|
||||
void TCBarrier::Wait() {
|
||||
((TCBarrierImpl *)m_Impl)->Wait();
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#ifndef __TEX_COMP_THREAD_H__
|
||||
#define __TEX_COMP_THREAD_H__
|
||||
|
||||
#include "FasTC/TexCompTypes.h"
|
||||
|
||||
//!HACK! Apparently MSVC has issues with Yield()...????
|
||||
#ifdef _MSC_VER
|
||||
#undef Yield
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Base implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class TCThreadBaseImpl {
|
||||
friend class TCThreadBase;
|
||||
private:
|
||||
int m_ReferenceCount;
|
||||
|
||||
void IncreaseReferenceCount() { m_ReferenceCount++; }
|
||||
void DecreaseReferenceCount() { m_ReferenceCount--; }
|
||||
|
||||
int GetReferenceCount() const { return m_ReferenceCount; }
|
||||
protected:
|
||||
TCThreadBaseImpl()
|
||||
: m_ReferenceCount(1)
|
||||
{ }
|
||||
|
||||
virtual ~TCThreadBaseImpl() { }
|
||||
};
|
||||
|
||||
class TCThreadBaseImplFactory {
|
||||
protected:
|
||||
TCThreadBaseImplFactory() { }
|
||||
virtual ~TCThreadBaseImplFactory() { }
|
||||
public:
|
||||
virtual TCThreadBaseImpl *CreateImpl() const = 0;
|
||||
};
|
||||
|
||||
class TCThreadBase {
|
||||
protected:
|
||||
TCThreadBase(const TCThreadBaseImplFactory &);
|
||||
TCThreadBase(const TCThreadBase &);
|
||||
TCThreadBase &operator=(const TCThreadBase &);
|
||||
~TCThreadBase();
|
||||
|
||||
TCThreadBaseImpl *m_Impl;
|
||||
#ifndef NDEBUG
|
||||
void CheckReferenceCount();
|
||||
#else
|
||||
void CheckReferenceCount() { }
|
||||
#endif
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Thread implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// The base class for a thread implementation
|
||||
class TCCallable {
|
||||
protected:
|
||||
TCCallable() { }
|
||||
public:
|
||||
virtual ~TCCallable() { }
|
||||
virtual void operator()() = 0;
|
||||
};
|
||||
|
||||
class TCThread : public TCThreadBase {
|
||||
|
||||
public:
|
||||
TCThread(TCCallable &);
|
||||
|
||||
static void Yield();
|
||||
static uint64 ThreadID();
|
||||
void Join();
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Mutex implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class TCMutex : public TCThreadBase {
|
||||
friend class TCLockImpl;
|
||||
public:
|
||||
TCMutex();
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Lock implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class TCLock : public TCThreadBase {
|
||||
friend class TCConditionVariableImpl;
|
||||
public:
|
||||
TCLock(TCMutex &);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Condition Variable implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class TCConditionVariable : public TCThreadBase {
|
||||
public:
|
||||
TCConditionVariable();
|
||||
void Wait(TCLock &);
|
||||
void NotifyOne();
|
||||
void NotifyAll();
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Barrier implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class TCBarrier : public TCThreadBase {
|
||||
public:
|
||||
TCBarrier(int threads);
|
||||
void Wait();
|
||||
};
|
||||
|
||||
#endif //__TEX_COMP_THREAD_H__
|
|
@ -1,253 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "ThreadGroup.h"
|
||||
#include "FasTC/BPTCCompressor.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
using FasTC::CompressionJob;
|
||||
|
||||
CmpThread::CmpThread()
|
||||
: m_ParentCounter(NULL)
|
||||
, m_StartBarrier(NULL)
|
||||
, m_ParentCounterLock(NULL)
|
||||
, m_FinishCV(NULL)
|
||||
, m_ParentExitFlag(NULL)
|
||||
, m_Job(CompressionJob(FasTC::kNumCompressionFormats, NULL, NULL, 0, 0))
|
||||
, m_CmpFunc(NULL)
|
||||
, m_CmpFuncWithStats(NULL)
|
||||
, m_LogStream(NULL)
|
||||
{ }
|
||||
|
||||
void CmpThread::operator()() {
|
||||
if(!m_Job.OutBuf() || !m_Job.InBuf()
|
||||
|| !m_ParentCounter || !m_ParentCounterLock || !m_FinishCV
|
||||
|| !m_StartBarrier
|
||||
|| !m_ParentExitFlag
|
||||
) {
|
||||
fprintf(stderr, "Incorrect thread initialization.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!(m_CmpFunc || (m_CmpFuncWithStats && m_LogStream))) {
|
||||
fprintf(stderr, "Incorrect thread function pointer.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
while(1) {
|
||||
// Wait for signal to start work...
|
||||
m_StartBarrier->Wait();
|
||||
|
||||
if(*m_ParentExitFlag) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_CmpFunc)
|
||||
(*m_CmpFunc)(m_Job);
|
||||
else
|
||||
(*m_CmpFuncWithStats)(m_Job, m_LogStream);
|
||||
|
||||
{
|
||||
TCLock lock(*m_ParentCounterLock);
|
||||
(*m_ParentCounter)++;
|
||||
}
|
||||
|
||||
m_FinishCV->NotifyOne();
|
||||
}
|
||||
}
|
||||
|
||||
ThreadGroup::ThreadGroup(uint32 numThreads,
|
||||
const CompressionJob &job,
|
||||
CompressionFunc func)
|
||||
: m_StartBarrier(new TCBarrier(numThreads + 1))
|
||||
, m_FinishMutex(new TCMutex())
|
||||
, m_FinishCV(new TCConditionVariable())
|
||||
, m_NumThreads(numThreads)
|
||||
, m_ActiveThreads(0)
|
||||
, m_Job(job)
|
||||
, m_ThreadState(eThreadState_Done)
|
||||
, m_ExitFlag(false)
|
||||
{
|
||||
for(uint32 i = 0; i < kMaxNumThreads; i++) {
|
||||
// Thread synchronization primitives
|
||||
m_Threads[i].m_ParentCounterLock = m_FinishMutex;
|
||||
m_Threads[i].m_FinishCV = m_FinishCV;
|
||||
m_Threads[i].m_ParentCounter = &m_ThreadsFinished;
|
||||
m_Threads[i].m_StartBarrier = m_StartBarrier;
|
||||
m_Threads[i].m_ParentExitFlag = &m_ExitFlag;
|
||||
m_Threads[i].m_CmpFunc = func;
|
||||
}
|
||||
}
|
||||
|
||||
ThreadGroup::ThreadGroup(
|
||||
uint32 numThreads,
|
||||
const CompressionJob &job,
|
||||
CompressionFuncWithStats func,
|
||||
std::ostream *logStream
|
||||
)
|
||||
: m_StartBarrier(new TCBarrier(numThreads + 1))
|
||||
, m_FinishMutex(new TCMutex())
|
||||
, m_FinishCV(new TCConditionVariable())
|
||||
, m_NumThreads(numThreads)
|
||||
, m_ActiveThreads(0)
|
||||
, m_Job(job)
|
||||
, m_ThreadState(eThreadState_Done)
|
||||
, m_ExitFlag(false)
|
||||
{
|
||||
for(uint32 i = 0; i < kMaxNumThreads; i++) {
|
||||
// Thread synchronization primitives
|
||||
m_Threads[i].m_ParentCounterLock = m_FinishMutex;
|
||||
m_Threads[i].m_FinishCV = m_FinishCV;
|
||||
m_Threads[i].m_ParentCounter = &m_ThreadsFinished;
|
||||
m_Threads[i].m_StartBarrier = m_StartBarrier;
|
||||
m_Threads[i].m_ParentExitFlag = &m_ExitFlag;
|
||||
m_Threads[i].m_CmpFuncWithStats = func;
|
||||
m_Threads[i].m_LogStream = logStream;
|
||||
}
|
||||
}
|
||||
|
||||
ThreadGroup::~ThreadGroup() {
|
||||
delete m_StartBarrier;
|
||||
delete m_FinishMutex;
|
||||
delete m_FinishCV;
|
||||
}
|
||||
|
||||
bool ThreadGroup::PrepareThreads() {
|
||||
|
||||
// Make sure that threads aren't running.
|
||||
if(m_ThreadState != eThreadState_Done) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Have we already activated the thread group?
|
||||
if(m_ActiveThreads > 0) {
|
||||
m_ThreadState = eThreadState_Waiting;
|
||||
return true;
|
||||
}
|
||||
|
||||
// We can assume that the image data is in block stream order
|
||||
// so, the size of the data given to each thread will be (nb*4)x4
|
||||
uint32 blockDim[2];
|
||||
GetBlockDimensions(m_Job.Format(), blockDim);
|
||||
uint32 numBlocks = (m_Job.Width() * m_Job.Height()) / (blockDim[0] * blockDim[1]);
|
||||
uint32 blocksProcessed = 0;
|
||||
uint32 blocksPerThread = (numBlocks/m_NumThreads) + ((numBlocks % m_NumThreads)? 1 : 0);
|
||||
|
||||
// Currently no threads are finished...
|
||||
m_ThreadsFinished = 0;
|
||||
for(int i = 0; i < m_NumThreads; i++) {
|
||||
|
||||
if(m_ActiveThreads >= kMaxNumThreads)
|
||||
break;
|
||||
|
||||
int numBlocksThisThread = blocksPerThread;
|
||||
if(blocksProcessed + numBlocksThisThread > numBlocks) {
|
||||
numBlocksThisThread = numBlocks - blocksProcessed;
|
||||
}
|
||||
|
||||
uint32 start[2], end[2];
|
||||
m_Job.BlockIdxToCoords(blocksProcessed, start);
|
||||
m_Job.BlockIdxToCoords(blocksProcessed + numBlocksThisThread, end);
|
||||
|
||||
// !TODO! This should be moved to a unit test...
|
||||
assert(m_Job.CoordsToBlockIdx(start[0], start[1]) == blocksProcessed);
|
||||
assert(m_Job.CoordsToBlockIdx(end[0], end[1]) == blocksProcessed + numBlocksThisThread);
|
||||
|
||||
CompressionJob cj(m_Job.Format(),
|
||||
m_Job.InBuf(), m_Job.OutBuf(),
|
||||
m_Job.Width(), m_Job.Height(),
|
||||
start[0], start[1],
|
||||
end[0], end[1]);
|
||||
|
||||
CmpThread &t = m_Threads[m_ActiveThreads];
|
||||
t.m_Job = cj;
|
||||
|
||||
blocksProcessed += numBlocksThisThread;
|
||||
|
||||
m_ThreadHandles[m_ActiveThreads] = new TCThread(t);
|
||||
|
||||
m_ActiveThreads++;
|
||||
}
|
||||
|
||||
m_ThreadState = eThreadState_Waiting;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThreadGroup::Start() {
|
||||
|
||||
if(m_ActiveThreads <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(m_ThreadState != eThreadState_Waiting) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_StopWatch.Reset();
|
||||
m_StopWatch.Start();
|
||||
|
||||
// Last thread to activate the barrier is this one.
|
||||
m_ThreadState = eThreadState_Running;
|
||||
m_StartBarrier->Wait();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThreadGroup::CleanUpThreads() {
|
||||
|
||||
// Are the threads currently running?
|
||||
if(m_ThreadState == eThreadState_Running) {
|
||||
// ... if so, wait for them to finish
|
||||
Join();
|
||||
}
|
||||
|
||||
assert(m_ThreadState == eThreadState_Done || m_ThreadState == eThreadState_Waiting);
|
||||
|
||||
// Mark all threads for exit
|
||||
m_ExitFlag = true;
|
||||
|
||||
// Hit the barrier to signal them to go.
|
||||
m_StartBarrier->Wait();
|
||||
|
||||
// Clean up.
|
||||
for(uint32 i = 0; i < m_ActiveThreads; i++) {
|
||||
m_ThreadHandles[i]->Join();
|
||||
delete m_ThreadHandles[i];
|
||||
}
|
||||
|
||||
// Reset active number of threads...
|
||||
m_ActiveThreads = 0;
|
||||
m_ExitFlag = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ThreadGroup::Join() {
|
||||
|
||||
TCLock lock(*m_FinishMutex);
|
||||
while(m_ThreadsFinished != m_ActiveThreads) {
|
||||
m_FinishCV->Wait(lock);
|
||||
}
|
||||
|
||||
m_StopWatch.Stop();
|
||||
m_ThreadState = eThreadState_Done;
|
||||
m_ThreadsFinished = 0;
|
||||
}
|
|
@ -1,105 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#ifndef _THREAD_GROUP_H_
|
||||
#define _THREAD_GROUP_H_
|
||||
|
||||
#include "FasTC/StopWatch.h"
|
||||
|
||||
#include "CompressionFuncs.h"
|
||||
#include "Thread.h"
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
struct CmpThread : public TCCallable {
|
||||
friend class ThreadGroup;
|
||||
|
||||
private:
|
||||
uint32 *m_ParentCounter;
|
||||
|
||||
TCBarrier *m_StartBarrier;
|
||||
TCMutex *m_ParentCounterLock;
|
||||
TCConditionVariable *m_FinishCV;
|
||||
|
||||
bool *m_ParentExitFlag;
|
||||
|
||||
FasTC::CompressionJob m_Job;
|
||||
CompressionFunc m_CmpFunc;
|
||||
CompressionFuncWithStats m_CmpFuncWithStats;
|
||||
std::ostream *m_LogStream;
|
||||
|
||||
CmpThread();
|
||||
|
||||
public:
|
||||
virtual ~CmpThread() { }
|
||||
virtual void operator ()();
|
||||
};
|
||||
|
||||
class ThreadGroup {
|
||||
public:
|
||||
ThreadGroup(
|
||||
uint32 numThreads,
|
||||
const FasTC::CompressionJob &cj,
|
||||
CompressionFunc func
|
||||
);
|
||||
|
||||
ThreadGroup(
|
||||
uint32 numThreads,
|
||||
const FasTC::CompressionJob &cj,
|
||||
CompressionFuncWithStats func,
|
||||
std::ostream *logStream
|
||||
);
|
||||
|
||||
~ThreadGroup();
|
||||
|
||||
bool PrepareThreads();
|
||||
bool Start();
|
||||
void Join();
|
||||
bool CleanUpThreads();
|
||||
|
||||
const StopWatch &GetStopWatch() const { return m_StopWatch; }
|
||||
|
||||
enum EThreadState {
|
||||
eThreadState_Waiting,
|
||||
eThreadState_Running,
|
||||
eThreadState_Done
|
||||
};
|
||||
|
||||
private:
|
||||
TCBarrier *const m_StartBarrier;
|
||||
|
||||
TCMutex *const m_FinishMutex;
|
||||
TCConditionVariable *const m_FinishCV;
|
||||
|
||||
static const uint32 kMaxNumThreads = 256;
|
||||
const int m_NumThreads;
|
||||
|
||||
uint32 m_ActiveThreads;
|
||||
uint32 m_ThreadsFinished;
|
||||
|
||||
CmpThread m_Threads[kMaxNumThreads];
|
||||
TCThread *m_ThreadHandles[kMaxNumThreads];
|
||||
|
||||
FasTC::CompressionJob m_Job;
|
||||
|
||||
StopWatch m_StopWatch;
|
||||
|
||||
EThreadState m_ThreadState;
|
||||
bool m_ExitFlag;
|
||||
};
|
||||
|
||||
#endif // _THREAD_GROUP_H_
|
|
@ -1,287 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "Thread.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <sched.h>
|
||||
#endif
|
||||
|
||||
static void ReportErrorAndExit(int err, const char *msg) {
|
||||
char errMsg[1024];
|
||||
sprintf(errMsg, "Thread error -- %s: ", msg);
|
||||
|
||||
errno = err;
|
||||
perror(errMsg);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Thread Implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class TCThreadImpl : public TCThreadBaseImpl {
|
||||
private:
|
||||
|
||||
static void *RunThread(void *arg) {
|
||||
TCThreadImpl *impl = (TCThreadImpl *)arg;
|
||||
|
||||
impl->m_Callable();
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pthread_t m_ThreadID;
|
||||
TCCallable &m_Callable;
|
||||
|
||||
public:
|
||||
TCThreadImpl(TCCallable &callable) :
|
||||
m_Callable(callable)
|
||||
{
|
||||
int result = pthread_create(&m_ThreadID, NULL, RunThread, (void *)this);
|
||||
if(result != 0) {
|
||||
ReportErrorAndExit(result, "pthread_create");
|
||||
}
|
||||
}
|
||||
virtual ~TCThreadImpl() { }
|
||||
|
||||
void Join() {
|
||||
void *status;
|
||||
int result = pthread_join(m_ThreadID, &status);
|
||||
if(result != 0) {
|
||||
ReportErrorAndExit(result, "pthread_join");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class TCThreadImplFactory : public TCThreadBaseImplFactory {
|
||||
TCCallable &m_Callable;
|
||||
public:
|
||||
TCThreadImplFactory(TCCallable &callable) : m_Callable(callable) { }
|
||||
virtual ~TCThreadImplFactory() { }
|
||||
virtual TCThreadBaseImpl *CreateImpl() const {
|
||||
return new TCThreadImpl(m_Callable);
|
||||
}
|
||||
};
|
||||
|
||||
TCThread::TCThread(TCCallable &callable)
|
||||
: TCThreadBase(TCThreadImplFactory(callable))
|
||||
{ }
|
||||
|
||||
void TCThread::Join() {
|
||||
CheckReferenceCount();
|
||||
((TCThreadImpl *)m_Impl)->Join();
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
#undef Yield
|
||||
#endif
|
||||
void TCThread::Yield() {
|
||||
#if defined(__APPLE__) || defined(__MINGW32__)
|
||||
int result = sched_yield();
|
||||
#else
|
||||
int result = pthread_yield();
|
||||
#endif
|
||||
if(result != 0) {
|
||||
ReportErrorAndExit(result, "pthread_yield");
|
||||
}
|
||||
}
|
||||
|
||||
uint64 TCThread::ThreadID() {
|
||||
#ifdef __MINGW32__
|
||||
return static_cast<uint64>(pthread_self().x);
|
||||
#elif defined __APPLE__
|
||||
return reinterpret_cast<uint64>(pthread_self());
|
||||
#else
|
||||
return static_cast<uint64>(pthread_self());
|
||||
#endif
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Mutex Implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class TCMutexImpl : public TCThreadBaseImpl {
|
||||
private:
|
||||
pthread_mutex_t m_Mutex;
|
||||
|
||||
public:
|
||||
pthread_mutex_t *GetMutex() { return &m_Mutex; }
|
||||
TCMutexImpl() : TCThreadBaseImpl() {
|
||||
int result = pthread_mutex_init( &m_Mutex, NULL );
|
||||
if(result != 0) {
|
||||
ReportErrorAndExit(result, "pthread_mutex_init");
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~TCMutexImpl() {
|
||||
int result = pthread_mutex_destroy( &m_Mutex );
|
||||
if(result != 0) {
|
||||
ReportErrorAndExit(result, "pthread_mutex_destroy");
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class TCMutexImplFactory : public TCThreadBaseImplFactory {
|
||||
public:
|
||||
TCMutexImplFactory() { }
|
||||
virtual ~TCMutexImplFactory() { }
|
||||
virtual TCThreadBaseImpl *CreateImpl() const {
|
||||
return new TCMutexImpl();
|
||||
}
|
||||
};
|
||||
|
||||
TCMutex::TCMutex() : TCThreadBase(TCMutexImplFactory())
|
||||
{ }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Lock Implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class TCLockImpl : public TCThreadBaseImpl {
|
||||
private:
|
||||
pthread_mutex_t *const m_MutexPtr;
|
||||
public:
|
||||
TCLockImpl(TCMutex &mutex)
|
||||
: m_MutexPtr(((TCMutexImpl *)(mutex.m_Impl))->GetMutex())
|
||||
{
|
||||
int result = pthread_mutex_lock( m_MutexPtr );
|
||||
if(result != 0) {
|
||||
ReportErrorAndExit(result, "pthread_mutex_lock");
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~TCLockImpl() {
|
||||
int result = pthread_mutex_unlock( m_MutexPtr );
|
||||
if(result != 0) {
|
||||
ReportErrorAndExit(result, "pthread_mutex_unlock");
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_t *GetMutexPtr() const { return m_MutexPtr; }
|
||||
};
|
||||
|
||||
class TCLockImplFactory : public TCThreadBaseImplFactory {
|
||||
private:
|
||||
TCMutex &m_Mutex;
|
||||
public:
|
||||
TCLockImplFactory(TCMutex &mutex) : m_Mutex(mutex){ }
|
||||
virtual ~TCLockImplFactory() { }
|
||||
virtual TCThreadBaseImpl *CreateImpl() const {
|
||||
return new TCLockImpl(m_Mutex);
|
||||
}
|
||||
};
|
||||
|
||||
TCLock::TCLock(TCMutex &mutex) : TCThreadBase(TCLockImplFactory(mutex))
|
||||
{ }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Condition Variable Implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class TCConditionVariableImpl : public TCThreadBaseImpl {
|
||||
private:
|
||||
pthread_cond_t m_CV;
|
||||
public:
|
||||
TCConditionVariableImpl() {
|
||||
int result = pthread_cond_init( &m_CV, NULL );
|
||||
if(result != 0) {
|
||||
ReportErrorAndExit(result, "pthread_cond_init");
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~TCConditionVariableImpl() {
|
||||
int result = pthread_cond_destroy( &m_CV );
|
||||
if(result != 0) {
|
||||
ReportErrorAndExit(result, "pthread_cond_destroy");
|
||||
}
|
||||
}
|
||||
|
||||
void Wait(TCLock &lock) {
|
||||
TCLockImpl *lockImpl = (TCLockImpl *)(lock.m_Impl);
|
||||
|
||||
int result = pthread_cond_wait( &m_CV, lockImpl->GetMutexPtr() );
|
||||
if(result != 0) {
|
||||
ReportErrorAndExit( result, "pthread_cond_wait" );
|
||||
}
|
||||
}
|
||||
|
||||
void NotifyOne() {
|
||||
int result = pthread_cond_signal( &m_CV );
|
||||
if(result != 0) {
|
||||
ReportErrorAndExit( result, "pthread_cond_signal" );
|
||||
}
|
||||
}
|
||||
|
||||
void NotifyAll() {
|
||||
int result = pthread_cond_broadcast( &m_CV );
|
||||
if(result != 0) {
|
||||
ReportErrorAndExit( result, "pthread_cond_broadcast" );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class TCConditionVariableImplFactory : public TCThreadBaseImplFactory {
|
||||
public:
|
||||
TCConditionVariableImplFactory() { }
|
||||
virtual ~TCConditionVariableImplFactory() { }
|
||||
virtual TCThreadBaseImpl *CreateImpl() const {
|
||||
return new TCConditionVariableImpl();
|
||||
}
|
||||
};
|
||||
|
||||
TCConditionVariable::TCConditionVariable()
|
||||
: TCThreadBase(TCConditionVariableImplFactory())
|
||||
{ }
|
||||
|
||||
void TCConditionVariable::Wait(TCLock &lock) {
|
||||
CheckReferenceCount();
|
||||
|
||||
TCConditionVariableImpl *impl = (TCConditionVariableImpl *)m_Impl;
|
||||
impl->Wait(lock);
|
||||
}
|
||||
|
||||
void TCConditionVariable::NotifyOne() {
|
||||
CheckReferenceCount();
|
||||
|
||||
TCConditionVariableImpl *impl = (TCConditionVariableImpl *)m_Impl;
|
||||
impl->NotifyOne();
|
||||
}
|
||||
|
||||
void TCConditionVariable::NotifyAll() {
|
||||
CheckReferenceCount();
|
||||
|
||||
TCConditionVariableImpl *impl = (TCConditionVariableImpl *)m_Impl;
|
||||
impl->NotifyAll();
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "FasTC/ThreadSafeStreambuf.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "Thread.h"
|
||||
|
||||
ThreadSafeStreambuf::ThreadSafeStreambuf(std::ostream &sink)
|
||||
: ::std::streambuf()
|
||||
, m_Sink(sink)
|
||||
, m_Mutex(new TCMutex)
|
||||
{ }
|
||||
|
||||
ThreadSafeStreambuf::~ThreadSafeStreambuf() {
|
||||
if(m_Mutex) {
|
||||
delete m_Mutex;
|
||||
}
|
||||
}
|
||||
|
||||
::std::streamsize ThreadSafeStreambuf::xsputn(const char_type *s,
|
||||
::std::streamsize count) {
|
||||
// Lock it.
|
||||
TCLock lock(*m_Mutex);
|
||||
::std::streambuf *sinkStream = m_Sink.rdbuf();
|
||||
return sinkStream->sputn(s, count);
|
||||
}
|
|
@ -1,255 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "Thread.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <tchar.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
void ErrorHandler(LPTSTR lpszFunction)
|
||||
{
|
||||
// Retrieve the system error message for the last-error code.
|
||||
LPVOID lpMsgBuf;
|
||||
LPVOID lpDisplayBuf;
|
||||
DWORD dw = GetLastError();
|
||||
|
||||
FormatMessage(
|
||||
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
||||
FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
dw,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR) &lpMsgBuf,
|
||||
0, NULL );
|
||||
|
||||
// Display the error message.
|
||||
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT,
|
||||
(lstrlen((LPCTSTR) lpMsgBuf) + lstrlen((LPCTSTR) lpszFunction) + 40) * sizeof(TCHAR));
|
||||
StringCchPrintf((LPTSTR)lpDisplayBuf,
|
||||
LocalSize(lpDisplayBuf) / sizeof(TCHAR),
|
||||
TEXT("%s failed with error %d: %s"),
|
||||
lpszFunction, dw, lpMsgBuf);
|
||||
MessageBox(NULL, (LPCTSTR) lpDisplayBuf, TEXT("Error"), MB_OK);
|
||||
|
||||
// Free error-handling buffer allocations.
|
||||
LocalFree(lpMsgBuf);
|
||||
LocalFree(lpDisplayBuf);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Thread Implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class TCThreadImpl : public TCThreadBaseImpl {
|
||||
private:
|
||||
static DWORD WINAPI RunThread(LPVOID arg) {
|
||||
TCThreadImpl *impl = (TCThreadImpl *)arg;
|
||||
impl->m_Callable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
HANDLE m_ThreadID;
|
||||
TCCallable &m_Callable;
|
||||
|
||||
public:
|
||||
TCThreadImpl(TCCallable &callable) :
|
||||
m_Callable(callable)
|
||||
{
|
||||
m_ThreadID = CreateThread(NULL, 0, RunThread, (void *)this, 0, 0);
|
||||
if(m_ThreadID == NULL) {
|
||||
ErrorHandler("CreateThread");
|
||||
}
|
||||
}
|
||||
virtual ~TCThreadImpl() { }
|
||||
|
||||
void Join() {
|
||||
DWORD result = WaitForSingleObject(m_ThreadID, INFINITE);
|
||||
if(result == WAIT_FAILED) {
|
||||
ErrorHandler("WaitForSingleObject");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class TCThreadImplFactory : public TCThreadBaseImplFactory {
|
||||
TCCallable &m_Callable;
|
||||
public:
|
||||
TCThreadImplFactory(TCCallable &callable) : m_Callable(callable) { }
|
||||
virtual ~TCThreadImplFactory() { }
|
||||
virtual TCThreadBaseImpl *CreateImpl() const {
|
||||
return new TCThreadImpl(m_Callable);
|
||||
}
|
||||
};
|
||||
|
||||
TCThread::TCThread(TCCallable &callable)
|
||||
: TCThreadBase(TCThreadImplFactory(callable))
|
||||
{ }
|
||||
|
||||
void TCThread::Join() {
|
||||
CheckReferenceCount();
|
||||
((TCThreadImpl *)m_Impl)->Join();
|
||||
}
|
||||
|
||||
// !HACK! wtf, Microsoft?
|
||||
#undef Yield
|
||||
void TCThread::Yield() {
|
||||
if(!SwitchToThread()) {
|
||||
ErrorHandler("SwitchToThread");
|
||||
}
|
||||
}
|
||||
|
||||
uint64 TCThread::ThreadID() {
|
||||
return static_cast<uint64>(GetCurrentThreadId());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Mutex Implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class TCMutexImpl : public TCThreadBaseImpl {
|
||||
private:
|
||||
CRITICAL_SECTION m_CS;
|
||||
|
||||
public:
|
||||
LPCRITICAL_SECTION GetMutex() { return &m_CS; }
|
||||
TCMutexImpl() : TCThreadBaseImpl() {
|
||||
InitializeCriticalSection( &m_CS );
|
||||
}
|
||||
|
||||
virtual ~TCMutexImpl() {
|
||||
DeleteCriticalSection( &m_CS );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class TCMutexImplFactory : public TCThreadBaseImplFactory {
|
||||
public:
|
||||
TCMutexImplFactory() { }
|
||||
virtual ~TCMutexImplFactory() { }
|
||||
virtual TCThreadBaseImpl *CreateImpl() const {
|
||||
return new TCMutexImpl();
|
||||
}
|
||||
};
|
||||
|
||||
TCMutex::TCMutex() : TCThreadBase(TCMutexImplFactory())
|
||||
{ }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Lock Implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class TCLockImpl : public TCThreadBaseImpl {
|
||||
private:
|
||||
LPCRITICAL_SECTION const m_CSPtr;
|
||||
// Disallow copy and assign...
|
||||
TCLockImpl(const TCLockImpl &) : m_CSPtr(NULL) { }
|
||||
TCLockImpl &operator =(const TCLockImpl &) { return *this; }
|
||||
public:
|
||||
TCLockImpl(TCMutex &mutex)
|
||||
: m_CSPtr(((TCMutexImpl *)(mutex.m_Impl))->GetMutex()) {
|
||||
EnterCriticalSection( m_CSPtr );
|
||||
}
|
||||
|
||||
virtual ~TCLockImpl() { LeaveCriticalSection( m_CSPtr ); }
|
||||
LPCRITICAL_SECTION GetMutexPtr() const { return m_CSPtr; }
|
||||
};
|
||||
|
||||
class TCLockImplFactory : public TCThreadBaseImplFactory {
|
||||
private:
|
||||
TCMutex &m_Mutex;
|
||||
public:
|
||||
TCLockImplFactory(TCMutex &mutex) : m_Mutex(mutex){ }
|
||||
virtual ~TCLockImplFactory() { }
|
||||
virtual TCThreadBaseImpl *CreateImpl() const {
|
||||
return new TCLockImpl(m_Mutex);
|
||||
}
|
||||
};
|
||||
|
||||
TCLock::TCLock(TCMutex &mutex) : TCThreadBase(TCLockImplFactory(mutex))
|
||||
{ }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Condition Variable Implementation
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class TCConditionVariableImpl : public TCThreadBaseImpl {
|
||||
private:
|
||||
CONDITION_VARIABLE m_CV;
|
||||
public:
|
||||
TCConditionVariableImpl() { InitializeConditionVariable( &m_CV ); }
|
||||
virtual ~TCConditionVariableImpl() {
|
||||
// No destroy condition variable...?
|
||||
}
|
||||
|
||||
void Wait(TCLock &lock) {
|
||||
TCLockImpl *lockImpl = (TCLockImpl *)(lock.m_Impl);
|
||||
|
||||
BOOL result = SleepConditionVariableCS( &m_CV, lockImpl->GetMutexPtr(), INFINITE );
|
||||
if(!result) {
|
||||
ErrorHandler( "SleepConditionVariableCS" );
|
||||
}
|
||||
}
|
||||
|
||||
void NotifyOne() { WakeConditionVariable( &m_CV ); }
|
||||
void NotifyAll() { WakeAllConditionVariable( &m_CV ); }
|
||||
};
|
||||
|
||||
class TCConditionVariableImplFactory : public TCThreadBaseImplFactory {
|
||||
public:
|
||||
TCConditionVariableImplFactory() { }
|
||||
virtual ~TCConditionVariableImplFactory() { }
|
||||
virtual TCThreadBaseImpl *CreateImpl() const {
|
||||
return new TCConditionVariableImpl();
|
||||
}
|
||||
};
|
||||
|
||||
TCConditionVariable::TCConditionVariable()
|
||||
: TCThreadBase(TCConditionVariableImplFactory())
|
||||
{ }
|
||||
|
||||
void TCConditionVariable::Wait(TCLock &lock) {
|
||||
CheckReferenceCount();
|
||||
|
||||
TCConditionVariableImpl *impl = (TCConditionVariableImpl *)m_Impl;
|
||||
impl->Wait(lock);
|
||||
}
|
||||
|
||||
void TCConditionVariable::NotifyOne() {
|
||||
CheckReferenceCount();
|
||||
|
||||
TCConditionVariableImpl *impl = (TCConditionVariableImpl *)m_Impl;
|
||||
impl->NotifyOne();
|
||||
}
|
||||
|
||||
void TCConditionVariable::NotifyAll() {
|
||||
CheckReferenceCount();
|
||||
|
||||
TCConditionVariableImpl *impl = (TCConditionVariableImpl *)m_Impl;
|
||||
impl->NotifyAll();
|
||||
}
|
|
@ -1,260 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "WorkerQueue.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
#include "FasTC/BPTCCompressor.h"
|
||||
|
||||
using FasTC::CompressionJob;
|
||||
|
||||
template <typename T>
|
||||
static inline void clamp(T &x, const T &min, const T &max) {
|
||||
if(x < min) x = min;
|
||||
else if(x > max) x = max;
|
||||
}
|
||||
|
||||
WorkerThread::WorkerThread(WorkerQueue * parent, uint32 idx)
|
||||
: TCCallable()
|
||||
, m_ThreadIdx(idx)
|
||||
, m_Parent(parent)
|
||||
{ }
|
||||
|
||||
void WorkerThread::operator()() {
|
||||
|
||||
if(!m_Parent) {
|
||||
fprintf(stderr, "%s\n", "Illegal worker thread initialization -- parent is NULL.");
|
||||
return;
|
||||
}
|
||||
|
||||
CompressionFunc f = m_Parent->GetCompressionFunc();
|
||||
CompressionFuncWithStats fStat = m_Parent->GetCompressionFuncWithStats();
|
||||
std::ostream *logStream = m_Parent->GetLogStream();
|
||||
|
||||
if(!(f || (fStat && logStream))) {
|
||||
fprintf(stderr, "%s\n", "Illegal worker queue initialization -- compression func is NULL.");
|
||||
return;
|
||||
}
|
||||
|
||||
bool quitFlag = false;
|
||||
while(!quitFlag) {
|
||||
|
||||
switch(m_Parent->AcceptThreadData(m_ThreadIdx)) {
|
||||
|
||||
case eAction_Quit:
|
||||
{
|
||||
quitFlag = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case eAction_Wait:
|
||||
{
|
||||
TCThread::Yield();
|
||||
break;
|
||||
}
|
||||
|
||||
case eAction_DoWork:
|
||||
{
|
||||
const CompressionJob &job = m_Parent->GetCompressionJob();
|
||||
|
||||
uint32 start[2];
|
||||
m_Parent->GetStartForThread(m_ThreadIdx, start);
|
||||
|
||||
uint32 end[2];
|
||||
m_Parent->GetEndForThread(m_ThreadIdx, end);
|
||||
|
||||
CompressionJob cj (job.Format(),
|
||||
job.InBuf(), job.OutBuf(),
|
||||
job.Width(), job.Height(),
|
||||
start[0], start[1],
|
||||
end[0], end[1]);
|
||||
if(f)
|
||||
(*f)(cj);
|
||||
else
|
||||
(*fStat)(cj, logStream);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
fprintf(stderr, "Unrecognized thread command!\n");
|
||||
quitFlag = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_Parent->NotifyWorkerFinished();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
WorkerQueue::WorkerQueue(
|
||||
uint32 numCompressions,
|
||||
uint32 numThreads,
|
||||
uint32 jobSize,
|
||||
const CompressionJob &job,
|
||||
CompressionFunc func
|
||||
)
|
||||
: m_NumCompressions(0)
|
||||
, m_TotalNumCompressions(std::max(uint32(1), numCompressions))
|
||||
, m_NumThreads(numThreads)
|
||||
, m_WaitingThreads(0)
|
||||
, m_ActiveThreads(0)
|
||||
, m_JobSize(std::max(uint32(1), jobSize))
|
||||
, m_Job(job)
|
||||
, m_NextBlock(0)
|
||||
, m_CompressionFunc(func)
|
||||
, m_CompressionFuncWithStats(NULL)
|
||||
, m_LogStream(NULL)
|
||||
{
|
||||
clamp(m_NumThreads, uint32(1), uint32(kMaxNumWorkerThreads));
|
||||
}
|
||||
|
||||
WorkerQueue::WorkerQueue(
|
||||
uint32 numCompressions,
|
||||
uint32 numThreads,
|
||||
uint32 jobSize,
|
||||
const CompressionJob &job,
|
||||
CompressionFuncWithStats func,
|
||||
std::ostream *logStream
|
||||
)
|
||||
: m_NumCompressions(0)
|
||||
, m_TotalNumCompressions(std::max(uint32(1), numCompressions))
|
||||
, m_NumThreads(numThreads)
|
||||
, m_WaitingThreads(0)
|
||||
, m_ActiveThreads(0)
|
||||
, m_JobSize(std::max(uint32(1), jobSize))
|
||||
, m_Job(job)
|
||||
, m_NextBlock(0)
|
||||
, m_CompressionFunc(NULL)
|
||||
, m_CompressionFuncWithStats(func)
|
||||
, m_LogStream(logStream)
|
||||
{
|
||||
clamp(m_NumThreads, uint32(1), uint32(kMaxNumWorkerThreads));
|
||||
}
|
||||
|
||||
void WorkerQueue::Run() {
|
||||
|
||||
// Spawn a bunch of threads...
|
||||
TCLock lock(m_Mutex);
|
||||
for(uint32 i = 0; i < m_NumThreads; i++) {
|
||||
m_Workers[i] = new WorkerThread(this, i);
|
||||
m_ThreadHandles[m_ActiveThreads] = new TCThread(*m_Workers[i]);
|
||||
m_ActiveThreads++;
|
||||
}
|
||||
|
||||
m_StopWatch.Reset();
|
||||
m_StopWatch.Start();
|
||||
|
||||
m_NextBlock = 0;
|
||||
m_WaitingThreads = 0;
|
||||
|
||||
// Wait for them to finish...
|
||||
while(m_ActiveThreads > 0) {
|
||||
m_CV.Wait(lock);
|
||||
}
|
||||
|
||||
m_StopWatch.Stop();
|
||||
|
||||
// Join them all together..
|
||||
for(uint32 i = 0; i < m_NumThreads; i++) {
|
||||
m_ThreadHandles[i]->Join();
|
||||
delete m_ThreadHandles[i];
|
||||
delete m_Workers[i];
|
||||
}
|
||||
}
|
||||
|
||||
void WorkerQueue::NotifyWorkerFinished() {
|
||||
{
|
||||
TCLock lock(m_Mutex);
|
||||
m_ActiveThreads--;
|
||||
}
|
||||
m_CV.NotifyOne();
|
||||
}
|
||||
|
||||
WorkerThread::EAction WorkerQueue::AcceptThreadData(uint32 threadIdx) {
|
||||
if(threadIdx >= m_ActiveThreads) {
|
||||
return WorkerThread::eAction_Quit;
|
||||
}
|
||||
|
||||
// How many blocks total do we have?
|
||||
uint32 blockDim[2];
|
||||
GetBlockDimensions(m_Job.Format(), blockDim);
|
||||
const uint32 totalBlocks = (m_Job.Width() * m_Job.Height()) / (blockDim[0] * blockDim[1]);
|
||||
|
||||
// Make sure we have exclusive access...
|
||||
TCLock lock(m_Mutex);
|
||||
|
||||
// If we've completed all blocks, then mark the thread for
|
||||
// completion.
|
||||
if(m_NextBlock == totalBlocks) {
|
||||
if(m_NumCompressions < m_TotalNumCompressions) {
|
||||
if(++m_WaitingThreads == m_ActiveThreads) {
|
||||
m_NextBlock = 0;
|
||||
m_WaitingThreads = 0;
|
||||
} else {
|
||||
return WorkerThread::eAction_Wait;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return WorkerThread::eAction_Quit;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, this thread's offset is the current block...
|
||||
m_Offsets[threadIdx] = m_NextBlock;
|
||||
|
||||
// The number of blocks to process is either the job size
|
||||
// or the number of blocks remaining.
|
||||
int blocksProcessed = std::min(m_JobSize, totalBlocks - m_NextBlock);
|
||||
m_NumBlocks[threadIdx] = blocksProcessed;
|
||||
|
||||
// Make sure the next block is updated.
|
||||
m_NextBlock += blocksProcessed;
|
||||
|
||||
if(m_NextBlock == totalBlocks) {
|
||||
++m_NumCompressions;
|
||||
}
|
||||
|
||||
return WorkerThread::eAction_DoWork;
|
||||
}
|
||||
|
||||
void WorkerQueue::GetStartForThread(const uint32 threadIdx, uint32 (&start)[2]) {
|
||||
assert(threadIdx >= 0);
|
||||
assert(threadIdx < m_NumThreads);
|
||||
assert(m_Offsets[threadIdx] >= 0);
|
||||
|
||||
const uint32 blockIdx = m_Offsets[threadIdx];
|
||||
m_Job.BlockIdxToCoords(blockIdx, start);
|
||||
}
|
||||
|
||||
void WorkerQueue::GetEndForThread(const uint32 threadIdx, uint32 (&end)[2]) {
|
||||
assert(threadIdx >= 0);
|
||||
assert(threadIdx < m_NumThreads);
|
||||
assert(m_Offsets[threadIdx] >= 0);
|
||||
assert(m_NumBlocks[threadIdx] >= 0);
|
||||
|
||||
const uint32 blockIdx = m_Offsets[threadIdx] + m_NumBlocks[threadIdx];
|
||||
m_Job.BlockIdxToCoords(blockIdx, end);
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#ifndef __TEXCOMP_WORKDER_QUEUE_H__
|
||||
#define __TEXCOMP_WORKDER_QUEUE_H__
|
||||
|
||||
// Forward declare...
|
||||
class WorkerQueue;
|
||||
|
||||
// Necessary includes...
|
||||
#include "FasTC/TexCompTypes.h"
|
||||
#include "FasTC/StopWatch.h"
|
||||
|
||||
#include "Thread.h"
|
||||
#include "CompressionFuncs.h"
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
class WorkerThread : public TCCallable {
|
||||
friend class WorkerQueue;
|
||||
public:
|
||||
|
||||
WorkerThread(WorkerQueue *, uint32 idx);
|
||||
virtual ~WorkerThread() { }
|
||||
virtual void operator ()();
|
||||
|
||||
enum EAction {
|
||||
eAction_Wait,
|
||||
eAction_DoWork,
|
||||
eAction_Quit,
|
||||
|
||||
kNumWorkerThreadActions
|
||||
};
|
||||
|
||||
private:
|
||||
uint32 m_ThreadIdx;
|
||||
WorkerQueue *const m_Parent;
|
||||
};
|
||||
|
||||
class WorkerQueue {
|
||||
friend class WorkerThread;
|
||||
public:
|
||||
WorkerQueue(
|
||||
uint32 numCompressions,
|
||||
uint32 numThreads,
|
||||
uint32 jobSize,
|
||||
const FasTC::CompressionJob &job,
|
||||
CompressionFunc func
|
||||
);
|
||||
|
||||
WorkerQueue(
|
||||
uint32 numCompressions,
|
||||
uint32 numThreads,
|
||||
uint32 jobSize,
|
||||
const FasTC::CompressionJob &job,
|
||||
CompressionFuncWithStats func,
|
||||
std::ostream *logStream
|
||||
);
|
||||
|
||||
~WorkerQueue() { }
|
||||
|
||||
// Runs the workers
|
||||
void Run();
|
||||
const StopWatch &GetStopWatch() const { return m_StopWatch; }
|
||||
|
||||
private:
|
||||
uint32 m_NumCompressions;
|
||||
const uint32 m_TotalNumCompressions;
|
||||
uint32 m_NumThreads;
|
||||
uint32 m_WaitingThreads;
|
||||
uint32 m_ActiveThreads;
|
||||
uint32 m_JobSize;
|
||||
FasTC::CompressionJob m_Job;
|
||||
|
||||
TCConditionVariable m_CV;
|
||||
TCMutex m_Mutex;
|
||||
|
||||
uint32 m_NextBlock;
|
||||
|
||||
static const int kMaxNumWorkerThreads = 256;
|
||||
uint32 m_Offsets[kMaxNumWorkerThreads];
|
||||
uint32 m_NumBlocks[kMaxNumWorkerThreads];
|
||||
|
||||
WorkerThread *m_Workers[kMaxNumWorkerThreads];
|
||||
TCThread *m_ThreadHandles[kMaxNumWorkerThreads];
|
||||
|
||||
const FasTC::CompressionJob &GetCompressionJob() const { return m_Job; }
|
||||
void GetStartForThread(const uint32 threadIdx, uint32 (&start)[2]);
|
||||
void GetEndForThread(const uint32 threadIdx, uint32 (&start)[2]);
|
||||
|
||||
const CompressionFunc m_CompressionFunc;
|
||||
CompressionFunc GetCompressionFunc() const { return m_CompressionFunc; }
|
||||
|
||||
const CompressionFuncWithStats m_CompressionFuncWithStats;
|
||||
CompressionFuncWithStats GetCompressionFuncWithStats() const { return m_CompressionFuncWithStats; }
|
||||
|
||||
std::ostream *m_LogStream;
|
||||
std::ostream *GetLogStream() const { return m_LogStream; }
|
||||
|
||||
StopWatch m_StopWatch;
|
||||
|
||||
WorkerThread::EAction AcceptThreadData(uint32 threadIdx);
|
||||
void NotifyWorkerFinished();
|
||||
};
|
||||
|
||||
#endif //__TEXCOMP_WORKDER_QUEUE_H__
|
|
@ -1,43 +0,0 @@
|
|||
# Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
# <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
SET( LIBRARY_HEADERS
|
||||
"include/FasTC/DXTCompressor.h"
|
||||
)
|
||||
|
||||
SET( SOURCES
|
||||
"src/Compressor.cpp"
|
||||
"src/Decompressor.cpp"
|
||||
)
|
||||
|
||||
INCLUDE_DIRECTORIES(${FasTC_SOURCE_DIR}/Base/include)
|
||||
INCLUDE_DIRECTORIES(${FasTC_BINARY_DIR}/Base/include)
|
||||
INCLUDE_DIRECTORIES(${FasTC_SOURCE_DIR}/DXTEncoder/include)
|
||||
INCLUDE_DIRECTORIES(${FasTC_BINARY_DIR}/DXTEncoder/include)
|
||||
|
||||
ADD_LIBRARY( DXTEncoder
|
||||
${HEADERS}
|
||||
${SOURCES}
|
||||
)
|
||||
|
||||
INSTALL(TARGETS DXTEncoder EXPORT FasTCTargets ARCHIVE DESTINATION lib COMPONENT lib)
|
||||
INSTALL(
|
||||
FILES ${LIBRARY_HEADERS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/FasTC
|
||||
COMPONENT dev)
|
||||
|
||||
TARGET_LINK_LIBRARIES( DXTEncoder FasTCBase )
|
|
@ -1,29 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "FasTC/TexCompTypes.h"
|
||||
#include "FasTC/CompressionJob.h"
|
||||
|
||||
namespace DXTC
|
||||
{
|
||||
// DXT compressor
|
||||
void CompressImageDXT1(const FasTC::CompressionJob &);
|
||||
void CompressImageDXT5(const FasTC::CompressionJob &);
|
||||
|
||||
void DecompressDXT1(const FasTC::DecompressionJob &);
|
||||
void DecompressDXT5(const FasTC::DecompressionJob &);
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "FasTC/DXTCompressor.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#define STB_DXT_IMPLEMENTATION
|
||||
#include "stb_dxt.h"
|
||||
|
||||
namespace DXTC
|
||||
{
|
||||
// Function prototypes
|
||||
void ExtractBlock(const uint32* inPtr, uint32 width, uint8* colorBlock);
|
||||
|
||||
// Extract a 4 by 4 block of pixels from inPtr and store it in colorBlock. The width parameter
|
||||
// specifies the size of the image in pixels.
|
||||
void ExtractBlock(const uint32* inPtr, uint32 width, uint8* colorBlock)
|
||||
{
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
memcpy(&colorBlock[j * 4 * 4], inPtr, 4 * 4);
|
||||
inPtr += width;
|
||||
}
|
||||
}
|
||||
|
||||
// Compress an image using DXT1 compression. Use the inBuf parameter to point to an image in
|
||||
// 4-byte RGBA format. The width and height parameters specify the size of the image in pixels.
|
||||
// The buffer pointed to by outBuf should be large enough to store the compressed image. This
|
||||
// implementation has an 8:1 compression ratio.
|
||||
void CompressImageDXT1(const FasTC::CompressionJob &cj) {
|
||||
uint8 block[64];
|
||||
|
||||
const uint32 kBlockSz = GetBlockSize(FasTC::eCompressionFormat_DXT1);
|
||||
const uint32 startBlock = cj.CoordsToBlockIdx(cj.XStart(), cj.YStart());
|
||||
uint8 *outBuf = cj.OutBuf() + startBlock * kBlockSz;
|
||||
|
||||
const uint32 *inPixels = reinterpret_cast<const uint32 *>(cj.InBuf());
|
||||
uint32 endY = std::min(cj.YEnd(), cj.Height() - 4);
|
||||
uint32 startX = cj.XStart();
|
||||
for(uint32 j = cj.YStart(); j <= endY; j += 4) {
|
||||
const uint32 endX = j == cj.YEnd()? cj.XEnd() : cj.Width();
|
||||
for(uint32 i = startX; i < endX; i += 4) {
|
||||
|
||||
const uint32 kOffset = j*cj.Width() + i;
|
||||
ExtractBlock(inPixels + kOffset, cj.Width(), block);
|
||||
stb_compress_dxt_block(outBuf, block, 0, STB_DXT_DITHER);
|
||||
outBuf += 8;
|
||||
}
|
||||
startX = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Compress an image using DXT5 compression. Use the inBuf parameter to point to an image in
|
||||
// 4-byte RGBA format. The width and height parameters specify the size of the image in pixels.
|
||||
// The buffer pointed to by outBuf should be large enough to store the compressed image. This
|
||||
// implementation has an 4:1 compression ratio.
|
||||
void CompressImageDXT5(const FasTC::CompressionJob &cj) {
|
||||
uint8 block[64];
|
||||
|
||||
const uint32 kBlockSz = GetBlockSize(FasTC::eCompressionFormat_DXT5);
|
||||
const uint32 startBlock = cj.CoordsToBlockIdx(cj.XStart(), cj.YStart());
|
||||
uint8 *outBuf = cj.OutBuf() + startBlock * kBlockSz;
|
||||
|
||||
const uint32 *inPixels = reinterpret_cast<const uint32 *>(cj.InBuf());
|
||||
uint32 endY = std::min(cj.YEnd(), cj.Height() - 4);
|
||||
uint32 startX = cj.XStart();
|
||||
for(uint32 j = cj.YStart(); j <= endY; j += 4) {
|
||||
const uint32 endX = j == cj.YEnd()? cj.XEnd() : cj.Width();
|
||||
for(uint32 i = startX; i < endX; i += 4) {
|
||||
|
||||
const uint32 kOffset = j*cj.Width() + i;
|
||||
ExtractBlock(inPixels + kOffset, cj.Width(), block);
|
||||
stb_compress_dxt_block(outBuf, block, 1, STB_DXT_DITHER);
|
||||
outBuf += 16;
|
||||
}
|
||||
startX = 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,156 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "FasTC/DXTCompressor.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
#include "FasTC/Pixel.h"
|
||||
|
||||
namespace {
|
||||
void DecompressDXT1Block(const uint8 *block, uint32 *outBuf, bool check_order) {
|
||||
// When we call FasTC::Pixel::FromBits, we expect the bits
|
||||
// to be read out of memory in LSB (byte) order first. Hence,
|
||||
// we can't read the blocks directly as uint16 values out of
|
||||
// the DXT buffer and we have to swap the bytes before hand.
|
||||
uint16 colorA = block[1] | block[0] << 8;
|
||||
uint16 colorB = block[3] | block[2] << 8;
|
||||
|
||||
uint32 mod = reinterpret_cast<const uint32 *>(block + 4)[0];
|
||||
|
||||
uint8 kFiveSixFive[4] = { 0, 5, 6, 5 };
|
||||
FasTC::Pixel a, b, c, d;
|
||||
a.FromBits(reinterpret_cast<const uint8 *>(&colorA), kFiveSixFive);
|
||||
b.FromBits(reinterpret_cast<const uint8 *>(&colorB), kFiveSixFive);
|
||||
|
||||
uint8 kFullDepth[4] = { 8, 8, 8, 8 };
|
||||
a.ChangeBitDepth(kFullDepth);
|
||||
b.ChangeBitDepth(kFullDepth);
|
||||
|
||||
// However, for the purposes of properly decoding DXT, we can read them as ints...
|
||||
const uint16 *block_ptr = reinterpret_cast<const uint16 *>(block);
|
||||
if (!check_order || block_ptr[0] > block_ptr[1]) {
|
||||
c = (a * 2 + b) / 3;
|
||||
d = (a + b * 2) / 3;
|
||||
}
|
||||
else {
|
||||
c = (a + b) / 2;
|
||||
// d already initialized to zero...
|
||||
}
|
||||
|
||||
FasTC::Pixel *colors[4] = { &a, &b, &c, &d };
|
||||
|
||||
uint32 *outPixels = reinterpret_cast<uint32 *>(outBuf);
|
||||
for (uint32 i = 0; i < 16; i++) {
|
||||
outPixels[i] &= 0xFF000000;
|
||||
outPixels[i] |= colors[(mod >> (i * 2)) & 3]->Pack() & 0x00FFFFFF;
|
||||
}
|
||||
}
|
||||
|
||||
void DecompressDXT5Block(const uint8 *block, uint32 *outBuf) {
|
||||
int alpha0 = block[0];
|
||||
int alpha1 = block[1];
|
||||
|
||||
int palette[8];
|
||||
palette[0] = alpha0;
|
||||
palette[1] = alpha1;
|
||||
|
||||
if (alpha0 > alpha1) {
|
||||
for (int i = 2; i < 8; ++i) {
|
||||
palette[i] = ((8 - i) * alpha0 + (i - 1) * alpha1) / 7;
|
||||
}
|
||||
} else {
|
||||
for (int i = 2; i < 6; ++i) {
|
||||
palette[i] = ((6 - i) * alpha0 + (i - 1) * alpha1) / 5;
|
||||
}
|
||||
palette[6] = 0;
|
||||
palette[7] = 255;
|
||||
}
|
||||
|
||||
uint64 mod = *reinterpret_cast<const uint64 *>(block) >> 16;
|
||||
uint32 *outPixels = reinterpret_cast<uint32 *>(outBuf);
|
||||
for (uint32 i = 0; i < 16; i++) {
|
||||
outPixels[i] &= 0x00FFFFFF;
|
||||
outPixels[i] |= palette[(mod >> (i * 3)) & 7] << 24;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace DXTC
|
||||
{
|
||||
void DecompressDXT1(const FasTC::DecompressionJob &dcj) {
|
||||
uint32 blockW = (dcj.Width() + 3) >> 2;
|
||||
uint32 blockH = (dcj.Height() + 3) >> 2;
|
||||
|
||||
const uint32 blockSz = GetBlockSize(FasTC::eCompressionFormat_DXT1);
|
||||
|
||||
uint32 *outPixels = reinterpret_cast<uint32 *>(dcj.OutBuf());
|
||||
|
||||
uint32 outBlock[16];
|
||||
memset(outBlock, 0xFF, sizeof(outBlock));
|
||||
|
||||
for(uint32 j = 0; j < blockH; j++) {
|
||||
for(uint32 i = 0; i < blockW; i++) {
|
||||
|
||||
uint32 offset = (j * blockW + i) * blockSz;
|
||||
DecompressDXT1Block(dcj.InBuf() + offset, outBlock, true);
|
||||
|
||||
uint32 decompWidth = std::min(4U, dcj.Width() - i * 4);
|
||||
uint32 decompHeight = std::min(4U, dcj.Height() - j * 4);
|
||||
|
||||
for(uint32 y = 0; y < decompHeight; y++)
|
||||
for(uint32 x = 0; x < decompWidth; x++) {
|
||||
offset = (j*4 + y)*dcj.Width() + ((i*4)+x);
|
||||
outPixels[offset] = outBlock[y*4 + x];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DecompressDXT5(const FasTC::DecompressionJob &dcj) {
|
||||
uint32 blockW = (dcj.Width() + 3) >> 2;
|
||||
uint32 blockH = (dcj.Height() + 3) >> 2;
|
||||
|
||||
const uint32 blockSz = GetBlockSize(FasTC::eCompressionFormat_DXT5);
|
||||
|
||||
uint32 *outPixels = reinterpret_cast<uint32 *>(dcj.OutBuf());
|
||||
|
||||
uint32 outBlock[16];
|
||||
memset(outBlock, 0xFF, sizeof(outBlock));
|
||||
|
||||
for (uint32 j = 0; j < blockH; j++) {
|
||||
for (uint32 i = 0; i < blockW; i++) {
|
||||
|
||||
uint32 offset = (j * blockW + i) * blockSz;
|
||||
DecompressDXT5Block(dcj.InBuf() + offset, outBlock);
|
||||
DecompressDXT1Block(dcj.InBuf() + offset + blockSz / 2, outBlock, false);
|
||||
|
||||
uint32 decompWidth = std::min(4U, dcj.Width() - i * 4);
|
||||
uint32 decompHeight = std::min(4U, dcj.Height() - j * 4);
|
||||
|
||||
for (uint32 y = 0; y < decompHeight; y++)
|
||||
for (uint32 x = 0; x < decompWidth; x++) {
|
||||
offset = (j * 4 + y)*dcj.Width() + ((i * 4) + x);
|
||||
outPixels[offset] = outBlock[y * 4 + x];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,687 +0,0 @@
|
|||
// stb_dxt.h - v1.06 - DXT1/DXT5 compressor - public domain
|
||||
// original by fabian "ryg" giesen - ported to C by stb
|
||||
// use '#define STB_DXT_IMPLEMENTATION' before including to create the implementation
|
||||
//
|
||||
// USAGE:
|
||||
// call stb_compress_dxt_block() for every block (you must pad)
|
||||
// source should be a 4x4 block of RGBA data in row-major order;
|
||||
// A is ignored if you specify alpha=0; you can turn on dithering
|
||||
// and "high quality" using mode.
|
||||
//
|
||||
// version history:
|
||||
// v1.06 - (stb) fix to known-broken 1.05
|
||||
// v1.05 - (stb) support bc5/3dc (Arvids Kokins), use extern "C" in C++ (Pavel Krajcevski)
|
||||
// v1.04 - (ryg) default to no rounding bias for lerped colors (as per S3TC/DX10 spec);
|
||||
// single color match fix (allow for inexact color interpolation);
|
||||
// optimal DXT5 index finder; "high quality" mode that runs multiple refinement steps.
|
||||
// v1.03 - (stb) endianness support
|
||||
// v1.02 - (stb) fix alpha encoding bug
|
||||
// v1.01 - (stb) fix bug converting to RGB that messed up quality, thanks ryg & cbloom
|
||||
// v1.00 - (stb) first release
|
||||
//
|
||||
// LICENSE
|
||||
//
|
||||
// See end of file for license information.
|
||||
|
||||
#ifndef STB_INCLUDE_STB_DXT_H
|
||||
#define STB_INCLUDE_STB_DXT_H
|
||||
|
||||
// compression mode (bitflags)
|
||||
#define STB_DXT_NORMAL 0
|
||||
#define STB_DXT_DITHER 1 // use dithering. dubious win. never use for normal maps and the like!
|
||||
#define STB_DXT_HIGHQUAL 2 // high quality mode, does two refinement steps instead of 1. ~30-40% slower.
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src_rgba_four_bytes_per_pixel, int alpha, int mode);
|
||||
void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src_rg_two_byte_per_pixel);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#define STB_COMPRESS_DXT_BLOCK
|
||||
|
||||
#ifdef STB_DXT_IMPLEMENTATION
|
||||
|
||||
// configuration options for DXT encoder. set them in the project/makefile or just define
|
||||
// them at the top.
|
||||
|
||||
// STB_DXT_USE_ROUNDING_BIAS
|
||||
// use a rounding bias during color interpolation. this is closer to what "ideal"
|
||||
// interpolation would do but doesn't match the S3TC/DX10 spec. old versions (pre-1.03)
|
||||
// implicitly had this turned on.
|
||||
//
|
||||
// in case you're targeting a specific type of hardware (e.g. console programmers):
|
||||
// NVidia and Intel GPUs (as of 2010) as well as DX9 ref use DXT decoders that are closer
|
||||
// to STB_DXT_USE_ROUNDING_BIAS. AMD/ATI, S3 and DX10 ref are closer to rounding with no bias.
|
||||
// you also see "(a*5 + b*3) / 8" on some old GPU designs.
|
||||
// #define STB_DXT_USE_ROUNDING_BIAS
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h> // memset
|
||||
|
||||
static unsigned char stb__Expand5[32];
|
||||
static unsigned char stb__Expand6[64];
|
||||
static unsigned char stb__OMatch5[256][2];
|
||||
static unsigned char stb__OMatch6[256][2];
|
||||
static unsigned char stb__QuantRBTab[256+16];
|
||||
static unsigned char stb__QuantGTab[256+16];
|
||||
|
||||
static int stb__Mul8Bit(int a, int b)
|
||||
{
|
||||
int t = a*b + 128;
|
||||
return (t + (t >> 8)) >> 8;
|
||||
}
|
||||
|
||||
static void stb__From16Bit(unsigned char *out, unsigned short v)
|
||||
{
|
||||
int rv = (v & 0xf800) >> 11;
|
||||
int gv = (v & 0x07e0) >> 5;
|
||||
int bv = (v & 0x001f) >> 0;
|
||||
|
||||
out[0] = stb__Expand5[rv];
|
||||
out[1] = stb__Expand6[gv];
|
||||
out[2] = stb__Expand5[bv];
|
||||
out[3] = 0;
|
||||
}
|
||||
|
||||
static unsigned short stb__As16Bit(int r, int g, int b)
|
||||
{
|
||||
return (stb__Mul8Bit(r,31) << 11) + (stb__Mul8Bit(g,63) << 5) + stb__Mul8Bit(b,31);
|
||||
}
|
||||
|
||||
// linear interpolation at 1/3 point between a and b, using desired rounding type
|
||||
static int stb__Lerp13(int a, int b)
|
||||
{
|
||||
#ifdef STB_DXT_USE_ROUNDING_BIAS
|
||||
// with rounding bias
|
||||
return a + stb__Mul8Bit(b-a, 0x55);
|
||||
#else
|
||||
// without rounding bias
|
||||
// replace "/ 3" by "* 0xaaab) >> 17" if your compiler sucks or you really need every ounce of speed.
|
||||
return (2*a + b) / 3;
|
||||
#endif
|
||||
}
|
||||
|
||||
// lerp RGB color
|
||||
static void stb__Lerp13RGB(unsigned char *out, unsigned char *p1, unsigned char *p2)
|
||||
{
|
||||
out[0] = stb__Lerp13(p1[0], p2[0]);
|
||||
out[1] = stb__Lerp13(p1[1], p2[1]);
|
||||
out[2] = stb__Lerp13(p1[2], p2[2]);
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
// compute table to reproduce constant colors as accurately as possible
|
||||
static void stb__PrepareOptTable(unsigned char *Table,const unsigned char *expand,int size)
|
||||
{
|
||||
int i,mn,mx;
|
||||
for (i=0;i<256;i++) {
|
||||
int bestErr = 256;
|
||||
for (mn=0;mn<size;mn++) {
|
||||
for (mx=0;mx<size;mx++) {
|
||||
int mine = expand[mn];
|
||||
int maxe = expand[mx];
|
||||
int err = abs(stb__Lerp13(maxe, mine) - i);
|
||||
|
||||
// DX10 spec says that interpolation must be within 3% of "correct" result,
|
||||
// add this as error term. (normally we'd expect a random distribution of
|
||||
// +-1.5% error, but nowhere in the spec does it say that the error has to be
|
||||
// unbiased - better safe than sorry).
|
||||
err += abs(maxe - mine) * 3 / 100;
|
||||
|
||||
if(err < bestErr)
|
||||
{
|
||||
Table[i*2+0] = mx;
|
||||
Table[i*2+1] = mn;
|
||||
bestErr = err;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void stb__EvalColors(unsigned char *color,unsigned short c0,unsigned short c1)
|
||||
{
|
||||
stb__From16Bit(color+ 0, c0);
|
||||
stb__From16Bit(color+ 4, c1);
|
||||
stb__Lerp13RGB(color+ 8, color+0, color+4);
|
||||
stb__Lerp13RGB(color+12, color+4, color+0);
|
||||
}
|
||||
|
||||
// Block dithering function. Simply dithers a block to 565 RGB.
|
||||
// (Floyd-Steinberg)
|
||||
static void stb__DitherBlock(unsigned char *dest, unsigned char *block)
|
||||
{
|
||||
int err[8],*ep1 = err,*ep2 = err+4, *et;
|
||||
int ch,y;
|
||||
|
||||
// process channels seperately
|
||||
for (ch=0; ch<3; ++ch) {
|
||||
unsigned char *bp = block+ch, *dp = dest+ch;
|
||||
unsigned char *quant = (ch == 1) ? stb__QuantGTab+8 : stb__QuantRBTab+8;
|
||||
memset(err, 0, sizeof(err));
|
||||
for(y=0; y<4; ++y) {
|
||||
dp[ 0] = quant[bp[ 0] + ((3*ep2[1] + 5*ep2[0]) >> 4)];
|
||||
ep1[0] = bp[ 0] - dp[ 0];
|
||||
dp[ 4] = quant[bp[ 4] + ((7*ep1[0] + 3*ep2[2] + 5*ep2[1] + ep2[0]) >> 4)];
|
||||
ep1[1] = bp[ 4] - dp[ 4];
|
||||
dp[ 8] = quant[bp[ 8] + ((7*ep1[1] + 3*ep2[3] + 5*ep2[2] + ep2[1]) >> 4)];
|
||||
ep1[2] = bp[ 8] - dp[ 8];
|
||||
dp[12] = quant[bp[12] + ((7*ep1[2] + 5*ep2[3] + ep2[2]) >> 4)];
|
||||
ep1[3] = bp[12] - dp[12];
|
||||
bp += 16;
|
||||
dp += 16;
|
||||
et = ep1, ep1 = ep2, ep2 = et; // swap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The color matching function
|
||||
static unsigned int stb__MatchColorsBlock(unsigned char *block, unsigned char *color,int dither)
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
int dirr = color[0*4+0] - color[1*4+0];
|
||||
int dirg = color[0*4+1] - color[1*4+1];
|
||||
int dirb = color[0*4+2] - color[1*4+2];
|
||||
int dots[16];
|
||||
int stops[4];
|
||||
int i;
|
||||
int c0Point, halfPoint, c3Point;
|
||||
|
||||
for(i=0;i<16;i++)
|
||||
dots[i] = block[i*4+0]*dirr + block[i*4+1]*dirg + block[i*4+2]*dirb;
|
||||
|
||||
for(i=0;i<4;i++)
|
||||
stops[i] = color[i*4+0]*dirr + color[i*4+1]*dirg + color[i*4+2]*dirb;
|
||||
|
||||
// think of the colors as arranged on a line; project point onto that line, then choose
|
||||
// next color out of available ones. we compute the crossover points for "best color in top
|
||||
// half"/"best in bottom half" and then the same inside that subinterval.
|
||||
//
|
||||
// relying on this 1d approximation isn't always optimal in terms of euclidean distance,
|
||||
// but it's very close and a lot faster.
|
||||
// http://cbloomrants.blogspot.com/2008/12/12-08-08-dxtc-summary.html
|
||||
|
||||
c0Point = (stops[1] + stops[3]) >> 1;
|
||||
halfPoint = (stops[3] + stops[2]) >> 1;
|
||||
c3Point = (stops[2] + stops[0]) >> 1;
|
||||
|
||||
if(!dither) {
|
||||
// the version without dithering is straightforward
|
||||
for (i=15;i>=0;i--) {
|
||||
int dot = dots[i];
|
||||
mask <<= 2;
|
||||
|
||||
if(dot < halfPoint)
|
||||
mask |= (dot < c0Point) ? 1 : 3;
|
||||
else
|
||||
mask |= (dot < c3Point) ? 2 : 0;
|
||||
}
|
||||
} else {
|
||||
// with floyd-steinberg dithering
|
||||
int err[8],*ep1 = err,*ep2 = err+4;
|
||||
int *dp = dots, y;
|
||||
|
||||
c0Point <<= 4;
|
||||
halfPoint <<= 4;
|
||||
c3Point <<= 4;
|
||||
for(i=0;i<8;i++)
|
||||
err[i] = 0;
|
||||
|
||||
for(y=0;y<4;y++)
|
||||
{
|
||||
int dot,lmask,step;
|
||||
|
||||
dot = (dp[0] << 4) + (3*ep2[1] + 5*ep2[0]);
|
||||
if(dot < halfPoint)
|
||||
step = (dot < c0Point) ? 1 : 3;
|
||||
else
|
||||
step = (dot < c3Point) ? 2 : 0;
|
||||
ep1[0] = dp[0] - stops[step];
|
||||
lmask = step;
|
||||
|
||||
dot = (dp[1] << 4) + (7*ep1[0] + 3*ep2[2] + 5*ep2[1] + ep2[0]);
|
||||
if(dot < halfPoint)
|
||||
step = (dot < c0Point) ? 1 : 3;
|
||||
else
|
||||
step = (dot < c3Point) ? 2 : 0;
|
||||
ep1[1] = dp[1] - stops[step];
|
||||
lmask |= step<<2;
|
||||
|
||||
dot = (dp[2] << 4) + (7*ep1[1] + 3*ep2[3] + 5*ep2[2] + ep2[1]);
|
||||
if(dot < halfPoint)
|
||||
step = (dot < c0Point) ? 1 : 3;
|
||||
else
|
||||
step = (dot < c3Point) ? 2 : 0;
|
||||
ep1[2] = dp[2] - stops[step];
|
||||
lmask |= step<<4;
|
||||
|
||||
dot = (dp[3] << 4) + (7*ep1[2] + 5*ep2[3] + ep2[2]);
|
||||
if(dot < halfPoint)
|
||||
step = (dot < c0Point) ? 1 : 3;
|
||||
else
|
||||
step = (dot < c3Point) ? 2 : 0;
|
||||
ep1[3] = dp[3] - stops[step];
|
||||
lmask |= step<<6;
|
||||
|
||||
dp += 4;
|
||||
mask |= lmask << (y*8);
|
||||
{ int *et = ep1; ep1 = ep2; ep2 = et; } // swap
|
||||
}
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
// The color optimization function. (Clever code, part 1)
|
||||
static void stb__OptimizeColorsBlock(unsigned char *block, unsigned short *pmax16, unsigned short *pmin16)
|
||||
{
|
||||
int mind = 0x7fffffff,maxd = -0x7fffffff;
|
||||
unsigned char *minp, *maxp;
|
||||
double magn;
|
||||
int v_r,v_g,v_b;
|
||||
static const int nIterPower = 4;
|
||||
float covf[6],vfr,vfg,vfb;
|
||||
|
||||
// determine color distribution
|
||||
int cov[6];
|
||||
int mu[3],min[3],max[3];
|
||||
int ch,i,iter;
|
||||
|
||||
for(ch=0;ch<3;ch++)
|
||||
{
|
||||
const unsigned char *bp = ((const unsigned char *) block) + ch;
|
||||
int muv,minv,maxv;
|
||||
|
||||
muv = minv = maxv = bp[0];
|
||||
for(i=4;i<64;i+=4)
|
||||
{
|
||||
muv += bp[i];
|
||||
if (bp[i] < minv) minv = bp[i];
|
||||
else if (bp[i] > maxv) maxv = bp[i];
|
||||
}
|
||||
|
||||
mu[ch] = (muv + 8) >> 4;
|
||||
min[ch] = minv;
|
||||
max[ch] = maxv;
|
||||
}
|
||||
|
||||
// determine covariance matrix
|
||||
for (i=0;i<6;i++)
|
||||
cov[i] = 0;
|
||||
|
||||
for (i=0;i<16;i++)
|
||||
{
|
||||
int r = block[i*4+0] - mu[0];
|
||||
int g = block[i*4+1] - mu[1];
|
||||
int b = block[i*4+2] - mu[2];
|
||||
|
||||
cov[0] += r*r;
|
||||
cov[1] += r*g;
|
||||
cov[2] += r*b;
|
||||
cov[3] += g*g;
|
||||
cov[4] += g*b;
|
||||
cov[5] += b*b;
|
||||
}
|
||||
|
||||
// convert covariance matrix to float, find principal axis via power iter
|
||||
for(i=0;i<6;i++)
|
||||
covf[i] = cov[i] / 255.0f;
|
||||
|
||||
vfr = (float) (max[0] - min[0]);
|
||||
vfg = (float) (max[1] - min[1]);
|
||||
vfb = (float) (max[2] - min[2]);
|
||||
|
||||
for(iter=0;iter<nIterPower;iter++)
|
||||
{
|
||||
float r = vfr*covf[0] + vfg*covf[1] + vfb*covf[2];
|
||||
float g = vfr*covf[1] + vfg*covf[3] + vfb*covf[4];
|
||||
float b = vfr*covf[2] + vfg*covf[4] + vfb*covf[5];
|
||||
|
||||
vfr = r;
|
||||
vfg = g;
|
||||
vfb = b;
|
||||
}
|
||||
|
||||
magn = fabs(vfr);
|
||||
if (fabs(vfg) > magn) magn = fabs(vfg);
|
||||
if (fabs(vfb) > magn) magn = fabs(vfb);
|
||||
|
||||
if(magn < 4.0f) { // too small, default to luminance
|
||||
v_r = 299; // JPEG YCbCr luma coefs, scaled by 1000.
|
||||
v_g = 587;
|
||||
v_b = 114;
|
||||
} else {
|
||||
magn = 512.0 / magn;
|
||||
v_r = (int) (vfr * magn);
|
||||
v_g = (int) (vfg * magn);
|
||||
v_b = (int) (vfb * magn);
|
||||
}
|
||||
|
||||
// Pick colors at extreme points
|
||||
for(i=0;i<16;i++)
|
||||
{
|
||||
int dot = block[i*4+0]*v_r + block[i*4+1]*v_g + block[i*4+2]*v_b;
|
||||
|
||||
if (dot < mind) {
|
||||
mind = dot;
|
||||
minp = block+i*4;
|
||||
}
|
||||
|
||||
if (dot > maxd) {
|
||||
maxd = dot;
|
||||
maxp = block+i*4;
|
||||
}
|
||||
}
|
||||
|
||||
*pmax16 = stb__As16Bit(maxp[0],maxp[1],maxp[2]);
|
||||
*pmin16 = stb__As16Bit(minp[0],minp[1],minp[2]);
|
||||
}
|
||||
|
||||
static int stb__sclamp(float y, int p0, int p1)
|
||||
{
|
||||
int x = (int) y;
|
||||
if (x < p0) return p0;
|
||||
if (x > p1) return p1;
|
||||
return x;
|
||||
}
|
||||
|
||||
// The refinement function. (Clever code, part 2)
|
||||
// Tries to optimize colors to suit block contents better.
|
||||
// (By solving a least squares system via normal equations+Cramer's rule)
|
||||
static int stb__RefineBlock(unsigned char *block, unsigned short *pmax16, unsigned short *pmin16, unsigned int mask)
|
||||
{
|
||||
static const int w1Tab[4] = { 3,0,2,1 };
|
||||
static const int prods[4] = { 0x090000,0x000900,0x040102,0x010402 };
|
||||
// ^some magic to save a lot of multiplies in the accumulating loop...
|
||||
// (precomputed products of weights for least squares system, accumulated inside one 32-bit register)
|
||||
|
||||
float frb,fg;
|
||||
unsigned short oldMin, oldMax, min16, max16;
|
||||
int i, akku = 0, xx,xy,yy;
|
||||
int At1_r,At1_g,At1_b;
|
||||
int At2_r,At2_g,At2_b;
|
||||
unsigned int cm = mask;
|
||||
|
||||
oldMin = *pmin16;
|
||||
oldMax = *pmax16;
|
||||
|
||||
if((mask ^ (mask<<2)) < 4) // all pixels have the same index?
|
||||
{
|
||||
// yes, linear system would be singular; solve using optimal
|
||||
// single-color match on average color
|
||||
int r = 8, g = 8, b = 8;
|
||||
for (i=0;i<16;++i) {
|
||||
r += block[i*4+0];
|
||||
g += block[i*4+1];
|
||||
b += block[i*4+2];
|
||||
}
|
||||
|
||||
r >>= 4; g >>= 4; b >>= 4;
|
||||
|
||||
max16 = (stb__OMatch5[r][0]<<11) | (stb__OMatch6[g][0]<<5) | stb__OMatch5[b][0];
|
||||
min16 = (stb__OMatch5[r][1]<<11) | (stb__OMatch6[g][1]<<5) | stb__OMatch5[b][1];
|
||||
} else {
|
||||
At1_r = At1_g = At1_b = 0;
|
||||
At2_r = At2_g = At2_b = 0;
|
||||
for (i=0;i<16;++i,cm>>=2) {
|
||||
int step = cm&3;
|
||||
int w1 = w1Tab[step];
|
||||
int r = block[i*4+0];
|
||||
int g = block[i*4+1];
|
||||
int b = block[i*4+2];
|
||||
|
||||
akku += prods[step];
|
||||
At1_r += w1*r;
|
||||
At1_g += w1*g;
|
||||
At1_b += w1*b;
|
||||
At2_r += r;
|
||||
At2_g += g;
|
||||
At2_b += b;
|
||||
}
|
||||
|
||||
At2_r = 3*At2_r - At1_r;
|
||||
At2_g = 3*At2_g - At1_g;
|
||||
At2_b = 3*At2_b - At1_b;
|
||||
|
||||
// extract solutions and decide solvability
|
||||
xx = akku >> 16;
|
||||
yy = (akku >> 8) & 0xff;
|
||||
xy = (akku >> 0) & 0xff;
|
||||
|
||||
frb = 3.0f * 31.0f / 255.0f / (xx*yy - xy*xy);
|
||||
fg = frb * 63.0f / 31.0f;
|
||||
|
||||
// solve.
|
||||
max16 = stb__sclamp((At1_r*yy - At2_r*xy)*frb+0.5f,0,31) << 11;
|
||||
max16 |= stb__sclamp((At1_g*yy - At2_g*xy)*fg +0.5f,0,63) << 5;
|
||||
max16 |= stb__sclamp((At1_b*yy - At2_b*xy)*frb+0.5f,0,31) << 0;
|
||||
|
||||
min16 = stb__sclamp((At2_r*xx - At1_r*xy)*frb+0.5f,0,31) << 11;
|
||||
min16 |= stb__sclamp((At2_g*xx - At1_g*xy)*fg +0.5f,0,63) << 5;
|
||||
min16 |= stb__sclamp((At2_b*xx - At1_b*xy)*frb+0.5f,0,31) << 0;
|
||||
}
|
||||
|
||||
*pmin16 = min16;
|
||||
*pmax16 = max16;
|
||||
return oldMin != min16 || oldMax != max16;
|
||||
}
|
||||
|
||||
// Color block compression
|
||||
static void stb__CompressColorBlock(unsigned char *dest, unsigned char *block, int mode)
|
||||
{
|
||||
unsigned int mask;
|
||||
int i;
|
||||
int dither;
|
||||
int refinecount;
|
||||
unsigned short max16, min16;
|
||||
unsigned char dblock[16*4],color[4*4];
|
||||
|
||||
dither = mode & STB_DXT_DITHER;
|
||||
refinecount = (mode & STB_DXT_HIGHQUAL) ? 2 : 1;
|
||||
|
||||
// check if block is constant
|
||||
for (i=1;i<16;i++)
|
||||
if (((unsigned int *) block)[i] != ((unsigned int *) block)[0])
|
||||
break;
|
||||
|
||||
if(i == 16) { // constant color
|
||||
int r = block[0], g = block[1], b = block[2];
|
||||
mask = 0xaaaaaaaa;
|
||||
max16 = (stb__OMatch5[r][0]<<11) | (stb__OMatch6[g][0]<<5) | stb__OMatch5[b][0];
|
||||
min16 = (stb__OMatch5[r][1]<<11) | (stb__OMatch6[g][1]<<5) | stb__OMatch5[b][1];
|
||||
} else {
|
||||
// first step: compute dithered version for PCA if desired
|
||||
if(dither)
|
||||
stb__DitherBlock(dblock,block);
|
||||
|
||||
// second step: pca+map along principal axis
|
||||
stb__OptimizeColorsBlock(dither ? dblock : block,&max16,&min16);
|
||||
if (max16 != min16) {
|
||||
stb__EvalColors(color,max16,min16);
|
||||
mask = stb__MatchColorsBlock(block,color,dither);
|
||||
} else
|
||||
mask = 0;
|
||||
|
||||
// third step: refine (multiple times if requested)
|
||||
for (i=0;i<refinecount;i++) {
|
||||
unsigned int lastmask = mask;
|
||||
|
||||
if (stb__RefineBlock(dither ? dblock : block,&max16,&min16,mask)) {
|
||||
if (max16 != min16) {
|
||||
stb__EvalColors(color,max16,min16);
|
||||
mask = stb__MatchColorsBlock(block,color,dither);
|
||||
} else {
|
||||
mask = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(mask == lastmask)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// write the color block
|
||||
if(max16 < min16)
|
||||
{
|
||||
unsigned short t = min16;
|
||||
min16 = max16;
|
||||
max16 = t;
|
||||
mask ^= 0x55555555;
|
||||
}
|
||||
|
||||
dest[0] = (unsigned char) (max16);
|
||||
dest[1] = (unsigned char) (max16 >> 8);
|
||||
dest[2] = (unsigned char) (min16);
|
||||
dest[3] = (unsigned char) (min16 >> 8);
|
||||
dest[4] = (unsigned char) (mask);
|
||||
dest[5] = (unsigned char) (mask >> 8);
|
||||
dest[6] = (unsigned char) (mask >> 16);
|
||||
dest[7] = (unsigned char) (mask >> 24);
|
||||
}
|
||||
|
||||
// Alpha block compression (this is easy for a change)
|
||||
static void stb__CompressAlphaBlock(unsigned char *dest,unsigned char *src, int stride)
|
||||
{
|
||||
int i,dist,bias,dist4,dist2,bits,mask;
|
||||
|
||||
// find min/max color
|
||||
int mn,mx;
|
||||
mn = mx = src[0];
|
||||
|
||||
for (i=1;i<16;i++)
|
||||
{
|
||||
if (src[i*stride] < mn) mn = src[i*stride];
|
||||
else if (src[i*stride] > mx) mx = src[i*stride];
|
||||
}
|
||||
|
||||
// encode them
|
||||
((unsigned char *)dest)[0] = mx;
|
||||
((unsigned char *)dest)[1] = mn;
|
||||
dest += 2;
|
||||
|
||||
// determine bias and emit color indices
|
||||
// given the choice of mx/mn, these indices are optimal:
|
||||
// http://fgiesen.wordpress.com/2009/12/15/dxt5-alpha-block-index-determination/
|
||||
dist = mx-mn;
|
||||
dist4 = dist*4;
|
||||
dist2 = dist*2;
|
||||
bias = (dist < 8) ? (dist - 1) : (dist/2 + 2);
|
||||
bias -= mn * 7;
|
||||
bits = 0,mask=0;
|
||||
|
||||
for (i=0;i<16;i++) {
|
||||
int a = src[i*stride]*7 + bias;
|
||||
int ind,t;
|
||||
|
||||
// select index. this is a "linear scale" lerp factor between 0 (val=min) and 7 (val=max).
|
||||
t = (a >= dist4) ? -1 : 0; ind = t & 4; a -= dist4 & t;
|
||||
t = (a >= dist2) ? -1 : 0; ind += t & 2; a -= dist2 & t;
|
||||
ind += (a >= dist);
|
||||
|
||||
// turn linear scale into DXT index (0/1 are extremal pts)
|
||||
ind = -ind & 7;
|
||||
ind ^= (2 > ind);
|
||||
|
||||
// write index
|
||||
mask |= ind << bits;
|
||||
if((bits += 3) >= 8) {
|
||||
*dest++ = mask;
|
||||
mask >>= 8;
|
||||
bits -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void stb__InitDXT()
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<32;i++)
|
||||
stb__Expand5[i] = (i<<3)|(i>>2);
|
||||
|
||||
for(i=0;i<64;i++)
|
||||
stb__Expand6[i] = (i<<2)|(i>>4);
|
||||
|
||||
for(i=0;i<256+16;i++)
|
||||
{
|
||||
int v = i-8 < 0 ? 0 : i-8 > 255 ? 255 : i-8;
|
||||
stb__QuantRBTab[i] = stb__Expand5[stb__Mul8Bit(v,31)];
|
||||
stb__QuantGTab[i] = stb__Expand6[stb__Mul8Bit(v,63)];
|
||||
}
|
||||
|
||||
stb__PrepareOptTable(&stb__OMatch5[0][0],stb__Expand5,32);
|
||||
stb__PrepareOptTable(&stb__OMatch6[0][0],stb__Expand6,64);
|
||||
}
|
||||
|
||||
void stb_compress_dxt_block(unsigned char *dest, const unsigned char *src, int alpha, int mode)
|
||||
{
|
||||
static int init=1;
|
||||
if (init) {
|
||||
stb__InitDXT();
|
||||
init=0;
|
||||
}
|
||||
|
||||
if (alpha) {
|
||||
stb__CompressAlphaBlock(dest,(unsigned char*) src+3, 4);
|
||||
dest += 8;
|
||||
}
|
||||
|
||||
stb__CompressColorBlock(dest,(unsigned char*) src,mode);
|
||||
}
|
||||
|
||||
void stb_compress_bc5_block(unsigned char *dest, const unsigned char *src)
|
||||
{
|
||||
stb__CompressAlphaBlock(dest,(unsigned char*) src,2);
|
||||
stb__CompressAlphaBlock(dest + 8,(unsigned char*) src+1,2);
|
||||
}
|
||||
#endif // STB_DXT_IMPLEMENTATION
|
||||
#endif // STB_INCLUDE_STB_DXT_H
|
||||
|
||||
/*
|
||||
------------------------------------------------------------------------------
|
||||
This software is available under 2 licenses -- choose whichever you prefer.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE A - MIT License
|
||||
Copyright (c) 2017 Sean Barrett
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
ALTERNATIVE B - Public Domain (www.unlicense.org)
|
||||
This is free and unencumbered software released into the public domain.
|
||||
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
|
||||
software, either in source code form or as a compiled binary, for any purpose,
|
||||
commercial or non-commercial, and by any means.
|
||||
In jurisdictions that recognize copyright laws, the author or authors of this
|
||||
software dedicate any and all copyright interest in the software to the public
|
||||
domain. We make this dedication for the benefit of the public at large and to
|
||||
the detriment of our heirs and successors. We intend this dedication to be an
|
||||
overt act of relinquishment in perpetuity of all present and future rights to
|
||||
this software under copyright law.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
------------------------------------------------------------------------------
|
||||
*/
|
|
@ -1,49 +0,0 @@
|
|||
# Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
# <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
SET( LIBRARY_HEADERS
|
||||
"include/FasTC/ETCCompressor.h"
|
||||
)
|
||||
|
||||
SET( HEADERS
|
||||
${LIBRARY_HEADERS}
|
||||
src/rg_etc1.h
|
||||
)
|
||||
|
||||
SET( SOURCES
|
||||
src/Compressor.cpp
|
||||
src/Decompressor.cpp
|
||||
src/rg_etc1.cpp
|
||||
)
|
||||
|
||||
INCLUDE_DIRECTORIES(${FasTC_SOURCE_DIR}/Base/include)
|
||||
INCLUDE_DIRECTORIES(${FasTC_BINARY_DIR}/Base/include)
|
||||
INCLUDE_DIRECTORIES(${FasTC_SOURCE_DIR}/ETCEncoder/include)
|
||||
INCLUDE_DIRECTORIES(${FasTC_BINARY_DIR}/ETCEncoder/include)
|
||||
|
||||
ADD_LIBRARY( ETCEncoder
|
||||
${HEADERS}
|
||||
${SOURCES}
|
||||
)
|
||||
|
||||
INSTALL(TARGETS ETCEncoder EXPORT FasTCTargets ARCHIVE DESTINATION lib COMPONENT lib)
|
||||
INSTALL(
|
||||
FILES ${LIBRARY_HEADERS}
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/FasTC
|
||||
COMPONENT dev)
|
||||
|
||||
TARGET_LINK_LIBRARIES( ETCEncoder FasTCBase )
|
|
@ -1,39 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#ifndef ETCENCODER_INCLUDE_ETCCOMPRESSOR_H_
|
||||
#define ETCENCODER_INCLUDE_ETCCOMPRESSOR_H_
|
||||
|
||||
#include "FasTC/CompressionJob.h"
|
||||
#include "FasTC/TexCompTypes.h"
|
||||
|
||||
namespace ETCC {
|
||||
|
||||
// Takes a stream of compressed ETC1 data and decompresses it into R8G8B8A8
|
||||
// format. The width and height must be specified in order to properly
|
||||
// decompress the data.
|
||||
void Decompress(const FasTC::DecompressionJob &);
|
||||
|
||||
// Takes a stream of uncompressed RGBA8 data and compresses it into ETC1
|
||||
// version one. The width and height must be specified in order to properly
|
||||
// decompress the data. This uses the library created by Rich Geldreich found here:
|
||||
// https://code.google.com/p/rg-etc1
|
||||
void Compress_RG(const FasTC::CompressionJob &);
|
||||
|
||||
} // namespace PVRTCC
|
||||
|
||||
#endif // ETCENCODER_INCLUDE_ETCCOMPRESSOR_H_
|
|
@ -1,55 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "FasTC/ETCCompressor.h"
|
||||
|
||||
#include "rg_etc1.h"
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
namespace ETCC {
|
||||
|
||||
void Compress_RG(const FasTC::CompressionJob &cj) {
|
||||
|
||||
rg_etc1::etc1_pack_params params;
|
||||
params.m_quality = rg_etc1::cLowQuality;
|
||||
rg_etc1::pack_etc1_block_init();
|
||||
|
||||
uint32 kBlockSz = GetBlockSize(FasTC::eCompressionFormat_ETC1);
|
||||
const uint32 startBlock = cj.CoordsToBlockIdx(cj.XStart(), cj.YStart());
|
||||
uint8 *outBuf = cj.OutBuf() + startBlock * kBlockSz;
|
||||
|
||||
const uint32 endY = std::min(cj.YEnd(), cj.Height() - 4);
|
||||
uint32 startX = cj.XStart();
|
||||
for(uint32 j = cj.YStart(); j <= endY; j += 4) {
|
||||
const uint32 endX = j == cj.YEnd()? cj.XEnd() : cj.Width();
|
||||
for(uint32 i = startX; i < endX; i += 4) {
|
||||
|
||||
uint32 pixels[16];
|
||||
const uint32 *inPixels = reinterpret_cast<const uint32 *>(cj.InBuf());
|
||||
memcpy(pixels, inPixels + j*cj.Width() + i, 4 * sizeof(uint32));
|
||||
memcpy(pixels + 4, inPixels + (j+1)*cj.Width() + i, 4 * sizeof(uint32));
|
||||
memcpy(pixels + 8, inPixels + (j+2)*cj.Width() + i, 4 * sizeof(uint32));
|
||||
memcpy(pixels + 12, inPixels + (j+3)*cj.Width() + i, 4 * sizeof(uint32));
|
||||
|
||||
pack_etc1_block(outBuf, pixels, params);
|
||||
outBuf += kBlockSz;
|
||||
}
|
||||
startX = 0;
|
||||
}
|
||||
}
|
||||
} // namespace PVRTCC
|
|
@ -1,49 +0,0 @@
|
|||
// Copyright 2016 The University of North Carolina at Chapel Hill
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
// <http://gamma.cs.unc.edu/FasTC/>
|
||||
|
||||
#include "FasTC/ETCCompressor.h"
|
||||
|
||||
#include "rg_etc1.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
namespace ETCC {
|
||||
|
||||
void Decompress(const FasTC::DecompressionJob &dcj) {
|
||||
uint32 blocksX = (dcj.Width() + 3) / 4;
|
||||
uint32 blocksY = (dcj.Height() + 3) / 4;
|
||||
|
||||
for(uint32 j = 0; j < blocksY; j++) {
|
||||
for(uint32 i = 0; i < blocksX; i++) {
|
||||
uint32 pixels[16];
|
||||
uint32 blockIdx = j*blocksX + i;
|
||||
rg_etc1::unpack_etc1_block(dcj.InBuf() + blockIdx * 8, pixels);
|
||||
|
||||
uint32 decompWidth = std::min(4U, dcj.Width() - i * 4);
|
||||
uint32 decompHeight = std::min(4U, dcj.Height() - j * 4);
|
||||
|
||||
for(uint32 y = 0; y < decompHeight; y++)
|
||||
for(uint32 x = 0; x < decompWidth; x++) {
|
||||
uint32 *out = reinterpret_cast<uint32 *>(dcj.OutBuf());
|
||||
out[(j*4 + y)*dcj.Width() + (i*4 + x)] = pixels[y*4 + x];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace PVRTCC
|
File diff suppressed because it is too large
Load diff
|
@ -1,76 +0,0 @@
|
|||
// File: rg_etc1.h - Fast, high quality ETC1 block packer/unpacker - Rich Geldreich <richgel99@gmail.com>
|
||||
// Please see ZLIB license at the end of this file.
|
||||
#pragma once
|
||||
|
||||
namespace rg_etc1
|
||||
{
|
||||
// Unpacks an 8-byte ETC1 compressed block to a block of 4x4 32bpp RGBA pixels.
|
||||
// Returns false if the block is invalid. Invalid blocks will still be unpacked with clamping.
|
||||
// This function is thread safe, and does not dynamically allocate any memory.
|
||||
// If preserve_alpha is true, the alpha channel of the destination pixels will not be overwritten. Otherwise, alpha will be set to 255.
|
||||
bool unpack_etc1_block(const void *pETC1_block, unsigned int* pDst_pixels_rgba, bool preserve_alpha = false);
|
||||
|
||||
// Quality setting = the higher the quality, the slower.
|
||||
// To pack large textures, it is highly recommended to call pack_etc1_block() in parallel, on different blocks, from multiple threads (particularly when using cHighQuality).
|
||||
enum etc1_quality
|
||||
{
|
||||
cLowQuality,
|
||||
cMediumQuality,
|
||||
cHighQuality,
|
||||
};
|
||||
|
||||
struct etc1_pack_params
|
||||
{
|
||||
etc1_quality m_quality;
|
||||
bool m_dithering;
|
||||
|
||||
inline etc1_pack_params()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
m_quality = cHighQuality;
|
||||
m_dithering = false;
|
||||
}
|
||||
};
|
||||
|
||||
// Important: pack_etc1_block_init() must be called before calling pack_etc1_block().
|
||||
void pack_etc1_block_init();
|
||||
|
||||
// Packs a 4x4 block of 32bpp RGBA pixels to an 8-byte ETC1 block.
|
||||
// 32-bit RGBA pixels must always be arranged as (R,G,B,A) (R first, A last) in memory, independent of platform endianness. A should always be 255.
|
||||
// Returns squared error of result.
|
||||
// This function is thread safe, and does not dynamically allocate any memory.
|
||||
// pack_etc1_block() does not currently support "perceptual" colorspace metrics - it primarily optimizes for RGB RMSE.
|
||||
unsigned int pack_etc1_block(void* pETC1_block, const unsigned int* pSrc_pixels_rgba, etc1_pack_params& pack_params);
|
||||
|
||||
} // namespace rg_etc1
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// rg_etc1 uses the ZLIB license:
|
||||
// http://opensource.org/licenses/Zlib
|
||||
//
|
||||
// Copyright (c) 2012 Rich Geldreich
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software.
|
||||
//
|
||||
// Permission is granted to anyone to use this software for any purpose,
|
||||
// including commercial applications, and to alter it and redistribute it
|
||||
// freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
//
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
//
|
||||
// 3. This notice may not be removed or altered from any source distribution.
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
153
GTest/CHANGES
153
GTest/CHANGES
|
@ -1,153 +0,0 @@
|
|||
Changes for 1.7.0:
|
||||
|
||||
* New feature: death tests are supported on OpenBSD and in iOS
|
||||
simulator now.
|
||||
* New feature: Test::RecordProperty() can now be used outside of the
|
||||
lifespan of a test method, in which case it will be attributed to
|
||||
the current test case or the test program in the XML report.
|
||||
* New feature (potentially breaking): --gtest_list_tests now prints
|
||||
the type parameters and value parameters for each test.
|
||||
* Improvement: char pointers and char arrays are now escaped properly
|
||||
in failure messages.
|
||||
* Improvement: failure summary in XML reports now includes file and
|
||||
line information.
|
||||
* Improvement: the <testsuites> XML element now has a timestamp attribute.
|
||||
* Improvement: When --gtest_filter is specified, XML report now doesn't
|
||||
contain information about tests that are filtered out.
|
||||
* Fixed the bug where long --gtest_filter flag values are truncated in
|
||||
death tests.
|
||||
* Potentially breaking change: RUN_ALL_TESTS() is now implemented as a
|
||||
function instead of a macro in order to work better with Clang.
|
||||
* Compatibility fixes with C++ 11 and various platforms.
|
||||
* Bug/warning fixes.
|
||||
|
||||
Changes for 1.6.0:
|
||||
|
||||
* New feature: ADD_FAILURE_AT() for reporting a test failure at the
|
||||
given source location -- useful for writing testing utilities.
|
||||
* New feature: the universal value printer is moved from Google Mock
|
||||
to Google Test.
|
||||
* New feature: type parameters and value parameters are reported in
|
||||
the XML report now.
|
||||
* A gtest_disable_pthreads CMake option.
|
||||
* Colored output works in GNU Screen sessions now.
|
||||
* Parameters of value-parameterized tests are now printed in the
|
||||
textual output.
|
||||
* Failures from ad hoc test assertions run before RUN_ALL_TESTS() are
|
||||
now correctly reported.
|
||||
* Arguments of ASSERT_XY and EXPECT_XY no longer need to support << to
|
||||
ostream.
|
||||
* More complete handling of exceptions.
|
||||
* GTEST_ASSERT_XY can be used instead of ASSERT_XY in case the latter
|
||||
name is already used by another library.
|
||||
* --gtest_catch_exceptions is now true by default, allowing a test
|
||||
program to continue after an exception is thrown.
|
||||
* Value-parameterized test fixtures can now derive from Test and
|
||||
WithParamInterface<T> separately, easing conversion of legacy tests.
|
||||
* Death test messages are clearly marked to make them more
|
||||
distinguishable from other messages.
|
||||
* Compatibility fixes for Android, Google Native Client, MinGW, HP UX,
|
||||
PowerPC, Lucid autotools, libCStd, Sun C++, Borland C++ Builder (Code Gear),
|
||||
IBM XL C++ (Visual Age C++), and C++0x.
|
||||
* Bug fixes and implementation clean-ups.
|
||||
* Potentially incompatible changes: disables the harmful 'make install'
|
||||
command in autotools.
|
||||
|
||||
Changes for 1.5.0:
|
||||
|
||||
* New feature: assertions can be safely called in multiple threads
|
||||
where the pthreads library is available.
|
||||
* New feature: predicates used inside EXPECT_TRUE() and friends
|
||||
can now generate custom failure messages.
|
||||
* New feature: Google Test can now be compiled as a DLL.
|
||||
* New feature: fused source files are included.
|
||||
* New feature: prints help when encountering unrecognized Google Test flags.
|
||||
* Experimental feature: CMake build script (requires CMake 2.6.4+).
|
||||
* Experimental feature: the Pump script for meta programming.
|
||||
* double values streamed to an assertion are printed with enough precision
|
||||
to differentiate any two different values.
|
||||
* Google Test now works on Solaris and AIX.
|
||||
* Build and test script improvements.
|
||||
* Bug fixes and implementation clean-ups.
|
||||
|
||||
Potentially breaking changes:
|
||||
|
||||
* Stopped supporting VC++ 7.1 with exceptions disabled.
|
||||
* Dropped support for 'make install'.
|
||||
|
||||
Changes for 1.4.0:
|
||||
|
||||
* New feature: the event listener API
|
||||
* New feature: test shuffling
|
||||
* New feature: the XML report format is closer to junitreport and can
|
||||
be parsed by Hudson now.
|
||||
* New feature: when a test runs under Visual Studio, its failures are
|
||||
integrated in the IDE.
|
||||
* New feature: /MD(d) versions of VC++ projects.
|
||||
* New feature: elapsed time for the tests is printed by default.
|
||||
* New feature: comes with a TR1 tuple implementation such that Boost
|
||||
is no longer needed for Combine().
|
||||
* New feature: EXPECT_DEATH_IF_SUPPORTED macro and friends.
|
||||
* New feature: the Xcode project can now produce static gtest
|
||||
libraries in addition to a framework.
|
||||
* Compatibility fixes for Solaris, Cygwin, minGW, Windows Mobile,
|
||||
Symbian, gcc, and C++Builder.
|
||||
* Bug fixes and implementation clean-ups.
|
||||
|
||||
Changes for 1.3.0:
|
||||
|
||||
* New feature: death tests on Windows, Cygwin, and Mac.
|
||||
* New feature: ability to use Google Test assertions in other testing
|
||||
frameworks.
|
||||
* New feature: ability to run disabled test via
|
||||
--gtest_also_run_disabled_tests.
|
||||
* New feature: the --help flag for printing the usage.
|
||||
* New feature: access to Google Test flag values in user code.
|
||||
* New feature: a script that packs Google Test into one .h and one
|
||||
.cc file for easy deployment.
|
||||
* New feature: support for distributing test functions to multiple
|
||||
machines (requires support from the test runner).
|
||||
* Bug fixes and implementation clean-ups.
|
||||
|
||||
Changes for 1.2.1:
|
||||
|
||||
* Compatibility fixes for Linux IA-64 and IBM z/OS.
|
||||
* Added support for using Boost and other TR1 implementations.
|
||||
* Changes to the build scripts to support upcoming release of Google C++
|
||||
Mocking Framework.
|
||||
* Added Makefile to the distribution package.
|
||||
* Improved build instructions in README.
|
||||
|
||||
Changes for 1.2.0:
|
||||
|
||||
* New feature: value-parameterized tests.
|
||||
* New feature: the ASSERT/EXPECT_(NON)FATAL_FAILURE(_ON_ALL_THREADS)
|
||||
macros.
|
||||
* Changed the XML report format to match JUnit/Ant's.
|
||||
* Added tests to the Xcode project.
|
||||
* Added scons/SConscript for building with SCons.
|
||||
* Added src/gtest-all.cc for building Google Test from a single file.
|
||||
* Fixed compatibility with Solaris and z/OS.
|
||||
* Enabled running Python tests on systems with python 2.3 installed,
|
||||
e.g. Mac OS X 10.4.
|
||||
* Bug fixes.
|
||||
|
||||
Changes for 1.1.0:
|
||||
|
||||
* New feature: type-parameterized tests.
|
||||
* New feature: exception assertions.
|
||||
* New feature: printing elapsed time of tests.
|
||||
* Improved the robustness of death tests.
|
||||
* Added an Xcode project and samples.
|
||||
* Adjusted the output format on Windows to be understandable by Visual Studio.
|
||||
* Minor bug fixes.
|
||||
|
||||
Changes for 1.0.1:
|
||||
|
||||
* Added project files for Visual Studio 7.1.
|
||||
* Fixed issues with compiling on Mac OS X.
|
||||
* Fixed issues with compiling on Cygwin.
|
||||
|
||||
Changes for 1.0.0:
|
||||
|
||||
* Initial Open Source release of Google Test
|
|
@ -1,250 +0,0 @@
|
|||
########################################################################
|
||||
# CMake build script for Google Test.
|
||||
#
|
||||
# To run the tests for Google Test itself on Linux, use 'make test' or
|
||||
# ctest. You can select which tests to run using 'ctest -R regex'.
|
||||
# For more options, run 'ctest --help'.
|
||||
|
||||
# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to
|
||||
# make it prominent in the GUI.
|
||||
option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF)
|
||||
|
||||
# When other libraries are using a shared version of runtime libraries,
|
||||
# Google Test also has to use one.
|
||||
option(
|
||||
gtest_force_shared_crt
|
||||
"Use shared (DLL) run-time lib even when Google Test is built as static lib."
|
||||
OFF)
|
||||
|
||||
option(gtest_build_tests "Build all of gtest's own tests." OFF)
|
||||
|
||||
option(gtest_build_samples "Build gtest's sample programs." OFF)
|
||||
|
||||
option(gtest_disable_pthreads "Disable uses of pthreads in gtest." OFF)
|
||||
|
||||
# Defines pre_project_set_up_hermetic_build() and set_up_hermetic_build().
|
||||
include(cmake/hermetic_build.cmake OPTIONAL)
|
||||
|
||||
if (COMMAND pre_project_set_up_hermetic_build)
|
||||
pre_project_set_up_hermetic_build()
|
||||
endif()
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Project-wide settings
|
||||
|
||||
# Name of the project.
|
||||
#
|
||||
# CMake files in this project can refer to the root source directory
|
||||
# as ${gtest_SOURCE_DIR} and to the root binary directory as
|
||||
# ${gtest_BINARY_DIR}.
|
||||
# Language "C" is required for find_package(Threads).
|
||||
project(gtest CXX C)
|
||||
cmake_minimum_required(VERSION 2.6.2)
|
||||
|
||||
if (COMMAND set_up_hermetic_build)
|
||||
set_up_hermetic_build()
|
||||
endif()
|
||||
|
||||
# Define helper functions and macros used by Google Test.
|
||||
include(cmake/internal_utils.cmake)
|
||||
|
||||
config_compiler_and_linker() # Defined in internal_utils.cmake.
|
||||
|
||||
# Where Google Test's .h files can be found.
|
||||
include_directories(
|
||||
${gtest_SOURCE_DIR}/include
|
||||
${gtest_SOURCE_DIR})
|
||||
|
||||
# Where Google Test's libraries can be found.
|
||||
link_directories(${gtest_BINARY_DIR}/src)
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Defines the gtest & gtest_main libraries. User tests should link
|
||||
# with one of them.
|
||||
|
||||
# Google Test libraries. We build them using more strict warnings than what
|
||||
# are used for other targets, to ensure that gtest can be compiled by a user
|
||||
# aggressive about warnings.
|
||||
cxx_library(gtest "${cxx_strict}" src/gtest-all.cc)
|
||||
cxx_library(gtest_main "${cxx_strict}" src/gtest_main.cc)
|
||||
target_link_libraries(gtest_main gtest)
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Samples on how to link user tests with gtest or gtest_main.
|
||||
#
|
||||
# They are not built by default. To build them, set the
|
||||
# gtest_build_samples option to ON. You can do it by running ccmake
|
||||
# or specifying the -Dgtest_build_samples=ON flag when running cmake.
|
||||
|
||||
if (gtest_build_samples)
|
||||
cxx_executable(sample1_unittest samples gtest_main samples/sample1.cc)
|
||||
cxx_executable(sample2_unittest samples gtest_main samples/sample2.cc)
|
||||
cxx_executable(sample3_unittest samples gtest_main)
|
||||
cxx_executable(sample4_unittest samples gtest_main samples/sample4.cc)
|
||||
cxx_executable(sample5_unittest samples gtest_main samples/sample1.cc)
|
||||
cxx_executable(sample6_unittest samples gtest_main)
|
||||
cxx_executable(sample7_unittest samples gtest_main)
|
||||
cxx_executable(sample8_unittest samples gtest_main)
|
||||
cxx_executable(sample9_unittest samples gtest)
|
||||
cxx_executable(sample10_unittest samples gtest)
|
||||
endif()
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Google Test's own tests.
|
||||
#
|
||||
# You can skip this section if you aren't interested in testing
|
||||
# Google Test itself.
|
||||
#
|
||||
# The tests are not built by default. To build them, set the
|
||||
# gtest_build_tests option to ON. You can do it by running ccmake
|
||||
# or specifying the -Dgtest_build_tests=ON flag when running cmake.
|
||||
|
||||
if (gtest_build_tests)
|
||||
# This must be set in the root directory for the tests to be run by
|
||||
# 'make test' or ctest.
|
||||
enable_testing()
|
||||
|
||||
############################################################
|
||||
# C++ tests built with standard compiler flags.
|
||||
|
||||
cxx_test(gtest-death-test_test gtest_main)
|
||||
cxx_test(gtest_environment_test gtest)
|
||||
cxx_test(gtest-filepath_test gtest_main)
|
||||
cxx_test(gtest-linked_ptr_test gtest_main)
|
||||
cxx_test(gtest-listener_test gtest_main)
|
||||
cxx_test(gtest_main_unittest gtest_main)
|
||||
cxx_test(gtest-message_test gtest_main)
|
||||
cxx_test(gtest_no_test_unittest gtest)
|
||||
cxx_test(gtest-options_test gtest_main)
|
||||
cxx_test(gtest-param-test_test gtest
|
||||
test/gtest-param-test2_test.cc)
|
||||
cxx_test(gtest-port_test gtest_main)
|
||||
cxx_test(gtest_pred_impl_unittest gtest_main)
|
||||
cxx_test(gtest-printers_test gtest_main)
|
||||
cxx_test(gtest_prod_test gtest_main
|
||||
test/production.cc)
|
||||
cxx_test(gtest_repeat_test gtest)
|
||||
cxx_test(gtest_sole_header_test gtest_main)
|
||||
cxx_test(gtest_stress_test gtest)
|
||||
cxx_test(gtest-test-part_test gtest_main)
|
||||
cxx_test(gtest_throw_on_failure_ex_test gtest)
|
||||
cxx_test(gtest-typed-test_test gtest_main
|
||||
test/gtest-typed-test2_test.cc)
|
||||
cxx_test(gtest_unittest gtest_main)
|
||||
cxx_test(gtest-unittest-api_test gtest)
|
||||
|
||||
############################################################
|
||||
# C++ tests built with non-standard compiler flags.
|
||||
|
||||
# MSVC 7.1 does not support STL with exceptions disabled.
|
||||
if (NOT MSVC OR MSVC_VERSION GREATER 1310)
|
||||
cxx_library(gtest_no_exception "${cxx_no_exception}"
|
||||
src/gtest-all.cc)
|
||||
cxx_library(gtest_main_no_exception "${cxx_no_exception}"
|
||||
src/gtest-all.cc src/gtest_main.cc)
|
||||
endif()
|
||||
cxx_library(gtest_main_no_rtti "${cxx_no_rtti}"
|
||||
src/gtest-all.cc src/gtest_main.cc)
|
||||
|
||||
cxx_test_with_flags(gtest-death-test_ex_nocatch_test
|
||||
"${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=0"
|
||||
gtest test/gtest-death-test_ex_test.cc)
|
||||
cxx_test_with_flags(gtest-death-test_ex_catch_test
|
||||
"${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=1"
|
||||
gtest test/gtest-death-test_ex_test.cc)
|
||||
|
||||
cxx_test_with_flags(gtest_no_rtti_unittest "${cxx_no_rtti}"
|
||||
gtest_main_no_rtti test/gtest_unittest.cc)
|
||||
|
||||
cxx_shared_library(gtest_dll "${cxx_default}"
|
||||
src/gtest-all.cc src/gtest_main.cc)
|
||||
|
||||
cxx_executable_with_flags(gtest_dll_test_ "${cxx_default}"
|
||||
gtest_dll test/gtest_all_test.cc)
|
||||
set_target_properties(gtest_dll_test_
|
||||
PROPERTIES
|
||||
COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
|
||||
|
||||
if (NOT MSVC OR NOT MSVC_VERSION EQUAL 1600)
|
||||
# The C++ Standard specifies tuple_element<int, class>.
|
||||
# Yet MSVC 10's <utility> declares tuple_element<size_t, class>.
|
||||
# That declaration conflicts with our own standard-conforming
|
||||
# tuple implementation. Therefore using our own tuple with
|
||||
# MSVC 10 doesn't compile.
|
||||
cxx_library(gtest_main_use_own_tuple "${cxx_use_own_tuple}"
|
||||
src/gtest-all.cc src/gtest_main.cc)
|
||||
|
||||
cxx_test_with_flags(gtest-tuple_test "${cxx_use_own_tuple}"
|
||||
gtest_main_use_own_tuple test/gtest-tuple_test.cc)
|
||||
|
||||
cxx_test_with_flags(gtest_use_own_tuple_test "${cxx_use_own_tuple}"
|
||||
gtest_main_use_own_tuple
|
||||
test/gtest-param-test_test.cc test/gtest-param-test2_test.cc)
|
||||
endif()
|
||||
|
||||
############################################################
|
||||
# Python tests.
|
||||
|
||||
cxx_executable(gtest_break_on_failure_unittest_ test gtest)
|
||||
py_test(gtest_break_on_failure_unittest)
|
||||
|
||||
# MSVC 7.1 does not support STL with exceptions disabled.
|
||||
if (NOT MSVC OR MSVC_VERSION GREATER 1310)
|
||||
cxx_executable_with_flags(
|
||||
gtest_catch_exceptions_no_ex_test_
|
||||
"${cxx_no_exception}"
|
||||
gtest_main_no_exception
|
||||
test/gtest_catch_exceptions_test_.cc)
|
||||
endif()
|
||||
|
||||
cxx_executable_with_flags(
|
||||
gtest_catch_exceptions_ex_test_
|
||||
"${cxx_exception}"
|
||||
gtest_main
|
||||
test/gtest_catch_exceptions_test_.cc)
|
||||
py_test(gtest_catch_exceptions_test)
|
||||
|
||||
cxx_executable(gtest_color_test_ test gtest)
|
||||
py_test(gtest_color_test)
|
||||
|
||||
cxx_executable(gtest_env_var_test_ test gtest)
|
||||
py_test(gtest_env_var_test)
|
||||
|
||||
cxx_executable(gtest_filter_unittest_ test gtest)
|
||||
py_test(gtest_filter_unittest)
|
||||
|
||||
cxx_executable(gtest_help_test_ test gtest_main)
|
||||
py_test(gtest_help_test)
|
||||
|
||||
cxx_executable(gtest_list_tests_unittest_ test gtest)
|
||||
py_test(gtest_list_tests_unittest)
|
||||
|
||||
cxx_executable(gtest_output_test_ test gtest)
|
||||
py_test(gtest_output_test)
|
||||
|
||||
cxx_executable(gtest_shuffle_test_ test gtest)
|
||||
py_test(gtest_shuffle_test)
|
||||
|
||||
# MSVC 7.1 does not support STL with exceptions disabled.
|
||||
if (NOT MSVC OR MSVC_VERSION GREATER 1310)
|
||||
cxx_executable(gtest_throw_on_failure_test_ test gtest_no_exception)
|
||||
set_target_properties(gtest_throw_on_failure_test_
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "${cxx_no_exception}")
|
||||
py_test(gtest_throw_on_failure_test)
|
||||
endif()
|
||||
|
||||
cxx_executable(gtest_uninitialized_test_ test gtest)
|
||||
py_test(gtest_uninitialized_test)
|
||||
|
||||
cxx_executable(gtest_xml_outfile1_test_ test gtest_main)
|
||||
cxx_executable(gtest_xml_outfile2_test_ test gtest_main)
|
||||
py_test(gtest_xml_outfiles_test)
|
||||
|
||||
cxx_executable(gtest_xml_output_unittest_ test gtest)
|
||||
py_test(gtest_xml_output_unittest)
|
||||
endif()
|
|
@ -1,37 +0,0 @@
|
|||
# This file contains a list of people who've made non-trivial
|
||||
# contribution to the Google C++ Testing Framework project. People
|
||||
# who commit code to the project are encouraged to add their names
|
||||
# here. Please keep the list sorted by first names.
|
||||
|
||||
Ajay Joshi <jaj@google.com>
|
||||
Balázs Dán <balazs.dan@gmail.com>
|
||||
Bharat Mediratta <bharat@menalto.com>
|
||||
Chandler Carruth <chandlerc@google.com>
|
||||
Chris Prince <cprince@google.com>
|
||||
Chris Taylor <taylorc@google.com>
|
||||
Dan Egnor <egnor@google.com>
|
||||
Eric Roman <eroman@chromium.org>
|
||||
Hady Zalek <hady.zalek@gmail.com>
|
||||
Jeffrey Yasskin <jyasskin@google.com>
|
||||
Jói Sigurðsson <joi@google.com>
|
||||
Keir Mierle <mierle@gmail.com>
|
||||
Keith Ray <keith.ray@gmail.com>
|
||||
Kenton Varda <kenton@google.com>
|
||||
Manuel Klimek <klimek@google.com>
|
||||
Markus Heule <markus.heule@gmail.com>
|
||||
Mika Raento <mikie@iki.fi>
|
||||
Miklós Fazekas <mfazekas@szemafor.com>
|
||||
Pasi Valminen <pasi.valminen@gmail.com>
|
||||
Patrick Hanna <phanna@google.com>
|
||||
Patrick Riley <pfr@google.com>
|
||||
Peter Kaminski <piotrk@google.com>
|
||||
Preston Jackson <preston.a.jackson@gmail.com>
|
||||
Rainer Klaffenboeck <rainer.klaffenboeck@dynatrace.com>
|
||||
Russ Cox <rsc@google.com>
|
||||
Russ Rufer <russ@pentad.com>
|
||||
Sean Mcafee <eefacm@gmail.com>
|
||||
Sigurður Ásgeirsson <siggi@google.com>
|
||||
Tracy Bialik <tracy@pentad.com>
|
||||
Vadim Berman <vadimb@google.com>
|
||||
Vlad Losev <vladl@google.com>
|
||||
Zhanyong Wan <wan@google.com>
|
|
@ -1,28 +0,0 @@
|
|||
Copyright 2008, Google 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:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,305 +0,0 @@
|
|||
# Automake file
|
||||
|
||||
ACLOCAL_AMFLAGS = -I m4
|
||||
|
||||
# Nonstandard package files for distribution
|
||||
EXTRA_DIST = \
|
||||
CHANGES \
|
||||
CONTRIBUTORS \
|
||||
LICENSE \
|
||||
include/gtest/gtest-param-test.h.pump \
|
||||
include/gtest/internal/gtest-param-util-generated.h.pump \
|
||||
include/gtest/internal/gtest-tuple.h.pump \
|
||||
include/gtest/internal/gtest-type-util.h.pump \
|
||||
make/Makefile \
|
||||
scripts/fuse_gtest_files.py \
|
||||
scripts/gen_gtest_pred_impl.py \
|
||||
scripts/pump.py \
|
||||
scripts/test/Makefile
|
||||
|
||||
# gtest source files that we don't compile directly. They are
|
||||
# #included by gtest-all.cc.
|
||||
GTEST_SRC = \
|
||||
src/gtest-death-test.cc \
|
||||
src/gtest-filepath.cc \
|
||||
src/gtest-internal-inl.h \
|
||||
src/gtest-port.cc \
|
||||
src/gtest-printers.cc \
|
||||
src/gtest-test-part.cc \
|
||||
src/gtest-typed-test.cc \
|
||||
src/gtest.cc
|
||||
|
||||
EXTRA_DIST += $(GTEST_SRC)
|
||||
|
||||
# Sample files that we don't compile.
|
||||
EXTRA_DIST += \
|
||||
samples/prime_tables.h \
|
||||
samples/sample2_unittest.cc \
|
||||
samples/sample3_unittest.cc \
|
||||
samples/sample4_unittest.cc \
|
||||
samples/sample5_unittest.cc \
|
||||
samples/sample6_unittest.cc \
|
||||
samples/sample7_unittest.cc \
|
||||
samples/sample8_unittest.cc \
|
||||
samples/sample9_unittest.cc
|
||||
|
||||
# C++ test files that we don't compile directly.
|
||||
EXTRA_DIST += \
|
||||
test/gtest-death-test_ex_test.cc \
|
||||
test/gtest-death-test_test.cc \
|
||||
test/gtest-filepath_test.cc \
|
||||
test/gtest-linked_ptr_test.cc \
|
||||
test/gtest-listener_test.cc \
|
||||
test/gtest-message_test.cc \
|
||||
test/gtest-options_test.cc \
|
||||
test/gtest-param-test2_test.cc \
|
||||
test/gtest-param-test2_test.cc \
|
||||
test/gtest-param-test_test.cc \
|
||||
test/gtest-param-test_test.cc \
|
||||
test/gtest-param-test_test.h \
|
||||
test/gtest-port_test.cc \
|
||||
test/gtest-printers_test.cc \
|
||||
test/gtest-test-part_test.cc \
|
||||
test/gtest-tuple_test.cc \
|
||||
test/gtest-typed-test2_test.cc \
|
||||
test/gtest-typed-test_test.cc \
|
||||
test/gtest-typed-test_test.h \
|
||||
test/gtest-unittest-api_test.cc \
|
||||
test/gtest_break_on_failure_unittest_.cc \
|
||||
test/gtest_catch_exceptions_test_.cc \
|
||||
test/gtest_color_test_.cc \
|
||||
test/gtest_env_var_test_.cc \
|
||||
test/gtest_environment_test.cc \
|
||||
test/gtest_filter_unittest_.cc \
|
||||
test/gtest_help_test_.cc \
|
||||
test/gtest_list_tests_unittest_.cc \
|
||||
test/gtest_main_unittest.cc \
|
||||
test/gtest_no_test_unittest.cc \
|
||||
test/gtest_output_test_.cc \
|
||||
test/gtest_pred_impl_unittest.cc \
|
||||
test/gtest_prod_test.cc \
|
||||
test/gtest_repeat_test.cc \
|
||||
test/gtest_shuffle_test_.cc \
|
||||
test/gtest_sole_header_test.cc \
|
||||
test/gtest_stress_test.cc \
|
||||
test/gtest_throw_on_failure_ex_test.cc \
|
||||
test/gtest_throw_on_failure_test_.cc \
|
||||
test/gtest_uninitialized_test_.cc \
|
||||
test/gtest_unittest.cc \
|
||||
test/gtest_unittest.cc \
|
||||
test/gtest_xml_outfile1_test_.cc \
|
||||
test/gtest_xml_outfile2_test_.cc \
|
||||
test/gtest_xml_output_unittest_.cc \
|
||||
test/production.cc \
|
||||
test/production.h
|
||||
|
||||
# Python tests that we don't run.
|
||||
EXTRA_DIST += \
|
||||
test/gtest_break_on_failure_unittest.py \
|
||||
test/gtest_catch_exceptions_test.py \
|
||||
test/gtest_color_test.py \
|
||||
test/gtest_env_var_test.py \
|
||||
test/gtest_filter_unittest.py \
|
||||
test/gtest_help_test.py \
|
||||
test/gtest_list_tests_unittest.py \
|
||||
test/gtest_output_test.py \
|
||||
test/gtest_output_test_golden_lin.txt \
|
||||
test/gtest_shuffle_test.py \
|
||||
test/gtest_test_utils.py \
|
||||
test/gtest_throw_on_failure_test.py \
|
||||
test/gtest_uninitialized_test.py \
|
||||
test/gtest_xml_outfiles_test.py \
|
||||
test/gtest_xml_output_unittest.py \
|
||||
test/gtest_xml_test_utils.py
|
||||
|
||||
# CMake script
|
||||
EXTRA_DIST += \
|
||||
CMakeLists.txt \
|
||||
cmake/internal_utils.cmake
|
||||
|
||||
# MSVC project files
|
||||
EXTRA_DIST += \
|
||||
msvc/gtest-md.sln \
|
||||
msvc/gtest-md.vcproj \
|
||||
msvc/gtest.sln \
|
||||
msvc/gtest.vcproj \
|
||||
msvc/gtest_main-md.vcproj \
|
||||
msvc/gtest_main.vcproj \
|
||||
msvc/gtest_prod_test-md.vcproj \
|
||||
msvc/gtest_prod_test.vcproj \
|
||||
msvc/gtest_unittest-md.vcproj \
|
||||
msvc/gtest_unittest.vcproj
|
||||
|
||||
# xcode project files
|
||||
EXTRA_DIST += \
|
||||
xcode/Config/DebugProject.xcconfig \
|
||||
xcode/Config/FrameworkTarget.xcconfig \
|
||||
xcode/Config/General.xcconfig \
|
||||
xcode/Config/ReleaseProject.xcconfig \
|
||||
xcode/Config/StaticLibraryTarget.xcconfig \
|
||||
xcode/Config/TestTarget.xcconfig \
|
||||
xcode/Resources/Info.plist \
|
||||
xcode/Scripts/runtests.sh \
|
||||
xcode/Scripts/versiongenerate.py \
|
||||
xcode/gtest.xcodeproj/project.pbxproj
|
||||
|
||||
# xcode sample files
|
||||
EXTRA_DIST += \
|
||||
xcode/Samples/FrameworkSample/Info.plist \
|
||||
xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj \
|
||||
xcode/Samples/FrameworkSample/runtests.sh \
|
||||
xcode/Samples/FrameworkSample/widget.cc \
|
||||
xcode/Samples/FrameworkSample/widget.h \
|
||||
xcode/Samples/FrameworkSample/widget_test.cc
|
||||
|
||||
# C++Builder project files
|
||||
EXTRA_DIST += \
|
||||
codegear/gtest.cbproj \
|
||||
codegear/gtest.groupproj \
|
||||
codegear/gtest_all.cc \
|
||||
codegear/gtest_link.cc \
|
||||
codegear/gtest_main.cbproj \
|
||||
codegear/gtest_unittest.cbproj
|
||||
|
||||
# Distribute and install M4 macro
|
||||
m4datadir = $(datadir)/aclocal
|
||||
m4data_DATA = m4/gtest.m4
|
||||
EXTRA_DIST += $(m4data_DATA)
|
||||
|
||||
# We define the global AM_CPPFLAGS as everything we compile includes from these
|
||||
# directories.
|
||||
AM_CPPFLAGS = -I$(srcdir) -I$(srcdir)/include
|
||||
|
||||
# Modifies compiler and linker flags for pthreads compatibility.
|
||||
if HAVE_PTHREADS
|
||||
AM_CXXFLAGS = @PTHREAD_CFLAGS@ -DGTEST_HAS_PTHREAD=1
|
||||
AM_LIBS = @PTHREAD_LIBS@
|
||||
else
|
||||
AM_CXXFLAGS = -DGTEST_HAS_PTHREAD=0
|
||||
endif
|
||||
|
||||
# Build rules for libraries.
|
||||
lib_LTLIBRARIES = lib/libgtest.la lib/libgtest_main.la
|
||||
|
||||
lib_libgtest_la_SOURCES = src/gtest-all.cc
|
||||
|
||||
pkginclude_HEADERS = \
|
||||
include/gtest/gtest-death-test.h \
|
||||
include/gtest/gtest-message.h \
|
||||
include/gtest/gtest-param-test.h \
|
||||
include/gtest/gtest-printers.h \
|
||||
include/gtest/gtest-spi.h \
|
||||
include/gtest/gtest-test-part.h \
|
||||
include/gtest/gtest-typed-test.h \
|
||||
include/gtest/gtest.h \
|
||||
include/gtest/gtest_pred_impl.h \
|
||||
include/gtest/gtest_prod.h
|
||||
|
||||
pkginclude_internaldir = $(pkgincludedir)/internal
|
||||
pkginclude_internal_HEADERS = \
|
||||
include/gtest/internal/gtest-death-test-internal.h \
|
||||
include/gtest/internal/gtest-filepath.h \
|
||||
include/gtest/internal/gtest-internal.h \
|
||||
include/gtest/internal/gtest-linked_ptr.h \
|
||||
include/gtest/internal/gtest-param-util-generated.h \
|
||||
include/gtest/internal/gtest-param-util.h \
|
||||
include/gtest/internal/gtest-port.h \
|
||||
include/gtest/internal/gtest-string.h \
|
||||
include/gtest/internal/gtest-tuple.h \
|
||||
include/gtest/internal/gtest-type-util.h
|
||||
|
||||
lib_libgtest_main_la_SOURCES = src/gtest_main.cc
|
||||
lib_libgtest_main_la_LIBADD = lib/libgtest.la
|
||||
|
||||
# Bulid rules for samples and tests. Automake's naming for some of
|
||||
# these variables isn't terribly obvious, so this is a brief
|
||||
# reference:
|
||||
#
|
||||
# TESTS -- Programs run automatically by "make check"
|
||||
# check_PROGRAMS -- Programs built by "make check" but not necessarily run
|
||||
|
||||
noinst_LTLIBRARIES = samples/libsamples.la
|
||||
|
||||
samples_libsamples_la_SOURCES = \
|
||||
samples/sample1.cc \
|
||||
samples/sample1.h \
|
||||
samples/sample2.cc \
|
||||
samples/sample2.h \
|
||||
samples/sample3-inl.h \
|
||||
samples/sample4.cc \
|
||||
samples/sample4.h
|
||||
|
||||
TESTS=
|
||||
TESTS_ENVIRONMENT = GTEST_SOURCE_DIR="$(srcdir)/test" \
|
||||
GTEST_BUILD_DIR="$(top_builddir)/test"
|
||||
check_PROGRAMS=
|
||||
|
||||
# A simple sample on using gtest.
|
||||
TESTS += samples/sample1_unittest
|
||||
check_PROGRAMS += samples/sample1_unittest
|
||||
samples_sample1_unittest_SOURCES = samples/sample1_unittest.cc
|
||||
samples_sample1_unittest_LDADD = lib/libgtest_main.la \
|
||||
lib/libgtest.la \
|
||||
samples/libsamples.la
|
||||
|
||||
# Another sample. It also verifies that libgtest works.
|
||||
TESTS += samples/sample10_unittest
|
||||
check_PROGRAMS += samples/sample10_unittest
|
||||
samples_sample10_unittest_SOURCES = samples/sample10_unittest.cc
|
||||
samples_sample10_unittest_LDADD = lib/libgtest.la
|
||||
|
||||
# This tests most constructs of gtest and verifies that libgtest_main
|
||||
# and libgtest work.
|
||||
TESTS += test/gtest_all_test
|
||||
check_PROGRAMS += test/gtest_all_test
|
||||
test_gtest_all_test_SOURCES = test/gtest_all_test.cc
|
||||
test_gtest_all_test_LDADD = lib/libgtest_main.la \
|
||||
lib/libgtest.la
|
||||
|
||||
# Tests that fused gtest files compile and work.
|
||||
FUSED_GTEST_SRC = \
|
||||
fused-src/gtest/gtest-all.cc \
|
||||
fused-src/gtest/gtest.h \
|
||||
fused-src/gtest/gtest_main.cc
|
||||
|
||||
if HAVE_PYTHON
|
||||
TESTS += test/fused_gtest_test
|
||||
check_PROGRAMS += test/fused_gtest_test
|
||||
test_fused_gtest_test_SOURCES = $(FUSED_GTEST_SRC) \
|
||||
samples/sample1.cc samples/sample1_unittest.cc
|
||||
test_fused_gtest_test_CPPFLAGS = -I"$(srcdir)/fused-src"
|
||||
|
||||
# Build rules for putting fused Google Test files into the distribution
|
||||
# package. The user can also create those files by manually running
|
||||
# scripts/fuse_gtest_files.py.
|
||||
$(test_fused_gtest_test_SOURCES): fused-gtest
|
||||
|
||||
fused-gtest: $(pkginclude_HEADERS) $(pkginclude_internal_HEADERS) \
|
||||
$(GTEST_SRC) src/gtest-all.cc src/gtest_main.cc \
|
||||
scripts/fuse_gtest_files.py
|
||||
mkdir -p "$(srcdir)/fused-src"
|
||||
chmod -R u+w "$(srcdir)/fused-src"
|
||||
rm -f "$(srcdir)/fused-src/gtest/gtest-all.cc"
|
||||
rm -f "$(srcdir)/fused-src/gtest/gtest.h"
|
||||
"$(srcdir)/scripts/fuse_gtest_files.py" "$(srcdir)/fused-src"
|
||||
cp -f "$(srcdir)/src/gtest_main.cc" "$(srcdir)/fused-src/gtest/"
|
||||
|
||||
maintainer-clean-local:
|
||||
rm -rf "$(srcdir)/fused-src"
|
||||
endif
|
||||
|
||||
# Death tests may produce core dumps in the build directory. In case
|
||||
# this happens, clean them to keep distcleancheck happy.
|
||||
CLEANFILES = core
|
||||
|
||||
# Disables 'make install' as installing a compiled version of Google
|
||||
# Test can lead to undefined behavior due to violation of the
|
||||
# One-Definition Rule.
|
||||
|
||||
install-exec-local:
|
||||
echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Test into your build system."
|
||||
false
|
||||
|
||||
install-data-local:
|
||||
echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Test into your build system."
|
||||
false
|
435
GTest/README
435
GTest/README
|
@ -1,435 +0,0 @@
|
|||
Google C++ Testing Framework
|
||||
============================
|
||||
|
||||
http://code.google.com/p/googletest/
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
Google's framework for writing C++ tests on a variety of platforms
|
||||
(Linux, Mac OS X, Windows, Windows CE, Symbian, etc). Based on the
|
||||
xUnit architecture. Supports automatic test discovery, a rich set of
|
||||
assertions, user-defined assertions, death tests, fatal and non-fatal
|
||||
failures, various options for running the tests, and XML test report
|
||||
generation.
|
||||
|
||||
Please see the project page above for more information as well as the
|
||||
mailing list for questions, discussions, and development. There is
|
||||
also an IRC channel on OFTC (irc.oftc.net) #gtest available. Please
|
||||
join us!
|
||||
|
||||
Requirements for End Users
|
||||
--------------------------
|
||||
|
||||
Google Test is designed to have fairly minimal requirements to build
|
||||
and use with your projects, but there are some. Currently, we support
|
||||
Linux, Windows, Mac OS X, and Cygwin. We will also make our best
|
||||
effort to support other platforms (e.g. Solaris, AIX, and z/OS).
|
||||
However, since core members of the Google Test project have no access
|
||||
to these platforms, Google Test may have outstanding issues there. If
|
||||
you notice any problems on your platform, please notify
|
||||
googletestframework@googlegroups.com. Patches for fixing them are
|
||||
even more welcome!
|
||||
|
||||
### Linux Requirements ###
|
||||
|
||||
These are the base requirements to build and use Google Test from a source
|
||||
package (as described below):
|
||||
* GNU-compatible Make or gmake
|
||||
* POSIX-standard shell
|
||||
* POSIX(-2) Regular Expressions (regex.h)
|
||||
* A C++98-standard-compliant compiler
|
||||
|
||||
### Windows Requirements ###
|
||||
|
||||
* Microsoft Visual C++ 7.1 or newer
|
||||
|
||||
### Cygwin Requirements ###
|
||||
|
||||
* Cygwin 1.5.25-14 or newer
|
||||
|
||||
### Mac OS X Requirements ###
|
||||
|
||||
* Mac OS X 10.4 Tiger or newer
|
||||
* Developer Tools Installed
|
||||
|
||||
Also, you'll need CMake 2.6.4 or higher if you want to build the
|
||||
samples using the provided CMake script, regardless of the platform.
|
||||
|
||||
Requirements for Contributors
|
||||
-----------------------------
|
||||
|
||||
We welcome patches. If you plan to contribute a patch, you need to
|
||||
build Google Test and its own tests from an SVN checkout (described
|
||||
below), which has further requirements:
|
||||
|
||||
* Python version 2.3 or newer (for running some of the tests and
|
||||
re-generating certain source files from templates)
|
||||
* CMake 2.6.4 or newer
|
||||
|
||||
Getting the Source
|
||||
------------------
|
||||
|
||||
There are two primary ways of getting Google Test's source code: you
|
||||
can download a stable source release in your preferred archive format,
|
||||
or directly check out the source from our Subversion (SVN) repositary.
|
||||
The SVN checkout requires a few extra steps and some extra software
|
||||
packages on your system, but lets you track the latest development and
|
||||
make patches much more easily, so we highly encourage it.
|
||||
|
||||
### Source Package ###
|
||||
|
||||
Google Test is released in versioned source packages which can be
|
||||
downloaded from the download page [1]. Several different archive
|
||||
formats are provided, but the only difference is the tools used to
|
||||
manipulate them, and the size of the resulting file. Download
|
||||
whichever you are most comfortable with.
|
||||
|
||||
[1] http://code.google.com/p/googletest/downloads/list
|
||||
|
||||
Once the package is downloaded, expand it using whichever tools you
|
||||
prefer for that type. This will result in a new directory with the
|
||||
name "gtest-X.Y.Z" which contains all of the source code. Here are
|
||||
some examples on Linux:
|
||||
|
||||
tar -xvzf gtest-X.Y.Z.tar.gz
|
||||
tar -xvjf gtest-X.Y.Z.tar.bz2
|
||||
unzip gtest-X.Y.Z.zip
|
||||
|
||||
### SVN Checkout ###
|
||||
|
||||
To check out the main branch (also known as the "trunk") of Google
|
||||
Test, run the following Subversion command:
|
||||
|
||||
svn checkout http://googletest.googlecode.com/svn/trunk/ gtest-svn
|
||||
|
||||
Setting up the Build
|
||||
--------------------
|
||||
|
||||
To build Google Test and your tests that use it, you need to tell your
|
||||
build system where to find its headers and source files. The exact
|
||||
way to do it depends on which build system you use, and is usually
|
||||
straightforward.
|
||||
|
||||
### Generic Build Instructions ###
|
||||
|
||||
Suppose you put Google Test in directory ${GTEST_DIR}. To build it,
|
||||
create a library build target (or a project as called by Visual Studio
|
||||
and Xcode) to compile
|
||||
|
||||
${GTEST_DIR}/src/gtest-all.cc
|
||||
|
||||
with ${GTEST_DIR}/include in the system header search path and ${GTEST_DIR}
|
||||
in the normal header search path. Assuming a Linux-like system and gcc,
|
||||
something like the following will do:
|
||||
|
||||
g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \
|
||||
-pthread -c ${GTEST_DIR}/src/gtest-all.cc
|
||||
ar -rv libgtest.a gtest-all.o
|
||||
|
||||
(We need -pthread as Google Test uses threads.)
|
||||
|
||||
Next, you should compile your test source file with
|
||||
${GTEST_DIR}/include in the system header search path, and link it
|
||||
with gtest and any other necessary libraries:
|
||||
|
||||
g++ -isystem ${GTEST_DIR}/include -pthread path/to/your_test.cc libgtest.a \
|
||||
-o your_test
|
||||
|
||||
As an example, the make/ directory contains a Makefile that you can
|
||||
use to build Google Test on systems where GNU make is available
|
||||
(e.g. Linux, Mac OS X, and Cygwin). It doesn't try to build Google
|
||||
Test's own tests. Instead, it just builds the Google Test library and
|
||||
a sample test. You can use it as a starting point for your own build
|
||||
script.
|
||||
|
||||
If the default settings are correct for your environment, the
|
||||
following commands should succeed:
|
||||
|
||||
cd ${GTEST_DIR}/make
|
||||
make
|
||||
./sample1_unittest
|
||||
|
||||
If you see errors, try to tweak the contents of make/Makefile to make
|
||||
them go away. There are instructions in make/Makefile on how to do
|
||||
it.
|
||||
|
||||
### Using CMake ###
|
||||
|
||||
Google Test comes with a CMake build script (CMakeLists.txt) that can
|
||||
be used on a wide range of platforms ("C" stands for cross-platofrm.).
|
||||
If you don't have CMake installed already, you can download it for
|
||||
free from http://www.cmake.org/.
|
||||
|
||||
CMake works by generating native makefiles or build projects that can
|
||||
be used in the compiler environment of your choice. The typical
|
||||
workflow starts with:
|
||||
|
||||
mkdir mybuild # Create a directory to hold the build output.
|
||||
cd mybuild
|
||||
cmake ${GTEST_DIR} # Generate native build scripts.
|
||||
|
||||
If you want to build Google Test's samples, you should replace the
|
||||
last command with
|
||||
|
||||
cmake -Dgtest_build_samples=ON ${GTEST_DIR}
|
||||
|
||||
If you are on a *nix system, you should now see a Makefile in the
|
||||
current directory. Just type 'make' to build gtest.
|
||||
|
||||
If you use Windows and have Vistual Studio installed, a gtest.sln file
|
||||
and several .vcproj files will be created. You can then build them
|
||||
using Visual Studio.
|
||||
|
||||
On Mac OS X with Xcode installed, a .xcodeproj file will be generated.
|
||||
|
||||
### Legacy Build Scripts ###
|
||||
|
||||
Before settling on CMake, we have been providing hand-maintained build
|
||||
projects/scripts for Visual Studio, Xcode, and Autotools. While we
|
||||
continue to provide them for convenience, they are not actively
|
||||
maintained any more. We highly recommend that you follow the
|
||||
instructions in the previous two sections to integrate Google Test
|
||||
with your existing build system.
|
||||
|
||||
If you still need to use the legacy build scripts, here's how:
|
||||
|
||||
The msvc\ folder contains two solutions with Visual C++ projects.
|
||||
Open the gtest.sln or gtest-md.sln file using Visual Studio, and you
|
||||
are ready to build Google Test the same way you build any Visual
|
||||
Studio project. Files that have names ending with -md use DLL
|
||||
versions of Microsoft runtime libraries (the /MD or the /MDd compiler
|
||||
option). Files without that suffix use static versions of the runtime
|
||||
libraries (the /MT or the /MTd option). Please note that one must use
|
||||
the same option to compile both gtest and the test code. If you use
|
||||
Visual Studio 2005 or above, we recommend the -md version as /MD is
|
||||
the default for new projects in these versions of Visual Studio.
|
||||
|
||||
On Mac OS X, open the gtest.xcodeproj in the xcode/ folder using
|
||||
Xcode. Build the "gtest" target. The universal binary framework will
|
||||
end up in your selected build directory (selected in the Xcode
|
||||
"Preferences..." -> "Building" pane and defaults to xcode/build).
|
||||
Alternatively, at the command line, enter:
|
||||
|
||||
xcodebuild
|
||||
|
||||
This will build the "Release" configuration of gtest.framework in your
|
||||
default build location. See the "xcodebuild" man page for more
|
||||
information about building different configurations and building in
|
||||
different locations.
|
||||
|
||||
If you wish to use the Google Test Xcode project with Xcode 4.x and
|
||||
above, you need to either:
|
||||
* update the SDK configuration options in xcode/Config/General.xconfig.
|
||||
Comment options SDKROOT, MACOS_DEPLOYMENT_TARGET, and GCC_VERSION. If
|
||||
you choose this route you lose the ability to target earlier versions
|
||||
of MacOS X.
|
||||
* Install an SDK for an earlier version. This doesn't appear to be
|
||||
supported by Apple, but has been reported to work
|
||||
(http://stackoverflow.com/questions/5378518).
|
||||
|
||||
Tweaking Google Test
|
||||
--------------------
|
||||
|
||||
Google Test can be used in diverse environments. The default
|
||||
configuration may not work (or may not work well) out of the box in
|
||||
some environments. However, you can easily tweak Google Test by
|
||||
defining control macros on the compiler command line. Generally,
|
||||
these macros are named like GTEST_XYZ and you define them to either 1
|
||||
or 0 to enable or disable a certain feature.
|
||||
|
||||
We list the most frequently used macros below. For a complete list,
|
||||
see file include/gtest/internal/gtest-port.h.
|
||||
|
||||
### Choosing a TR1 Tuple Library ###
|
||||
|
||||
Some Google Test features require the C++ Technical Report 1 (TR1)
|
||||
tuple library, which is not yet available with all compilers. The
|
||||
good news is that Google Test implements a subset of TR1 tuple that's
|
||||
enough for its own need, and will automatically use this when the
|
||||
compiler doesn't provide TR1 tuple.
|
||||
|
||||
Usually you don't need to care about which tuple library Google Test
|
||||
uses. However, if your project already uses TR1 tuple, you need to
|
||||
tell Google Test to use the same TR1 tuple library the rest of your
|
||||
project uses, or the two tuple implementations will clash. To do
|
||||
that, add
|
||||
|
||||
-DGTEST_USE_OWN_TR1_TUPLE=0
|
||||
|
||||
to the compiler flags while compiling Google Test and your tests. If
|
||||
you want to force Google Test to use its own tuple library, just add
|
||||
|
||||
-DGTEST_USE_OWN_TR1_TUPLE=1
|
||||
|
||||
to the compiler flags instead.
|
||||
|
||||
If you don't want Google Test to use tuple at all, add
|
||||
|
||||
-DGTEST_HAS_TR1_TUPLE=0
|
||||
|
||||
and all features using tuple will be disabled.
|
||||
|
||||
### Multi-threaded Tests ###
|
||||
|
||||
Google Test is thread-safe where the pthread library is available.
|
||||
After #include "gtest/gtest.h", you can check the GTEST_IS_THREADSAFE
|
||||
macro to see whether this is the case (yes if the macro is #defined to
|
||||
1, no if it's undefined.).
|
||||
|
||||
If Google Test doesn't correctly detect whether pthread is available
|
||||
in your environment, you can force it with
|
||||
|
||||
-DGTEST_HAS_PTHREAD=1
|
||||
|
||||
or
|
||||
|
||||
-DGTEST_HAS_PTHREAD=0
|
||||
|
||||
When Google Test uses pthread, you may need to add flags to your
|
||||
compiler and/or linker to select the pthread library, or you'll get
|
||||
link errors. If you use the CMake script or the deprecated Autotools
|
||||
script, this is taken care of for you. If you use your own build
|
||||
script, you'll need to read your compiler and linker's manual to
|
||||
figure out what flags to add.
|
||||
|
||||
### As a Shared Library (DLL) ###
|
||||
|
||||
Google Test is compact, so most users can build and link it as a
|
||||
static library for the simplicity. You can choose to use Google Test
|
||||
as a shared library (known as a DLL on Windows) if you prefer.
|
||||
|
||||
To compile *gtest* as a shared library, add
|
||||
|
||||
-DGTEST_CREATE_SHARED_LIBRARY=1
|
||||
|
||||
to the compiler flags. You'll also need to tell the linker to produce
|
||||
a shared library instead - consult your linker's manual for how to do
|
||||
it.
|
||||
|
||||
To compile your *tests* that use the gtest shared library, add
|
||||
|
||||
-DGTEST_LINKED_AS_SHARED_LIBRARY=1
|
||||
|
||||
to the compiler flags.
|
||||
|
||||
Note: while the above steps aren't technically necessary today when
|
||||
using some compilers (e.g. GCC), they may become necessary in the
|
||||
future, if we decide to improve the speed of loading the library (see
|
||||
http://gcc.gnu.org/wiki/Visibility for details). Therefore you are
|
||||
recommended to always add the above flags when using Google Test as a
|
||||
shared library. Otherwise a future release of Google Test may break
|
||||
your build script.
|
||||
|
||||
### Avoiding Macro Name Clashes ###
|
||||
|
||||
In C++, macros don't obey namespaces. Therefore two libraries that
|
||||
both define a macro of the same name will clash if you #include both
|
||||
definitions. In case a Google Test macro clashes with another
|
||||
library, you can force Google Test to rename its macro to avoid the
|
||||
conflict.
|
||||
|
||||
Specifically, if both Google Test and some other code define macro
|
||||
FOO, you can add
|
||||
|
||||
-DGTEST_DONT_DEFINE_FOO=1
|
||||
|
||||
to the compiler flags to tell Google Test to change the macro's name
|
||||
from FOO to GTEST_FOO. Currently FOO can be FAIL, SUCCEED, or TEST.
|
||||
For example, with -DGTEST_DONT_DEFINE_TEST=1, you'll need to write
|
||||
|
||||
GTEST_TEST(SomeTest, DoesThis) { ... }
|
||||
|
||||
instead of
|
||||
|
||||
TEST(SomeTest, DoesThis) { ... }
|
||||
|
||||
in order to define a test.
|
||||
|
||||
Upgrating from an Earlier Version
|
||||
---------------------------------
|
||||
|
||||
We strive to keep Google Test releases backward compatible.
|
||||
Sometimes, though, we have to make some breaking changes for the
|
||||
users' long-term benefits. This section describes what you'll need to
|
||||
do if you are upgrading from an earlier version of Google Test.
|
||||
|
||||
### Upgrading from 1.3.0 or Earlier ###
|
||||
|
||||
You may need to explicitly enable or disable Google Test's own TR1
|
||||
tuple library. See the instructions in section "Choosing a TR1 Tuple
|
||||
Library".
|
||||
|
||||
### Upgrading from 1.4.0 or Earlier ###
|
||||
|
||||
The Autotools build script (configure + make) is no longer officially
|
||||
supportted. You are encouraged to migrate to your own build system or
|
||||
use CMake. If you still need to use Autotools, you can find
|
||||
instructions in the README file from Google Test 1.4.0.
|
||||
|
||||
On platforms where the pthread library is available, Google Test uses
|
||||
it in order to be thread-safe. See the "Multi-threaded Tests" section
|
||||
for what this means to your build script.
|
||||
|
||||
If you use Microsoft Visual C++ 7.1 with exceptions disabled, Google
|
||||
Test will no longer compile. This should affect very few people, as a
|
||||
large portion of STL (including <string>) doesn't compile in this mode
|
||||
anyway. We decided to stop supporting it in order to greatly simplify
|
||||
Google Test's implementation.
|
||||
|
||||
Developing Google Test
|
||||
----------------------
|
||||
|
||||
This section discusses how to make your own changes to Google Test.
|
||||
|
||||
### Testing Google Test Itself ###
|
||||
|
||||
To make sure your changes work as intended and don't break existing
|
||||
functionality, you'll want to compile and run Google Test's own tests.
|
||||
For that you can use CMake:
|
||||
|
||||
mkdir mybuild
|
||||
cd mybuild
|
||||
cmake -Dgtest_build_tests=ON ${GTEST_DIR}
|
||||
|
||||
Make sure you have Python installed, as some of Google Test's tests
|
||||
are written in Python. If the cmake command complains about not being
|
||||
able to find Python ("Could NOT find PythonInterp (missing:
|
||||
PYTHON_EXECUTABLE)"), try telling it explicitly where your Python
|
||||
executable can be found:
|
||||
|
||||
cmake -DPYTHON_EXECUTABLE=path/to/python -Dgtest_build_tests=ON ${GTEST_DIR}
|
||||
|
||||
Next, you can build Google Test and all of its own tests. On *nix,
|
||||
this is usually done by 'make'. To run the tests, do
|
||||
|
||||
make test
|
||||
|
||||
All tests should pass.
|
||||
|
||||
### Regenerating Source Files ###
|
||||
|
||||
Some of Google Test's source files are generated from templates (not
|
||||
in the C++ sense) using a script. A template file is named FOO.pump,
|
||||
where FOO is the name of the file it will generate. For example, the
|
||||
file include/gtest/internal/gtest-type-util.h.pump is used to generate
|
||||
gtest-type-util.h in the same directory.
|
||||
|
||||
Normally you don't need to worry about regenerating the source files,
|
||||
unless you need to modify them. In that case, you should modify the
|
||||
corresponding .pump files instead and run the pump.py Python script to
|
||||
regenerate them. You can find pump.py in the scripts/ directory.
|
||||
Read the Pump manual [2] for how to use it.
|
||||
|
||||
[2] http://code.google.com/p/googletest/wiki/PumpManual
|
||||
|
||||
### Contributing a Patch ###
|
||||
|
||||
We welcome patches. Please read the Google Test developer's guide [3]
|
||||
for how you can contribute. In particular, make sure you have signed
|
||||
the Contributor License Agreement, or we won't be able to accept the
|
||||
patch.
|
||||
|
||||
[3] http://code.google.com/p/googletest/wiki/GoogleTestDevGuide
|
||||
|
||||
Happy testing!
|
|
@ -1,228 +0,0 @@
|
|||
# Defines functions and macros useful for building Google Test and
|
||||
# Google Mock.
|
||||
#
|
||||
# Note:
|
||||
#
|
||||
# - This file will be run twice when building Google Mock (once via
|
||||
# Google Test's CMakeLists.txt, and once via Google Mock's).
|
||||
# Therefore it shouldn't have any side effects other than defining
|
||||
# the functions and macros.
|
||||
#
|
||||
# - The functions/macros defined in this file may depend on Google
|
||||
# Test and Google Mock's option() definitions, and thus must be
|
||||
# called *after* the options have been defined.
|
||||
|
||||
# Tweaks CMake's default compiler/linker settings to suit Google Test's needs.
|
||||
#
|
||||
# This must be a macro(), as inside a function string() can only
|
||||
# update variables in the function scope.
|
||||
macro(fix_default_compiler_settings_)
|
||||
if (MSVC)
|
||||
# For MSVC, CMake sets certain flags to defaults we want to override.
|
||||
# This replacement code is taken from sample in the CMake Wiki at
|
||||
# http://www.cmake.org/Wiki/CMake_FAQ#Dynamic_Replace.
|
||||
foreach (flag_var
|
||||
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
|
||||
CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
|
||||
if (NOT BUILD_SHARED_LIBS AND NOT gtest_force_shared_crt)
|
||||
# When Google Test is built as a shared library, it should also use
|
||||
# shared runtime libraries. Otherwise, it may end up with multiple
|
||||
# copies of runtime library data in different modules, resulting in
|
||||
# hard-to-find crashes. When it is built as a static library, it is
|
||||
# preferable to use CRT as static libraries, as we don't have to rely
|
||||
# on CRT DLLs being available. CMake always defaults to using shared
|
||||
# CRT libraries, so we override that default here.
|
||||
string(REPLACE "/MD" "-MT" ${flag_var} "${${flag_var}}")
|
||||
endif()
|
||||
|
||||
# We prefer more strict warning checking for building Google Test.
|
||||
# Replaces /W3 with /W4 in defaults.
|
||||
string(REPLACE "/W3" "-W4" ${flag_var} "${${flag_var}}")
|
||||
endforeach()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Defines the compiler/linker flags used to build Google Test and
|
||||
# Google Mock. You can tweak these definitions to suit your need. A
|
||||
# variable's value is empty before it's explicitly assigned to.
|
||||
macro(config_compiler_and_linker)
|
||||
if (NOT gtest_disable_pthreads)
|
||||
# Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT.
|
||||
find_package(Threads)
|
||||
endif()
|
||||
|
||||
fix_default_compiler_settings_()
|
||||
if (MSVC)
|
||||
# Newlines inside flags variables break CMake's NMake generator.
|
||||
# TODO(vladl@google.com): Add -RTCs and -RTCu to debug builds.
|
||||
set(cxx_base_flags "-GS -W4 -WX -wd4127 -wd4251 -wd4275 -nologo -J -Zi")
|
||||
if (MSVC_VERSION LESS 1400)
|
||||
# Suppress spurious warnings MSVC 7.1 sometimes issues.
|
||||
# Forcing value to bool.
|
||||
set(cxx_base_flags "${cxx_base_flags} -wd4800")
|
||||
# Copy constructor and assignment operator could not be generated.
|
||||
set(cxx_base_flags "${cxx_base_flags} -wd4511 -wd4512")
|
||||
# Compatibility warnings not applicable to Google Test.
|
||||
# Resolved overload was found by argument-dependent lookup.
|
||||
set(cxx_base_flags "${cxx_base_flags} -wd4675")
|
||||
endif()
|
||||
set(cxx_base_flags "${cxx_base_flags} -D_UNICODE -DUNICODE -DWIN32 -D_WIN32")
|
||||
set(cxx_base_flags "${cxx_base_flags} -DSTRICT -DWIN32_LEAN_AND_MEAN")
|
||||
set(cxx_exception_flags "-EHsc -D_HAS_EXCEPTIONS=1")
|
||||
set(cxx_no_exception_flags "-D_HAS_EXCEPTIONS=0")
|
||||
set(cxx_no_rtti_flags "-GR-")
|
||||
add_definitions(-D_VARIADIC_MAX=10)
|
||||
elseif (CMAKE_COMPILER_IS_GNUCXX)
|
||||
set(cxx_base_flags "-Wall -Wshadow")
|
||||
set(cxx_exception_flags "-fexceptions")
|
||||
set(cxx_no_exception_flags "-fno-exceptions")
|
||||
# Until version 4.3.2, GCC doesn't define a macro to indicate
|
||||
# whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI
|
||||
# explicitly.
|
||||
set(cxx_no_rtti_flags "-fno-rtti -DGTEST_HAS_RTTI=0")
|
||||
set(cxx_strict_flags
|
||||
"-Wextra -Wno-unused-parameter -Wno-missing-field-initializers")
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "SunPro")
|
||||
set(cxx_exception_flags "-features=except")
|
||||
# Sun Pro doesn't provide macros to indicate whether exceptions and
|
||||
# RTTI are enabled, so we define GTEST_HAS_* explicitly.
|
||||
set(cxx_no_exception_flags "-features=no%except -DGTEST_HAS_EXCEPTIONS=0")
|
||||
set(cxx_no_rtti_flags "-features=no%rtti -DGTEST_HAS_RTTI=0")
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "VisualAge" OR
|
||||
CMAKE_CXX_COMPILER_ID STREQUAL "XL")
|
||||
# CMake 2.8 changes Visual Age's compiler ID to "XL".
|
||||
set(cxx_exception_flags "-qeh")
|
||||
set(cxx_no_exception_flags "-qnoeh")
|
||||
# Until version 9.0, Visual Age doesn't define a macro to indicate
|
||||
# whether RTTI is enabled. Therefore we define GTEST_HAS_RTTI
|
||||
# explicitly.
|
||||
set(cxx_no_rtti_flags "-qnortti -DGTEST_HAS_RTTI=0")
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "HP")
|
||||
set(cxx_base_flags "-AA -mt")
|
||||
set(cxx_exception_flags "-DGTEST_HAS_EXCEPTIONS=1")
|
||||
set(cxx_no_exception_flags "+noeh -DGTEST_HAS_EXCEPTIONS=0")
|
||||
# RTTI can not be disabled in HP aCC compiler.
|
||||
set(cxx_no_rtti_flags "")
|
||||
endif()
|
||||
|
||||
if (CMAKE_USE_PTHREADS_INIT AND NOT MINGW) # The pthreads library is available and allowed.
|
||||
set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=1")
|
||||
else()
|
||||
set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=0")
|
||||
endif()
|
||||
|
||||
# For building gtest's own tests and samples.
|
||||
set(cxx_exception "${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_exception_flags}")
|
||||
set(cxx_no_exception
|
||||
"${CMAKE_CXX_FLAGS} ${cxx_base_flags} ${cxx_no_exception_flags}")
|
||||
set(cxx_default "${cxx_exception}")
|
||||
set(cxx_no_rtti "${cxx_default} ${cxx_no_rtti_flags}")
|
||||
set(cxx_use_own_tuple "${cxx_default} -DGTEST_USE_OWN_TR1_TUPLE=1")
|
||||
|
||||
# For building the gtest libraries.
|
||||
set(cxx_strict "${cxx_default} ${cxx_strict_flags}")
|
||||
endmacro()
|
||||
|
||||
# Defines the gtest & gtest_main libraries. User tests should link
|
||||
# with one of them.
|
||||
function(cxx_library_with_type name type cxx_flags)
|
||||
# type can be either STATIC or SHARED to denote a static or shared library.
|
||||
# ARGN refers to additional arguments after 'cxx_flags'.
|
||||
add_library(${name} ${type} ${ARGN})
|
||||
set_target_properties(${name}
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "${cxx_flags}")
|
||||
if (BUILD_SHARED_LIBS OR type STREQUAL "SHARED")
|
||||
set_target_properties(${name}
|
||||
PROPERTIES
|
||||
COMPILE_DEFINITIONS "GTEST_CREATE_SHARED_LIBRARY=1")
|
||||
endif()
|
||||
if (CMAKE_USE_PTHREADS_INIT)
|
||||
target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# Helper functions for creating build targets.
|
||||
|
||||
function(cxx_shared_library name cxx_flags)
|
||||
cxx_library_with_type(${name} SHARED "${cxx_flags}" ${ARGN})
|
||||
endfunction()
|
||||
|
||||
function(cxx_library name cxx_flags)
|
||||
cxx_library_with_type(${name} "" "${cxx_flags}" ${ARGN})
|
||||
endfunction()
|
||||
|
||||
# cxx_executable_with_flags(name cxx_flags libs srcs...)
|
||||
#
|
||||
# creates a named C++ executable that depends on the given libraries and
|
||||
# is built from the given source files with the given compiler flags.
|
||||
function(cxx_executable_with_flags name cxx_flags libs)
|
||||
add_executable(${name} ${ARGN})
|
||||
if (cxx_flags)
|
||||
set_target_properties(${name}
|
||||
PROPERTIES
|
||||
COMPILE_FLAGS "${cxx_flags}")
|
||||
endif()
|
||||
if (BUILD_SHARED_LIBS)
|
||||
set_target_properties(${name}
|
||||
PROPERTIES
|
||||
COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1")
|
||||
endif()
|
||||
# To support mixing linking in static and dynamic libraries, link each
|
||||
# library in with an extra call to target_link_libraries.
|
||||
foreach (lib "${libs}")
|
||||
target_link_libraries(${name} ${lib})
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
# cxx_executable(name dir lib srcs...)
|
||||
#
|
||||
# creates a named target that depends on the given libs and is built
|
||||
# from the given source files. dir/name.cc is implicitly included in
|
||||
# the source file list.
|
||||
function(cxx_executable name dir libs)
|
||||
cxx_executable_with_flags(
|
||||
${name} "${cxx_default}" "${libs}" "${dir}/${name}.cc" ${ARGN})
|
||||
endfunction()
|
||||
|
||||
# Sets PYTHONINTERP_FOUND and PYTHON_EXECUTABLE.
|
||||
find_package(PythonInterp)
|
||||
|
||||
# cxx_test_with_flags(name cxx_flags libs srcs...)
|
||||
#
|
||||
# creates a named C++ test that depends on the given libs and is built
|
||||
# from the given source files with the given compiler flags.
|
||||
function(cxx_test_with_flags name cxx_flags libs)
|
||||
cxx_executable_with_flags(${name} "${cxx_flags}" "${libs}" ${ARGN})
|
||||
add_test(${name} ${name})
|
||||
endfunction()
|
||||
|
||||
# cxx_test(name libs srcs...)
|
||||
#
|
||||
# creates a named test target that depends on the given libs and is
|
||||
# built from the given source files. Unlike cxx_test_with_flags,
|
||||
# test/name.cc is already implicitly included in the source file list.
|
||||
function(cxx_test name libs)
|
||||
cxx_test_with_flags("${name}" "${cxx_default}" "${libs}"
|
||||
"test/${name}.cc" ${ARGN})
|
||||
endfunction()
|
||||
|
||||
# py_test(name)
|
||||
#
|
||||
# creates a Python test with the given name whose main module is in
|
||||
# test/name.py. It does nothing if Python is not installed.
|
||||
function(py_test name)
|
||||
# We are not supporting Python tests on Linux yet as they consider
|
||||
# all Linux environments to be google3 and try to use google3 features.
|
||||
if (PYTHONINTERP_FOUND)
|
||||
# ${CMAKE_BINARY_DIR} is known at configuration time, so we can
|
||||
# directly bind it from cmake. ${CTEST_CONFIGURATION_TYPE} is known
|
||||
# only at ctest runtime (by calling ctest -c <Configuration>), so
|
||||
# we have to escape $ to delay variable substitution here.
|
||||
add_test(${name}
|
||||
${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py
|
||||
--build_dir=${CMAKE_CURRENT_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE})
|
||||
endif()
|
||||
endfunction()
|
|
@ -1,138 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{bca37a72-5b07-46cf-b44e-89f8e06451a2}</ProjectGuid>
|
||||
<Config Condition="'$(Config)'==''">Release</Config>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
|
||||
<Base>true</Base>
|
||||
<Cfg_1>true</Cfg_1>
|
||||
<CfgParent>Base</CfgParent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
|
||||
<Base>true</Base>
|
||||
<Cfg_2>true</Cfg_2>
|
||||
<CfgParent>Base</CfgParent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base)'!=''">
|
||||
<BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
|
||||
<OutputExt>lib</OutputExt>
|
||||
<DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
|
||||
<Defines>NO_STRICT</Defines>
|
||||
<DynamicRTL>true</DynamicRTL>
|
||||
<UsePackages>true</UsePackages>
|
||||
<ProjectType>CppStaticLibrary</ProjectType>
|
||||
<BCC_CPPCompileAlways>true</BCC_CPPCompileAlways>
|
||||
<PackageImports>rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;dclZipForged11.bpi;vclZipForged11.bpi;GR32_BDS2006.bpi;GR32_DSGN_BDS2006.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi;CExceptionExpert11.bpi</PackageImports>
|
||||
<BCC_wpar>false</BCC_wpar>
|
||||
<IncludePath>$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</IncludePath>
|
||||
<AllPackageLibs>rtl.lib;vcl.lib</AllPackageLibs>
|
||||
<TLIB_PageSize>32</TLIB_PageSize>
|
||||
<ILINK_LibraryPath>$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk</ILINK_LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_1)'!=''">
|
||||
<BCC_OptimizeForSpeed>false</BCC_OptimizeForSpeed>
|
||||
<DCC_Optimize>false</DCC_Optimize>
|
||||
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
|
||||
<Defines>_DEBUG;$(Defines)</Defines>
|
||||
<ILINK_FullDebugInfo>true</ILINK_FullDebugInfo>
|
||||
<BCC_InlineFunctionExpansion>false</BCC_InlineFunctionExpansion>
|
||||
<ILINK_DisableIncrementalLinking>true</ILINK_DisableIncrementalLinking>
|
||||
<BCC_UseRegisterVariables>None</BCC_UseRegisterVariables>
|
||||
<DCC_Define>DEBUG</DCC_Define>
|
||||
<BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
|
||||
<IntermediateOutputDir>Debug</IntermediateOutputDir>
|
||||
<TASM_DisplaySourceLines>true</TASM_DisplaySourceLines>
|
||||
<BCC_StackFrames>true</BCC_StackFrames>
|
||||
<BCC_DisableOptimizations>true</BCC_DisableOptimizations>
|
||||
<ILINK_LibraryPath>$(BDS)\lib\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
|
||||
<TASM_Debugging>Full</TASM_Debugging>
|
||||
<BCC_SourceDebuggingOn>true</BCC_SourceDebuggingOn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_2)'!=''">
|
||||
<Defines>NDEBUG;$(Defines)</Defines>
|
||||
<IntermediateOutputDir>Release</IntermediateOutputDir>
|
||||
<ILINK_LibraryPath>$(BDS)\lib\release;$(ILINK_LibraryPath)</ILINK_LibraryPath>
|
||||
<TASM_Debugging>None</TASM_Debugging>
|
||||
</PropertyGroup>
|
||||
<ProjectExtensions>
|
||||
<Borland.Personality>CPlusPlusBuilder.Personality</Borland.Personality>
|
||||
<Borland.ProjectType>CppStaticLibrary</Borland.ProjectType>
|
||||
<BorlandProject>
|
||||
<BorlandProject><CPlusPlusBuilder.Personality><VersionInfo><VersionInfo Name="IncludeVerInfo">False</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">1</VersionInfo><VersionInfo Name="MinorVer">0</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo Name="Private">False</VersionInfo><VersionInfo Name="DLL">False</VersionInfo><VersionInfo Name="Locale">1033</VersionInfo><VersionInfo Name="CodePage">1252</VersionInfo></VersionInfo><VersionInfoKeys><VersionInfoKeys Name="CompanyName"></VersionInfoKeys><VersionInfoKeys Name="FileDescription"></VersionInfoKeys><VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="InternalName"></VersionInfoKeys><VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys><VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys><VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys><VersionInfoKeys Name="ProductName"></VersionInfoKeys><VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="Comments"></VersionInfoKeys></VersionInfoKeys><Debugging><Debugging Name="DebugSourceDirs"></Debugging></Debugging><Parameters><Parameters Name="RunParams"></Parameters><Parameters Name="Launcher"></Parameters><Parameters Name="UseLauncher">False</Parameters><Parameters Name="DebugCWD"></Parameters><Parameters Name="HostApplication"></Parameters><Parameters Name="RemoteHost"></Parameters><Parameters Name="RemotePath"></Parameters><Parameters Name="RemoteParams"></Parameters><Parameters Name="RemoteLauncher"></Parameters><Parameters Name="UseRemoteLauncher">False</Parameters><Parameters Name="RemoteCWD"></Parameters><Parameters Name="RemoteDebug">False</Parameters><Parameters Name="Debug Symbols Search Path"></Parameters><Parameters Name="LoadAllSymbols">True</Parameters><Parameters Name="LoadUnspecifiedSymbols">False</Parameters></Parameters><Excluded_Packages>
|
||||
|
||||
|
||||
<Excluded_Packages Name="$(BDS)\bin\bcboffice2k100.bpl">CodeGear C++Builder Office 2000 Servers Package</Excluded_Packages>
|
||||
<Excluded_Packages Name="$(BDS)\bin\bcbofficexp100.bpl">CodeGear C++Builder Office XP Servers Package</Excluded_Packages>
|
||||
</Excluded_Packages><Linker><Linker Name="LibPrefix"></Linker><Linker Name="LibSuffix"></Linker><Linker Name="LibVersion"></Linker></Linker><ProjectProperties><ProjectProperties Name="AutoShowDeps">False</ProjectProperties><ProjectProperties Name="ManagePaths">True</ProjectProperties><ProjectProperties Name="VerifyPackages">True</ProjectProperties></ProjectProperties><HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Count">3</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item0">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item1">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item2">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\src;..\include</HistoryLists_hlIncludePath></HistoryLists_hlIncludePath><HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Count">1</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item0">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk</HistoryLists_hlILINK_LibraryPath></HistoryLists_hlILINK_LibraryPath><HistoryLists_hlDefines><HistoryLists_hlDefines Name="Count">1</HistoryLists_hlDefines><HistoryLists_hlDefines Name="Item0">NO_STRICT</HistoryLists_hlDefines></HistoryLists_hlDefines><HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Count">1</HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Item0">32</HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Item1">16</HistoryLists_hlTLIB_PageSize></HistoryLists_hlTLIB_PageSize></CPlusPlusBuilder.Personality></BorlandProject></BorlandProject>
|
||||
</ProjectExtensions>
|
||||
<Import Project="$(MSBuildBinPath)\Borland.Cpp.Targets" />
|
||||
<ItemGroup>
|
||||
<None Include="..\include\gtest\gtest-death-test.h">
|
||||
<BuildOrder>3</BuildOrder>
|
||||
</None>
|
||||
<None Include="..\include\gtest\gtest-message.h">
|
||||
<BuildOrder>4</BuildOrder>
|
||||
</None>
|
||||
<None Include="..\include\gtest\gtest-param-test.h">
|
||||
<BuildOrder>5</BuildOrder>
|
||||
</None>
|
||||
<None Include="..\include\gtest\gtest-spi.h">
|
||||
<BuildOrder>6</BuildOrder>
|
||||
</None>
|
||||
<None Include="..\include\gtest\gtest-test-part.h">
|
||||
<BuildOrder>7</BuildOrder>
|
||||
</None>
|
||||
<None Include="..\include\gtest\gtest-typed-test.h">
|
||||
<BuildOrder>8</BuildOrder>
|
||||
</None>
|
||||
<None Include="..\include\gtest\gtest.h">
|
||||
<BuildOrder>0</BuildOrder>
|
||||
</None>
|
||||
<None Include="..\include\gtest\gtest_pred_impl.h">
|
||||
<BuildOrder>1</BuildOrder>
|
||||
</None>
|
||||
<None Include="..\include\gtest\gtest_prod.h">
|
||||
<BuildOrder>2</BuildOrder>
|
||||
</None>
|
||||
<None Include="..\include\gtest\internal\gtest-death-test-internal.h">
|
||||
<BuildOrder>9</BuildOrder>
|
||||
</None>
|
||||
<None Include="..\include\gtest\internal\gtest-filepath.h">
|
||||
<BuildOrder>10</BuildOrder>
|
||||
</None>
|
||||
<None Include="..\include\gtest\internal\gtest-internal.h">
|
||||
<BuildOrder>11</BuildOrder>
|
||||
</None>
|
||||
<None Include="..\include\gtest\internal\gtest-linked_ptr.h">
|
||||
<BuildOrder>12</BuildOrder>
|
||||
</None>
|
||||
<None Include="..\include\gtest\internal\gtest-param-util-generated.h">
|
||||
<BuildOrder>14</BuildOrder>
|
||||
</None>
|
||||
<None Include="..\include\gtest\internal\gtest-param-util.h">
|
||||
<BuildOrder>13</BuildOrder>
|
||||
</None>
|
||||
<None Include="..\include\gtest\internal\gtest-port.h">
|
||||
<BuildOrder>15</BuildOrder>
|
||||
</None>
|
||||
<None Include="..\include\gtest\internal\gtest-string.h">
|
||||
<BuildOrder>16</BuildOrder>
|
||||
</None>
|
||||
<None Include="..\include\gtest\internal\gtest-type-util.h">
|
||||
<BuildOrder>17</BuildOrder>
|
||||
</None>
|
||||
<CppCompile Include="gtest_all.cc">
|
||||
<BuildOrder>18</BuildOrder>
|
||||
</CppCompile>
|
||||
<BuildConfiguration Include="Debug">
|
||||
<Key>Cfg_1</Key>
|
||||
</BuildConfiguration>
|
||||
<BuildConfiguration Include="Release">
|
||||
<Key>Cfg_2</Key>
|
||||
</BuildConfiguration>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,54 +0,0 @@
|
|||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{c1d923e0-6cba-4332-9b6f-3420acbf5091}</ProjectGuid>
|
||||
</PropertyGroup>
|
||||
<ItemGroup />
|
||||
<ItemGroup>
|
||||
<Projects Include="gtest.cbproj" />
|
||||
<Projects Include="gtest_main.cbproj" />
|
||||
<Projects Include="gtest_unittest.cbproj" />
|
||||
</ItemGroup>
|
||||
<ProjectExtensions>
|
||||
<Borland.Personality>Default.Personality</Borland.Personality>
|
||||
<Borland.ProjectType />
|
||||
<BorlandProject>
|
||||
<BorlandProject xmlns=""><Default.Personality></Default.Personality></BorlandProject></BorlandProject>
|
||||
</ProjectExtensions>
|
||||
<Target Name="gtest">
|
||||
<MSBuild Projects="gtest.cbproj" Targets="" />
|
||||
</Target>
|
||||
<Target Name="gtest:Clean">
|
||||
<MSBuild Projects="gtest.cbproj" Targets="Clean" />
|
||||
</Target>
|
||||
<Target Name="gtest:Make">
|
||||
<MSBuild Projects="gtest.cbproj" Targets="Make" />
|
||||
</Target>
|
||||
<Target Name="gtest_main">
|
||||
<MSBuild Projects="gtest_main.cbproj" Targets="" />
|
||||
</Target>
|
||||
<Target Name="gtest_main:Clean">
|
||||
<MSBuild Projects="gtest_main.cbproj" Targets="Clean" />
|
||||
</Target>
|
||||
<Target Name="gtest_main:Make">
|
||||
<MSBuild Projects="gtest_main.cbproj" Targets="Make" />
|
||||
</Target>
|
||||
<Target Name="gtest_unittest">
|
||||
<MSBuild Projects="gtest_unittest.cbproj" Targets="" />
|
||||
</Target>
|
||||
<Target Name="gtest_unittest:Clean">
|
||||
<MSBuild Projects="gtest_unittest.cbproj" Targets="Clean" />
|
||||
</Target>
|
||||
<Target Name="gtest_unittest:Make">
|
||||
<MSBuild Projects="gtest_unittest.cbproj" Targets="Make" />
|
||||
</Target>
|
||||
<Target Name="Build">
|
||||
<CallTarget Targets="gtest;gtest_main;gtest_unittest" />
|
||||
</Target>
|
||||
<Target Name="Clean">
|
||||
<CallTarget Targets="gtest:Clean;gtest_main:Clean;gtest_unittest:Clean" />
|
||||
</Target>
|
||||
<Target Name="Make">
|
||||
<CallTarget Targets="gtest:Make;gtest_main:Make;gtest_unittest:Make" />
|
||||
</Target>
|
||||
<Import Condition="Exists('$(MSBuildBinPath)\Borland.Group.Targets')" Project="$(MSBuildBinPath)\Borland.Group.Targets" />
|
||||
</Project>
|
|
@ -1,38 +0,0 @@
|
|||
// Copyright 2009, Google 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:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: Josh Kelley (joshkel@gmail.com)
|
||||
//
|
||||
// Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// C++Builder's IDE cannot build a static library from files with hyphens
|
||||
// in their name. See http://qc.codegear.com/wc/qcmain.aspx?d=70977 .
|
||||
// This file serves as a workaround.
|
||||
|
||||
#include "src/gtest-all.cc"
|
|
@ -1,40 +0,0 @@
|
|||
// Copyright 2009, Google 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:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: Josh Kelley (joshkel@gmail.com)
|
||||
//
|
||||
// Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// Links gtest.lib and gtest_main.lib into the current project in C++Builder.
|
||||
// This means that these libraries can't be renamed, but it's the only way to
|
||||
// ensure that Debug versus Release test builds are linked against the
|
||||
// appropriate Debug or Release build of the libraries.
|
||||
|
||||
#pragma link "gtest.lib"
|
||||
#pragma link "gtest_main.lib"
|
|
@ -1,82 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{bca37a72-5b07-46cf-b44e-89f8e06451a2}</ProjectGuid>
|
||||
<Config Condition="'$(Config)'==''">Release</Config>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
|
||||
<Base>true</Base>
|
||||
<Cfg_1>true</Cfg_1>
|
||||
<CfgParent>Base</CfgParent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
|
||||
<Base>true</Base>
|
||||
<Cfg_2>true</Cfg_2>
|
||||
<CfgParent>Base</CfgParent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base)'!=''">
|
||||
<BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
|
||||
<OutputExt>lib</OutputExt>
|
||||
<DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
|
||||
<Defines>NO_STRICT</Defines>
|
||||
<DynamicRTL>true</DynamicRTL>
|
||||
<UsePackages>true</UsePackages>
|
||||
<ProjectType>CppStaticLibrary</ProjectType>
|
||||
<BCC_CPPCompileAlways>true</BCC_CPPCompileAlways>
|
||||
<PackageImports>rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;dclZipForged11.bpi;vclZipForged11.bpi;GR32_BDS2006.bpi;GR32_DSGN_BDS2006.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi;CExceptionExpert11.bpi</PackageImports>
|
||||
<BCC_wpar>false</BCC_wpar>
|
||||
<IncludePath>$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</IncludePath>
|
||||
<AllPackageLibs>rtl.lib;vcl.lib</AllPackageLibs>
|
||||
<TLIB_PageSize>32</TLIB_PageSize>
|
||||
<ILINK_LibraryPath>$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk</ILINK_LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_1)'!=''">
|
||||
<BCC_OptimizeForSpeed>false</BCC_OptimizeForSpeed>
|
||||
<DCC_Optimize>false</DCC_Optimize>
|
||||
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
|
||||
<Defines>_DEBUG;$(Defines)</Defines>
|
||||
<ILINK_FullDebugInfo>true</ILINK_FullDebugInfo>
|
||||
<BCC_InlineFunctionExpansion>false</BCC_InlineFunctionExpansion>
|
||||
<ILINK_DisableIncrementalLinking>true</ILINK_DisableIncrementalLinking>
|
||||
<BCC_UseRegisterVariables>None</BCC_UseRegisterVariables>
|
||||
<DCC_Define>DEBUG</DCC_Define>
|
||||
<BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
|
||||
<IntermediateOutputDir>Debug</IntermediateOutputDir>
|
||||
<TASM_DisplaySourceLines>true</TASM_DisplaySourceLines>
|
||||
<BCC_StackFrames>true</BCC_StackFrames>
|
||||
<BCC_DisableOptimizations>true</BCC_DisableOptimizations>
|
||||
<ILINK_LibraryPath>$(BDS)\lib\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
|
||||
<TASM_Debugging>Full</TASM_Debugging>
|
||||
<BCC_SourceDebuggingOn>true</BCC_SourceDebuggingOn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_2)'!=''">
|
||||
<Defines>NDEBUG;$(Defines)</Defines>
|
||||
<IntermediateOutputDir>Release</IntermediateOutputDir>
|
||||
<ILINK_LibraryPath>$(BDS)\lib\release;$(ILINK_LibraryPath)</ILINK_LibraryPath>
|
||||
<TASM_Debugging>None</TASM_Debugging>
|
||||
</PropertyGroup>
|
||||
<ProjectExtensions>
|
||||
<Borland.Personality>CPlusPlusBuilder.Personality</Borland.Personality>
|
||||
<Borland.ProjectType>CppStaticLibrary</Borland.ProjectType>
|
||||
<BorlandProject>
|
||||
<BorlandProject><CPlusPlusBuilder.Personality><VersionInfo><VersionInfo Name="IncludeVerInfo">False</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">1</VersionInfo><VersionInfo Name="MinorVer">0</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo Name="Private">False</VersionInfo><VersionInfo Name="DLL">False</VersionInfo><VersionInfo Name="Locale">1033</VersionInfo><VersionInfo Name="CodePage">1252</VersionInfo></VersionInfo><VersionInfoKeys><VersionInfoKeys Name="CompanyName"></VersionInfoKeys><VersionInfoKeys Name="FileDescription"></VersionInfoKeys><VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="InternalName"></VersionInfoKeys><VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys><VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys><VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys><VersionInfoKeys Name="ProductName"></VersionInfoKeys><VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="Comments"></VersionInfoKeys></VersionInfoKeys><Debugging><Debugging Name="DebugSourceDirs"></Debugging></Debugging><Parameters><Parameters Name="RunParams"></Parameters><Parameters Name="Launcher"></Parameters><Parameters Name="UseLauncher">False</Parameters><Parameters Name="DebugCWD"></Parameters><Parameters Name="HostApplication"></Parameters><Parameters Name="RemoteHost"></Parameters><Parameters Name="RemotePath"></Parameters><Parameters Name="RemoteParams"></Parameters><Parameters Name="RemoteLauncher"></Parameters><Parameters Name="UseRemoteLauncher">False</Parameters><Parameters Name="RemoteCWD"></Parameters><Parameters Name="RemoteDebug">False</Parameters><Parameters Name="Debug Symbols Search Path"></Parameters><Parameters Name="LoadAllSymbols">True</Parameters><Parameters Name="LoadUnspecifiedSymbols">False</Parameters></Parameters><Excluded_Packages>
|
||||
<Excluded_Packages Name="$(BDS)\bin\bcboffice2k100.bpl">CodeGear C++Builder Office 2000 Servers Package</Excluded_Packages>
|
||||
<Excluded_Packages Name="$(BDS)\bin\bcbofficexp100.bpl">CodeGear C++Builder Office XP Servers Package</Excluded_Packages>
|
||||
</Excluded_Packages><Linker><Linker Name="LibPrefix"></Linker><Linker Name="LibSuffix"></Linker><Linker Name="LibVersion"></Linker></Linker><ProjectProperties><ProjectProperties Name="AutoShowDeps">False</ProjectProperties><ProjectProperties Name="ManagePaths">True</ProjectProperties><ProjectProperties Name="VerifyPackages">True</ProjectProperties></ProjectProperties><HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Count">3</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item0">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item1">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item2">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\src;..\include</HistoryLists_hlIncludePath></HistoryLists_hlIncludePath><HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Count">1</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item0">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk</HistoryLists_hlILINK_LibraryPath></HistoryLists_hlILINK_LibraryPath><HistoryLists_hlDefines><HistoryLists_hlDefines Name="Count">1</HistoryLists_hlDefines><HistoryLists_hlDefines Name="Item0">NO_STRICT</HistoryLists_hlDefines></HistoryLists_hlDefines><HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Count">1</HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Item0">32</HistoryLists_hlTLIB_PageSize><HistoryLists_hlTLIB_PageSize Name="Item1">16</HistoryLists_hlTLIB_PageSize></HistoryLists_hlTLIB_PageSize></CPlusPlusBuilder.Personality></BorlandProject></BorlandProject>
|
||||
</ProjectExtensions>
|
||||
<Import Project="$(MSBuildBinPath)\Borland.Cpp.Targets" />
|
||||
<ItemGroup>
|
||||
<CppCompile Include="..\src\gtest_main.cc">
|
||||
<BuildOrder>0</BuildOrder>
|
||||
</CppCompile>
|
||||
<BuildConfiguration Include="Debug">
|
||||
<Key>Cfg_1</Key>
|
||||
</BuildConfiguration>
|
||||
<BuildConfiguration Include="Release">
|
||||
<Key>Cfg_2</Key>
|
||||
</BuildConfiguration>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,88 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectGuid>{eea63393-5ac5-4b9c-8909-d75fef2daa41}</ProjectGuid>
|
||||
<Config Condition="'$(Config)'==''">Release</Config>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
|
||||
<Base>true</Base>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
|
||||
<Base>true</Base>
|
||||
<Cfg_1>true</Cfg_1>
|
||||
<CfgParent>Base</CfgParent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
|
||||
<Base>true</Base>
|
||||
<Cfg_2>true</Cfg_2>
|
||||
<CfgParent>Base</CfgParent>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Base)'!=''">
|
||||
<OutputExt>exe</OutputExt>
|
||||
<BCC_OptimizeForSpeed>true</BCC_OptimizeForSpeed>
|
||||
<Defines>NO_STRICT</Defines>
|
||||
<DCC_CBuilderOutput>JPHNE</DCC_CBuilderOutput>
|
||||
<DynamicRTL>true</DynamicRTL>
|
||||
<ILINK_ObjectSearchPath>..\test</ILINK_ObjectSearchPath>
|
||||
<UsePackages>true</UsePackages>
|
||||
<ProjectType>CppConsoleApplication</ProjectType>
|
||||
<NoVCL>true</NoVCL>
|
||||
<BCC_CPPCompileAlways>true</BCC_CPPCompileAlways>
|
||||
<PackageImports>rtl.bpi;vcl.bpi;bcbie.bpi;vclx.bpi;vclactnband.bpi;xmlrtl.bpi;bcbsmp.bpi;dbrtl.bpi;vcldb.bpi;bdertl.bpi;vcldbx.bpi;dsnap.bpi;dsnapcon.bpi;vclib.bpi;ibxpress.bpi;adortl.bpi;dbxcds.bpi;dbexpress.bpi;DbxCommonDriver.bpi;websnap.bpi;vclie.bpi;webdsnap.bpi;inet.bpi;inetdbbde.bpi;inetdbxpress.bpi;soaprtl.bpi;Rave75VCL.bpi;teeUI.bpi;tee.bpi;teedb.bpi;IndyCore.bpi;IndySystem.bpi;IndyProtocols.bpi;IntrawebDB_90_100.bpi;Intraweb_90_100.bpi;Jcl.bpi;JclVcl.bpi;JvCoreD11R.bpi;JvSystemD11R.bpi;JvStdCtrlsD11R.bpi;JvAppFrmD11R.bpi;JvBandsD11R.bpi;JvDBD11R.bpi;JvDlgsD11R.bpi;JvBDED11R.bpi;JvCmpD11R.bpi;JvCryptD11R.bpi;JvCtrlsD11R.bpi;JvCustomD11R.bpi;JvDockingD11R.bpi;JvDotNetCtrlsD11R.bpi;JvEDID11R.bpi;JvGlobusD11R.bpi;JvHMID11R.bpi;JvInterpreterD11R.bpi;JvJansD11R.bpi;JvManagedThreadsD11R.bpi;JvMMD11R.bpi;JvNetD11R.bpi;JvPageCompsD11R.bpi;JvPluginD11R.bpi;JvPrintPreviewD11R.bpi;JvRuntimeDesignD11R.bpi;JvTimeFrameworkD11R.bpi;JvValidatorsD11R.bpi;JvWizardD11R.bpi;JvXPCtrlsD11R.bpi;VclSmp.bpi</PackageImports>
|
||||
<BCC_wpar>false</BCC_wpar>
|
||||
<IncludePath>$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test;..</IncludePath>
|
||||
<ILINK_LibraryPath>$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test</ILINK_LibraryPath>
|
||||
<Multithreaded>true</Multithreaded>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_1)'!=''">
|
||||
<BCC_OptimizeForSpeed>false</BCC_OptimizeForSpeed>
|
||||
<DCC_Optimize>false</DCC_Optimize>
|
||||
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
|
||||
<Defines>_DEBUG;$(Defines)</Defines>
|
||||
<ILINK_FullDebugInfo>true</ILINK_FullDebugInfo>
|
||||
<BCC_InlineFunctionExpansion>false</BCC_InlineFunctionExpansion>
|
||||
<ILINK_DisableIncrementalLinking>true</ILINK_DisableIncrementalLinking>
|
||||
<BCC_UseRegisterVariables>None</BCC_UseRegisterVariables>
|
||||
<DCC_Define>DEBUG</DCC_Define>
|
||||
<BCC_DebugLineNumbers>true</BCC_DebugLineNumbers>
|
||||
<IntermediateOutputDir>Debug</IntermediateOutputDir>
|
||||
<TASM_DisplaySourceLines>true</TASM_DisplaySourceLines>
|
||||
<BCC_StackFrames>true</BCC_StackFrames>
|
||||
<BCC_DisableOptimizations>true</BCC_DisableOptimizations>
|
||||
<ILINK_LibraryPath>$(BDS)\lib\debug;$(ILINK_LibraryPath)</ILINK_LibraryPath>
|
||||
<TASM_Debugging>Full</TASM_Debugging>
|
||||
<BCC_SourceDebuggingOn>true</BCC_SourceDebuggingOn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Cfg_2)'!=''">
|
||||
<Defines>NDEBUG;$(Defines)</Defines>
|
||||
<IntermediateOutputDir>Release</IntermediateOutputDir>
|
||||
<ILINK_LibraryPath>$(BDS)\lib\release;$(ILINK_LibraryPath)</ILINK_LibraryPath>
|
||||
<TASM_Debugging>None</TASM_Debugging>
|
||||
</PropertyGroup>
|
||||
<ProjectExtensions>
|
||||
<Borland.Personality>CPlusPlusBuilder.Personality</Borland.Personality>
|
||||
<Borland.ProjectType>CppConsoleApplication</Borland.ProjectType>
|
||||
<BorlandProject>
|
||||
<BorlandProject><CPlusPlusBuilder.Personality><VersionInfo><VersionInfo Name="IncludeVerInfo">False</VersionInfo><VersionInfo Name="AutoIncBuild">False</VersionInfo><VersionInfo Name="MajorVer">1</VersionInfo><VersionInfo Name="MinorVer">0</VersionInfo><VersionInfo Name="Release">0</VersionInfo><VersionInfo Name="Build">0</VersionInfo><VersionInfo Name="Debug">False</VersionInfo><VersionInfo Name="PreRelease">False</VersionInfo><VersionInfo Name="Special">False</VersionInfo><VersionInfo Name="Private">False</VersionInfo><VersionInfo Name="DLL">False</VersionInfo><VersionInfo Name="Locale">1033</VersionInfo><VersionInfo Name="CodePage">1252</VersionInfo></VersionInfo><VersionInfoKeys><VersionInfoKeys Name="CompanyName"></VersionInfoKeys><VersionInfoKeys Name="FileDescription"></VersionInfoKeys><VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="InternalName"></VersionInfoKeys><VersionInfoKeys Name="LegalCopyright"></VersionInfoKeys><VersionInfoKeys Name="LegalTrademarks"></VersionInfoKeys><VersionInfoKeys Name="OriginalFilename"></VersionInfoKeys><VersionInfoKeys Name="ProductName"></VersionInfoKeys><VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys><VersionInfoKeys Name="Comments"></VersionInfoKeys></VersionInfoKeys><Debugging><Debugging Name="DebugSourceDirs"></Debugging></Debugging><Parameters><Parameters Name="RunParams"></Parameters><Parameters Name="Launcher"></Parameters><Parameters Name="UseLauncher">False</Parameters><Parameters Name="DebugCWD"></Parameters><Parameters Name="HostApplication"></Parameters><Parameters Name="RemoteHost"></Parameters><Parameters Name="RemotePath"></Parameters><Parameters Name="RemoteParams"></Parameters><Parameters Name="RemoteLauncher"></Parameters><Parameters Name="UseRemoteLauncher">False</Parameters><Parameters Name="RemoteCWD"></Parameters><Parameters Name="RemoteDebug">False</Parameters><Parameters Name="Debug Symbols Search Path"></Parameters><Parameters Name="LoadAllSymbols">True</Parameters><Parameters Name="LoadUnspecifiedSymbols">False</Parameters></Parameters><Excluded_Packages>
|
||||
|
||||
|
||||
<Excluded_Packages Name="$(BDS)\bin\bcboffice2k100.bpl">CodeGear C++Builder Office 2000 Servers Package</Excluded_Packages>
|
||||
<Excluded_Packages Name="$(BDS)\bin\bcbofficexp100.bpl">CodeGear C++Builder Office XP Servers Package</Excluded_Packages>
|
||||
</Excluded_Packages><Linker><Linker Name="LibPrefix"></Linker><Linker Name="LibSuffix"></Linker><Linker Name="LibVersion"></Linker></Linker><ProjectProperties><ProjectProperties Name="AutoShowDeps">False</ProjectProperties><ProjectProperties Name="ManagePaths">True</ProjectProperties><ProjectProperties Name="VerifyPackages">True</ProjectProperties></ProjectProperties><HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Count">3</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item0">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test;..</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item1">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test</HistoryLists_hlIncludePath><HistoryLists_hlIncludePath Name="Item2">$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include</HistoryLists_hlIncludePath></HistoryLists_hlIncludePath><HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Count">1</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item0">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item1">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test</HistoryLists_hlILINK_LibraryPath><HistoryLists_hlILINK_LibraryPath Name="Item2">$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;$(OUTPUTDIR);..\test</HistoryLists_hlILINK_LibraryPath></HistoryLists_hlILINK_LibraryPath><HistoryLists_hlDefines><HistoryLists_hlDefines Name="Count">2</HistoryLists_hlDefines><HistoryLists_hlDefines Name="Item0">NO_STRICT</HistoryLists_hlDefines><HistoryLists_hlDefines Name="Item1">STRICT</HistoryLists_hlDefines></HistoryLists_hlDefines></CPlusPlusBuilder.Personality></BorlandProject></BorlandProject>
|
||||
</ProjectExtensions>
|
||||
<Import Project="$(MSBuildBinPath)\Borland.Cpp.Targets" />
|
||||
<ItemGroup>
|
||||
<CppCompile Include="..\test\gtest_unittest.cc">
|
||||
<BuildOrder>0</BuildOrder>
|
||||
</CppCompile>
|
||||
<CppCompile Include="gtest_link.cc">
|
||||
<BuildOrder>1</BuildOrder>
|
||||
</CppCompile>
|
||||
<BuildConfiguration Include="Debug">
|
||||
<Key>Cfg_1</Key>
|
||||
</BuildConfiguration>
|
||||
<BuildConfiguration Include="Release">
|
||||
<Key>Cfg_2</Key>
|
||||
</BuildConfiguration>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -1,68 +0,0 @@
|
|||
m4_include(m4/acx_pthread.m4)
|
||||
|
||||
# At this point, the Xcode project assumes the version string will be three
|
||||
# integers separated by periods and surrounded by square brackets (e.g.
|
||||
# "[1.0.1]"). It also asumes that there won't be any closing parenthesis
|
||||
# between "AC_INIT(" and the closing ")" including comments and strings.
|
||||
AC_INIT([Google C++ Testing Framework],
|
||||
[1.7.0],
|
||||
[googletestframework@googlegroups.com],
|
||||
[gtest])
|
||||
|
||||
# Provide various options to initialize the Autoconf and configure processes.
|
||||
AC_PREREQ([2.59])
|
||||
AC_CONFIG_SRCDIR([./LICENSE])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AC_CONFIG_HEADERS([build-aux/config.h])
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_CONFIG_FILES([scripts/gtest-config], [chmod +x scripts/gtest-config])
|
||||
|
||||
# Initialize Automake with various options. We require at least v1.9, prevent
|
||||
# pedantic complaints about package files, and enable various distribution
|
||||
# targets.
|
||||
AM_INIT_AUTOMAKE([1.9 dist-bzip2 dist-zip foreign subdir-objects])
|
||||
|
||||
# Check for programs used in building Google Test.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AC_LANG([C++])
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
# TODO(chandlerc@google.com): Currently we aren't running the Python tests
|
||||
# against the interpreter detected by AM_PATH_PYTHON, and so we condition
|
||||
# HAVE_PYTHON by requiring "python" to be in the PATH, and that interpreter's
|
||||
# version to be >= 2.3. This will allow the scripts to use a "/usr/bin/env"
|
||||
# hashbang.
|
||||
PYTHON= # We *do not* allow the user to specify a python interpreter
|
||||
AC_PATH_PROG([PYTHON],[python],[:])
|
||||
AS_IF([test "$PYTHON" != ":"],
|
||||
[AM_PYTHON_CHECK_VERSION([$PYTHON],[2.3],[:],[PYTHON=":"])])
|
||||
AM_CONDITIONAL([HAVE_PYTHON],[test "$PYTHON" != ":"])
|
||||
|
||||
# Configure pthreads.
|
||||
AC_ARG_WITH([pthreads],
|
||||
[AS_HELP_STRING([--with-pthreads],
|
||||
[use pthreads (default is yes)])],
|
||||
[with_pthreads=$withval],
|
||||
[with_pthreads=check])
|
||||
|
||||
have_pthreads=no
|
||||
AS_IF([test "x$with_pthreads" != "xno"],
|
||||
[ACX_PTHREAD(
|
||||
[],
|
||||
[AS_IF([test "x$with_pthreads" != "xcheck"],
|
||||
[AC_MSG_FAILURE(
|
||||
[--with-pthreads was specified, but unable to be used])])])
|
||||
have_pthreads="$acx_pthread_ok"])
|
||||
AM_CONDITIONAL([HAVE_PTHREADS],[test "x$have_pthreads" = "xyes"])
|
||||
AC_SUBST(PTHREAD_CFLAGS)
|
||||
AC_SUBST(PTHREAD_LIBS)
|
||||
|
||||
# TODO(chandlerc@google.com) Check for the necessary system headers.
|
||||
|
||||
# TODO(chandlerc@google.com) Check the types, structures, and other compiler
|
||||
# and architecture characteristics.
|
||||
|
||||
# Output the generated files. No further autoconf macros may be used.
|
||||
AC_OUTPUT
|
|
@ -1,294 +0,0 @@
|
|||
// Copyright 2005, Google 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:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
//
|
||||
// The Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// This header file defines the public API for death tests. It is
|
||||
// #included by gtest.h so a user doesn't need to include this
|
||||
// directly.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
|
||||
|
||||
#include "gtest/internal/gtest-death-test-internal.h"
|
||||
|
||||
namespace testing {
|
||||
|
||||
// This flag controls the style of death tests. Valid values are "threadsafe",
|
||||
// meaning that the death test child process will re-execute the test binary
|
||||
// from the start, running only a single death test, or "fast",
|
||||
// meaning that the child process will execute the test logic immediately
|
||||
// after forking.
|
||||
GTEST_DECLARE_string_(death_test_style);
|
||||
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Returns a Boolean value indicating whether the caller is currently
|
||||
// executing in the context of the death test child process. Tools such as
|
||||
// Valgrind heap checkers may need this to modify their behavior in death
|
||||
// tests. IMPORTANT: This is an internal utility. Using it may break the
|
||||
// implementation of death tests. User code MUST NOT use it.
|
||||
GTEST_API_ bool InDeathTestChild();
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// The following macros are useful for writing death tests.
|
||||
|
||||
// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is
|
||||
// executed:
|
||||
//
|
||||
// 1. It generates a warning if there is more than one active
|
||||
// thread. This is because it's safe to fork() or clone() only
|
||||
// when there is a single thread.
|
||||
//
|
||||
// 2. The parent process clone()s a sub-process and runs the death
|
||||
// test in it; the sub-process exits with code 0 at the end of the
|
||||
// death test, if it hasn't exited already.
|
||||
//
|
||||
// 3. The parent process waits for the sub-process to terminate.
|
||||
//
|
||||
// 4. The parent process checks the exit code and error message of
|
||||
// the sub-process.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number");
|
||||
// for (int i = 0; i < 5; i++) {
|
||||
// EXPECT_DEATH(server.ProcessRequest(i),
|
||||
// "Invalid request .* in ProcessRequest()")
|
||||
// << "Failed to die on request " << i;
|
||||
// }
|
||||
//
|
||||
// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting");
|
||||
//
|
||||
// bool KilledBySIGHUP(int exit_code) {
|
||||
// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP;
|
||||
// }
|
||||
//
|
||||
// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!");
|
||||
//
|
||||
// On the regular expressions used in death tests:
|
||||
//
|
||||
// On POSIX-compliant systems (*nix), we use the <regex.h> library,
|
||||
// which uses the POSIX extended regex syntax.
|
||||
//
|
||||
// On other platforms (e.g. Windows), we only support a simple regex
|
||||
// syntax implemented as part of Google Test. This limited
|
||||
// implementation should be enough most of the time when writing
|
||||
// death tests; though it lacks many features you can find in PCRE
|
||||
// or POSIX extended regex syntax. For example, we don't support
|
||||
// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and
|
||||
// repetition count ("x{5,7}"), among others.
|
||||
//
|
||||
// Below is the syntax that we do support. We chose it to be a
|
||||
// subset of both PCRE and POSIX extended regex, so it's easy to
|
||||
// learn wherever you come from. In the following: 'A' denotes a
|
||||
// literal character, period (.), or a single \\ escape sequence;
|
||||
// 'x' and 'y' denote regular expressions; 'm' and 'n' are for
|
||||
// natural numbers.
|
||||
//
|
||||
// c matches any literal character c
|
||||
// \\d matches any decimal digit
|
||||
// \\D matches any character that's not a decimal digit
|
||||
// \\f matches \f
|
||||
// \\n matches \n
|
||||
// \\r matches \r
|
||||
// \\s matches any ASCII whitespace, including \n
|
||||
// \\S matches any character that's not a whitespace
|
||||
// \\t matches \t
|
||||
// \\v matches \v
|
||||
// \\w matches any letter, _, or decimal digit
|
||||
// \\W matches any character that \\w doesn't match
|
||||
// \\c matches any literal character c, which must be a punctuation
|
||||
// . matches any single character except \n
|
||||
// A? matches 0 or 1 occurrences of A
|
||||
// A* matches 0 or many occurrences of A
|
||||
// A+ matches 1 or many occurrences of A
|
||||
// ^ matches the beginning of a string (not that of each line)
|
||||
// $ matches the end of a string (not that of each line)
|
||||
// xy matches x followed by y
|
||||
//
|
||||
// If you accidentally use PCRE or POSIX extended regex features
|
||||
// not implemented by us, you will get a run-time failure. In that
|
||||
// case, please try to rewrite your regular expression within the
|
||||
// above syntax.
|
||||
//
|
||||
// This implementation is *not* meant to be as highly tuned or robust
|
||||
// as a compiled regex library, but should perform well enough for a
|
||||
// death test, which already incurs significant overhead by launching
|
||||
// a child process.
|
||||
//
|
||||
// Known caveats:
|
||||
//
|
||||
// A "threadsafe" style death test obtains the path to the test
|
||||
// program from argv[0] and re-executes it in the sub-process. For
|
||||
// simplicity, the current implementation doesn't search the PATH
|
||||
// when launching the sub-process. This means that the user must
|
||||
// invoke the test program via a path that contains at least one
|
||||
// path separator (e.g. path/to/foo_test and
|
||||
// /absolute/path/to/bar_test are fine, but foo_test is not). This
|
||||
// is rarely a problem as people usually don't put the test binary
|
||||
// directory in PATH.
|
||||
//
|
||||
// TODO(wan@google.com): make thread-safe death tests search the PATH.
|
||||
|
||||
// Asserts that a given statement causes the program to exit, with an
|
||||
// integer exit status that satisfies predicate, and emitting error output
|
||||
// that matches regex.
|
||||
# define ASSERT_EXIT(statement, predicate, regex) \
|
||||
GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_)
|
||||
|
||||
// Like ASSERT_EXIT, but continues on to successive tests in the
|
||||
// test case, if any:
|
||||
# define EXPECT_EXIT(statement, predicate, regex) \
|
||||
GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_)
|
||||
|
||||
// Asserts that a given statement causes the program to exit, either by
|
||||
// explicitly exiting with a nonzero exit code or being killed by a
|
||||
// signal, and emitting error output that matches regex.
|
||||
# define ASSERT_DEATH(statement, regex) \
|
||||
ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
|
||||
|
||||
// Like ASSERT_DEATH, but continues on to successive tests in the
|
||||
// test case, if any:
|
||||
# define EXPECT_DEATH(statement, regex) \
|
||||
EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex)
|
||||
|
||||
// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*:
|
||||
|
||||
// Tests that an exit code describes a normal exit with a given exit code.
|
||||
class GTEST_API_ ExitedWithCode {
|
||||
public:
|
||||
explicit ExitedWithCode(int exit_code);
|
||||
bool operator()(int exit_status) const;
|
||||
private:
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const ExitedWithCode& other);
|
||||
|
||||
const int exit_code_;
|
||||
};
|
||||
|
||||
# if !GTEST_OS_WINDOWS
|
||||
// Tests that an exit code describes an exit due to termination by a
|
||||
// given signal.
|
||||
class GTEST_API_ KilledBySignal {
|
||||
public:
|
||||
explicit KilledBySignal(int signum);
|
||||
bool operator()(int exit_status) const;
|
||||
private:
|
||||
const int signum_;
|
||||
};
|
||||
# endif // !GTEST_OS_WINDOWS
|
||||
|
||||
// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode.
|
||||
// The death testing framework causes this to have interesting semantics,
|
||||
// since the sideeffects of the call are only visible in opt mode, and not
|
||||
// in debug mode.
|
||||
//
|
||||
// In practice, this can be used to test functions that utilize the
|
||||
// LOG(DFATAL) macro using the following style:
|
||||
//
|
||||
// int DieInDebugOr12(int* sideeffect) {
|
||||
// if (sideeffect) {
|
||||
// *sideeffect = 12;
|
||||
// }
|
||||
// LOG(DFATAL) << "death";
|
||||
// return 12;
|
||||
// }
|
||||
//
|
||||
// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) {
|
||||
// int sideeffect = 0;
|
||||
// // Only asserts in dbg.
|
||||
// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death");
|
||||
//
|
||||
// #ifdef NDEBUG
|
||||
// // opt-mode has sideeffect visible.
|
||||
// EXPECT_EQ(12, sideeffect);
|
||||
// #else
|
||||
// // dbg-mode no visible sideeffect.
|
||||
// EXPECT_EQ(0, sideeffect);
|
||||
// #endif
|
||||
// }
|
||||
//
|
||||
// This will assert that DieInDebugReturn12InOpt() crashes in debug
|
||||
// mode, usually due to a DCHECK or LOG(DFATAL), but returns the
|
||||
// appropriate fallback value (12 in this case) in opt mode. If you
|
||||
// need to test that a function has appropriate side-effects in opt
|
||||
// mode, include assertions against the side-effects. A general
|
||||
// pattern for this is:
|
||||
//
|
||||
// EXPECT_DEBUG_DEATH({
|
||||
// // Side-effects here will have an effect after this statement in
|
||||
// // opt mode, but none in debug mode.
|
||||
// EXPECT_EQ(12, DieInDebugOr12(&sideeffect));
|
||||
// }, "death");
|
||||
//
|
||||
# ifdef NDEBUG
|
||||
|
||||
# define EXPECT_DEBUG_DEATH(statement, regex) \
|
||||
GTEST_EXECUTE_STATEMENT_(statement, regex)
|
||||
|
||||
# define ASSERT_DEBUG_DEATH(statement, regex) \
|
||||
GTEST_EXECUTE_STATEMENT_(statement, regex)
|
||||
|
||||
# else
|
||||
|
||||
# define EXPECT_DEBUG_DEATH(statement, regex) \
|
||||
EXPECT_DEATH(statement, regex)
|
||||
|
||||
# define ASSERT_DEBUG_DEATH(statement, regex) \
|
||||
ASSERT_DEATH(statement, regex)
|
||||
|
||||
# endif // NDEBUG for EXPECT_DEBUG_DEATH
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and
|
||||
// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if
|
||||
// death tests are supported; otherwise they just issue a warning. This is
|
||||
// useful when you are combining death test assertions with normal test
|
||||
// assertions in one test.
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
|
||||
EXPECT_DEATH(statement, regex)
|
||||
# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
|
||||
ASSERT_DEATH(statement, regex)
|
||||
#else
|
||||
# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \
|
||||
GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, )
|
||||
# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \
|
||||
GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return)
|
||||
#endif
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_
|
|
@ -1,250 +0,0 @@
|
|||
// Copyright 2005, Google 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:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
//
|
||||
// The Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// This header file defines the Message class.
|
||||
//
|
||||
// IMPORTANT NOTE: Due to limitation of the C++ language, we have to
|
||||
// leave some internal implementation details in this header file.
|
||||
// They are clearly marked by comments like this:
|
||||
//
|
||||
// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
|
||||
//
|
||||
// Such code is NOT meant to be used by a user directly, and is subject
|
||||
// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user
|
||||
// program!
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
// Ensures that there is at least one operator<< in the global namespace.
|
||||
// See Message& operator<<(...) below for why.
|
||||
void operator<<(const testing::internal::Secret&, int);
|
||||
|
||||
namespace testing {
|
||||
|
||||
// The Message class works like an ostream repeater.
|
||||
//
|
||||
// Typical usage:
|
||||
//
|
||||
// 1. You stream a bunch of values to a Message object.
|
||||
// It will remember the text in a stringstream.
|
||||
// 2. Then you stream the Message object to an ostream.
|
||||
// This causes the text in the Message to be streamed
|
||||
// to the ostream.
|
||||
//
|
||||
// For example;
|
||||
//
|
||||
// testing::Message foo;
|
||||
// foo << 1 << " != " << 2;
|
||||
// std::cout << foo;
|
||||
//
|
||||
// will print "1 != 2".
|
||||
//
|
||||
// Message is not intended to be inherited from. In particular, its
|
||||
// destructor is not virtual.
|
||||
//
|
||||
// Note that stringstream behaves differently in gcc and in MSVC. You
|
||||
// can stream a NULL char pointer to it in the former, but not in the
|
||||
// latter (it causes an access violation if you do). The Message
|
||||
// class hides this difference by treating a NULL char pointer as
|
||||
// "(null)".
|
||||
class GTEST_API_ Message {
|
||||
private:
|
||||
// The type of basic IO manipulators (endl, ends, and flush) for
|
||||
// narrow streams.
|
||||
typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&);
|
||||
|
||||
public:
|
||||
// Constructs an empty Message.
|
||||
Message();
|
||||
|
||||
// Copy constructor.
|
||||
Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT
|
||||
*ss_ << msg.GetString();
|
||||
}
|
||||
|
||||
// Constructs a Message from a C-string.
|
||||
explicit Message(const char* str) : ss_(new ::std::stringstream) {
|
||||
*ss_ << str;
|
||||
}
|
||||
|
||||
#if GTEST_OS_SYMBIAN
|
||||
// Streams a value (either a pointer or not) to this object.
|
||||
template <typename T>
|
||||
inline Message& operator <<(const T& value) {
|
||||
StreamHelper(typename internal::is_pointer<T>::type(), value);
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
// Streams a non-pointer value to this object.
|
||||
template <typename T>
|
||||
inline Message& operator <<(const T& val) {
|
||||
// Some libraries overload << for STL containers. These
|
||||
// overloads are defined in the global namespace instead of ::std.
|
||||
//
|
||||
// C++'s symbol lookup rule (i.e. Koenig lookup) says that these
|
||||
// overloads are visible in either the std namespace or the global
|
||||
// namespace, but not other namespaces, including the testing
|
||||
// namespace which Google Test's Message class is in.
|
||||
//
|
||||
// To allow STL containers (and other types that has a << operator
|
||||
// defined in the global namespace) to be used in Google Test
|
||||
// assertions, testing::Message must access the custom << operator
|
||||
// from the global namespace. With this using declaration,
|
||||
// overloads of << defined in the global namespace and those
|
||||
// visible via Koenig lookup are both exposed in this function.
|
||||
using ::operator <<;
|
||||
*ss_ << val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Streams a pointer value to this object.
|
||||
//
|
||||
// This function is an overload of the previous one. When you
|
||||
// stream a pointer to a Message, this definition will be used as it
|
||||
// is more specialized. (The C++ Standard, section
|
||||
// [temp.func.order].) If you stream a non-pointer, then the
|
||||
// previous definition will be used.
|
||||
//
|
||||
// The reason for this overload is that streaming a NULL pointer to
|
||||
// ostream is undefined behavior. Depending on the compiler, you
|
||||
// may get "0", "(nil)", "(null)", or an access violation. To
|
||||
// ensure consistent result across compilers, we always treat NULL
|
||||
// as "(null)".
|
||||
template <typename T>
|
||||
inline Message& operator <<(T* const& pointer) { // NOLINT
|
||||
if (pointer == NULL) {
|
||||
*ss_ << "(null)";
|
||||
} else {
|
||||
*ss_ << pointer;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
#endif // GTEST_OS_SYMBIAN
|
||||
|
||||
// Since the basic IO manipulators are overloaded for both narrow
|
||||
// and wide streams, we have to provide this specialized definition
|
||||
// of operator <<, even though its body is the same as the
|
||||
// templatized version above. Without this definition, streaming
|
||||
// endl or other basic IO manipulators to Message will confuse the
|
||||
// compiler.
|
||||
Message& operator <<(BasicNarrowIoManip val) {
|
||||
*ss_ << val;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Instead of 1/0, we want to see true/false for bool values.
|
||||
Message& operator <<(bool b) {
|
||||
return *this << (b ? "true" : "false");
|
||||
}
|
||||
|
||||
// These two overloads allow streaming a wide C string to a Message
|
||||
// using the UTF-8 encoding.
|
||||
Message& operator <<(const wchar_t* wide_c_str);
|
||||
Message& operator <<(wchar_t* wide_c_str);
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
// Converts the given wide string to a narrow string using the UTF-8
|
||||
// encoding, and streams the result to this Message object.
|
||||
Message& operator <<(const ::std::wstring& wstr);
|
||||
#endif // GTEST_HAS_STD_WSTRING
|
||||
|
||||
#if GTEST_HAS_GLOBAL_WSTRING
|
||||
// Converts the given wide string to a narrow string using the UTF-8
|
||||
// encoding, and streams the result to this Message object.
|
||||
Message& operator <<(const ::wstring& wstr);
|
||||
#endif // GTEST_HAS_GLOBAL_WSTRING
|
||||
|
||||
// Gets the text streamed to this object so far as an std::string.
|
||||
// Each '\0' character in the buffer is replaced with "\\0".
|
||||
//
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
|
||||
std::string GetString() const;
|
||||
|
||||
private:
|
||||
|
||||
#if GTEST_OS_SYMBIAN
|
||||
// These are needed as the Nokia Symbian Compiler cannot decide between
|
||||
// const T& and const T* in a function template. The Nokia compiler _can_
|
||||
// decide between class template specializations for T and T*, so a
|
||||
// tr1::type_traits-like is_pointer works, and we can overload on that.
|
||||
template <typename T>
|
||||
inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) {
|
||||
if (pointer == NULL) {
|
||||
*ss_ << "(null)";
|
||||
} else {
|
||||
*ss_ << pointer;
|
||||
}
|
||||
}
|
||||
template <typename T>
|
||||
inline void StreamHelper(internal::false_type /*is_pointer*/,
|
||||
const T& value) {
|
||||
// See the comments in Message& operator <<(const T&) above for why
|
||||
// we need this using statement.
|
||||
using ::operator <<;
|
||||
*ss_ << value;
|
||||
}
|
||||
#endif // GTEST_OS_SYMBIAN
|
||||
|
||||
// We'll hold the text streamed to this object here.
|
||||
const internal::scoped_ptr< ::std::stringstream> ss_;
|
||||
|
||||
// We declare (but don't implement) this to prevent the compiler
|
||||
// from implementing the assignment operator.
|
||||
void operator=(const Message&);
|
||||
};
|
||||
|
||||
// Streams a Message to an ostream.
|
||||
inline std::ostream& operator <<(std::ostream& os, const Message& sb) {
|
||||
return os << sb.GetString();
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Converts a streamable value to an std::string. A NULL pointer is
|
||||
// converted to "(null)". When the input value is a ::string,
|
||||
// ::std::string, ::wstring, or ::std::wstring object, each NUL
|
||||
// character in it is replaced with "\\0".
|
||||
template <typename T>
|
||||
std::string StreamableToString(const T& streamable) {
|
||||
return (Message() << streamable).GetString();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_
|
File diff suppressed because it is too large
Load diff
|
@ -1,487 +0,0 @@
|
|||
$$ -*- mode: c++; -*-
|
||||
$var n = 50 $$ Maximum length of Values arguments we want to support.
|
||||
$var maxtuple = 10 $$ Maximum number of Combine arguments we want to support.
|
||||
// Copyright 2008, Google 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:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Authors: vladl@google.com (Vlad Losev)
|
||||
//
|
||||
// Macros and functions for implementing parameterized tests
|
||||
// in Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
|
||||
//
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
|
||||
|
||||
|
||||
// Value-parameterized tests allow you to test your code with different
|
||||
// parameters without writing multiple copies of the same test.
|
||||
//
|
||||
// Here is how you use value-parameterized tests:
|
||||
|
||||
#if 0
|
||||
|
||||
// To write value-parameterized tests, first you should define a fixture
|
||||
// class. It is usually derived from testing::TestWithParam<T> (see below for
|
||||
// another inheritance scheme that's sometimes useful in more complicated
|
||||
// class hierarchies), where the type of your parameter values.
|
||||
// TestWithParam<T> is itself derived from testing::Test. T can be any
|
||||
// copyable type. If it's a raw pointer, you are responsible for managing the
|
||||
// lifespan of the pointed values.
|
||||
|
||||
class FooTest : public ::testing::TestWithParam<const char*> {
|
||||
// You can implement all the usual class fixture members here.
|
||||
};
|
||||
|
||||
// Then, use the TEST_P macro to define as many parameterized tests
|
||||
// for this fixture as you want. The _P suffix is for "parameterized"
|
||||
// or "pattern", whichever you prefer to think.
|
||||
|
||||
TEST_P(FooTest, DoesBlah) {
|
||||
// Inside a test, access the test parameter with the GetParam() method
|
||||
// of the TestWithParam<T> class:
|
||||
EXPECT_TRUE(foo.Blah(GetParam()));
|
||||
...
|
||||
}
|
||||
|
||||
TEST_P(FooTest, HasBlahBlah) {
|
||||
...
|
||||
}
|
||||
|
||||
// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test
|
||||
// case with any set of parameters you want. Google Test defines a number
|
||||
// of functions for generating test parameters. They return what we call
|
||||
// (surprise!) parameter generators. Here is a summary of them, which
|
||||
// are all in the testing namespace:
|
||||
//
|
||||
//
|
||||
// Range(begin, end [, step]) - Yields values {begin, begin+step,
|
||||
// begin+step+step, ...}. The values do not
|
||||
// include end. step defaults to 1.
|
||||
// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}.
|
||||
// ValuesIn(container) - Yields values from a C-style array, an STL
|
||||
// ValuesIn(begin,end) container, or an iterator range [begin, end).
|
||||
// Bool() - Yields sequence {false, true}.
|
||||
// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product
|
||||
// for the math savvy) of the values generated
|
||||
// by the N generators.
|
||||
//
|
||||
// For more details, see comments at the definitions of these functions below
|
||||
// in this file.
|
||||
//
|
||||
// The following statement will instantiate tests from the FooTest test case
|
||||
// each with parameter values "meeny", "miny", and "moe".
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(InstantiationName,
|
||||
FooTest,
|
||||
Values("meeny", "miny", "moe"));
|
||||
|
||||
// To distinguish different instances of the pattern, (yes, you
|
||||
// can instantiate it more then once) the first argument to the
|
||||
// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the
|
||||
// actual test case name. Remember to pick unique prefixes for different
|
||||
// instantiations. The tests from the instantiation above will have
|
||||
// these names:
|
||||
//
|
||||
// * InstantiationName/FooTest.DoesBlah/0 for "meeny"
|
||||
// * InstantiationName/FooTest.DoesBlah/1 for "miny"
|
||||
// * InstantiationName/FooTest.DoesBlah/2 for "moe"
|
||||
// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny"
|
||||
// * InstantiationName/FooTest.HasBlahBlah/1 for "miny"
|
||||
// * InstantiationName/FooTest.HasBlahBlah/2 for "moe"
|
||||
//
|
||||
// You can use these names in --gtest_filter.
|
||||
//
|
||||
// This statement will instantiate all tests from FooTest again, each
|
||||
// with parameter values "cat" and "dog":
|
||||
|
||||
const char* pets[] = {"cat", "dog"};
|
||||
INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets));
|
||||
|
||||
// The tests from the instantiation above will have these names:
|
||||
//
|
||||
// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat"
|
||||
// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog"
|
||||
// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat"
|
||||
// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog"
|
||||
//
|
||||
// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests
|
||||
// in the given test case, whether their definitions come before or
|
||||
// AFTER the INSTANTIATE_TEST_CASE_P statement.
|
||||
//
|
||||
// Please also note that generator expressions (including parameters to the
|
||||
// generators) are evaluated in InitGoogleTest(), after main() has started.
|
||||
// This allows the user on one hand, to adjust generator parameters in order
|
||||
// to dynamically determine a set of tests to run and on the other hand,
|
||||
// give the user a chance to inspect the generated tests with Google Test
|
||||
// reflection API before RUN_ALL_TESTS() is executed.
|
||||
//
|
||||
// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc
|
||||
// for more examples.
|
||||
//
|
||||
// In the future, we plan to publish the API for defining new parameter
|
||||
// generators. But for now this interface remains part of the internal
|
||||
// implementation and is subject to change.
|
||||
//
|
||||
//
|
||||
// A parameterized test fixture must be derived from testing::Test and from
|
||||
// testing::WithParamInterface<T>, where T is the type of the parameter
|
||||
// values. Inheriting from TestWithParam<T> satisfies that requirement because
|
||||
// TestWithParam<T> inherits from both Test and WithParamInterface. In more
|
||||
// complicated hierarchies, however, it is occasionally useful to inherit
|
||||
// separately from Test and WithParamInterface. For example:
|
||||
|
||||
class BaseTest : public ::testing::Test {
|
||||
// You can inherit all the usual members for a non-parameterized test
|
||||
// fixture here.
|
||||
};
|
||||
|
||||
class DerivedTest : public BaseTest, public ::testing::WithParamInterface<int> {
|
||||
// The usual test fixture members go here too.
|
||||
};
|
||||
|
||||
TEST_F(BaseTest, HasFoo) {
|
||||
// This is an ordinary non-parameterized test.
|
||||
}
|
||||
|
||||
TEST_P(DerivedTest, DoesBlah) {
|
||||
// GetParam works just the same here as if you inherit from TestWithParam.
|
||||
EXPECT_TRUE(foo.Blah(GetParam()));
|
||||
}
|
||||
|
||||
#endif // 0
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
#if !GTEST_OS_SYMBIAN
|
||||
# include <utility>
|
||||
#endif
|
||||
|
||||
// scripts/fuse_gtest.py depends on gtest's own header being #included
|
||||
// *unconditionally*. Therefore these #includes cannot be moved
|
||||
// inside #if GTEST_HAS_PARAM_TEST.
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
#include "gtest/internal/gtest-param-util.h"
|
||||
#include "gtest/internal/gtest-param-util-generated.h"
|
||||
|
||||
#if GTEST_HAS_PARAM_TEST
|
||||
|
||||
namespace testing {
|
||||
|
||||
// Functions producing parameter generators.
|
||||
//
|
||||
// Google Test uses these generators to produce parameters for value-
|
||||
// parameterized tests. When a parameterized test case is instantiated
|
||||
// with a particular generator, Google Test creates and runs tests
|
||||
// for each element in the sequence produced by the generator.
|
||||
//
|
||||
// In the following sample, tests from test case FooTest are instantiated
|
||||
// each three times with parameter values 3, 5, and 8:
|
||||
//
|
||||
// class FooTest : public TestWithParam<int> { ... };
|
||||
//
|
||||
// TEST_P(FooTest, TestThis) {
|
||||
// }
|
||||
// TEST_P(FooTest, TestThat) {
|
||||
// }
|
||||
// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8));
|
||||
//
|
||||
|
||||
// Range() returns generators providing sequences of values in a range.
|
||||
//
|
||||
// Synopsis:
|
||||
// Range(start, end)
|
||||
// - returns a generator producing a sequence of values {start, start+1,
|
||||
// start+2, ..., }.
|
||||
// Range(start, end, step)
|
||||
// - returns a generator producing a sequence of values {start, start+step,
|
||||
// start+step+step, ..., }.
|
||||
// Notes:
|
||||
// * The generated sequences never include end. For example, Range(1, 5)
|
||||
// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2)
|
||||
// returns a generator producing {1, 3, 5, 7}.
|
||||
// * start and end must have the same type. That type may be any integral or
|
||||
// floating-point type or a user defined type satisfying these conditions:
|
||||
// * It must be assignable (have operator=() defined).
|
||||
// * It must have operator+() (operator+(int-compatible type) for
|
||||
// two-operand version).
|
||||
// * It must have operator<() defined.
|
||||
// Elements in the resulting sequences will also have that type.
|
||||
// * Condition start < end must be satisfied in order for resulting sequences
|
||||
// to contain any elements.
|
||||
//
|
||||
template <typename T, typename IncrementT>
|
||||
internal::ParamGenerator<T> Range(T start, T end, IncrementT step) {
|
||||
return internal::ParamGenerator<T>(
|
||||
new internal::RangeGenerator<T, IncrementT>(start, end, step));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
internal::ParamGenerator<T> Range(T start, T end) {
|
||||
return Range(start, end, 1);
|
||||
}
|
||||
|
||||
// ValuesIn() function allows generation of tests with parameters coming from
|
||||
// a container.
|
||||
//
|
||||
// Synopsis:
|
||||
// ValuesIn(const T (&array)[N])
|
||||
// - returns a generator producing sequences with elements from
|
||||
// a C-style array.
|
||||
// ValuesIn(const Container& container)
|
||||
// - returns a generator producing sequences with elements from
|
||||
// an STL-style container.
|
||||
// ValuesIn(Iterator begin, Iterator end)
|
||||
// - returns a generator producing sequences with elements from
|
||||
// a range [begin, end) defined by a pair of STL-style iterators. These
|
||||
// iterators can also be plain C pointers.
|
||||
//
|
||||
// Please note that ValuesIn copies the values from the containers
|
||||
// passed in and keeps them to generate tests in RUN_ALL_TESTS().
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// This instantiates tests from test case StringTest
|
||||
// each with C-string values of "foo", "bar", and "baz":
|
||||
//
|
||||
// const char* strings[] = {"foo", "bar", "baz"};
|
||||
// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings));
|
||||
//
|
||||
// This instantiates tests from test case StlStringTest
|
||||
// each with STL strings with values "a" and "b":
|
||||
//
|
||||
// ::std::vector< ::std::string> GetParameterStrings() {
|
||||
// ::std::vector< ::std::string> v;
|
||||
// v.push_back("a");
|
||||
// v.push_back("b");
|
||||
// return v;
|
||||
// }
|
||||
//
|
||||
// INSTANTIATE_TEST_CASE_P(CharSequence,
|
||||
// StlStringTest,
|
||||
// ValuesIn(GetParameterStrings()));
|
||||
//
|
||||
//
|
||||
// This will also instantiate tests from CharTest
|
||||
// each with parameter values 'a' and 'b':
|
||||
//
|
||||
// ::std::list<char> GetParameterChars() {
|
||||
// ::std::list<char> list;
|
||||
// list.push_back('a');
|
||||
// list.push_back('b');
|
||||
// return list;
|
||||
// }
|
||||
// ::std::list<char> l = GetParameterChars();
|
||||
// INSTANTIATE_TEST_CASE_P(CharSequence2,
|
||||
// CharTest,
|
||||
// ValuesIn(l.begin(), l.end()));
|
||||
//
|
||||
template <typename ForwardIterator>
|
||||
internal::ParamGenerator<
|
||||
typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
|
||||
ValuesIn(ForwardIterator begin, ForwardIterator end) {
|
||||
typedef typename ::testing::internal::IteratorTraits<ForwardIterator>
|
||||
::value_type ParamType;
|
||||
return internal::ParamGenerator<ParamType>(
|
||||
new internal::ValuesInIteratorRangeGenerator<ParamType>(begin, end));
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
internal::ParamGenerator<T> ValuesIn(const T (&array)[N]) {
|
||||
return ValuesIn(array, array + N);
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
internal::ParamGenerator<typename Container::value_type> ValuesIn(
|
||||
const Container& container) {
|
||||
return ValuesIn(container.begin(), container.end());
|
||||
}
|
||||
|
||||
// Values() allows generating tests from explicitly specified list of
|
||||
// parameters.
|
||||
//
|
||||
// Synopsis:
|
||||
// Values(T v1, T v2, ..., T vN)
|
||||
// - returns a generator producing sequences with elements v1, v2, ..., vN.
|
||||
//
|
||||
// For example, this instantiates tests from test case BarTest each
|
||||
// with values "one", "two", and "three":
|
||||
//
|
||||
// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three"));
|
||||
//
|
||||
// This instantiates tests from test case BazTest each with values 1, 2, 3.5.
|
||||
// The exact type of values will depend on the type of parameter in BazTest.
|
||||
//
|
||||
// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5));
|
||||
//
|
||||
// Currently, Values() supports from 1 to $n parameters.
|
||||
//
|
||||
$range i 1..n
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
|
||||
template <$for j, [[typename T$j]]>
|
||||
internal::ValueArray$i<$for j, [[T$j]]> Values($for j, [[T$j v$j]]) {
|
||||
return internal::ValueArray$i<$for j, [[T$j]]>($for j, [[v$j]]);
|
||||
}
|
||||
|
||||
]]
|
||||
|
||||
// Bool() allows generating tests with parameters in a set of (false, true).
|
||||
//
|
||||
// Synopsis:
|
||||
// Bool()
|
||||
// - returns a generator producing sequences with elements {false, true}.
|
||||
//
|
||||
// It is useful when testing code that depends on Boolean flags. Combinations
|
||||
// of multiple flags can be tested when several Bool()'s are combined using
|
||||
// Combine() function.
|
||||
//
|
||||
// In the following example all tests in the test case FlagDependentTest
|
||||
// will be instantiated twice with parameters false and true.
|
||||
//
|
||||
// class FlagDependentTest : public testing::TestWithParam<bool> {
|
||||
// virtual void SetUp() {
|
||||
// external_flag = GetParam();
|
||||
// }
|
||||
// }
|
||||
// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool());
|
||||
//
|
||||
inline internal::ParamGenerator<bool> Bool() {
|
||||
return Values(false, true);
|
||||
}
|
||||
|
||||
# if GTEST_HAS_COMBINE
|
||||
// Combine() allows the user to combine two or more sequences to produce
|
||||
// values of a Cartesian product of those sequences' elements.
|
||||
//
|
||||
// Synopsis:
|
||||
// Combine(gen1, gen2, ..., genN)
|
||||
// - returns a generator producing sequences with elements coming from
|
||||
// the Cartesian product of elements from the sequences generated by
|
||||
// gen1, gen2, ..., genN. The sequence elements will have a type of
|
||||
// tuple<T1, T2, ..., TN> where T1, T2, ..., TN are the types
|
||||
// of elements from sequences produces by gen1, gen2, ..., genN.
|
||||
//
|
||||
// Combine can have up to $maxtuple arguments. This number is currently limited
|
||||
// by the maximum number of elements in the tuple implementation used by Google
|
||||
// Test.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// This will instantiate tests in test case AnimalTest each one with
|
||||
// the parameter values tuple("cat", BLACK), tuple("cat", WHITE),
|
||||
// tuple("dog", BLACK), and tuple("dog", WHITE):
|
||||
//
|
||||
// enum Color { BLACK, GRAY, WHITE };
|
||||
// class AnimalTest
|
||||
// : public testing::TestWithParam<tuple<const char*, Color> > {...};
|
||||
//
|
||||
// TEST_P(AnimalTest, AnimalLooksNice) {...}
|
||||
//
|
||||
// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest,
|
||||
// Combine(Values("cat", "dog"),
|
||||
// Values(BLACK, WHITE)));
|
||||
//
|
||||
// This will instantiate tests in FlagDependentTest with all variations of two
|
||||
// Boolean flags:
|
||||
//
|
||||
// class FlagDependentTest
|
||||
// : public testing::TestWithParam<tuple<bool, bool> > {
|
||||
// virtual void SetUp() {
|
||||
// // Assigns external_flag_1 and external_flag_2 values from the tuple.
|
||||
// tie(external_flag_1, external_flag_2) = GetParam();
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// TEST_P(FlagDependentTest, TestFeature1) {
|
||||
// // Test your code using external_flag_1 and external_flag_2 here.
|
||||
// }
|
||||
// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest,
|
||||
// Combine(Bool(), Bool()));
|
||||
//
|
||||
$range i 2..maxtuple
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
|
||||
template <$for j, [[typename Generator$j]]>
|
||||
internal::CartesianProductHolder$i<$for j, [[Generator$j]]> Combine(
|
||||
$for j, [[const Generator$j& g$j]]) {
|
||||
return internal::CartesianProductHolder$i<$for j, [[Generator$j]]>(
|
||||
$for j, [[g$j]]);
|
||||
}
|
||||
|
||||
]]
|
||||
# endif // GTEST_HAS_COMBINE
|
||||
|
||||
|
||||
|
||||
# define TEST_P(test_case_name, test_name) \
|
||||
class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \
|
||||
: public test_case_name { \
|
||||
public: \
|
||||
GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \
|
||||
virtual void TestBody(); \
|
||||
private: \
|
||||
static int AddToRegistry() { \
|
||||
::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
|
||||
GetTestCasePatternHolder<test_case_name>(\
|
||||
#test_case_name, __FILE__, __LINE__)->AddTestPattern(\
|
||||
#test_case_name, \
|
||||
#test_name, \
|
||||
new ::testing::internal::TestMetaFactory< \
|
||||
GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \
|
||||
return 0; \
|
||||
} \
|
||||
static int gtest_registering_dummy_; \
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(\
|
||||
GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \
|
||||
}; \
|
||||
int GTEST_TEST_CLASS_NAME_(test_case_name, \
|
||||
test_name)::gtest_registering_dummy_ = \
|
||||
GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \
|
||||
void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody()
|
||||
|
||||
# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \
|
||||
::testing::internal::ParamGenerator<test_case_name::ParamType> \
|
||||
gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \
|
||||
int gtest_##prefix##test_case_name##_dummy_ = \
|
||||
::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
|
||||
GetTestCasePatternHolder<test_case_name>(\
|
||||
#test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\
|
||||
#prefix, \
|
||||
>est_##prefix##test_case_name##_EvalGenerator_, \
|
||||
__FILE__, __LINE__)
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_HAS_PARAM_TEST
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_
|
|
@ -1,855 +0,0 @@
|
|||
// Copyright 2007, Google 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:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
|
||||
// Google Test - The Google C++ Testing Framework
|
||||
//
|
||||
// This file implements a universal value printer that can print a
|
||||
// value of any type T:
|
||||
//
|
||||
// void ::testing::internal::UniversalPrinter<T>::Print(value, ostream_ptr);
|
||||
//
|
||||
// A user can teach this function how to print a class type T by
|
||||
// defining either operator<<() or PrintTo() in the namespace that
|
||||
// defines T. More specifically, the FIRST defined function in the
|
||||
// following list will be used (assuming T is defined in namespace
|
||||
// foo):
|
||||
//
|
||||
// 1. foo::PrintTo(const T&, ostream*)
|
||||
// 2. operator<<(ostream&, const T&) defined in either foo or the
|
||||
// global namespace.
|
||||
//
|
||||
// If none of the above is defined, it will print the debug string of
|
||||
// the value if it is a protocol buffer, or print the raw bytes in the
|
||||
// value otherwise.
|
||||
//
|
||||
// To aid debugging: when T is a reference type, the address of the
|
||||
// value is also printed; when T is a (const) char pointer, both the
|
||||
// pointer value and the NUL-terminated string it points to are
|
||||
// printed.
|
||||
//
|
||||
// We also provide some convenient wrappers:
|
||||
//
|
||||
// // Prints a value to a string. For a (const or not) char
|
||||
// // pointer, the NUL-terminated string (but not the pointer) is
|
||||
// // printed.
|
||||
// std::string ::testing::PrintToString(const T& value);
|
||||
//
|
||||
// // Prints a value tersely: for a reference type, the referenced
|
||||
// // value (but not the address) is printed; for a (const or not) char
|
||||
// // pointer, the NUL-terminated string (but not the pointer) is
|
||||
// // printed.
|
||||
// void ::testing::internal::UniversalTersePrint(const T& value, ostream*);
|
||||
//
|
||||
// // Prints value using the type inferred by the compiler. The difference
|
||||
// // from UniversalTersePrint() is that this function prints both the
|
||||
// // pointer and the NUL-terminated string for a (const or not) char pointer.
|
||||
// void ::testing::internal::UniversalPrint(const T& value, ostream*);
|
||||
//
|
||||
// // Prints the fields of a tuple tersely to a string vector, one
|
||||
// // element for each field. Tuple support must be enabled in
|
||||
// // gtest-port.h.
|
||||
// std::vector<string> UniversalTersePrintTupleFieldsToStrings(
|
||||
// const Tuple& value);
|
||||
//
|
||||
// Known limitation:
|
||||
//
|
||||
// The print primitives print the elements of an STL-style container
|
||||
// using the compiler-inferred type of *iter where iter is a
|
||||
// const_iterator of the container. When const_iterator is an input
|
||||
// iterator but not a forward iterator, this inferred type may not
|
||||
// match value_type, and the print output may be incorrect. In
|
||||
// practice, this is rarely a problem as for most containers
|
||||
// const_iterator is a forward iterator. We'll fix this if there's an
|
||||
// actual need for it. Note that this fix cannot rely on value_type
|
||||
// being defined as many user-defined container types don't have
|
||||
// value_type.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
|
||||
|
||||
#include <ostream> // NOLINT
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
|
||||
namespace testing {
|
||||
|
||||
// Definitions in the 'internal' and 'internal2' name spaces are
|
||||
// subject to change without notice. DO NOT USE THEM IN USER CODE!
|
||||
namespace internal2 {
|
||||
|
||||
// Prints the given number of bytes in the given object to the given
|
||||
// ostream.
|
||||
GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes,
|
||||
size_t count,
|
||||
::std::ostream* os);
|
||||
|
||||
// For selecting which printer to use when a given type has neither <<
|
||||
// nor PrintTo().
|
||||
enum TypeKind {
|
||||
kProtobuf, // a protobuf type
|
||||
kConvertibleToInteger, // a type implicitly convertible to BiggestInt
|
||||
// (e.g. a named or unnamed enum type)
|
||||
kOtherType // anything else
|
||||
};
|
||||
|
||||
// TypeWithoutFormatter<T, kTypeKind>::PrintValue(value, os) is called
|
||||
// by the universal printer to print a value of type T when neither
|
||||
// operator<< nor PrintTo() is defined for T, where kTypeKind is the
|
||||
// "kind" of T as defined by enum TypeKind.
|
||||
template <typename T, TypeKind kTypeKind>
|
||||
class TypeWithoutFormatter {
|
||||
public:
|
||||
// This default version is called when kTypeKind is kOtherType.
|
||||
static void PrintValue(const T& value, ::std::ostream* os) {
|
||||
PrintBytesInObjectTo(reinterpret_cast<const unsigned char*>(&value),
|
||||
sizeof(value), os);
|
||||
}
|
||||
};
|
||||
|
||||
// We print a protobuf using its ShortDebugString() when the string
|
||||
// doesn't exceed this many characters; otherwise we print it using
|
||||
// DebugString() for better readability.
|
||||
const size_t kProtobufOneLinerMaxLength = 50;
|
||||
|
||||
template <typename T>
|
||||
class TypeWithoutFormatter<T, kProtobuf> {
|
||||
public:
|
||||
static void PrintValue(const T& value, ::std::ostream* os) {
|
||||
const ::testing::internal::string short_str = value.ShortDebugString();
|
||||
const ::testing::internal::string pretty_str =
|
||||
short_str.length() <= kProtobufOneLinerMaxLength ?
|
||||
short_str : ("\n" + value.DebugString());
|
||||
*os << ("<" + pretty_str + ">");
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class TypeWithoutFormatter<T, kConvertibleToInteger> {
|
||||
public:
|
||||
// Since T has no << operator or PrintTo() but can be implicitly
|
||||
// converted to BiggestInt, we print it as a BiggestInt.
|
||||
//
|
||||
// Most likely T is an enum type (either named or unnamed), in which
|
||||
// case printing it as an integer is the desired behavior. In case
|
||||
// T is not an enum, printing it as an integer is the best we can do
|
||||
// given that it has no user-defined printer.
|
||||
static void PrintValue(const T& value, ::std::ostream* os) {
|
||||
const internal::BiggestInt kBigInt = value;
|
||||
*os << kBigInt;
|
||||
}
|
||||
};
|
||||
|
||||
// Prints the given value to the given ostream. If the value is a
|
||||
// protocol message, its debug string is printed; if it's an enum or
|
||||
// of a type implicitly convertible to BiggestInt, it's printed as an
|
||||
// integer; otherwise the bytes in the value are printed. This is
|
||||
// what UniversalPrinter<T>::Print() does when it knows nothing about
|
||||
// type T and T has neither << operator nor PrintTo().
|
||||
//
|
||||
// A user can override this behavior for a class type Foo by defining
|
||||
// a << operator in the namespace where Foo is defined.
|
||||
//
|
||||
// We put this operator in namespace 'internal2' instead of 'internal'
|
||||
// to simplify the implementation, as much code in 'internal' needs to
|
||||
// use << in STL, which would conflict with our own << were it defined
|
||||
// in 'internal'.
|
||||
//
|
||||
// Note that this operator<< takes a generic std::basic_ostream<Char,
|
||||
// CharTraits> type instead of the more restricted std::ostream. If
|
||||
// we define it to take an std::ostream instead, we'll get an
|
||||
// "ambiguous overloads" compiler error when trying to print a type
|
||||
// Foo that supports streaming to std::basic_ostream<Char,
|
||||
// CharTraits>, as the compiler cannot tell whether
|
||||
// operator<<(std::ostream&, const T&) or
|
||||
// operator<<(std::basic_stream<Char, CharTraits>, const Foo&) is more
|
||||
// specific.
|
||||
template <typename Char, typename CharTraits, typename T>
|
||||
::std::basic_ostream<Char, CharTraits>& operator<<(
|
||||
::std::basic_ostream<Char, CharTraits>& os, const T& x) {
|
||||
TypeWithoutFormatter<T,
|
||||
(internal::IsAProtocolMessage<T>::value ? kProtobuf :
|
||||
internal::ImplicitlyConvertible<const T&, internal::BiggestInt>::value ?
|
||||
kConvertibleToInteger : kOtherType)>::PrintValue(x, &os);
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace internal2
|
||||
} // namespace testing
|
||||
|
||||
// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up
|
||||
// magic needed for implementing UniversalPrinter won't work.
|
||||
namespace testing_internal {
|
||||
|
||||
// Used to print a value that is not an STL-style container when the
|
||||
// user doesn't define PrintTo() for it.
|
||||
template <typename T>
|
||||
void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) {
|
||||
// With the following statement, during unqualified name lookup,
|
||||
// testing::internal2::operator<< appears as if it was declared in
|
||||
// the nearest enclosing namespace that contains both
|
||||
// ::testing_internal and ::testing::internal2, i.e. the global
|
||||
// namespace. For more details, refer to the C++ Standard section
|
||||
// 7.3.4-1 [namespace.udir]. This allows us to fall back onto
|
||||
// testing::internal2::operator<< in case T doesn't come with a <<
|
||||
// operator.
|
||||
//
|
||||
// We cannot write 'using ::testing::internal2::operator<<;', which
|
||||
// gcc 3.3 fails to compile due to a compiler bug.
|
||||
using namespace ::testing::internal2; // NOLINT
|
||||
|
||||
// Assuming T is defined in namespace foo, in the next statement,
|
||||
// the compiler will consider all of:
|
||||
//
|
||||
// 1. foo::operator<< (thanks to Koenig look-up),
|
||||
// 2. ::operator<< (as the current namespace is enclosed in ::),
|
||||
// 3. testing::internal2::operator<< (thanks to the using statement above).
|
||||
//
|
||||
// The operator<< whose type matches T best will be picked.
|
||||
//
|
||||
// We deliberately allow #2 to be a candidate, as sometimes it's
|
||||
// impossible to define #1 (e.g. when foo is ::std, defining
|
||||
// anything in it is undefined behavior unless you are a compiler
|
||||
// vendor.).
|
||||
*os << value;
|
||||
}
|
||||
|
||||
} // namespace testing_internal
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// UniversalPrinter<T>::Print(value, ostream_ptr) prints the given
|
||||
// value to the given ostream. The caller must ensure that
|
||||
// 'ostream_ptr' is not NULL, or the behavior is undefined.
|
||||
//
|
||||
// We define UniversalPrinter as a class template (as opposed to a
|
||||
// function template), as we need to partially specialize it for
|
||||
// reference types, which cannot be done with function templates.
|
||||
template <typename T>
|
||||
class UniversalPrinter;
|
||||
|
||||
template <typename T>
|
||||
void UniversalPrint(const T& value, ::std::ostream* os);
|
||||
|
||||
// Used to print an STL-style container when the user doesn't define
|
||||
// a PrintTo() for it.
|
||||
template <typename C>
|
||||
void DefaultPrintTo(IsContainer /* dummy */,
|
||||
false_type /* is not a pointer */,
|
||||
const C& container, ::std::ostream* os) {
|
||||
const size_t kMaxCount = 32; // The maximum number of elements to print.
|
||||
*os << '{';
|
||||
size_t count = 0;
|
||||
for (typename C::const_iterator it = container.begin();
|
||||
it != container.end(); ++it, ++count) {
|
||||
if (count > 0) {
|
||||
*os << ',';
|
||||
if (count == kMaxCount) { // Enough has been printed.
|
||||
*os << " ...";
|
||||
break;
|
||||
}
|
||||
}
|
||||
*os << ' ';
|
||||
// We cannot call PrintTo(*it, os) here as PrintTo() doesn't
|
||||
// handle *it being a native array.
|
||||
internal::UniversalPrint(*it, os);
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
*os << ' ';
|
||||
}
|
||||
*os << '}';
|
||||
}
|
||||
|
||||
// Used to print a pointer that is neither a char pointer nor a member
|
||||
// pointer, when the user doesn't define PrintTo() for it. (A member
|
||||
// variable pointer or member function pointer doesn't really point to
|
||||
// a location in the address space. Their representation is
|
||||
// implementation-defined. Therefore they will be printed as raw
|
||||
// bytes.)
|
||||
template <typename T>
|
||||
void DefaultPrintTo(IsNotContainer /* dummy */,
|
||||
true_type /* is a pointer */,
|
||||
T* p, ::std::ostream* os) {
|
||||
if (p == NULL) {
|
||||
*os << "NULL";
|
||||
} else {
|
||||
// C++ doesn't allow casting from a function pointer to any object
|
||||
// pointer.
|
||||
//
|
||||
// IsTrue() silences warnings: "Condition is always true",
|
||||
// "unreachable code".
|
||||
if (IsTrue(ImplicitlyConvertible<T*, const void*>::value)) {
|
||||
// T is not a function type. We just call << to print p,
|
||||
// relying on ADL to pick up user-defined << for their pointer
|
||||
// types, if any.
|
||||
*os << p;
|
||||
} else {
|
||||
// T is a function type, so '*os << p' doesn't do what we want
|
||||
// (it just prints p as bool). We want to print p as a const
|
||||
// void*. However, we cannot cast it to const void* directly,
|
||||
// even using reinterpret_cast, as earlier versions of gcc
|
||||
// (e.g. 3.4.5) cannot compile the cast when p is a function
|
||||
// pointer. Casting to UInt64 first solves the problem.
|
||||
*os << reinterpret_cast<const void*>(
|
||||
reinterpret_cast<internal::UInt64>(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Used to print a non-container, non-pointer value when the user
|
||||
// doesn't define PrintTo() for it.
|
||||
template <typename T>
|
||||
void DefaultPrintTo(IsNotContainer /* dummy */,
|
||||
false_type /* is not a pointer */,
|
||||
const T& value, ::std::ostream* os) {
|
||||
::testing_internal::DefaultPrintNonContainerTo(value, os);
|
||||
}
|
||||
|
||||
// Prints the given value using the << operator if it has one;
|
||||
// otherwise prints the bytes in it. This is what
|
||||
// UniversalPrinter<T>::Print() does when PrintTo() is not specialized
|
||||
// or overloaded for type T.
|
||||
//
|
||||
// A user can override this behavior for a class type Foo by defining
|
||||
// an overload of PrintTo() in the namespace where Foo is defined. We
|
||||
// give the user this option as sometimes defining a << operator for
|
||||
// Foo is not desirable (e.g. the coding style may prevent doing it,
|
||||
// or there is already a << operator but it doesn't do what the user
|
||||
// wants).
|
||||
template <typename T>
|
||||
void PrintTo(const T& value, ::std::ostream* os) {
|
||||
// DefaultPrintTo() is overloaded. The type of its first two
|
||||
// arguments determine which version will be picked. If T is an
|
||||
// STL-style container, the version for container will be called; if
|
||||
// T is a pointer, the pointer version will be called; otherwise the
|
||||
// generic version will be called.
|
||||
//
|
||||
// Note that we check for container types here, prior to we check
|
||||
// for protocol message types in our operator<<. The rationale is:
|
||||
//
|
||||
// For protocol messages, we want to give people a chance to
|
||||
// override Google Mock's format by defining a PrintTo() or
|
||||
// operator<<. For STL containers, other formats can be
|
||||
// incompatible with Google Mock's format for the container
|
||||
// elements; therefore we check for container types here to ensure
|
||||
// that our format is used.
|
||||
//
|
||||
// The second argument of DefaultPrintTo() is needed to bypass a bug
|
||||
// in Symbian's C++ compiler that prevents it from picking the right
|
||||
// overload between:
|
||||
//
|
||||
// PrintTo(const T& x, ...);
|
||||
// PrintTo(T* x, ...);
|
||||
DefaultPrintTo(IsContainerTest<T>(0), is_pointer<T>(), value, os);
|
||||
}
|
||||
|
||||
// The following list of PrintTo() overloads tells
|
||||
// UniversalPrinter<T>::Print() how to print standard types (built-in
|
||||
// types, strings, plain arrays, and pointers).
|
||||
|
||||
// Overloads for various char types.
|
||||
GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os);
|
||||
GTEST_API_ void PrintTo(signed char c, ::std::ostream* os);
|
||||
inline void PrintTo(char c, ::std::ostream* os) {
|
||||
// When printing a plain char, we always treat it as unsigned. This
|
||||
// way, the output won't be affected by whether the compiler thinks
|
||||
// char is signed or not.
|
||||
PrintTo(static_cast<unsigned char>(c), os);
|
||||
}
|
||||
|
||||
// Overloads for other simple built-in types.
|
||||
inline void PrintTo(bool x, ::std::ostream* os) {
|
||||
*os << (x ? "true" : "false");
|
||||
}
|
||||
|
||||
// Overload for wchar_t type.
|
||||
// Prints a wchar_t as a symbol if it is printable or as its internal
|
||||
// code otherwise and also as its decimal code (except for L'\0').
|
||||
// The L'\0' char is printed as "L'\\0'". The decimal code is printed
|
||||
// as signed integer when wchar_t is implemented by the compiler
|
||||
// as a signed type and is printed as an unsigned integer when wchar_t
|
||||
// is implemented as an unsigned type.
|
||||
GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os);
|
||||
|
||||
// Overloads for C strings.
|
||||
GTEST_API_ void PrintTo(const char* s, ::std::ostream* os);
|
||||
inline void PrintTo(char* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const char*>(s), os);
|
||||
}
|
||||
|
||||
// signed/unsigned char is often used for representing binary data, so
|
||||
// we print pointers to it as void* to be safe.
|
||||
inline void PrintTo(const signed char* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||
}
|
||||
inline void PrintTo(signed char* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||
}
|
||||
inline void PrintTo(const unsigned char* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||
}
|
||||
inline void PrintTo(unsigned char* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const void*>(s), os);
|
||||
}
|
||||
|
||||
// MSVC can be configured to define wchar_t as a typedef of unsigned
|
||||
// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native
|
||||
// type. When wchar_t is a typedef, defining an overload for const
|
||||
// wchar_t* would cause unsigned short* be printed as a wide string,
|
||||
// possibly causing invalid memory accesses.
|
||||
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
|
||||
// Overloads for wide C strings
|
||||
GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os);
|
||||
inline void PrintTo(wchar_t* s, ::std::ostream* os) {
|
||||
PrintTo(ImplicitCast_<const wchar_t*>(s), os);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Overload for C arrays. Multi-dimensional arrays are printed
|
||||
// properly.
|
||||
|
||||
// Prints the given number of elements in an array, without printing
|
||||
// the curly braces.
|
||||
template <typename T>
|
||||
void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) {
|
||||
UniversalPrint(a[0], os);
|
||||
for (size_t i = 1; i != count; i++) {
|
||||
*os << ", ";
|
||||
UniversalPrint(a[i], os);
|
||||
}
|
||||
}
|
||||
|
||||
// Overloads for ::string and ::std::string.
|
||||
#if GTEST_HAS_GLOBAL_STRING
|
||||
GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::string& s, ::std::ostream* os) {
|
||||
PrintStringTo(s, os);
|
||||
}
|
||||
#endif // GTEST_HAS_GLOBAL_STRING
|
||||
|
||||
GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::std::string& s, ::std::ostream* os) {
|
||||
PrintStringTo(s, os);
|
||||
}
|
||||
|
||||
// Overloads for ::wstring and ::std::wstring.
|
||||
#if GTEST_HAS_GLOBAL_WSTRING
|
||||
GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::wstring& s, ::std::ostream* os) {
|
||||
PrintWideStringTo(s, os);
|
||||
}
|
||||
#endif // GTEST_HAS_GLOBAL_WSTRING
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os);
|
||||
inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) {
|
||||
PrintWideStringTo(s, os);
|
||||
}
|
||||
#endif // GTEST_HAS_STD_WSTRING
|
||||
|
||||
#if GTEST_HAS_TR1_TUPLE
|
||||
// Overload for ::std::tr1::tuple. Needed for printing function arguments,
|
||||
// which are packed as tuples.
|
||||
|
||||
// Helper function for printing a tuple. T must be instantiated with
|
||||
// a tuple type.
|
||||
template <typename T>
|
||||
void PrintTupleTo(const T& t, ::std::ostream* os);
|
||||
|
||||
// Overloaded PrintTo() for tuples of various arities. We support
|
||||
// tuples of up-to 10 fields. The following implementation works
|
||||
// regardless of whether tr1::tuple is implemented using the
|
||||
// non-standard variadic template feature or not.
|
||||
|
||||
inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1>
|
||||
void PrintTo(const ::std::tr1::tuple<T1>& t, ::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2>& t, ::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3>& t, ::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4>& t, ::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5>& t,
|
||||
::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6>& t,
|
||||
::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6, typename T7>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7>& t,
|
||||
::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6, typename T7, typename T8>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8>& t,
|
||||
::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6, typename T7, typename T8, typename T9>
|
||||
void PrintTo(const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9>& t,
|
||||
::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4, typename T5,
|
||||
typename T6, typename T7, typename T8, typename T9, typename T10>
|
||||
void PrintTo(
|
||||
const ::std::tr1::tuple<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>& t,
|
||||
::std::ostream* os) {
|
||||
PrintTupleTo(t, os);
|
||||
}
|
||||
#endif // GTEST_HAS_TR1_TUPLE
|
||||
|
||||
// Overload for std::pair.
|
||||
template <typename T1, typename T2>
|
||||
void PrintTo(const ::std::pair<T1, T2>& value, ::std::ostream* os) {
|
||||
*os << '(';
|
||||
// We cannot use UniversalPrint(value.first, os) here, as T1 may be
|
||||
// a reference type. The same for printing value.second.
|
||||
UniversalPrinter<T1>::Print(value.first, os);
|
||||
*os << ", ";
|
||||
UniversalPrinter<T2>::Print(value.second, os);
|
||||
*os << ')';
|
||||
}
|
||||
|
||||
// Implements printing a non-reference type T by letting the compiler
|
||||
// pick the right overload of PrintTo() for T.
|
||||
template <typename T>
|
||||
class UniversalPrinter {
|
||||
public:
|
||||
// MSVC warns about adding const to a function type, so we want to
|
||||
// disable the warning.
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(push) // Saves the current warning state.
|
||||
# pragma warning(disable:4180) // Temporarily disables warning 4180.
|
||||
#endif // _MSC_VER
|
||||
|
||||
// Note: we deliberately don't call this PrintTo(), as that name
|
||||
// conflicts with ::testing::internal::PrintTo in the body of the
|
||||
// function.
|
||||
static void Print(const T& value, ::std::ostream* os) {
|
||||
// By default, ::testing::internal::PrintTo() is used for printing
|
||||
// the value.
|
||||
//
|
||||
// Thanks to Koenig look-up, if T is a class and has its own
|
||||
// PrintTo() function defined in its namespace, that function will
|
||||
// be visible here. Since it is more specific than the generic ones
|
||||
// in ::testing::internal, it will be picked by the compiler in the
|
||||
// following statement - exactly what we want.
|
||||
PrintTo(value, os);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop) // Restores the warning state.
|
||||
#endif // _MSC_VER
|
||||
};
|
||||
|
||||
// UniversalPrintArray(begin, len, os) prints an array of 'len'
|
||||
// elements, starting at address 'begin'.
|
||||
template <typename T>
|
||||
void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) {
|
||||
if (len == 0) {
|
||||
*os << "{}";
|
||||
} else {
|
||||
*os << "{ ";
|
||||
const size_t kThreshold = 18;
|
||||
const size_t kChunkSize = 8;
|
||||
// If the array has more than kThreshold elements, we'll have to
|
||||
// omit some details by printing only the first and the last
|
||||
// kChunkSize elements.
|
||||
// TODO(wan@google.com): let the user control the threshold using a flag.
|
||||
if (len <= kThreshold) {
|
||||
PrintRawArrayTo(begin, len, os);
|
||||
} else {
|
||||
PrintRawArrayTo(begin, kChunkSize, os);
|
||||
*os << ", ..., ";
|
||||
PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os);
|
||||
}
|
||||
*os << " }";
|
||||
}
|
||||
}
|
||||
// This overload prints a (const) char array compactly.
|
||||
GTEST_API_ void UniversalPrintArray(
|
||||
const char* begin, size_t len, ::std::ostream* os);
|
||||
|
||||
// This overload prints a (const) wchar_t array compactly.
|
||||
GTEST_API_ void UniversalPrintArray(
|
||||
const wchar_t* begin, size_t len, ::std::ostream* os);
|
||||
|
||||
// Implements printing an array type T[N].
|
||||
template <typename T, size_t N>
|
||||
class UniversalPrinter<T[N]> {
|
||||
public:
|
||||
// Prints the given array, omitting some elements when there are too
|
||||
// many.
|
||||
static void Print(const T (&a)[N], ::std::ostream* os) {
|
||||
UniversalPrintArray(a, N, os);
|
||||
}
|
||||
};
|
||||
|
||||
// Implements printing a reference type T&.
|
||||
template <typename T>
|
||||
class UniversalPrinter<T&> {
|
||||
public:
|
||||
// MSVC warns about adding const to a function type, so we want to
|
||||
// disable the warning.
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(push) // Saves the current warning state.
|
||||
# pragma warning(disable:4180) // Temporarily disables warning 4180.
|
||||
#endif // _MSC_VER
|
||||
|
||||
static void Print(const T& value, ::std::ostream* os) {
|
||||
// Prints the address of the value. We use reinterpret_cast here
|
||||
// as static_cast doesn't compile when T is a function type.
|
||||
*os << "@" << reinterpret_cast<const void*>(&value) << " ";
|
||||
|
||||
// Then prints the value itself.
|
||||
UniversalPrint(value, os);
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# pragma warning(pop) // Restores the warning state.
|
||||
#endif // _MSC_VER
|
||||
};
|
||||
|
||||
// Prints a value tersely: for a reference type, the referenced value
|
||||
// (but not the address) is printed; for a (const) char pointer, the
|
||||
// NUL-terminated string (but not the pointer) is printed.
|
||||
|
||||
template <typename T>
|
||||
class UniversalTersePrinter {
|
||||
public:
|
||||
static void Print(const T& value, ::std::ostream* os) {
|
||||
UniversalPrint(value, os);
|
||||
}
|
||||
};
|
||||
template <typename T>
|
||||
class UniversalTersePrinter<T&> {
|
||||
public:
|
||||
static void Print(const T& value, ::std::ostream* os) {
|
||||
UniversalPrint(value, os);
|
||||
}
|
||||
};
|
||||
template <typename T, size_t N>
|
||||
class UniversalTersePrinter<T[N]> {
|
||||
public:
|
||||
static void Print(const T (&value)[N], ::std::ostream* os) {
|
||||
UniversalPrinter<T[N]>::Print(value, os);
|
||||
}
|
||||
};
|
||||
template <>
|
||||
class UniversalTersePrinter<const char*> {
|
||||
public:
|
||||
static void Print(const char* str, ::std::ostream* os) {
|
||||
if (str == NULL) {
|
||||
*os << "NULL";
|
||||
} else {
|
||||
UniversalPrint(string(str), os);
|
||||
}
|
||||
}
|
||||
};
|
||||
template <>
|
||||
class UniversalTersePrinter<char*> {
|
||||
public:
|
||||
static void Print(char* str, ::std::ostream* os) {
|
||||
UniversalTersePrinter<const char*>::Print(str, os);
|
||||
}
|
||||
};
|
||||
|
||||
#if GTEST_HAS_STD_WSTRING
|
||||
template <>
|
||||
class UniversalTersePrinter<const wchar_t*> {
|
||||
public:
|
||||
static void Print(const wchar_t* str, ::std::ostream* os) {
|
||||
if (str == NULL) {
|
||||
*os << "NULL";
|
||||
} else {
|
||||
UniversalPrint(::std::wstring(str), os);
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
template <>
|
||||
class UniversalTersePrinter<wchar_t*> {
|
||||
public:
|
||||
static void Print(wchar_t* str, ::std::ostream* os) {
|
||||
UniversalTersePrinter<const wchar_t*>::Print(str, os);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void UniversalTersePrint(const T& value, ::std::ostream* os) {
|
||||
UniversalTersePrinter<T>::Print(value, os);
|
||||
}
|
||||
|
||||
// Prints a value using the type inferred by the compiler. The
|
||||
// difference between this and UniversalTersePrint() is that for a
|
||||
// (const) char pointer, this prints both the pointer and the
|
||||
// NUL-terminated string.
|
||||
template <typename T>
|
||||
void UniversalPrint(const T& value, ::std::ostream* os) {
|
||||
// A workarond for the bug in VC++ 7.1 that prevents us from instantiating
|
||||
// UniversalPrinter with T directly.
|
||||
typedef T T1;
|
||||
UniversalPrinter<T1>::Print(value, os);
|
||||
}
|
||||
|
||||
#if GTEST_HAS_TR1_TUPLE
|
||||
typedef ::std::vector<string> Strings;
|
||||
|
||||
// This helper template allows PrintTo() for tuples and
|
||||
// UniversalTersePrintTupleFieldsToStrings() to be defined by
|
||||
// induction on the number of tuple fields. The idea is that
|
||||
// TuplePrefixPrinter<N>::PrintPrefixTo(t, os) prints the first N
|
||||
// fields in tuple t, and can be defined in terms of
|
||||
// TuplePrefixPrinter<N - 1>.
|
||||
|
||||
// The inductive case.
|
||||
template <size_t N>
|
||||
struct TuplePrefixPrinter {
|
||||
// Prints the first N fields of a tuple.
|
||||
template <typename Tuple>
|
||||
static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
|
||||
TuplePrefixPrinter<N - 1>::PrintPrefixTo(t, os);
|
||||
*os << ", ";
|
||||
UniversalPrinter<typename ::std::tr1::tuple_element<N - 1, Tuple>::type>
|
||||
::Print(::std::tr1::get<N - 1>(t), os);
|
||||
}
|
||||
|
||||
// Tersely prints the first N fields of a tuple to a string vector,
|
||||
// one element for each field.
|
||||
template <typename Tuple>
|
||||
static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
|
||||
TuplePrefixPrinter<N - 1>::TersePrintPrefixToStrings(t, strings);
|
||||
::std::stringstream ss;
|
||||
UniversalTersePrint(::std::tr1::get<N - 1>(t), &ss);
|
||||
strings->push_back(ss.str());
|
||||
}
|
||||
};
|
||||
|
||||
// Base cases.
|
||||
template <>
|
||||
struct TuplePrefixPrinter<0> {
|
||||
template <typename Tuple>
|
||||
static void PrintPrefixTo(const Tuple&, ::std::ostream*) {}
|
||||
|
||||
template <typename Tuple>
|
||||
static void TersePrintPrefixToStrings(const Tuple&, Strings*) {}
|
||||
};
|
||||
// We have to specialize the entire TuplePrefixPrinter<> class
|
||||
// template here, even though the definition of
|
||||
// TersePrintPrefixToStrings() is the same as the generic version, as
|
||||
// Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't
|
||||
// support specializing a method template of a class template.
|
||||
template <>
|
||||
struct TuplePrefixPrinter<1> {
|
||||
template <typename Tuple>
|
||||
static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) {
|
||||
UniversalPrinter<typename ::std::tr1::tuple_element<0, Tuple>::type>::
|
||||
Print(::std::tr1::get<0>(t), os);
|
||||
}
|
||||
|
||||
template <typename Tuple>
|
||||
static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) {
|
||||
::std::stringstream ss;
|
||||
UniversalTersePrint(::std::tr1::get<0>(t), &ss);
|
||||
strings->push_back(ss.str());
|
||||
}
|
||||
};
|
||||
|
||||
// Helper function for printing a tuple. T must be instantiated with
|
||||
// a tuple type.
|
||||
template <typename T>
|
||||
void PrintTupleTo(const T& t, ::std::ostream* os) {
|
||||
*os << "(";
|
||||
TuplePrefixPrinter< ::std::tr1::tuple_size<T>::value>::
|
||||
PrintPrefixTo(t, os);
|
||||
*os << ")";
|
||||
}
|
||||
|
||||
// Prints the fields of a tuple tersely to a string vector, one
|
||||
// element for each field. See the comment before
|
||||
// UniversalTersePrint() for how we define "tersely".
|
||||
template <typename Tuple>
|
||||
Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) {
|
||||
Strings result;
|
||||
TuplePrefixPrinter< ::std::tr1::tuple_size<Tuple>::value>::
|
||||
TersePrintPrefixToStrings(value, &result);
|
||||
return result;
|
||||
}
|
||||
#endif // GTEST_HAS_TR1_TUPLE
|
||||
|
||||
} // namespace internal
|
||||
|
||||
template <typename T>
|
||||
::std::string PrintToString(const T& value) {
|
||||
::std::stringstream ss;
|
||||
internal::UniversalTersePrinter<T>::Print(value, &ss);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_
|
|
@ -1,232 +0,0 @@
|
|||
// Copyright 2007, Google 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:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
//
|
||||
// Utilities for testing Google Test itself and code that uses Google Test
|
||||
// (e.g. frameworks built on top of Google Test).
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
namespace testing {
|
||||
|
||||
// This helper class can be used to mock out Google Test failure reporting
|
||||
// so that we can test Google Test or code that builds on Google Test.
|
||||
//
|
||||
// An object of this class appends a TestPartResult object to the
|
||||
// TestPartResultArray object given in the constructor whenever a Google Test
|
||||
// failure is reported. It can either intercept only failures that are
|
||||
// generated in the same thread that created this object or it can intercept
|
||||
// all generated failures. The scope of this mock object can be controlled with
|
||||
// the second argument to the two arguments constructor.
|
||||
class GTEST_API_ ScopedFakeTestPartResultReporter
|
||||
: public TestPartResultReporterInterface {
|
||||
public:
|
||||
// The two possible mocking modes of this object.
|
||||
enum InterceptMode {
|
||||
INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures.
|
||||
INTERCEPT_ALL_THREADS // Intercepts all failures.
|
||||
};
|
||||
|
||||
// The c'tor sets this object as the test part result reporter used
|
||||
// by Google Test. The 'result' parameter specifies where to report the
|
||||
// results. This reporter will only catch failures generated in the current
|
||||
// thread. DEPRECATED
|
||||
explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result);
|
||||
|
||||
// Same as above, but you can choose the interception scope of this object.
|
||||
ScopedFakeTestPartResultReporter(InterceptMode intercept_mode,
|
||||
TestPartResultArray* result);
|
||||
|
||||
// The d'tor restores the previous test part result reporter.
|
||||
virtual ~ScopedFakeTestPartResultReporter();
|
||||
|
||||
// Appends the TestPartResult object to the TestPartResultArray
|
||||
// received in the constructor.
|
||||
//
|
||||
// This method is from the TestPartResultReporterInterface
|
||||
// interface.
|
||||
virtual void ReportTestPartResult(const TestPartResult& result);
|
||||
private:
|
||||
void Init();
|
||||
|
||||
const InterceptMode intercept_mode_;
|
||||
TestPartResultReporterInterface* old_reporter_;
|
||||
TestPartResultArray* const result_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter);
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
// A helper class for implementing EXPECT_FATAL_FAILURE() and
|
||||
// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given
|
||||
// TestPartResultArray contains exactly one failure that has the given
|
||||
// type and contains the given substring. If that's not the case, a
|
||||
// non-fatal failure will be generated.
|
||||
class GTEST_API_ SingleFailureChecker {
|
||||
public:
|
||||
// The constructor remembers the arguments.
|
||||
SingleFailureChecker(const TestPartResultArray* results,
|
||||
TestPartResult::Type type,
|
||||
const string& substr);
|
||||
~SingleFailureChecker();
|
||||
private:
|
||||
const TestPartResultArray* const results_;
|
||||
const TestPartResult::Type type_;
|
||||
const string substr_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace testing
|
||||
|
||||
// A set of macros for testing Google Test assertions or code that's expected
|
||||
// to generate Google Test fatal failures. It verifies that the given
|
||||
// statement will cause exactly one fatal Google Test failure with 'substr'
|
||||
// being part of the failure message.
|
||||
//
|
||||
// There are two different versions of this macro. EXPECT_FATAL_FAILURE only
|
||||
// affects and considers failures generated in the current thread and
|
||||
// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
|
||||
//
|
||||
// The verification of the assertion is done correctly even when the statement
|
||||
// throws an exception or aborts the current function.
|
||||
//
|
||||
// Known restrictions:
|
||||
// - 'statement' cannot reference local non-static variables or
|
||||
// non-static members of the current object.
|
||||
// - 'statement' cannot return a value.
|
||||
// - You cannot stream a failure message to this macro.
|
||||
//
|
||||
// Note that even though the implementations of the following two
|
||||
// macros are much alike, we cannot refactor them to use a common
|
||||
// helper macro, due to some peculiarity in how the preprocessor
|
||||
// works. The AcceptsMacroThatExpandsToUnprotectedComma test in
|
||||
// gtest_unittest.cc will fail to compile if we do that.
|
||||
#define EXPECT_FATAL_FAILURE(statement, substr) \
|
||||
do { \
|
||||
class GTestExpectFatalFailureHelper {\
|
||||
public:\
|
||||
static void Execute() { statement; }\
|
||||
};\
|
||||
::testing::TestPartResultArray gtest_failures;\
|
||||
::testing::internal::SingleFailureChecker gtest_checker(\
|
||||
>est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
|
||||
{\
|
||||
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
|
||||
::testing::ScopedFakeTestPartResultReporter:: \
|
||||
INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\
|
||||
GTestExpectFatalFailureHelper::Execute();\
|
||||
}\
|
||||
} while (::testing::internal::AlwaysFalse())
|
||||
|
||||
#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
|
||||
do { \
|
||||
class GTestExpectFatalFailureHelper {\
|
||||
public:\
|
||||
static void Execute() { statement; }\
|
||||
};\
|
||||
::testing::TestPartResultArray gtest_failures;\
|
||||
::testing::internal::SingleFailureChecker gtest_checker(\
|
||||
>est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
|
||||
{\
|
||||
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
|
||||
::testing::ScopedFakeTestPartResultReporter:: \
|
||||
INTERCEPT_ALL_THREADS, >est_failures);\
|
||||
GTestExpectFatalFailureHelper::Execute();\
|
||||
}\
|
||||
} while (::testing::internal::AlwaysFalse())
|
||||
|
||||
// A macro for testing Google Test assertions or code that's expected to
|
||||
// generate Google Test non-fatal failures. It asserts that the given
|
||||
// statement will cause exactly one non-fatal Google Test failure with 'substr'
|
||||
// being part of the failure message.
|
||||
//
|
||||
// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only
|
||||
// affects and considers failures generated in the current thread and
|
||||
// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads.
|
||||
//
|
||||
// 'statement' is allowed to reference local variables and members of
|
||||
// the current object.
|
||||
//
|
||||
// The verification of the assertion is done correctly even when the statement
|
||||
// throws an exception or aborts the current function.
|
||||
//
|
||||
// Known restrictions:
|
||||
// - You cannot stream a failure message to this macro.
|
||||
//
|
||||
// Note that even though the implementations of the following two
|
||||
// macros are much alike, we cannot refactor them to use a common
|
||||
// helper macro, due to some peculiarity in how the preprocessor
|
||||
// works. If we do that, the code won't compile when the user gives
|
||||
// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that
|
||||
// expands to code containing an unprotected comma. The
|
||||
// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc
|
||||
// catches that.
|
||||
//
|
||||
// For the same reason, we have to write
|
||||
// if (::testing::internal::AlwaysTrue()) { statement; }
|
||||
// instead of
|
||||
// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
|
||||
// to avoid an MSVC warning on unreachable code.
|
||||
#define EXPECT_NONFATAL_FAILURE(statement, substr) \
|
||||
do {\
|
||||
::testing::TestPartResultArray gtest_failures;\
|
||||
::testing::internal::SingleFailureChecker gtest_checker(\
|
||||
>est_failures, ::testing::TestPartResult::kNonFatalFailure, \
|
||||
(substr));\
|
||||
{\
|
||||
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
|
||||
::testing::ScopedFakeTestPartResultReporter:: \
|
||||
INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\
|
||||
if (::testing::internal::AlwaysTrue()) { statement; }\
|
||||
}\
|
||||
} while (::testing::internal::AlwaysFalse())
|
||||
|
||||
#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \
|
||||
do {\
|
||||
::testing::TestPartResultArray gtest_failures;\
|
||||
::testing::internal::SingleFailureChecker gtest_checker(\
|
||||
>est_failures, ::testing::TestPartResult::kNonFatalFailure, \
|
||||
(substr));\
|
||||
{\
|
||||
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
|
||||
::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \
|
||||
>est_failures);\
|
||||
if (::testing::internal::AlwaysTrue()) { statement; }\
|
||||
}\
|
||||
} while (::testing::internal::AlwaysFalse())
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_
|
|
@ -1,179 +0,0 @@
|
|||
// Copyright 2008, Google 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:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: mheule@google.com (Markus Heule)
|
||||
//
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
|
||||
|
||||
#include <iosfwd>
|
||||
#include <vector>
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
#include "gtest/internal/gtest-string.h"
|
||||
|
||||
namespace testing {
|
||||
|
||||
// A copyable object representing the result of a test part (i.e. an
|
||||
// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()).
|
||||
//
|
||||
// Don't inherit from TestPartResult as its destructor is not virtual.
|
||||
class GTEST_API_ TestPartResult {
|
||||
public:
|
||||
// The possible outcomes of a test part (i.e. an assertion or an
|
||||
// explicit SUCCEED(), FAIL(), or ADD_FAILURE()).
|
||||
enum Type {
|
||||
kSuccess, // Succeeded.
|
||||
kNonFatalFailure, // Failed but the test can continue.
|
||||
kFatalFailure // Failed and the test should be terminated.
|
||||
};
|
||||
|
||||
// C'tor. TestPartResult does NOT have a default constructor.
|
||||
// Always use this constructor (with parameters) to create a
|
||||
// TestPartResult object.
|
||||
TestPartResult(Type a_type,
|
||||
const char* a_file_name,
|
||||
int a_line_number,
|
||||
const char* a_message)
|
||||
: type_(a_type),
|
||||
file_name_(a_file_name == NULL ? "" : a_file_name),
|
||||
line_number_(a_line_number),
|
||||
summary_(ExtractSummary(a_message)),
|
||||
message_(a_message) {
|
||||
}
|
||||
|
||||
// Gets the outcome of the test part.
|
||||
Type type() const { return type_; }
|
||||
|
||||
// Gets the name of the source file where the test part took place, or
|
||||
// NULL if it's unknown.
|
||||
const char* file_name() const {
|
||||
return file_name_.empty() ? NULL : file_name_.c_str();
|
||||
}
|
||||
|
||||
// Gets the line in the source file where the test part took place,
|
||||
// or -1 if it's unknown.
|
||||
int line_number() const { return line_number_; }
|
||||
|
||||
// Gets the summary of the failure message.
|
||||
const char* summary() const { return summary_.c_str(); }
|
||||
|
||||
// Gets the message associated with the test part.
|
||||
const char* message() const { return message_.c_str(); }
|
||||
|
||||
// Returns true iff the test part passed.
|
||||
bool passed() const { return type_ == kSuccess; }
|
||||
|
||||
// Returns true iff the test part failed.
|
||||
bool failed() const { return type_ != kSuccess; }
|
||||
|
||||
// Returns true iff the test part non-fatally failed.
|
||||
bool nonfatally_failed() const { return type_ == kNonFatalFailure; }
|
||||
|
||||
// Returns true iff the test part fatally failed.
|
||||
bool fatally_failed() const { return type_ == kFatalFailure; }
|
||||
|
||||
private:
|
||||
Type type_;
|
||||
|
||||
// Gets the summary of the failure message by omitting the stack
|
||||
// trace in it.
|
||||
static std::string ExtractSummary(const char* message);
|
||||
|
||||
// The name of the source file where the test part took place, or
|
||||
// "" if the source file is unknown.
|
||||
std::string file_name_;
|
||||
// The line in the source file where the test part took place, or -1
|
||||
// if the line number is unknown.
|
||||
int line_number_;
|
||||
std::string summary_; // The test failure summary.
|
||||
std::string message_; // The test failure message.
|
||||
};
|
||||
|
||||
// Prints a TestPartResult object.
|
||||
std::ostream& operator<<(std::ostream& os, const TestPartResult& result);
|
||||
|
||||
// An array of TestPartResult objects.
|
||||
//
|
||||
// Don't inherit from TestPartResultArray as its destructor is not
|
||||
// virtual.
|
||||
class GTEST_API_ TestPartResultArray {
|
||||
public:
|
||||
TestPartResultArray() {}
|
||||
|
||||
// Appends the given TestPartResult to the array.
|
||||
void Append(const TestPartResult& result);
|
||||
|
||||
// Returns the TestPartResult at the given index (0-based).
|
||||
const TestPartResult& GetTestPartResult(int index) const;
|
||||
|
||||
// Returns the number of TestPartResult objects in the array.
|
||||
int size() const;
|
||||
|
||||
private:
|
||||
std::vector<TestPartResult> array_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray);
|
||||
};
|
||||
|
||||
// This interface knows how to report a test part result.
|
||||
class TestPartResultReporterInterface {
|
||||
public:
|
||||
virtual ~TestPartResultReporterInterface() {}
|
||||
|
||||
virtual void ReportTestPartResult(const TestPartResult& result) = 0;
|
||||
};
|
||||
|
||||
namespace internal {
|
||||
|
||||
// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a
|
||||
// statement generates new fatal failures. To do so it registers itself as the
|
||||
// current test part result reporter. Besides checking if fatal failures were
|
||||
// reported, it only delegates the reporting to the former result reporter.
|
||||
// The original result reporter is restored in the destructor.
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
|
||||
class GTEST_API_ HasNewFatalFailureHelper
|
||||
: public TestPartResultReporterInterface {
|
||||
public:
|
||||
HasNewFatalFailureHelper();
|
||||
virtual ~HasNewFatalFailureHelper();
|
||||
virtual void ReportTestPartResult(const TestPartResult& result);
|
||||
bool has_new_fatal_failure() const { return has_new_fatal_failure_; }
|
||||
private:
|
||||
bool has_new_fatal_failure_;
|
||||
TestPartResultReporterInterface* original_reporter_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_
|
|
@ -1,259 +0,0 @@
|
|||
// Copyright 2008 Google 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:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
|
||||
|
||||
// This header implements typed tests and type-parameterized tests.
|
||||
|
||||
// Typed (aka type-driven) tests repeat the same test for types in a
|
||||
// list. You must know which types you want to test with when writing
|
||||
// typed tests. Here's how you do it:
|
||||
|
||||
#if 0
|
||||
|
||||
// First, define a fixture class template. It should be parameterized
|
||||
// by a type. Remember to derive it from testing::Test.
|
||||
template <typename T>
|
||||
class FooTest : public testing::Test {
|
||||
public:
|
||||
...
|
||||
typedef std::list<T> List;
|
||||
static T shared_;
|
||||
T value_;
|
||||
};
|
||||
|
||||
// Next, associate a list of types with the test case, which will be
|
||||
// repeated for each type in the list. The typedef is necessary for
|
||||
// the macro to parse correctly.
|
||||
typedef testing::Types<char, int, unsigned int> MyTypes;
|
||||
TYPED_TEST_CASE(FooTest, MyTypes);
|
||||
|
||||
// If the type list contains only one type, you can write that type
|
||||
// directly without Types<...>:
|
||||
// TYPED_TEST_CASE(FooTest, int);
|
||||
|
||||
// Then, use TYPED_TEST() instead of TEST_F() to define as many typed
|
||||
// tests for this test case as you want.
|
||||
TYPED_TEST(FooTest, DoesBlah) {
|
||||
// Inside a test, refer to TypeParam to get the type parameter.
|
||||
// Since we are inside a derived class template, C++ requires use to
|
||||
// visit the members of FooTest via 'this'.
|
||||
TypeParam n = this->value_;
|
||||
|
||||
// To visit static members of the fixture, add the TestFixture::
|
||||
// prefix.
|
||||
n += TestFixture::shared_;
|
||||
|
||||
// To refer to typedefs in the fixture, add the "typename
|
||||
// TestFixture::" prefix.
|
||||
typename TestFixture::List values;
|
||||
values.push_back(n);
|
||||
...
|
||||
}
|
||||
|
||||
TYPED_TEST(FooTest, HasPropertyA) { ... }
|
||||
|
||||
#endif // 0
|
||||
|
||||
// Type-parameterized tests are abstract test patterns parameterized
|
||||
// by a type. Compared with typed tests, type-parameterized tests
|
||||
// allow you to define the test pattern without knowing what the type
|
||||
// parameters are. The defined pattern can be instantiated with
|
||||
// different types any number of times, in any number of translation
|
||||
// units.
|
||||
//
|
||||
// If you are designing an interface or concept, you can define a
|
||||
// suite of type-parameterized tests to verify properties that any
|
||||
// valid implementation of the interface/concept should have. Then,
|
||||
// each implementation can easily instantiate the test suite to verify
|
||||
// that it conforms to the requirements, without having to write
|
||||
// similar tests repeatedly. Here's an example:
|
||||
|
||||
#if 0
|
||||
|
||||
// First, define a fixture class template. It should be parameterized
|
||||
// by a type. Remember to derive it from testing::Test.
|
||||
template <typename T>
|
||||
class FooTest : public testing::Test {
|
||||
...
|
||||
};
|
||||
|
||||
// Next, declare that you will define a type-parameterized test case
|
||||
// (the _P suffix is for "parameterized" or "pattern", whichever you
|
||||
// prefer):
|
||||
TYPED_TEST_CASE_P(FooTest);
|
||||
|
||||
// Then, use TYPED_TEST_P() to define as many type-parameterized tests
|
||||
// for this type-parameterized test case as you want.
|
||||
TYPED_TEST_P(FooTest, DoesBlah) {
|
||||
// Inside a test, refer to TypeParam to get the type parameter.
|
||||
TypeParam n = 0;
|
||||
...
|
||||
}
|
||||
|
||||
TYPED_TEST_P(FooTest, HasPropertyA) { ... }
|
||||
|
||||
// Now the tricky part: you need to register all test patterns before
|
||||
// you can instantiate them. The first argument of the macro is the
|
||||
// test case name; the rest are the names of the tests in this test
|
||||
// case.
|
||||
REGISTER_TYPED_TEST_CASE_P(FooTest,
|
||||
DoesBlah, HasPropertyA);
|
||||
|
||||
// Finally, you are free to instantiate the pattern with the types you
|
||||
// want. If you put the above code in a header file, you can #include
|
||||
// it in multiple C++ source files and instantiate it multiple times.
|
||||
//
|
||||
// To distinguish different instances of the pattern, the first
|
||||
// argument to the INSTANTIATE_* macro is a prefix that will be added
|
||||
// to the actual test case name. Remember to pick unique prefixes for
|
||||
// different instances.
|
||||
typedef testing::Types<char, int, unsigned int> MyTypes;
|
||||
INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);
|
||||
|
||||
// If the type list contains only one type, you can write that type
|
||||
// directly without Types<...>:
|
||||
// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int);
|
||||
|
||||
#endif // 0
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
#include "gtest/internal/gtest-type-util.h"
|
||||
|
||||
// Implements typed tests.
|
||||
|
||||
#if GTEST_HAS_TYPED_TEST
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Expands to the name of the typedef for the type parameters of the
|
||||
// given test case.
|
||||
# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_
|
||||
|
||||
// The 'Types' template argument below must have spaces around it
|
||||
// since some compilers may choke on '>>' when passing a template
|
||||
// instance (e.g. Types<int>)
|
||||
# define TYPED_TEST_CASE(CaseName, Types) \
|
||||
typedef ::testing::internal::TypeList< Types >::type \
|
||||
GTEST_TYPE_PARAMS_(CaseName)
|
||||
|
||||
# define TYPED_TEST(CaseName, TestName) \
|
||||
template <typename gtest_TypeParam_> \
|
||||
class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
|
||||
: public CaseName<gtest_TypeParam_> { \
|
||||
private: \
|
||||
typedef CaseName<gtest_TypeParam_> TestFixture; \
|
||||
typedef gtest_TypeParam_ TypeParam; \
|
||||
virtual void TestBody(); \
|
||||
}; \
|
||||
bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \
|
||||
::testing::internal::TypeParameterizedTest< \
|
||||
CaseName, \
|
||||
::testing::internal::TemplateSel< \
|
||||
GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \
|
||||
GTEST_TYPE_PARAMS_(CaseName)>::Register(\
|
||||
"", #CaseName, #TestName, 0); \
|
||||
template <typename gtest_TypeParam_> \
|
||||
void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody()
|
||||
|
||||
#endif // GTEST_HAS_TYPED_TEST
|
||||
|
||||
// Implements type-parameterized tests.
|
||||
|
||||
#if GTEST_HAS_TYPED_TEST_P
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Expands to the namespace name that the type-parameterized tests for
|
||||
// the given type-parameterized test case are defined in. The exact
|
||||
// name of the namespace is subject to change without notice.
|
||||
# define GTEST_CASE_NAMESPACE_(TestCaseName) \
|
||||
gtest_case_##TestCaseName##_
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Expands to the name of the variable used to remember the names of
|
||||
// the defined tests in the given test case.
|
||||
# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \
|
||||
gtest_typed_test_case_p_state_##TestCaseName##_
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY.
|
||||
//
|
||||
// Expands to the name of the variable used to remember the names of
|
||||
// the registered tests in the given test case.
|
||||
# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \
|
||||
gtest_registered_test_names_##TestCaseName##_
|
||||
|
||||
// The variables defined in the type-parameterized test macros are
|
||||
// static as typically these macros are used in a .h file that can be
|
||||
// #included in multiple translation units linked together.
|
||||
# define TYPED_TEST_CASE_P(CaseName) \
|
||||
static ::testing::internal::TypedTestCasePState \
|
||||
GTEST_TYPED_TEST_CASE_P_STATE_(CaseName)
|
||||
|
||||
# define TYPED_TEST_P(CaseName, TestName) \
|
||||
namespace GTEST_CASE_NAMESPACE_(CaseName) { \
|
||||
template <typename gtest_TypeParam_> \
|
||||
class TestName : public CaseName<gtest_TypeParam_> { \
|
||||
private: \
|
||||
typedef CaseName<gtest_TypeParam_> TestFixture; \
|
||||
typedef gtest_TypeParam_ TypeParam; \
|
||||
virtual void TestBody(); \
|
||||
}; \
|
||||
static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \
|
||||
GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\
|
||||
__FILE__, __LINE__, #CaseName, #TestName); \
|
||||
} \
|
||||
template <typename gtest_TypeParam_> \
|
||||
void GTEST_CASE_NAMESPACE_(CaseName)::TestName<gtest_TypeParam_>::TestBody()
|
||||
|
||||
# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \
|
||||
namespace GTEST_CASE_NAMESPACE_(CaseName) { \
|
||||
typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \
|
||||
} \
|
||||
static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \
|
||||
GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\
|
||||
__FILE__, __LINE__, #__VA_ARGS__)
|
||||
|
||||
// The 'Types' template argument below must have spaces around it
|
||||
// since some compilers may choke on '>>' when passing a template
|
||||
// instance (e.g. Types<int>)
|
||||
# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \
|
||||
bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \
|
||||
::testing::internal::TypeParameterizedTestCase<CaseName, \
|
||||
GTEST_CASE_NAMESPACE_(CaseName)::gtest_AllTests_, \
|
||||
::testing::internal::TypeList< Types >::type>::Register(\
|
||||
#Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName))
|
||||
|
||||
#endif // GTEST_HAS_TYPED_TEST_P
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_
|
File diff suppressed because it is too large
Load diff
|
@ -1,358 +0,0 @@
|
|||
// Copyright 2006, Google 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:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// This file is AUTOMATICALLY GENERATED on 10/31/2011 by command
|
||||
// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND!
|
||||
//
|
||||
// Implements a family of generic predicate assertion macros.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
|
||||
|
||||
// Makes sure this header is not included before gtest.h.
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_H_
|
||||
# error Do not include gtest_pred_impl.h directly. Include gtest.h instead.
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_H_
|
||||
|
||||
// This header implements a family of generic predicate assertion
|
||||
// macros:
|
||||
//
|
||||
// ASSERT_PRED_FORMAT1(pred_format, v1)
|
||||
// ASSERT_PRED_FORMAT2(pred_format, v1, v2)
|
||||
// ...
|
||||
//
|
||||
// where pred_format is a function or functor that takes n (in the
|
||||
// case of ASSERT_PRED_FORMATn) values and their source expression
|
||||
// text, and returns a testing::AssertionResult. See the definition
|
||||
// of ASSERT_EQ in gtest.h for an example.
|
||||
//
|
||||
// If you don't care about formatting, you can use the more
|
||||
// restrictive version:
|
||||
//
|
||||
// ASSERT_PRED1(pred, v1)
|
||||
// ASSERT_PRED2(pred, v1, v2)
|
||||
// ...
|
||||
//
|
||||
// where pred is an n-ary function or functor that returns bool,
|
||||
// and the values v1, v2, ..., must support the << operator for
|
||||
// streaming to std::ostream.
|
||||
//
|
||||
// We also define the EXPECT_* variations.
|
||||
//
|
||||
// For now we only support predicates whose arity is at most 5.
|
||||
// Please email googletestframework@googlegroups.com if you need
|
||||
// support for higher arities.
|
||||
|
||||
// GTEST_ASSERT_ is the basic statement to which all of the assertions
|
||||
// in this file reduce. Don't use this in your code.
|
||||
|
||||
#define GTEST_ASSERT_(expression, on_failure) \
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
if (const ::testing::AssertionResult gtest_ar = (expression)) \
|
||||
; \
|
||||
else \
|
||||
on_failure(gtest_ar.failure_message())
|
||||
|
||||
|
||||
// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use
|
||||
// this in your code.
|
||||
template <typename Pred,
|
||||
typename T1>
|
||||
AssertionResult AssertPred1Helper(const char* pred_text,
|
||||
const char* e1,
|
||||
Pred pred,
|
||||
const T1& v1) {
|
||||
if (pred(v1)) return AssertionSuccess();
|
||||
|
||||
return AssertionFailure() << pred_text << "("
|
||||
<< e1 << ") evaluates to false, where"
|
||||
<< "\n" << e1 << " evaluates to " << v1;
|
||||
}
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, v1), \
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use
|
||||
// this in your code.
|
||||
#define GTEST_PRED1_(pred, v1, on_failure)\
|
||||
GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \
|
||||
#v1, \
|
||||
pred, \
|
||||
v1), on_failure)
|
||||
|
||||
// Unary predicate assertion macros.
|
||||
#define EXPECT_PRED_FORMAT1(pred_format, v1) \
|
||||
GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_)
|
||||
#define EXPECT_PRED1(pred, v1) \
|
||||
GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_)
|
||||
#define ASSERT_PRED_FORMAT1(pred_format, v1) \
|
||||
GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_)
|
||||
#define ASSERT_PRED1(pred, v1) \
|
||||
GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_)
|
||||
|
||||
|
||||
|
||||
// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use
|
||||
// this in your code.
|
||||
template <typename Pred,
|
||||
typename T1,
|
||||
typename T2>
|
||||
AssertionResult AssertPred2Helper(const char* pred_text,
|
||||
const char* e1,
|
||||
const char* e2,
|
||||
Pred pred,
|
||||
const T1& v1,
|
||||
const T2& v2) {
|
||||
if (pred(v1, v2)) return AssertionSuccess();
|
||||
|
||||
return AssertionFailure() << pred_text << "("
|
||||
<< e1 << ", "
|
||||
<< e2 << ") evaluates to false, where"
|
||||
<< "\n" << e1 << " evaluates to " << v1
|
||||
<< "\n" << e2 << " evaluates to " << v2;
|
||||
}
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use
|
||||
// this in your code.
|
||||
#define GTEST_PRED2_(pred, v1, v2, on_failure)\
|
||||
GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \
|
||||
#v1, \
|
||||
#v2, \
|
||||
pred, \
|
||||
v1, \
|
||||
v2), on_failure)
|
||||
|
||||
// Binary predicate assertion macros.
|
||||
#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \
|
||||
GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_)
|
||||
#define EXPECT_PRED2(pred, v1, v2) \
|
||||
GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_)
|
||||
#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \
|
||||
GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_)
|
||||
#define ASSERT_PRED2(pred, v1, v2) \
|
||||
GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_)
|
||||
|
||||
|
||||
|
||||
// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use
|
||||
// this in your code.
|
||||
template <typename Pred,
|
||||
typename T1,
|
||||
typename T2,
|
||||
typename T3>
|
||||
AssertionResult AssertPred3Helper(const char* pred_text,
|
||||
const char* e1,
|
||||
const char* e2,
|
||||
const char* e3,
|
||||
Pred pred,
|
||||
const T1& v1,
|
||||
const T2& v2,
|
||||
const T3& v3) {
|
||||
if (pred(v1, v2, v3)) return AssertionSuccess();
|
||||
|
||||
return AssertionFailure() << pred_text << "("
|
||||
<< e1 << ", "
|
||||
<< e2 << ", "
|
||||
<< e3 << ") evaluates to false, where"
|
||||
<< "\n" << e1 << " evaluates to " << v1
|
||||
<< "\n" << e2 << " evaluates to " << v2
|
||||
<< "\n" << e3 << " evaluates to " << v3;
|
||||
}
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use
|
||||
// this in your code.
|
||||
#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\
|
||||
GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \
|
||||
#v1, \
|
||||
#v2, \
|
||||
#v3, \
|
||||
pred, \
|
||||
v1, \
|
||||
v2, \
|
||||
v3), on_failure)
|
||||
|
||||
// Ternary predicate assertion macros.
|
||||
#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \
|
||||
GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
|
||||
#define EXPECT_PRED3(pred, v1, v2, v3) \
|
||||
GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_)
|
||||
#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \
|
||||
GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_)
|
||||
#define ASSERT_PRED3(pred, v1, v2, v3) \
|
||||
GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_)
|
||||
|
||||
|
||||
|
||||
// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use
|
||||
// this in your code.
|
||||
template <typename Pred,
|
||||
typename T1,
|
||||
typename T2,
|
||||
typename T3,
|
||||
typename T4>
|
||||
AssertionResult AssertPred4Helper(const char* pred_text,
|
||||
const char* e1,
|
||||
const char* e2,
|
||||
const char* e3,
|
||||
const char* e4,
|
||||
Pred pred,
|
||||
const T1& v1,
|
||||
const T2& v2,
|
||||
const T3& v3,
|
||||
const T4& v4) {
|
||||
if (pred(v1, v2, v3, v4)) return AssertionSuccess();
|
||||
|
||||
return AssertionFailure() << pred_text << "("
|
||||
<< e1 << ", "
|
||||
<< e2 << ", "
|
||||
<< e3 << ", "
|
||||
<< e4 << ") evaluates to false, where"
|
||||
<< "\n" << e1 << " evaluates to " << v1
|
||||
<< "\n" << e2 << " evaluates to " << v2
|
||||
<< "\n" << e3 << " evaluates to " << v3
|
||||
<< "\n" << e4 << " evaluates to " << v4;
|
||||
}
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use
|
||||
// this in your code.
|
||||
#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\
|
||||
GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \
|
||||
#v1, \
|
||||
#v2, \
|
||||
#v3, \
|
||||
#v4, \
|
||||
pred, \
|
||||
v1, \
|
||||
v2, \
|
||||
v3, \
|
||||
v4), on_failure)
|
||||
|
||||
// 4-ary predicate assertion macros.
|
||||
#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
|
||||
GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
|
||||
#define EXPECT_PRED4(pred, v1, v2, v3, v4) \
|
||||
GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_)
|
||||
#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \
|
||||
GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
|
||||
#define ASSERT_PRED4(pred, v1, v2, v3, v4) \
|
||||
GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_)
|
||||
|
||||
|
||||
|
||||
// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use
|
||||
// this in your code.
|
||||
template <typename Pred,
|
||||
typename T1,
|
||||
typename T2,
|
||||
typename T3,
|
||||
typename T4,
|
||||
typename T5>
|
||||
AssertionResult AssertPred5Helper(const char* pred_text,
|
||||
const char* e1,
|
||||
const char* e2,
|
||||
const char* e3,
|
||||
const char* e4,
|
||||
const char* e5,
|
||||
Pred pred,
|
||||
const T1& v1,
|
||||
const T2& v2,
|
||||
const T3& v3,
|
||||
const T4& v4,
|
||||
const T5& v5) {
|
||||
if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess();
|
||||
|
||||
return AssertionFailure() << pred_text << "("
|
||||
<< e1 << ", "
|
||||
<< e2 << ", "
|
||||
<< e3 << ", "
|
||||
<< e4 << ", "
|
||||
<< e5 << ") evaluates to false, where"
|
||||
<< "\n" << e1 << " evaluates to " << v1
|
||||
<< "\n" << e2 << " evaluates to " << v2
|
||||
<< "\n" << e3 << " evaluates to " << v3
|
||||
<< "\n" << e4 << " evaluates to " << v4
|
||||
<< "\n" << e5 << " evaluates to " << v5;
|
||||
}
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5.
|
||||
// Don't use this in your code.
|
||||
#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\
|
||||
GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \
|
||||
on_failure)
|
||||
|
||||
// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use
|
||||
// this in your code.
|
||||
#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\
|
||||
GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \
|
||||
#v1, \
|
||||
#v2, \
|
||||
#v3, \
|
||||
#v4, \
|
||||
#v5, \
|
||||
pred, \
|
||||
v1, \
|
||||
v2, \
|
||||
v3, \
|
||||
v4, \
|
||||
v5), on_failure)
|
||||
|
||||
// 5-ary predicate assertion macros.
|
||||
#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
|
||||
GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
|
||||
#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \
|
||||
GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_)
|
||||
#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \
|
||||
GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
|
||||
#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \
|
||||
GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_)
|
||||
|
||||
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_
|
|
@ -1,58 +0,0 @@
|
|||
// Copyright 2006, Google 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:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
//
|
||||
// Google C++ Testing Framework definitions useful in production code.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_
|
||||
#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_
|
||||
|
||||
// When you need to test the private or protected members of a class,
|
||||
// use the FRIEND_TEST macro to declare your tests as friends of the
|
||||
// class. For example:
|
||||
//
|
||||
// class MyClass {
|
||||
// private:
|
||||
// void MyMethod();
|
||||
// FRIEND_TEST(MyClassTest, MyMethod);
|
||||
// };
|
||||
//
|
||||
// class MyClassTest : public testing::Test {
|
||||
// // ...
|
||||
// };
|
||||
//
|
||||
// TEST_F(MyClassTest, MyMethod) {
|
||||
// // Can call MyClass::MyMethod() here.
|
||||
// }
|
||||
|
||||
#define FRIEND_TEST(test_case_name, test_name)\
|
||||
friend class test_case_name##_##test_name##_Test
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_
|
|
@ -1,319 +0,0 @@
|
|||
// Copyright 2005, Google 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:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
|
||||
//
|
||||
// The Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// This header file defines internal utilities needed for implementing
|
||||
// death tests. They are subject to change without notice.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
|
||||
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
GTEST_DECLARE_string_(internal_run_death_test);
|
||||
|
||||
// Names of the flags (needed for parsing Google Test flags).
|
||||
const char kDeathTestStyleFlag[] = "death_test_style";
|
||||
const char kDeathTestUseFork[] = "death_test_use_fork";
|
||||
const char kInternalRunDeathTestFlag[] = "internal_run_death_test";
|
||||
|
||||
#if GTEST_HAS_DEATH_TEST
|
||||
|
||||
// DeathTest is a class that hides much of the complexity of the
|
||||
// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method
|
||||
// returns a concrete class that depends on the prevailing death test
|
||||
// style, as defined by the --gtest_death_test_style and/or
|
||||
// --gtest_internal_run_death_test flags.
|
||||
|
||||
// In describing the results of death tests, these terms are used with
|
||||
// the corresponding definitions:
|
||||
//
|
||||
// exit status: The integer exit information in the format specified
|
||||
// by wait(2)
|
||||
// exit code: The integer code passed to exit(3), _exit(2), or
|
||||
// returned from main()
|
||||
class GTEST_API_ DeathTest {
|
||||
public:
|
||||
// Create returns false if there was an error determining the
|
||||
// appropriate action to take for the current death test; for example,
|
||||
// if the gtest_death_test_style flag is set to an invalid value.
|
||||
// The LastMessage method will return a more detailed message in that
|
||||
// case. Otherwise, the DeathTest pointer pointed to by the "test"
|
||||
// argument is set. If the death test should be skipped, the pointer
|
||||
// is set to NULL; otherwise, it is set to the address of a new concrete
|
||||
// DeathTest object that controls the execution of the current test.
|
||||
static bool Create(const char* statement, const RE* regex,
|
||||
const char* file, int line, DeathTest** test);
|
||||
DeathTest();
|
||||
virtual ~DeathTest() { }
|
||||
|
||||
// A helper class that aborts a death test when it's deleted.
|
||||
class ReturnSentinel {
|
||||
public:
|
||||
explicit ReturnSentinel(DeathTest* test) : test_(test) { }
|
||||
~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); }
|
||||
private:
|
||||
DeathTest* const test_;
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel);
|
||||
} GTEST_ATTRIBUTE_UNUSED_;
|
||||
|
||||
// An enumeration of possible roles that may be taken when a death
|
||||
// test is encountered. EXECUTE means that the death test logic should
|
||||
// be executed immediately. OVERSEE means that the program should prepare
|
||||
// the appropriate environment for a child process to execute the death
|
||||
// test, then wait for it to complete.
|
||||
enum TestRole { OVERSEE_TEST, EXECUTE_TEST };
|
||||
|
||||
// An enumeration of the three reasons that a test might be aborted.
|
||||
enum AbortReason {
|
||||
TEST_ENCOUNTERED_RETURN_STATEMENT,
|
||||
TEST_THREW_EXCEPTION,
|
||||
TEST_DID_NOT_DIE
|
||||
};
|
||||
|
||||
// Assumes one of the above roles.
|
||||
virtual TestRole AssumeRole() = 0;
|
||||
|
||||
// Waits for the death test to finish and returns its status.
|
||||
virtual int Wait() = 0;
|
||||
|
||||
// Returns true if the death test passed; that is, the test process
|
||||
// exited during the test, its exit status matches a user-supplied
|
||||
// predicate, and its stderr output matches a user-supplied regular
|
||||
// expression.
|
||||
// The user-supplied predicate may be a macro expression rather
|
||||
// than a function pointer or functor, or else Wait and Passed could
|
||||
// be combined.
|
||||
virtual bool Passed(bool exit_status_ok) = 0;
|
||||
|
||||
// Signals that the death test did not die as expected.
|
||||
virtual void Abort(AbortReason reason) = 0;
|
||||
|
||||
// Returns a human-readable outcome message regarding the outcome of
|
||||
// the last death test.
|
||||
static const char* LastMessage();
|
||||
|
||||
static void set_last_death_test_message(const std::string& message);
|
||||
|
||||
private:
|
||||
// A string containing a description of the outcome of the last death test.
|
||||
static std::string last_death_test_message_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest);
|
||||
};
|
||||
|
||||
// Factory interface for death tests. May be mocked out for testing.
|
||||
class DeathTestFactory {
|
||||
public:
|
||||
virtual ~DeathTestFactory() { }
|
||||
virtual bool Create(const char* statement, const RE* regex,
|
||||
const char* file, int line, DeathTest** test) = 0;
|
||||
};
|
||||
|
||||
// A concrete DeathTestFactory implementation for normal use.
|
||||
class DefaultDeathTestFactory : public DeathTestFactory {
|
||||
public:
|
||||
virtual bool Create(const char* statement, const RE* regex,
|
||||
const char* file, int line, DeathTest** test);
|
||||
};
|
||||
|
||||
// Returns true if exit_status describes a process that was terminated
|
||||
// by a signal, or exited normally with a nonzero exit code.
|
||||
GTEST_API_ bool ExitedUnsuccessfully(int exit_status);
|
||||
|
||||
// Traps C++ exceptions escaping statement and reports them as test
|
||||
// failures. Note that trapping SEH exceptions is not implemented here.
|
||||
# if GTEST_HAS_EXCEPTIONS
|
||||
# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
|
||||
try { \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||
} catch (const ::std::exception& gtest_exception) { \
|
||||
fprintf(\
|
||||
stderr, \
|
||||
"\n%s: Caught std::exception-derived exception escaping the " \
|
||||
"death test statement. Exception message: %s\n", \
|
||||
::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \
|
||||
gtest_exception.what()); \
|
||||
fflush(stderr); \
|
||||
death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
|
||||
} catch (...) { \
|
||||
death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \
|
||||
}
|
||||
|
||||
# else
|
||||
# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement)
|
||||
|
||||
# endif
|
||||
|
||||
// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*,
|
||||
// ASSERT_EXIT*, and EXPECT_EXIT*.
|
||||
# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
if (::testing::internal::AlwaysTrue()) { \
|
||||
const ::testing::internal::RE& gtest_regex = (regex); \
|
||||
::testing::internal::DeathTest* gtest_dt; \
|
||||
if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \
|
||||
__FILE__, __LINE__, >est_dt)) { \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
|
||||
} \
|
||||
if (gtest_dt != NULL) { \
|
||||
::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \
|
||||
gtest_dt_ptr(gtest_dt); \
|
||||
switch (gtest_dt->AssumeRole()) { \
|
||||
case ::testing::internal::DeathTest::OVERSEE_TEST: \
|
||||
if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \
|
||||
goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \
|
||||
} \
|
||||
break; \
|
||||
case ::testing::internal::DeathTest::EXECUTE_TEST: { \
|
||||
::testing::internal::DeathTest::ReturnSentinel \
|
||||
gtest_sentinel(gtest_dt); \
|
||||
GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \
|
||||
gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \
|
||||
break; \
|
||||
} \
|
||||
default: \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
} else \
|
||||
GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \
|
||||
fail(::testing::internal::DeathTest::LastMessage())
|
||||
// The symbol "fail" here expands to something into which a message
|
||||
// can be streamed.
|
||||
|
||||
// This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in
|
||||
// NDEBUG mode. In this case we need the statements to be executed, the regex is
|
||||
// ignored, and the macro must accept a streamed message even though the message
|
||||
// is never printed.
|
||||
# define GTEST_EXECUTE_STATEMENT_(statement, regex) \
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
if (::testing::internal::AlwaysTrue()) { \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||
} else \
|
||||
::testing::Message()
|
||||
|
||||
// A class representing the parsed contents of the
|
||||
// --gtest_internal_run_death_test flag, as it existed when
|
||||
// RUN_ALL_TESTS was called.
|
||||
class InternalRunDeathTestFlag {
|
||||
public:
|
||||
InternalRunDeathTestFlag(const std::string& a_file,
|
||||
int a_line,
|
||||
int an_index,
|
||||
int a_write_fd)
|
||||
: file_(a_file), line_(a_line), index_(an_index),
|
||||
write_fd_(a_write_fd) {}
|
||||
|
||||
~InternalRunDeathTestFlag() {
|
||||
if (write_fd_ >= 0)
|
||||
posix::Close(write_fd_);
|
||||
}
|
||||
|
||||
const std::string& file() const { return file_; }
|
||||
int line() const { return line_; }
|
||||
int index() const { return index_; }
|
||||
int write_fd() const { return write_fd_; }
|
||||
|
||||
private:
|
||||
std::string file_;
|
||||
int line_;
|
||||
int index_;
|
||||
int write_fd_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag);
|
||||
};
|
||||
|
||||
// Returns a newly created InternalRunDeathTestFlag object with fields
|
||||
// initialized from the GTEST_FLAG(internal_run_death_test) flag if
|
||||
// the flag is specified; otherwise returns NULL.
|
||||
InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag();
|
||||
|
||||
#else // GTEST_HAS_DEATH_TEST
|
||||
|
||||
// This macro is used for implementing macros such as
|
||||
// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where
|
||||
// death tests are not supported. Those macros must compile on such systems
|
||||
// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on
|
||||
// systems that support death tests. This allows one to write such a macro
|
||||
// on a system that does not support death tests and be sure that it will
|
||||
// compile on a death-test supporting system.
|
||||
//
|
||||
// Parameters:
|
||||
// statement - A statement that a macro such as EXPECT_DEATH would test
|
||||
// for program termination. This macro has to make sure this
|
||||
// statement is compiled but not executed, to ensure that
|
||||
// EXPECT_DEATH_IF_SUPPORTED compiles with a certain
|
||||
// parameter iff EXPECT_DEATH compiles with it.
|
||||
// regex - A regex that a macro such as EXPECT_DEATH would use to test
|
||||
// the output of statement. This parameter has to be
|
||||
// compiled but not evaluated by this macro, to ensure that
|
||||
// this macro only accepts expressions that a macro such as
|
||||
// EXPECT_DEATH would accept.
|
||||
// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED
|
||||
// and a return statement for ASSERT_DEATH_IF_SUPPORTED.
|
||||
// This ensures that ASSERT_DEATH_IF_SUPPORTED will not
|
||||
// compile inside functions where ASSERT_DEATH doesn't
|
||||
// compile.
|
||||
//
|
||||
// The branch that has an always false condition is used to ensure that
|
||||
// statement and regex are compiled (and thus syntactically correct) but
|
||||
// never executed. The unreachable code macro protects the terminator
|
||||
// statement from generating an 'unreachable code' warning in case
|
||||
// statement unconditionally returns or throws. The Message constructor at
|
||||
// the end allows the syntax of streaming additional messages into the
|
||||
// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH.
|
||||
# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \
|
||||
GTEST_AMBIGUOUS_ELSE_BLOCKER_ \
|
||||
if (::testing::internal::AlwaysTrue()) { \
|
||||
GTEST_LOG_(WARNING) \
|
||||
<< "Death tests are not supported on this platform.\n" \
|
||||
<< "Statement '" #statement "' cannot be verified."; \
|
||||
} else if (::testing::internal::AlwaysFalse()) { \
|
||||
::testing::internal::RE::PartialMatch(".*", (regex)); \
|
||||
GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \
|
||||
terminator; \
|
||||
} else \
|
||||
::testing::Message()
|
||||
|
||||
#endif // GTEST_HAS_DEATH_TEST
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_
|
|
@ -1,206 +0,0 @@
|
|||
// Copyright 2008, Google 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:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: keith.ray@gmail.com (Keith Ray)
|
||||
//
|
||||
// Google Test filepath utilities
|
||||
//
|
||||
// This header file declares classes and functions used internally by
|
||||
// Google Test. They are subject to change without notice.
|
||||
//
|
||||
// This file is #included in <gtest/internal/gtest-internal.h>.
|
||||
// Do not include this header file separately!
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
|
||||
|
||||
#include "gtest/internal/gtest-string.h"
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// FilePath - a class for file and directory pathname manipulation which
|
||||
// handles platform-specific conventions (like the pathname separator).
|
||||
// Used for helper functions for naming files in a directory for xml output.
|
||||
// Except for Set methods, all methods are const or static, which provides an
|
||||
// "immutable value object" -- useful for peace of mind.
|
||||
// A FilePath with a value ending in a path separator ("like/this/") represents
|
||||
// a directory, otherwise it is assumed to represent a file. In either case,
|
||||
// it may or may not represent an actual file or directory in the file system.
|
||||
// Names are NOT checked for syntax correctness -- no checking for illegal
|
||||
// characters, malformed paths, etc.
|
||||
|
||||
class GTEST_API_ FilePath {
|
||||
public:
|
||||
FilePath() : pathname_("") { }
|
||||
FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { }
|
||||
|
||||
explicit FilePath(const std::string& pathname) : pathname_(pathname) {
|
||||
Normalize();
|
||||
}
|
||||
|
||||
FilePath& operator=(const FilePath& rhs) {
|
||||
Set(rhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Set(const FilePath& rhs) {
|
||||
pathname_ = rhs.pathname_;
|
||||
}
|
||||
|
||||
const std::string& string() const { return pathname_; }
|
||||
const char* c_str() const { return pathname_.c_str(); }
|
||||
|
||||
// Returns the current working directory, or "" if unsuccessful.
|
||||
static FilePath GetCurrentDir();
|
||||
|
||||
// Given directory = "dir", base_name = "test", number = 0,
|
||||
// extension = "xml", returns "dir/test.xml". If number is greater
|
||||
// than zero (e.g., 12), returns "dir/test_12.xml".
|
||||
// On Windows platform, uses \ as the separator rather than /.
|
||||
static FilePath MakeFileName(const FilePath& directory,
|
||||
const FilePath& base_name,
|
||||
int number,
|
||||
const char* extension);
|
||||
|
||||
// Given directory = "dir", relative_path = "test.xml",
|
||||
// returns "dir/test.xml".
|
||||
// On Windows, uses \ as the separator rather than /.
|
||||
static FilePath ConcatPaths(const FilePath& directory,
|
||||
const FilePath& relative_path);
|
||||
|
||||
// Returns a pathname for a file that does not currently exist. The pathname
|
||||
// will be directory/base_name.extension or
|
||||
// directory/base_name_<number>.extension if directory/base_name.extension
|
||||
// already exists. The number will be incremented until a pathname is found
|
||||
// that does not already exist.
|
||||
// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'.
|
||||
// There could be a race condition if two or more processes are calling this
|
||||
// function at the same time -- they could both pick the same filename.
|
||||
static FilePath GenerateUniqueFileName(const FilePath& directory,
|
||||
const FilePath& base_name,
|
||||
const char* extension);
|
||||
|
||||
// Returns true iff the path is "".
|
||||
bool IsEmpty() const { return pathname_.empty(); }
|
||||
|
||||
// If input name has a trailing separator character, removes it and returns
|
||||
// the name, otherwise return the name string unmodified.
|
||||
// On Windows platform, uses \ as the separator, other platforms use /.
|
||||
FilePath RemoveTrailingPathSeparator() const;
|
||||
|
||||
// Returns a copy of the FilePath with the directory part removed.
|
||||
// Example: FilePath("path/to/file").RemoveDirectoryName() returns
|
||||
// FilePath("file"). If there is no directory part ("just_a_file"), it returns
|
||||
// the FilePath unmodified. If there is no file part ("just_a_dir/") it
|
||||
// returns an empty FilePath ("").
|
||||
// On Windows platform, '\' is the path separator, otherwise it is '/'.
|
||||
FilePath RemoveDirectoryName() const;
|
||||
|
||||
// RemoveFileName returns the directory path with the filename removed.
|
||||
// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/".
|
||||
// If the FilePath is "a_file" or "/a_file", RemoveFileName returns
|
||||
// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does
|
||||
// not have a file, like "just/a/dir/", it returns the FilePath unmodified.
|
||||
// On Windows platform, '\' is the path separator, otherwise it is '/'.
|
||||
FilePath RemoveFileName() const;
|
||||
|
||||
// Returns a copy of the FilePath with the case-insensitive extension removed.
|
||||
// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns
|
||||
// FilePath("dir/file"). If a case-insensitive extension is not
|
||||
// found, returns a copy of the original FilePath.
|
||||
FilePath RemoveExtension(const char* extension) const;
|
||||
|
||||
// Creates directories so that path exists. Returns true if successful or if
|
||||
// the directories already exist; returns false if unable to create
|
||||
// directories for any reason. Will also return false if the FilePath does
|
||||
// not represent a directory (that is, it doesn't end with a path separator).
|
||||
bool CreateDirectoriesRecursively() const;
|
||||
|
||||
// Create the directory so that path exists. Returns true if successful or
|
||||
// if the directory already exists; returns false if unable to create the
|
||||
// directory for any reason, including if the parent directory does not
|
||||
// exist. Not named "CreateDirectory" because that's a macro on Windows.
|
||||
bool CreateFolder() const;
|
||||
|
||||
// Returns true if FilePath describes something in the file-system,
|
||||
// either a file, directory, or whatever, and that something exists.
|
||||
bool FileOrDirectoryExists() const;
|
||||
|
||||
// Returns true if pathname describes a directory in the file-system
|
||||
// that exists.
|
||||
bool DirectoryExists() const;
|
||||
|
||||
// Returns true if FilePath ends with a path separator, which indicates that
|
||||
// it is intended to represent a directory. Returns false otherwise.
|
||||
// This does NOT check that a directory (or file) actually exists.
|
||||
bool IsDirectory() const;
|
||||
|
||||
// Returns true if pathname describes a root directory. (Windows has one
|
||||
// root directory per disk drive.)
|
||||
bool IsRootDirectory() const;
|
||||
|
||||
// Returns true if pathname describes an absolute path.
|
||||
bool IsAbsolutePath() const;
|
||||
|
||||
private:
|
||||
// Replaces multiple consecutive separators with a single separator.
|
||||
// For example, "bar///foo" becomes "bar/foo". Does not eliminate other
|
||||
// redundancies that might be in a pathname involving "." or "..".
|
||||
//
|
||||
// A pathname with multiple consecutive separators may occur either through
|
||||
// user error or as a result of some scripts or APIs that generate a pathname
|
||||
// with a trailing separator. On other platforms the same API or script
|
||||
// may NOT generate a pathname with a trailing "/". Then elsewhere that
|
||||
// pathname may have another "/" and pathname components added to it,
|
||||
// without checking for the separator already being there.
|
||||
// The script language and operating system may allow paths like "foo//bar"
|
||||
// but some of the functions in FilePath will not handle that correctly. In
|
||||
// particular, RemoveTrailingPathSeparator() only removes one separator, and
|
||||
// it is called in CreateDirectoriesRecursively() assuming that it will change
|
||||
// a pathname from directory syntax (trailing separator) to filename syntax.
|
||||
//
|
||||
// On Windows this method also replaces the alternate path separator '/' with
|
||||
// the primary path separator '\\', so that for example "bar\\/\\foo" becomes
|
||||
// "bar\\foo".
|
||||
|
||||
void Normalize();
|
||||
|
||||
// Returns a pointer to the last occurence of a valid path separator in
|
||||
// the FilePath. On Windows, for example, both '/' and '\' are valid path
|
||||
// separators. Returns NULL if no path separator was found.
|
||||
const char* FindLastPathSeparator() const;
|
||||
|
||||
std::string pathname_;
|
||||
}; // class FilePath
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_
|
File diff suppressed because it is too large
Load diff
|
@ -1,233 +0,0 @@
|
|||
// Copyright 2003 Google 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:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Authors: Dan Egnor (egnor@google.com)
|
||||
//
|
||||
// A "smart" pointer type with reference tracking. Every pointer to a
|
||||
// particular object is kept on a circular linked list. When the last pointer
|
||||
// to an object is destroyed or reassigned, the object is deleted.
|
||||
//
|
||||
// Used properly, this deletes the object when the last reference goes away.
|
||||
// There are several caveats:
|
||||
// - Like all reference counting schemes, cycles lead to leaks.
|
||||
// - Each smart pointer is actually two pointers (8 bytes instead of 4).
|
||||
// - Every time a pointer is assigned, the entire list of pointers to that
|
||||
// object is traversed. This class is therefore NOT SUITABLE when there
|
||||
// will often be more than two or three pointers to a particular object.
|
||||
// - References are only tracked as long as linked_ptr<> objects are copied.
|
||||
// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS
|
||||
// will happen (double deletion).
|
||||
//
|
||||
// A good use of this class is storing object references in STL containers.
|
||||
// You can safely put linked_ptr<> in a vector<>.
|
||||
// Other uses may not be as good.
|
||||
//
|
||||
// Note: If you use an incomplete type with linked_ptr<>, the class
|
||||
// *containing* linked_ptr<> must have a constructor and destructor (even
|
||||
// if they do nothing!).
|
||||
//
|
||||
// Bill Gibbons suggested we use something like this.
|
||||
//
|
||||
// Thread Safety:
|
||||
// Unlike other linked_ptr implementations, in this implementation
|
||||
// a linked_ptr object is thread-safe in the sense that:
|
||||
// - it's safe to copy linked_ptr objects concurrently,
|
||||
// - it's safe to copy *from* a linked_ptr and read its underlying
|
||||
// raw pointer (e.g. via get()) concurrently, and
|
||||
// - it's safe to write to two linked_ptrs that point to the same
|
||||
// shared object concurrently.
|
||||
// TODO(wan@google.com): rename this to safe_linked_ptr to avoid
|
||||
// confusion with normal linked_ptr.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// Protects copying of all linked_ptr objects.
|
||||
GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex);
|
||||
|
||||
// This is used internally by all instances of linked_ptr<>. It needs to be
|
||||
// a non-template class because different types of linked_ptr<> can refer to
|
||||
// the same object (linked_ptr<Superclass>(obj) vs linked_ptr<Subclass>(obj)).
|
||||
// So, it needs to be possible for different types of linked_ptr to participate
|
||||
// in the same circular linked list, so we need a single class type here.
|
||||
//
|
||||
// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr<T>.
|
||||
class linked_ptr_internal {
|
||||
public:
|
||||
// Create a new circle that includes only this instance.
|
||||
void join_new() {
|
||||
next_ = this;
|
||||
}
|
||||
|
||||
// Many linked_ptr operations may change p.link_ for some linked_ptr
|
||||
// variable p in the same circle as this object. Therefore we need
|
||||
// to prevent two such operations from occurring concurrently.
|
||||
//
|
||||
// Note that different types of linked_ptr objects can coexist in a
|
||||
// circle (e.g. linked_ptr<Base>, linked_ptr<Derived1>, and
|
||||
// linked_ptr<Derived2>). Therefore we must use a single mutex to
|
||||
// protect all linked_ptr objects. This can create serious
|
||||
// contention in production code, but is acceptable in a testing
|
||||
// framework.
|
||||
|
||||
// Join an existing circle.
|
||||
void join(linked_ptr_internal const* ptr)
|
||||
GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) {
|
||||
MutexLock lock(&g_linked_ptr_mutex);
|
||||
|
||||
linked_ptr_internal const* p = ptr;
|
||||
while (p->next_ != ptr) p = p->next_;
|
||||
p->next_ = this;
|
||||
next_ = ptr;
|
||||
}
|
||||
|
||||
// Leave whatever circle we're part of. Returns true if we were the
|
||||
// last member of the circle. Once this is done, you can join() another.
|
||||
bool depart()
|
||||
GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) {
|
||||
MutexLock lock(&g_linked_ptr_mutex);
|
||||
|
||||
if (next_ == this) return true;
|
||||
linked_ptr_internal const* p = next_;
|
||||
while (p->next_ != this) p = p->next_;
|
||||
p->next_ = next_;
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable linked_ptr_internal const* next_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class linked_ptr {
|
||||
public:
|
||||
typedef T element_type;
|
||||
|
||||
// Take over ownership of a raw pointer. This should happen as soon as
|
||||
// possible after the object is created.
|
||||
explicit linked_ptr(T* ptr = NULL) { capture(ptr); }
|
||||
~linked_ptr() { depart(); }
|
||||
|
||||
// Copy an existing linked_ptr<>, adding ourselves to the list of references.
|
||||
template <typename U> linked_ptr(linked_ptr<U> const& ptr) { copy(&ptr); }
|
||||
linked_ptr(linked_ptr const& ptr) { // NOLINT
|
||||
assert(&ptr != this);
|
||||
copy(&ptr);
|
||||
}
|
||||
|
||||
// Assignment releases the old value and acquires the new.
|
||||
template <typename U> linked_ptr& operator=(linked_ptr<U> const& ptr) {
|
||||
depart();
|
||||
copy(&ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
linked_ptr& operator=(linked_ptr const& ptr) {
|
||||
if (&ptr != this) {
|
||||
depart();
|
||||
copy(&ptr);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Smart pointer members.
|
||||
void reset(T* ptr = NULL) {
|
||||
depart();
|
||||
capture(ptr);
|
||||
}
|
||||
T* get() const { return value_; }
|
||||
T* operator->() const { return value_; }
|
||||
T& operator*() const { return *value_; }
|
||||
|
||||
bool operator==(T* p) const { return value_ == p; }
|
||||
bool operator!=(T* p) const { return value_ != p; }
|
||||
template <typename U>
|
||||
bool operator==(linked_ptr<U> const& ptr) const {
|
||||
return value_ == ptr.get();
|
||||
}
|
||||
template <typename U>
|
||||
bool operator!=(linked_ptr<U> const& ptr) const {
|
||||
return value_ != ptr.get();
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename U>
|
||||
friend class linked_ptr;
|
||||
|
||||
T* value_;
|
||||
linked_ptr_internal link_;
|
||||
|
||||
void depart() {
|
||||
if (link_.depart()) delete value_;
|
||||
}
|
||||
|
||||
void capture(T* ptr) {
|
||||
value_ = ptr;
|
||||
link_.join_new();
|
||||
}
|
||||
|
||||
template <typename U> void copy(linked_ptr<U> const* ptr) {
|
||||
value_ = ptr->get();
|
||||
if (value_)
|
||||
link_.join(&ptr->link_);
|
||||
else
|
||||
link_.join_new();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T> inline
|
||||
bool operator==(T* ptr, const linked_ptr<T>& x) {
|
||||
return ptr == x.get();
|
||||
}
|
||||
|
||||
template<typename T> inline
|
||||
bool operator!=(T* ptr, const linked_ptr<T>& x) {
|
||||
return ptr != x.get();
|
||||
}
|
||||
|
||||
// A function to convert T* into linked_ptr<T>
|
||||
// Doing e.g. make_linked_ptr(new FooBarBaz<type>(arg)) is a shorter notation
|
||||
// for linked_ptr<FooBarBaz<type> >(new FooBarBaz<type>(arg))
|
||||
template <typename T>
|
||||
linked_ptr<T> make_linked_ptr(T* ptr) {
|
||||
return linked_ptr<T>(ptr);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_
|
File diff suppressed because it is too large
Load diff
|
@ -1,301 +0,0 @@
|
|||
$$ -*- mode: c++; -*-
|
||||
$var n = 50 $$ Maximum length of Values arguments we want to support.
|
||||
$var maxtuple = 10 $$ Maximum number of Combine arguments we want to support.
|
||||
// Copyright 2008 Google 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:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: vladl@google.com (Vlad Losev)
|
||||
|
||||
// Type and function utilities for implementing parameterized tests.
|
||||
// This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
|
||||
//
|
||||
// Currently Google Test supports at most $n arguments in Values,
|
||||
// and at most $maxtuple arguments in Combine. Please contact
|
||||
// googletestframework@googlegroups.com if you need more.
|
||||
// Please note that the number of arguments to Combine is limited
|
||||
// by the maximum arity of the implementation of tr1::tuple which is
|
||||
// currently set at $maxtuple.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
|
||||
|
||||
// scripts/fuse_gtest.py depends on gtest's own header being #included
|
||||
// *unconditionally*. Therefore these #includes cannot be moved
|
||||
// inside #if GTEST_HAS_PARAM_TEST.
|
||||
#include "gtest/internal/gtest-param-util.h"
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
#if GTEST_HAS_PARAM_TEST
|
||||
|
||||
namespace testing {
|
||||
|
||||
// Forward declarations of ValuesIn(), which is implemented in
|
||||
// include/gtest/gtest-param-test.h.
|
||||
template <typename ForwardIterator>
|
||||
internal::ParamGenerator<
|
||||
typename ::testing::internal::IteratorTraits<ForwardIterator>::value_type>
|
||||
ValuesIn(ForwardIterator begin, ForwardIterator end);
|
||||
|
||||
template <typename T, size_t N>
|
||||
internal::ParamGenerator<T> ValuesIn(const T (&array)[N]);
|
||||
|
||||
template <class Container>
|
||||
internal::ParamGenerator<typename Container::value_type> ValuesIn(
|
||||
const Container& container);
|
||||
|
||||
namespace internal {
|
||||
|
||||
// Used in the Values() function to provide polymorphic capabilities.
|
||||
template <typename T1>
|
||||
class ValueArray1 {
|
||||
public:
|
||||
explicit ValueArray1(T1 v1) : v1_(v1) {}
|
||||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const { return ValuesIn(&v1_, &v1_ + 1); }
|
||||
|
||||
private:
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const ValueArray1& other);
|
||||
|
||||
const T1 v1_;
|
||||
};
|
||||
|
||||
$range i 2..n
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
|
||||
template <$for j, [[typename T$j]]>
|
||||
class ValueArray$i {
|
||||
public:
|
||||
ValueArray$i($for j, [[T$j v$j]]) : $for j, [[v$(j)_(v$j)]] {}
|
||||
|
||||
template <typename T>
|
||||
operator ParamGenerator<T>() const {
|
||||
const T array[] = {$for j, [[static_cast<T>(v$(j)_)]]};
|
||||
return ValuesIn(array);
|
||||
}
|
||||
|
||||
private:
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const ValueArray$i& other);
|
||||
|
||||
$for j [[
|
||||
|
||||
const T$j v$(j)_;
|
||||
]]
|
||||
|
||||
};
|
||||
|
||||
]]
|
||||
|
||||
# if GTEST_HAS_COMBINE
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Generates values from the Cartesian product of values produced
|
||||
// by the argument generators.
|
||||
//
|
||||
$range i 2..maxtuple
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
$range k 2..i
|
||||
|
||||
template <$for j, [[typename T$j]]>
|
||||
class CartesianProductGenerator$i
|
||||
: public ParamGeneratorInterface< ::std::tr1::tuple<$for j, [[T$j]]> > {
|
||||
public:
|
||||
typedef ::std::tr1::tuple<$for j, [[T$j]]> ParamType;
|
||||
|
||||
CartesianProductGenerator$i($for j, [[const ParamGenerator<T$j>& g$j]])
|
||||
: $for j, [[g$(j)_(g$j)]] {}
|
||||
virtual ~CartesianProductGenerator$i() {}
|
||||
|
||||
virtual ParamIteratorInterface<ParamType>* Begin() const {
|
||||
return new Iterator(this, $for j, [[g$(j)_, g$(j)_.begin()]]);
|
||||
}
|
||||
virtual ParamIteratorInterface<ParamType>* End() const {
|
||||
return new Iterator(this, $for j, [[g$(j)_, g$(j)_.end()]]);
|
||||
}
|
||||
|
||||
private:
|
||||
class Iterator : public ParamIteratorInterface<ParamType> {
|
||||
public:
|
||||
Iterator(const ParamGeneratorInterface<ParamType>* base, $for j, [[
|
||||
|
||||
const ParamGenerator<T$j>& g$j,
|
||||
const typename ParamGenerator<T$j>::iterator& current$(j)]])
|
||||
: base_(base),
|
||||
$for j, [[
|
||||
|
||||
begin$(j)_(g$j.begin()), end$(j)_(g$j.end()), current$(j)_(current$j)
|
||||
]] {
|
||||
ComputeCurrentValue();
|
||||
}
|
||||
virtual ~Iterator() {}
|
||||
|
||||
virtual const ParamGeneratorInterface<ParamType>* BaseGenerator() const {
|
||||
return base_;
|
||||
}
|
||||
// Advance should not be called on beyond-of-range iterators
|
||||
// so no component iterators must be beyond end of range, either.
|
||||
virtual void Advance() {
|
||||
assert(!AtEnd());
|
||||
++current$(i)_;
|
||||
|
||||
$for k [[
|
||||
if (current$(i+2-k)_ == end$(i+2-k)_) {
|
||||
current$(i+2-k)_ = begin$(i+2-k)_;
|
||||
++current$(i+2-k-1)_;
|
||||
}
|
||||
|
||||
]]
|
||||
ComputeCurrentValue();
|
||||
}
|
||||
virtual ParamIteratorInterface<ParamType>* Clone() const {
|
||||
return new Iterator(*this);
|
||||
}
|
||||
virtual const ParamType* Current() const { return ¤t_value_; }
|
||||
virtual bool Equals(const ParamIteratorInterface<ParamType>& other) const {
|
||||
// Having the same base generator guarantees that the other
|
||||
// iterator is of the same type and we can downcast.
|
||||
GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
|
||||
<< "The program attempted to compare iterators "
|
||||
<< "from different generators." << std::endl;
|
||||
const Iterator* typed_other =
|
||||
CheckedDowncastToActualType<const Iterator>(&other);
|
||||
// We must report iterators equal if they both point beyond their
|
||||
// respective ranges. That can happen in a variety of fashions,
|
||||
// so we have to consult AtEnd().
|
||||
return (AtEnd() && typed_other->AtEnd()) ||
|
||||
($for j && [[
|
||||
|
||||
current$(j)_ == typed_other->current$(j)_
|
||||
]]);
|
||||
}
|
||||
|
||||
private:
|
||||
Iterator(const Iterator& other)
|
||||
: base_(other.base_), $for j, [[
|
||||
|
||||
begin$(j)_(other.begin$(j)_),
|
||||
end$(j)_(other.end$(j)_),
|
||||
current$(j)_(other.current$(j)_)
|
||||
]] {
|
||||
ComputeCurrentValue();
|
||||
}
|
||||
|
||||
void ComputeCurrentValue() {
|
||||
if (!AtEnd())
|
||||
current_value_ = ParamType($for j, [[*current$(j)_]]);
|
||||
}
|
||||
bool AtEnd() const {
|
||||
// We must report iterator past the end of the range when either of the
|
||||
// component iterators has reached the end of its range.
|
||||
return
|
||||
$for j || [[
|
||||
|
||||
current$(j)_ == end$(j)_
|
||||
]];
|
||||
}
|
||||
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const Iterator& other);
|
||||
|
||||
const ParamGeneratorInterface<ParamType>* const base_;
|
||||
// begin[i]_ and end[i]_ define the i-th range that Iterator traverses.
|
||||
// current[i]_ is the actual traversing iterator.
|
||||
$for j [[
|
||||
|
||||
const typename ParamGenerator<T$j>::iterator begin$(j)_;
|
||||
const typename ParamGenerator<T$j>::iterator end$(j)_;
|
||||
typename ParamGenerator<T$j>::iterator current$(j)_;
|
||||
]]
|
||||
|
||||
ParamType current_value_;
|
||||
}; // class CartesianProductGenerator$i::Iterator
|
||||
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const CartesianProductGenerator$i& other);
|
||||
|
||||
|
||||
$for j [[
|
||||
const ParamGenerator<T$j> g$(j)_;
|
||||
|
||||
]]
|
||||
}; // class CartesianProductGenerator$i
|
||||
|
||||
|
||||
]]
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Helper classes providing Combine() with polymorphic features. They allow
|
||||
// casting CartesianProductGeneratorN<T> to ParamGenerator<U> if T is
|
||||
// convertible to U.
|
||||
//
|
||||
$range i 2..maxtuple
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
|
||||
template <$for j, [[class Generator$j]]>
|
||||
class CartesianProductHolder$i {
|
||||
public:
|
||||
CartesianProductHolder$i($for j, [[const Generator$j& g$j]])
|
||||
: $for j, [[g$(j)_(g$j)]] {}
|
||||
template <$for j, [[typename T$j]]>
|
||||
operator ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >() const {
|
||||
return ParamGenerator< ::std::tr1::tuple<$for j, [[T$j]]> >(
|
||||
new CartesianProductGenerator$i<$for j, [[T$j]]>(
|
||||
$for j,[[
|
||||
|
||||
static_cast<ParamGenerator<T$j> >(g$(j)_)
|
||||
]]));
|
||||
}
|
||||
|
||||
private:
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const CartesianProductHolder$i& other);
|
||||
|
||||
|
||||
$for j [[
|
||||
const Generator$j g$(j)_;
|
||||
|
||||
]]
|
||||
}; // class CartesianProductHolder$i
|
||||
|
||||
]]
|
||||
|
||||
# endif // GTEST_HAS_COMBINE
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_HAS_PARAM_TEST
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_
|
|
@ -1,619 +0,0 @@
|
|||
// Copyright 2008 Google 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:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: vladl@google.com (Vlad Losev)
|
||||
|
||||
// Type and function utilities for implementing parameterized tests.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
|
||||
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
// scripts/fuse_gtest.py depends on gtest's own header being #included
|
||||
// *unconditionally*. Therefore these #includes cannot be moved
|
||||
// inside #if GTEST_HAS_PARAM_TEST.
|
||||
#include "gtest/internal/gtest-internal.h"
|
||||
#include "gtest/internal/gtest-linked_ptr.h"
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
#include "gtest/gtest-printers.h"
|
||||
|
||||
#if GTEST_HAS_PARAM_TEST
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Outputs a message explaining invalid registration of different
|
||||
// fixture class for the same test case. This may happen when
|
||||
// TEST_P macro is used to define two tests with the same name
|
||||
// but in different namespaces.
|
||||
GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name,
|
||||
const char* file, int line);
|
||||
|
||||
template <typename> class ParamGeneratorInterface;
|
||||
template <typename> class ParamGenerator;
|
||||
|
||||
// Interface for iterating over elements provided by an implementation
|
||||
// of ParamGeneratorInterface<T>.
|
||||
template <typename T>
|
||||
class ParamIteratorInterface {
|
||||
public:
|
||||
virtual ~ParamIteratorInterface() {}
|
||||
// A pointer to the base generator instance.
|
||||
// Used only for the purposes of iterator comparison
|
||||
// to make sure that two iterators belong to the same generator.
|
||||
virtual const ParamGeneratorInterface<T>* BaseGenerator() const = 0;
|
||||
// Advances iterator to point to the next element
|
||||
// provided by the generator. The caller is responsible
|
||||
// for not calling Advance() on an iterator equal to
|
||||
// BaseGenerator()->End().
|
||||
virtual void Advance() = 0;
|
||||
// Clones the iterator object. Used for implementing copy semantics
|
||||
// of ParamIterator<T>.
|
||||
virtual ParamIteratorInterface* Clone() const = 0;
|
||||
// Dereferences the current iterator and provides (read-only) access
|
||||
// to the pointed value. It is the caller's responsibility not to call
|
||||
// Current() on an iterator equal to BaseGenerator()->End().
|
||||
// Used for implementing ParamGenerator<T>::operator*().
|
||||
virtual const T* Current() const = 0;
|
||||
// Determines whether the given iterator and other point to the same
|
||||
// element in the sequence generated by the generator.
|
||||
// Used for implementing ParamGenerator<T>::operator==().
|
||||
virtual bool Equals(const ParamIteratorInterface& other) const = 0;
|
||||
};
|
||||
|
||||
// Class iterating over elements provided by an implementation of
|
||||
// ParamGeneratorInterface<T>. It wraps ParamIteratorInterface<T>
|
||||
// and implements the const forward iterator concept.
|
||||
template <typename T>
|
||||
class ParamIterator {
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef const T& reference;
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
||||
// ParamIterator assumes ownership of the impl_ pointer.
|
||||
ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {}
|
||||
ParamIterator& operator=(const ParamIterator& other) {
|
||||
if (this != &other)
|
||||
impl_.reset(other.impl_->Clone());
|
||||
return *this;
|
||||
}
|
||||
|
||||
const T& operator*() const { return *impl_->Current(); }
|
||||
const T* operator->() const { return impl_->Current(); }
|
||||
// Prefix version of operator++.
|
||||
ParamIterator& operator++() {
|
||||
impl_->Advance();
|
||||
return *this;
|
||||
}
|
||||
// Postfix version of operator++.
|
||||
ParamIterator operator++(int /*unused*/) {
|
||||
ParamIteratorInterface<T>* clone = impl_->Clone();
|
||||
impl_->Advance();
|
||||
return ParamIterator(clone);
|
||||
}
|
||||
bool operator==(const ParamIterator& other) const {
|
||||
return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_);
|
||||
}
|
||||
bool operator!=(const ParamIterator& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class ParamGenerator<T>;
|
||||
explicit ParamIterator(ParamIteratorInterface<T>* impl) : impl_(impl) {}
|
||||
scoped_ptr<ParamIteratorInterface<T> > impl_;
|
||||
};
|
||||
|
||||
// ParamGeneratorInterface<T> is the binary interface to access generators
|
||||
// defined in other translation units.
|
||||
template <typename T>
|
||||
class ParamGeneratorInterface {
|
||||
public:
|
||||
typedef T ParamType;
|
||||
|
||||
virtual ~ParamGeneratorInterface() {}
|
||||
|
||||
// Generator interface definition
|
||||
virtual ParamIteratorInterface<T>* Begin() const = 0;
|
||||
virtual ParamIteratorInterface<T>* End() const = 0;
|
||||
};
|
||||
|
||||
// Wraps ParamGeneratorInterface<T> and provides general generator syntax
|
||||
// compatible with the STL Container concept.
|
||||
// This class implements copy initialization semantics and the contained
|
||||
// ParamGeneratorInterface<T> instance is shared among all copies
|
||||
// of the original object. This is possible because that instance is immutable.
|
||||
template<typename T>
|
||||
class ParamGenerator {
|
||||
public:
|
||||
typedef ParamIterator<T> iterator;
|
||||
|
||||
explicit ParamGenerator(ParamGeneratorInterface<T>* impl) : impl_(impl) {}
|
||||
ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {}
|
||||
|
||||
ParamGenerator& operator=(const ParamGenerator& other) {
|
||||
impl_ = other.impl_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
iterator begin() const { return iterator(impl_->Begin()); }
|
||||
iterator end() const { return iterator(impl_->End()); }
|
||||
|
||||
private:
|
||||
linked_ptr<const ParamGeneratorInterface<T> > impl_;
|
||||
};
|
||||
|
||||
// Generates values from a range of two comparable values. Can be used to
|
||||
// generate sequences of user-defined types that implement operator+() and
|
||||
// operator<().
|
||||
// This class is used in the Range() function.
|
||||
template <typename T, typename IncrementT>
|
||||
class RangeGenerator : public ParamGeneratorInterface<T> {
|
||||
public:
|
||||
RangeGenerator(T begin, T end, IncrementT step)
|
||||
: begin_(begin), end_(end),
|
||||
step_(step), end_index_(CalculateEndIndex(begin, end, step)) {}
|
||||
virtual ~RangeGenerator() {}
|
||||
|
||||
virtual ParamIteratorInterface<T>* Begin() const {
|
||||
return new Iterator(this, begin_, 0, step_);
|
||||
}
|
||||
virtual ParamIteratorInterface<T>* End() const {
|
||||
return new Iterator(this, end_, end_index_, step_);
|
||||
}
|
||||
|
||||
private:
|
||||
class Iterator : public ParamIteratorInterface<T> {
|
||||
public:
|
||||
Iterator(const ParamGeneratorInterface<T>* base, T value, int index,
|
||||
IncrementT step)
|
||||
: base_(base), value_(value), index_(index), step_(step) {}
|
||||
virtual ~Iterator() {}
|
||||
|
||||
virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
|
||||
return base_;
|
||||
}
|
||||
virtual void Advance() {
|
||||
value_ = value_ + step_;
|
||||
index_++;
|
||||
}
|
||||
virtual ParamIteratorInterface<T>* Clone() const {
|
||||
return new Iterator(*this);
|
||||
}
|
||||
virtual const T* Current() const { return &value_; }
|
||||
virtual bool Equals(const ParamIteratorInterface<T>& other) const {
|
||||
// Having the same base generator guarantees that the other
|
||||
// iterator is of the same type and we can downcast.
|
||||
GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
|
||||
<< "The program attempted to compare iterators "
|
||||
<< "from different generators." << std::endl;
|
||||
const int other_index =
|
||||
CheckedDowncastToActualType<const Iterator>(&other)->index_;
|
||||
return index_ == other_index;
|
||||
}
|
||||
|
||||
private:
|
||||
Iterator(const Iterator& other)
|
||||
: ParamIteratorInterface<T>(),
|
||||
base_(other.base_), value_(other.value_), index_(other.index_),
|
||||
step_(other.step_) {}
|
||||
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const Iterator& other);
|
||||
|
||||
const ParamGeneratorInterface<T>* const base_;
|
||||
T value_;
|
||||
int index_;
|
||||
const IncrementT step_;
|
||||
}; // class RangeGenerator::Iterator
|
||||
|
||||
static int CalculateEndIndex(const T& begin,
|
||||
const T& end,
|
||||
const IncrementT& step) {
|
||||
int end_index = 0;
|
||||
for (T i = begin; i < end; i = i + step)
|
||||
end_index++;
|
||||
return end_index;
|
||||
}
|
||||
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const RangeGenerator& other);
|
||||
|
||||
const T begin_;
|
||||
const T end_;
|
||||
const IncrementT step_;
|
||||
// The index for the end() iterator. All the elements in the generated
|
||||
// sequence are indexed (0-based) to aid iterator comparison.
|
||||
const int end_index_;
|
||||
}; // class RangeGenerator
|
||||
|
||||
|
||||
// Generates values from a pair of STL-style iterators. Used in the
|
||||
// ValuesIn() function. The elements are copied from the source range
|
||||
// since the source can be located on the stack, and the generator
|
||||
// is likely to persist beyond that stack frame.
|
||||
template <typename T>
|
||||
class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface<T> {
|
||||
public:
|
||||
template <typename ForwardIterator>
|
||||
ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end)
|
||||
: container_(begin, end) {}
|
||||
virtual ~ValuesInIteratorRangeGenerator() {}
|
||||
|
||||
virtual ParamIteratorInterface<T>* Begin() const {
|
||||
return new Iterator(this, container_.begin());
|
||||
}
|
||||
virtual ParamIteratorInterface<T>* End() const {
|
||||
return new Iterator(this, container_.end());
|
||||
}
|
||||
|
||||
private:
|
||||
typedef typename ::std::vector<T> ContainerType;
|
||||
|
||||
class Iterator : public ParamIteratorInterface<T> {
|
||||
public:
|
||||
Iterator(const ParamGeneratorInterface<T>* base,
|
||||
typename ContainerType::const_iterator iterator)
|
||||
: base_(base), iterator_(iterator) {}
|
||||
virtual ~Iterator() {}
|
||||
|
||||
virtual const ParamGeneratorInterface<T>* BaseGenerator() const {
|
||||
return base_;
|
||||
}
|
||||
virtual void Advance() {
|
||||
++iterator_;
|
||||
value_.reset();
|
||||
}
|
||||
virtual ParamIteratorInterface<T>* Clone() const {
|
||||
return new Iterator(*this);
|
||||
}
|
||||
// We need to use cached value referenced by iterator_ because *iterator_
|
||||
// can return a temporary object (and of type other then T), so just
|
||||
// having "return &*iterator_;" doesn't work.
|
||||
// value_ is updated here and not in Advance() because Advance()
|
||||
// can advance iterator_ beyond the end of the range, and we cannot
|
||||
// detect that fact. The client code, on the other hand, is
|
||||
// responsible for not calling Current() on an out-of-range iterator.
|
||||
virtual const T* Current() const {
|
||||
if (value_.get() == NULL)
|
||||
value_.reset(new T(*iterator_));
|
||||
return value_.get();
|
||||
}
|
||||
virtual bool Equals(const ParamIteratorInterface<T>& other) const {
|
||||
// Having the same base generator guarantees that the other
|
||||
// iterator is of the same type and we can downcast.
|
||||
GTEST_CHECK_(BaseGenerator() == other.BaseGenerator())
|
||||
<< "The program attempted to compare iterators "
|
||||
<< "from different generators." << std::endl;
|
||||
return iterator_ ==
|
||||
CheckedDowncastToActualType<const Iterator>(&other)->iterator_;
|
||||
}
|
||||
|
||||
private:
|
||||
Iterator(const Iterator& other)
|
||||
// The explicit constructor call suppresses a false warning
|
||||
// emitted by gcc when supplied with the -Wextra option.
|
||||
: ParamIteratorInterface<T>(),
|
||||
base_(other.base_),
|
||||
iterator_(other.iterator_) {}
|
||||
|
||||
const ParamGeneratorInterface<T>* const base_;
|
||||
typename ContainerType::const_iterator iterator_;
|
||||
// A cached value of *iterator_. We keep it here to allow access by
|
||||
// pointer in the wrapping iterator's operator->().
|
||||
// value_ needs to be mutable to be accessed in Current().
|
||||
// Use of scoped_ptr helps manage cached value's lifetime,
|
||||
// which is bound by the lifespan of the iterator itself.
|
||||
mutable scoped_ptr<const T> value_;
|
||||
}; // class ValuesInIteratorRangeGenerator::Iterator
|
||||
|
||||
// No implementation - assignment is unsupported.
|
||||
void operator=(const ValuesInIteratorRangeGenerator& other);
|
||||
|
||||
const ContainerType container_;
|
||||
}; // class ValuesInIteratorRangeGenerator
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// Stores a parameter value and later creates tests parameterized with that
|
||||
// value.
|
||||
template <class TestClass>
|
||||
class ParameterizedTestFactory : public TestFactoryBase {
|
||||
public:
|
||||
typedef typename TestClass::ParamType ParamType;
|
||||
explicit ParameterizedTestFactory(ParamType parameter) :
|
||||
parameter_(parameter) {}
|
||||
virtual Test* CreateTest() {
|
||||
TestClass::SetParam(¶meter_);
|
||||
return new TestClass();
|
||||
}
|
||||
|
||||
private:
|
||||
const ParamType parameter_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory);
|
||||
};
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// TestMetaFactoryBase is a base class for meta-factories that create
|
||||
// test factories for passing into MakeAndRegisterTestInfo function.
|
||||
template <class ParamType>
|
||||
class TestMetaFactoryBase {
|
||||
public:
|
||||
virtual ~TestMetaFactoryBase() {}
|
||||
|
||||
virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0;
|
||||
};
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// TestMetaFactory creates test factories for passing into
|
||||
// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives
|
||||
// ownership of test factory pointer, same factory object cannot be passed
|
||||
// into that method twice. But ParameterizedTestCaseInfo is going to call
|
||||
// it for each Test/Parameter value combination. Thus it needs meta factory
|
||||
// creator class.
|
||||
template <class TestCase>
|
||||
class TestMetaFactory
|
||||
: public TestMetaFactoryBase<typename TestCase::ParamType> {
|
||||
public:
|
||||
typedef typename TestCase::ParamType ParamType;
|
||||
|
||||
TestMetaFactory() {}
|
||||
|
||||
virtual TestFactoryBase* CreateTestFactory(ParamType parameter) {
|
||||
return new ParameterizedTestFactory<TestCase>(parameter);
|
||||
}
|
||||
|
||||
private:
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory);
|
||||
};
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// ParameterizedTestCaseInfoBase is a generic interface
|
||||
// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase
|
||||
// accumulates test information provided by TEST_P macro invocations
|
||||
// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations
|
||||
// and uses that information to register all resulting test instances
|
||||
// in RegisterTests method. The ParameterizeTestCaseRegistry class holds
|
||||
// a collection of pointers to the ParameterizedTestCaseInfo objects
|
||||
// and calls RegisterTests() on each of them when asked.
|
||||
class ParameterizedTestCaseInfoBase {
|
||||
public:
|
||||
virtual ~ParameterizedTestCaseInfoBase() {}
|
||||
|
||||
// Base part of test case name for display purposes.
|
||||
virtual const string& GetTestCaseName() const = 0;
|
||||
// Test case id to verify identity.
|
||||
virtual TypeId GetTestCaseTypeId() const = 0;
|
||||
// UnitTest class invokes this method to register tests in this
|
||||
// test case right before running them in RUN_ALL_TESTS macro.
|
||||
// This method should not be called more then once on any single
|
||||
// instance of a ParameterizedTestCaseInfoBase derived class.
|
||||
virtual void RegisterTests() = 0;
|
||||
|
||||
protected:
|
||||
ParameterizedTestCaseInfoBase() {}
|
||||
|
||||
private:
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase);
|
||||
};
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P
|
||||
// macro invocations for a particular test case and generators
|
||||
// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that
|
||||
// test case. It registers tests with all values generated by all
|
||||
// generators when asked.
|
||||
template <class TestCase>
|
||||
class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase {
|
||||
public:
|
||||
// ParamType and GeneratorCreationFunc are private types but are required
|
||||
// for declarations of public methods AddTestPattern() and
|
||||
// AddTestCaseInstantiation().
|
||||
typedef typename TestCase::ParamType ParamType;
|
||||
// A function that returns an instance of appropriate generator type.
|
||||
typedef ParamGenerator<ParamType>(GeneratorCreationFunc)();
|
||||
|
||||
explicit ParameterizedTestCaseInfo(const char* name)
|
||||
: test_case_name_(name) {}
|
||||
|
||||
// Test case base name for display purposes.
|
||||
virtual const string& GetTestCaseName() const { return test_case_name_; }
|
||||
// Test case id to verify identity.
|
||||
virtual TypeId GetTestCaseTypeId() const { return GetTypeId<TestCase>(); }
|
||||
// TEST_P macro uses AddTestPattern() to record information
|
||||
// about a single test in a LocalTestInfo structure.
|
||||
// test_case_name is the base name of the test case (without invocation
|
||||
// prefix). test_base_name is the name of an individual test without
|
||||
// parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is
|
||||
// test case base name and DoBar is test base name.
|
||||
void AddTestPattern(const char* test_case_name,
|
||||
const char* test_base_name,
|
||||
TestMetaFactoryBase<ParamType>* meta_factory) {
|
||||
tests_.push_back(linked_ptr<TestInfo>(new TestInfo(test_case_name,
|
||||
test_base_name,
|
||||
meta_factory)));
|
||||
}
|
||||
// INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information
|
||||
// about a generator.
|
||||
int AddTestCaseInstantiation(const string& instantiation_name,
|
||||
GeneratorCreationFunc* func,
|
||||
const char* /* file */,
|
||||
int /* line */) {
|
||||
instantiations_.push_back(::std::make_pair(instantiation_name, func));
|
||||
return 0; // Return value used only to run this method in namespace scope.
|
||||
}
|
||||
// UnitTest class invokes this method to register tests in this test case
|
||||
// test cases right before running tests in RUN_ALL_TESTS macro.
|
||||
// This method should not be called more then once on any single
|
||||
// instance of a ParameterizedTestCaseInfoBase derived class.
|
||||
// UnitTest has a guard to prevent from calling this method more then once.
|
||||
virtual void RegisterTests() {
|
||||
for (typename TestInfoContainer::iterator test_it = tests_.begin();
|
||||
test_it != tests_.end(); ++test_it) {
|
||||
linked_ptr<TestInfo> test_info = *test_it;
|
||||
for (typename InstantiationContainer::iterator gen_it =
|
||||
instantiations_.begin(); gen_it != instantiations_.end();
|
||||
++gen_it) {
|
||||
const string& instantiation_name = gen_it->first;
|
||||
ParamGenerator<ParamType> generator((*gen_it->second)());
|
||||
|
||||
string test_case_name;
|
||||
if ( !instantiation_name.empty() )
|
||||
test_case_name = instantiation_name + "/";
|
||||
test_case_name += test_info->test_case_base_name;
|
||||
|
||||
int i = 0;
|
||||
for (typename ParamGenerator<ParamType>::iterator param_it =
|
||||
generator.begin();
|
||||
param_it != generator.end(); ++param_it, ++i) {
|
||||
Message test_name_stream;
|
||||
test_name_stream << test_info->test_base_name << "/" << i;
|
||||
MakeAndRegisterTestInfo(
|
||||
test_case_name.c_str(),
|
||||
test_name_stream.GetString().c_str(),
|
||||
NULL, // No type parameter.
|
||||
PrintToString(*param_it).c_str(),
|
||||
GetTestCaseTypeId(),
|
||||
TestCase::SetUpTestCase,
|
||||
TestCase::TearDownTestCase,
|
||||
test_info->test_meta_factory->CreateTestFactory(*param_it));
|
||||
} // for param_it
|
||||
} // for gen_it
|
||||
} // for test_it
|
||||
} // RegisterTests
|
||||
|
||||
private:
|
||||
// LocalTestInfo structure keeps information about a single test registered
|
||||
// with TEST_P macro.
|
||||
struct TestInfo {
|
||||
TestInfo(const char* a_test_case_base_name,
|
||||
const char* a_test_base_name,
|
||||
TestMetaFactoryBase<ParamType>* a_test_meta_factory) :
|
||||
test_case_base_name(a_test_case_base_name),
|
||||
test_base_name(a_test_base_name),
|
||||
test_meta_factory(a_test_meta_factory) {}
|
||||
|
||||
const string test_case_base_name;
|
||||
const string test_base_name;
|
||||
const scoped_ptr<TestMetaFactoryBase<ParamType> > test_meta_factory;
|
||||
};
|
||||
typedef ::std::vector<linked_ptr<TestInfo> > TestInfoContainer;
|
||||
// Keeps pairs of <Instantiation name, Sequence generator creation function>
|
||||
// received from INSTANTIATE_TEST_CASE_P macros.
|
||||
typedef ::std::vector<std::pair<string, GeneratorCreationFunc*> >
|
||||
InstantiationContainer;
|
||||
|
||||
const string test_case_name_;
|
||||
TestInfoContainer tests_;
|
||||
InstantiationContainer instantiations_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo);
|
||||
}; // class ParameterizedTestCaseInfo
|
||||
|
||||
// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE.
|
||||
//
|
||||
// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase
|
||||
// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P
|
||||
// macros use it to locate their corresponding ParameterizedTestCaseInfo
|
||||
// descriptors.
|
||||
class ParameterizedTestCaseRegistry {
|
||||
public:
|
||||
ParameterizedTestCaseRegistry() {}
|
||||
~ParameterizedTestCaseRegistry() {
|
||||
for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
|
||||
it != test_case_infos_.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
// Looks up or creates and returns a structure containing information about
|
||||
// tests and instantiations of a particular test case.
|
||||
template <class TestCase>
|
||||
ParameterizedTestCaseInfo<TestCase>* GetTestCasePatternHolder(
|
||||
const char* test_case_name,
|
||||
const char* file,
|
||||
int line) {
|
||||
ParameterizedTestCaseInfo<TestCase>* typed_test_info = NULL;
|
||||
for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
|
||||
it != test_case_infos_.end(); ++it) {
|
||||
if ((*it)->GetTestCaseName() == test_case_name) {
|
||||
if ((*it)->GetTestCaseTypeId() != GetTypeId<TestCase>()) {
|
||||
// Complain about incorrect usage of Google Test facilities
|
||||
// and terminate the program since we cannot guaranty correct
|
||||
// test case setup and tear-down in this case.
|
||||
ReportInvalidTestCaseType(test_case_name, file, line);
|
||||
posix::Abort();
|
||||
} else {
|
||||
// At this point we are sure that the object we found is of the same
|
||||
// type we are looking for, so we downcast it to that type
|
||||
// without further checks.
|
||||
typed_test_info = CheckedDowncastToActualType<
|
||||
ParameterizedTestCaseInfo<TestCase> >(*it);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (typed_test_info == NULL) {
|
||||
typed_test_info = new ParameterizedTestCaseInfo<TestCase>(test_case_name);
|
||||
test_case_infos_.push_back(typed_test_info);
|
||||
}
|
||||
return typed_test_info;
|
||||
}
|
||||
void RegisterTests() {
|
||||
for (TestCaseInfoContainer::iterator it = test_case_infos_.begin();
|
||||
it != test_case_infos_.end(); ++it) {
|
||||
(*it)->RegisterTests();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typedef ::std::vector<ParameterizedTestCaseInfoBase*> TestCaseInfoContainer;
|
||||
|
||||
TestCaseInfoContainer test_case_infos_;
|
||||
|
||||
GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_HAS_PARAM_TEST
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_
|
File diff suppressed because it is too large
Load diff
|
@ -1,167 +0,0 @@
|
|||
// Copyright 2005, Google 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:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee)
|
||||
//
|
||||
// The Google C++ Testing Framework (Google Test)
|
||||
//
|
||||
// This header file declares the String class and functions used internally by
|
||||
// Google Test. They are subject to change without notice. They should not used
|
||||
// by code external to Google Test.
|
||||
//
|
||||
// This header file is #included by <gtest/internal/gtest-internal.h>.
|
||||
// It should not be #included by other files.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
||||
|
||||
#ifdef __BORLANDC__
|
||||
// string.h is not guaranteed to provide strcpy on C++ Builder.
|
||||
# include <mem.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// String - an abstract class holding static string utilities.
|
||||
class GTEST_API_ String {
|
||||
public:
|
||||
// Static utility methods
|
||||
|
||||
// Clones a 0-terminated C string, allocating memory using new. The
|
||||
// caller is responsible for deleting the return value using
|
||||
// delete[]. Returns the cloned string, or NULL if the input is
|
||||
// NULL.
|
||||
//
|
||||
// This is different from strdup() in string.h, which allocates
|
||||
// memory using malloc().
|
||||
static const char* CloneCString(const char* c_str);
|
||||
|
||||
#if GTEST_OS_WINDOWS_MOBILE
|
||||
// Windows CE does not have the 'ANSI' versions of Win32 APIs. To be
|
||||
// able to pass strings to Win32 APIs on CE we need to convert them
|
||||
// to 'Unicode', UTF-16.
|
||||
|
||||
// Creates a UTF-16 wide string from the given ANSI string, allocating
|
||||
// memory using new. The caller is responsible for deleting the return
|
||||
// value using delete[]. Returns the wide string, or NULL if the
|
||||
// input is NULL.
|
||||
//
|
||||
// The wide string is created using the ANSI codepage (CP_ACP) to
|
||||
// match the behaviour of the ANSI versions of Win32 calls and the
|
||||
// C runtime.
|
||||
static LPCWSTR AnsiToUtf16(const char* c_str);
|
||||
|
||||
// Creates an ANSI string from the given wide string, allocating
|
||||
// memory using new. The caller is responsible for deleting the return
|
||||
// value using delete[]. Returns the ANSI string, or NULL if the
|
||||
// input is NULL.
|
||||
//
|
||||
// The returned string is created using the ANSI codepage (CP_ACP) to
|
||||
// match the behaviour of the ANSI versions of Win32 calls and the
|
||||
// C runtime.
|
||||
static const char* Utf16ToAnsi(LPCWSTR utf16_str);
|
||||
#endif
|
||||
|
||||
// Compares two C strings. Returns true iff they have the same content.
|
||||
//
|
||||
// Unlike strcmp(), this function can handle NULL argument(s). A
|
||||
// NULL C string is considered different to any non-NULL C string,
|
||||
// including the empty string.
|
||||
static bool CStringEquals(const char* lhs, const char* rhs);
|
||||
|
||||
// Converts a wide C string to a String using the UTF-8 encoding.
|
||||
// NULL will be converted to "(null)". If an error occurred during
|
||||
// the conversion, "(failed to convert from wide string)" is
|
||||
// returned.
|
||||
static std::string ShowWideCString(const wchar_t* wide_c_str);
|
||||
|
||||
// Compares two wide C strings. Returns true iff they have the same
|
||||
// content.
|
||||
//
|
||||
// Unlike wcscmp(), this function can handle NULL argument(s). A
|
||||
// NULL C string is considered different to any non-NULL C string,
|
||||
// including the empty string.
|
||||
static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs);
|
||||
|
||||
// Compares two C strings, ignoring case. Returns true iff they
|
||||
// have the same content.
|
||||
//
|
||||
// Unlike strcasecmp(), this function can handle NULL argument(s).
|
||||
// A NULL C string is considered different to any non-NULL C string,
|
||||
// including the empty string.
|
||||
static bool CaseInsensitiveCStringEquals(const char* lhs,
|
||||
const char* rhs);
|
||||
|
||||
// Compares two wide C strings, ignoring case. Returns true iff they
|
||||
// have the same content.
|
||||
//
|
||||
// Unlike wcscasecmp(), this function can handle NULL argument(s).
|
||||
// A NULL C string is considered different to any non-NULL wide C string,
|
||||
// including the empty string.
|
||||
// NB: The implementations on different platforms slightly differ.
|
||||
// On windows, this method uses _wcsicmp which compares according to LC_CTYPE
|
||||
// environment variable. On GNU platform this method uses wcscasecmp
|
||||
// which compares according to LC_CTYPE category of the current locale.
|
||||
// On MacOS X, it uses towlower, which also uses LC_CTYPE category of the
|
||||
// current locale.
|
||||
static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs,
|
||||
const wchar_t* rhs);
|
||||
|
||||
// Returns true iff the given string ends with the given suffix, ignoring
|
||||
// case. Any string is considered to end with an empty suffix.
|
||||
static bool EndsWithCaseInsensitive(
|
||||
const std::string& str, const std::string& suffix);
|
||||
|
||||
// Formats an int value as "%02d".
|
||||
static std::string FormatIntWidth2(int value); // "%02d" for width == 2
|
||||
|
||||
// Formats an int value as "%X".
|
||||
static std::string FormatHexInt(int value);
|
||||
|
||||
// Formats a byte as "%02X".
|
||||
static std::string FormatByte(unsigned char value);
|
||||
|
||||
private:
|
||||
String(); // Not meant to be instantiated.
|
||||
}; // class String
|
||||
|
||||
// Gets the content of the stringstream's buffer as an std::string. Each '\0'
|
||||
// character in the buffer is replaced with "\\0".
|
||||
GTEST_API_ std::string StringStreamToString(::std::stringstream* stream);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_
|
File diff suppressed because it is too large
Load diff
|
@ -1,339 +0,0 @@
|
|||
$$ -*- mode: c++; -*-
|
||||
$var n = 10 $$ Maximum number of tuple fields we want to support.
|
||||
$$ This meta comment fixes auto-indentation in Emacs. }}
|
||||
// Copyright 2009 Google 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:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
|
||||
// Implements a subset of TR1 tuple needed by Google Test and Google Mock.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
|
||||
|
||||
#include <utility> // For ::std::pair.
|
||||
|
||||
// The compiler used in Symbian has a bug that prevents us from declaring the
|
||||
// tuple template as a friend (it complains that tuple is redefined). This
|
||||
// hack bypasses the bug by declaring the members that should otherwise be
|
||||
// private as public.
|
||||
// Sun Studio versions < 12 also have the above bug.
|
||||
#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590)
|
||||
# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public:
|
||||
#else
|
||||
# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \
|
||||
template <GTEST_$(n)_TYPENAMES_(U)> friend class tuple; \
|
||||
private:
|
||||
#endif
|
||||
|
||||
|
||||
$range i 0..n-1
|
||||
$range j 0..n
|
||||
$range k 1..n
|
||||
// GTEST_n_TUPLE_(T) is the type of an n-tuple.
|
||||
#define GTEST_0_TUPLE_(T) tuple<>
|
||||
|
||||
$for k [[
|
||||
$range m 0..k-1
|
||||
$range m2 k..n-1
|
||||
#define GTEST_$(k)_TUPLE_(T) tuple<$for m, [[T##$m]]$for m2 [[, void]]>
|
||||
|
||||
]]
|
||||
|
||||
// GTEST_n_TYPENAMES_(T) declares a list of n typenames.
|
||||
|
||||
$for j [[
|
||||
$range m 0..j-1
|
||||
#define GTEST_$(j)_TYPENAMES_(T) $for m, [[typename T##$m]]
|
||||
|
||||
|
||||
]]
|
||||
|
||||
// In theory, defining stuff in the ::std namespace is undefined
|
||||
// behavior. We can do this as we are playing the role of a standard
|
||||
// library vendor.
|
||||
namespace std {
|
||||
namespace tr1 {
|
||||
|
||||
template <$for i, [[typename T$i = void]]>
|
||||
class tuple;
|
||||
|
||||
// Anything in namespace gtest_internal is Google Test's INTERNAL
|
||||
// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code.
|
||||
namespace gtest_internal {
|
||||
|
||||
// ByRef<T>::type is T if T is a reference; otherwise it's const T&.
|
||||
template <typename T>
|
||||
struct ByRef { typedef const T& type; }; // NOLINT
|
||||
template <typename T>
|
||||
struct ByRef<T&> { typedef T& type; }; // NOLINT
|
||||
|
||||
// A handy wrapper for ByRef.
|
||||
#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef<T>::type
|
||||
|
||||
// AddRef<T>::type is T if T is a reference; otherwise it's T&. This
|
||||
// is the same as tr1::add_reference<T>::type.
|
||||
template <typename T>
|
||||
struct AddRef { typedef T& type; }; // NOLINT
|
||||
template <typename T>
|
||||
struct AddRef<T&> { typedef T& type; }; // NOLINT
|
||||
|
||||
// A handy wrapper for AddRef.
|
||||
#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef<T>::type
|
||||
|
||||
// A helper for implementing get<k>().
|
||||
template <int k> class Get;
|
||||
|
||||
// A helper for implementing tuple_element<k, T>. kIndexValid is true
|
||||
// iff k < the number of fields in tuple type T.
|
||||
template <bool kIndexValid, int kIndex, class Tuple>
|
||||
struct TupleElement;
|
||||
|
||||
|
||||
$for i [[
|
||||
template <GTEST_$(n)_TYPENAMES_(T)>
|
||||
struct TupleElement<true, $i, GTEST_$(n)_TUPLE_(T) > {
|
||||
typedef T$i type;
|
||||
};
|
||||
|
||||
|
||||
]]
|
||||
} // namespace gtest_internal
|
||||
|
||||
template <>
|
||||
class tuple<> {
|
||||
public:
|
||||
tuple() {}
|
||||
tuple(const tuple& /* t */) {}
|
||||
tuple& operator=(const tuple& /* t */) { return *this; }
|
||||
};
|
||||
|
||||
|
||||
$for k [[
|
||||
$range m 0..k-1
|
||||
template <GTEST_$(k)_TYPENAMES_(T)>
|
||||
class $if k < n [[GTEST_$(k)_TUPLE_(T)]] $else [[tuple]] {
|
||||
public:
|
||||
template <int k> friend class gtest_internal::Get;
|
||||
|
||||
tuple() : $for m, [[f$(m)_()]] {}
|
||||
|
||||
explicit tuple($for m, [[GTEST_BY_REF_(T$m) f$m]]) : [[]]
|
||||
$for m, [[f$(m)_(f$m)]] {}
|
||||
|
||||
tuple(const tuple& t) : $for m, [[f$(m)_(t.f$(m)_)]] {}
|
||||
|
||||
template <GTEST_$(k)_TYPENAMES_(U)>
|
||||
tuple(const GTEST_$(k)_TUPLE_(U)& t) : $for m, [[f$(m)_(t.f$(m)_)]] {}
|
||||
|
||||
$if k == 2 [[
|
||||
template <typename U0, typename U1>
|
||||
tuple(const ::std::pair<U0, U1>& p) : f0_(p.first), f1_(p.second) {}
|
||||
|
||||
]]
|
||||
|
||||
tuple& operator=(const tuple& t) { return CopyFrom(t); }
|
||||
|
||||
template <GTEST_$(k)_TYPENAMES_(U)>
|
||||
tuple& operator=(const GTEST_$(k)_TUPLE_(U)& t) {
|
||||
return CopyFrom(t);
|
||||
}
|
||||
|
||||
$if k == 2 [[
|
||||
template <typename U0, typename U1>
|
||||
tuple& operator=(const ::std::pair<U0, U1>& p) {
|
||||
f0_ = p.first;
|
||||
f1_ = p.second;
|
||||
return *this;
|
||||
}
|
||||
|
||||
]]
|
||||
|
||||
GTEST_DECLARE_TUPLE_AS_FRIEND_
|
||||
|
||||
template <GTEST_$(k)_TYPENAMES_(U)>
|
||||
tuple& CopyFrom(const GTEST_$(k)_TUPLE_(U)& t) {
|
||||
|
||||
$for m [[
|
||||
f$(m)_ = t.f$(m)_;
|
||||
|
||||
]]
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
$for m [[
|
||||
T$m f$(m)_;
|
||||
|
||||
]]
|
||||
};
|
||||
|
||||
|
||||
]]
|
||||
// 6.1.3.2 Tuple creation functions.
|
||||
|
||||
// Known limitations: we don't support passing an
|
||||
// std::tr1::reference_wrapper<T> to make_tuple(). And we don't
|
||||
// implement tie().
|
||||
|
||||
inline tuple<> make_tuple() { return tuple<>(); }
|
||||
|
||||
$for k [[
|
||||
$range m 0..k-1
|
||||
|
||||
template <GTEST_$(k)_TYPENAMES_(T)>
|
||||
inline GTEST_$(k)_TUPLE_(T) make_tuple($for m, [[const T$m& f$m]]) {
|
||||
return GTEST_$(k)_TUPLE_(T)($for m, [[f$m]]);
|
||||
}
|
||||
|
||||
]]
|
||||
|
||||
// 6.1.3.3 Tuple helper classes.
|
||||
|
||||
template <typename Tuple> struct tuple_size;
|
||||
|
||||
|
||||
$for j [[
|
||||
template <GTEST_$(j)_TYPENAMES_(T)>
|
||||
struct tuple_size<GTEST_$(j)_TUPLE_(T) > {
|
||||
static const int value = $j;
|
||||
};
|
||||
|
||||
|
||||
]]
|
||||
template <int k, class Tuple>
|
||||
struct tuple_element {
|
||||
typedef typename gtest_internal::TupleElement<
|
||||
k < (tuple_size<Tuple>::value), k, Tuple>::type type;
|
||||
};
|
||||
|
||||
#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element<k, Tuple >::type
|
||||
|
||||
// 6.1.3.4 Element access.
|
||||
|
||||
namespace gtest_internal {
|
||||
|
||||
|
||||
$for i [[
|
||||
template <>
|
||||
class Get<$i> {
|
||||
public:
|
||||
template <class Tuple>
|
||||
static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple))
|
||||
Field(Tuple& t) { return t.f$(i)_; } // NOLINT
|
||||
|
||||
template <class Tuple>
|
||||
static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple))
|
||||
ConstField(const Tuple& t) { return t.f$(i)_; }
|
||||
};
|
||||
|
||||
|
||||
]]
|
||||
} // namespace gtest_internal
|
||||
|
||||
template <int k, GTEST_$(n)_TYPENAMES_(T)>
|
||||
GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T)))
|
||||
get(GTEST_$(n)_TUPLE_(T)& t) {
|
||||
return gtest_internal::Get<k>::Field(t);
|
||||
}
|
||||
|
||||
template <int k, GTEST_$(n)_TYPENAMES_(T)>
|
||||
GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T)))
|
||||
get(const GTEST_$(n)_TUPLE_(T)& t) {
|
||||
return gtest_internal::Get<k>::ConstField(t);
|
||||
}
|
||||
|
||||
// 6.1.3.5 Relational operators
|
||||
|
||||
// We only implement == and !=, as we don't have a need for the rest yet.
|
||||
|
||||
namespace gtest_internal {
|
||||
|
||||
// SameSizeTuplePrefixComparator<k, k>::Eq(t1, t2) returns true if the
|
||||
// first k fields of t1 equals the first k fields of t2.
|
||||
// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if
|
||||
// k1 != k2.
|
||||
template <int kSize1, int kSize2>
|
||||
struct SameSizeTuplePrefixComparator;
|
||||
|
||||
template <>
|
||||
struct SameSizeTuplePrefixComparator<0, 0> {
|
||||
template <class Tuple1, class Tuple2>
|
||||
static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <int k>
|
||||
struct SameSizeTuplePrefixComparator<k, k> {
|
||||
template <class Tuple1, class Tuple2>
|
||||
static bool Eq(const Tuple1& t1, const Tuple2& t2) {
|
||||
return SameSizeTuplePrefixComparator<k - 1, k - 1>::Eq(t1, t2) &&
|
||||
::std::tr1::get<k - 1>(t1) == ::std::tr1::get<k - 1>(t2);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gtest_internal
|
||||
|
||||
template <GTEST_$(n)_TYPENAMES_(T), GTEST_$(n)_TYPENAMES_(U)>
|
||||
inline bool operator==(const GTEST_$(n)_TUPLE_(T)& t,
|
||||
const GTEST_$(n)_TUPLE_(U)& u) {
|
||||
return gtest_internal::SameSizeTuplePrefixComparator<
|
||||
tuple_size<GTEST_$(n)_TUPLE_(T) >::value,
|
||||
tuple_size<GTEST_$(n)_TUPLE_(U) >::value>::Eq(t, u);
|
||||
}
|
||||
|
||||
template <GTEST_$(n)_TYPENAMES_(T), GTEST_$(n)_TYPENAMES_(U)>
|
||||
inline bool operator!=(const GTEST_$(n)_TUPLE_(T)& t,
|
||||
const GTEST_$(n)_TUPLE_(U)& u) { return !(t == u); }
|
||||
|
||||
// 6.1.4 Pairs.
|
||||
// Unimplemented.
|
||||
|
||||
} // namespace tr1
|
||||
} // namespace std
|
||||
|
||||
|
||||
$for j [[
|
||||
#undef GTEST_$(j)_TUPLE_
|
||||
|
||||
]]
|
||||
|
||||
|
||||
$for j [[
|
||||
#undef GTEST_$(j)_TYPENAMES_
|
||||
|
||||
]]
|
||||
|
||||
#undef GTEST_DECLARE_TUPLE_AS_FRIEND_
|
||||
#undef GTEST_BY_REF_
|
||||
#undef GTEST_ADD_REF_
|
||||
#undef GTEST_TUPLE_ELEMENT_
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_
|
File diff suppressed because it is too large
Load diff
|
@ -1,297 +0,0 @@
|
|||
$$ -*- mode: c++; -*-
|
||||
$var n = 50 $$ Maximum length of type lists we want to support.
|
||||
// Copyright 2008 Google 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:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Author: wan@google.com (Zhanyong Wan)
|
||||
|
||||
// Type utilities needed for implementing typed and type-parameterized
|
||||
// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND!
|
||||
//
|
||||
// Currently we support at most $n types in a list, and at most $n
|
||||
// type-parameterized tests in one type-parameterized test case.
|
||||
// Please contact googletestframework@googlegroups.com if you need
|
||||
// more.
|
||||
|
||||
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
|
||||
#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
|
||||
|
||||
#include "gtest/internal/gtest-port.h"
|
||||
|
||||
// #ifdef __GNUC__ is too general here. It is possible to use gcc without using
|
||||
// libstdc++ (which is where cxxabi.h comes from).
|
||||
# if GTEST_HAS_CXXABI_H_
|
||||
# include <cxxabi.h>
|
||||
# elif defined(__HP_aCC)
|
||||
# include <acxx_demangle.h>
|
||||
# endif // GTEST_HASH_CXXABI_H_
|
||||
|
||||
namespace testing {
|
||||
namespace internal {
|
||||
|
||||
// GetTypeName<T>() returns a human-readable name of type T.
|
||||
// NB: This function is also used in Google Mock, so don't move it inside of
|
||||
// the typed-test-only section below.
|
||||
template <typename T>
|
||||
std::string GetTypeName() {
|
||||
# if GTEST_HAS_RTTI
|
||||
|
||||
const char* const name = typeid(T).name();
|
||||
# if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC)
|
||||
int status = 0;
|
||||
// gcc's implementation of typeid(T).name() mangles the type name,
|
||||
// so we have to demangle it.
|
||||
# if GTEST_HAS_CXXABI_H_
|
||||
using abi::__cxa_demangle;
|
||||
# endif // GTEST_HAS_CXXABI_H_
|
||||
char* const readable_name = __cxa_demangle(name, 0, 0, &status);
|
||||
const std::string name_str(status == 0 ? readable_name : name);
|
||||
free(readable_name);
|
||||
return name_str;
|
||||
# else
|
||||
return name;
|
||||
# endif // GTEST_HAS_CXXABI_H_ || __HP_aCC
|
||||
|
||||
# else
|
||||
|
||||
return "<type>";
|
||||
|
||||
# endif // GTEST_HAS_RTTI
|
||||
}
|
||||
|
||||
#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
|
||||
|
||||
// AssertyTypeEq<T1, T2>::type is defined iff T1 and T2 are the same
|
||||
// type. This can be used as a compile-time assertion to ensure that
|
||||
// two types are equal.
|
||||
|
||||
template <typename T1, typename T2>
|
||||
struct AssertTypeEq;
|
||||
|
||||
template <typename T>
|
||||
struct AssertTypeEq<T, T> {
|
||||
typedef bool type;
|
||||
};
|
||||
|
||||
// A unique type used as the default value for the arguments of class
|
||||
// template Types. This allows us to simulate variadic templates
|
||||
// (e.g. Types<int>, Type<int, double>, and etc), which C++ doesn't
|
||||
// support directly.
|
||||
struct None {};
|
||||
|
||||
// The following family of struct and struct templates are used to
|
||||
// represent type lists. In particular, TypesN<T1, T2, ..., TN>
|
||||
// represents a type list with N types (T1, T2, ..., and TN) in it.
|
||||
// Except for Types0, every struct in the family has two member types:
|
||||
// Head for the first type in the list, and Tail for the rest of the
|
||||
// list.
|
||||
|
||||
// The empty type list.
|
||||
struct Types0 {};
|
||||
|
||||
// Type lists of length 1, 2, 3, and so on.
|
||||
|
||||
template <typename T1>
|
||||
struct Types1 {
|
||||
typedef T1 Head;
|
||||
typedef Types0 Tail;
|
||||
};
|
||||
|
||||
$range i 2..n
|
||||
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
$range k 2..i
|
||||
template <$for j, [[typename T$j]]>
|
||||
struct Types$i {
|
||||
typedef T1 Head;
|
||||
typedef Types$(i-1)<$for k, [[T$k]]> Tail;
|
||||
};
|
||||
|
||||
|
||||
]]
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// We don't want to require the users to write TypesN<...> directly,
|
||||
// as that would require them to count the length. Types<...> is much
|
||||
// easier to write, but generates horrible messages when there is a
|
||||
// compiler error, as gcc insists on printing out each template
|
||||
// argument, even if it has the default value (this means Types<int>
|
||||
// will appear as Types<int, None, None, ..., None> in the compiler
|
||||
// errors).
|
||||
//
|
||||
// Our solution is to combine the best part of the two approaches: a
|
||||
// user would write Types<T1, ..., TN>, and Google Test will translate
|
||||
// that to TypesN<T1, ..., TN> internally to make error messages
|
||||
// readable. The translation is done by the 'type' member of the
|
||||
// Types template.
|
||||
|
||||
$range i 1..n
|
||||
template <$for i, [[typename T$i = internal::None]]>
|
||||
struct Types {
|
||||
typedef internal::Types$n<$for i, [[T$i]]> type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Types<$for i, [[internal::None]]> {
|
||||
typedef internal::Types0 type;
|
||||
};
|
||||
|
||||
$range i 1..n-1
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
$range k i+1..n
|
||||
template <$for j, [[typename T$j]]>
|
||||
struct Types<$for j, [[T$j]]$for k[[, internal::None]]> {
|
||||
typedef internal::Types$i<$for j, [[T$j]]> type;
|
||||
};
|
||||
|
||||
]]
|
||||
|
||||
namespace internal {
|
||||
|
||||
# define GTEST_TEMPLATE_ template <typename T> class
|
||||
|
||||
// The template "selector" struct TemplateSel<Tmpl> is used to
|
||||
// represent Tmpl, which must be a class template with one type
|
||||
// parameter, as a type. TemplateSel<Tmpl>::Bind<T>::type is defined
|
||||
// as the type Tmpl<T>. This allows us to actually instantiate the
|
||||
// template "selected" by TemplateSel<Tmpl>.
|
||||
//
|
||||
// This trick is necessary for simulating typedef for class templates,
|
||||
// which C++ doesn't support directly.
|
||||
template <GTEST_TEMPLATE_ Tmpl>
|
||||
struct TemplateSel {
|
||||
template <typename T>
|
||||
struct Bind {
|
||||
typedef Tmpl<T> type;
|
||||
};
|
||||
};
|
||||
|
||||
# define GTEST_BIND_(TmplSel, T) \
|
||||
TmplSel::template Bind<T>::type
|
||||
|
||||
// A unique struct template used as the default value for the
|
||||
// arguments of class template Templates. This allows us to simulate
|
||||
// variadic templates (e.g. Templates<int>, Templates<int, double>,
|
||||
// and etc), which C++ doesn't support directly.
|
||||
template <typename T>
|
||||
struct NoneT {};
|
||||
|
||||
// The following family of struct and struct templates are used to
|
||||
// represent template lists. In particular, TemplatesN<T1, T2, ...,
|
||||
// TN> represents a list of N templates (T1, T2, ..., and TN). Except
|
||||
// for Templates0, every struct in the family has two member types:
|
||||
// Head for the selector of the first template in the list, and Tail
|
||||
// for the rest of the list.
|
||||
|
||||
// The empty template list.
|
||||
struct Templates0 {};
|
||||
|
||||
// Template lists of length 1, 2, 3, and so on.
|
||||
|
||||
template <GTEST_TEMPLATE_ T1>
|
||||
struct Templates1 {
|
||||
typedef TemplateSel<T1> Head;
|
||||
typedef Templates0 Tail;
|
||||
};
|
||||
|
||||
$range i 2..n
|
||||
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
$range k 2..i
|
||||
template <$for j, [[GTEST_TEMPLATE_ T$j]]>
|
||||
struct Templates$i {
|
||||
typedef TemplateSel<T1> Head;
|
||||
typedef Templates$(i-1)<$for k, [[T$k]]> Tail;
|
||||
};
|
||||
|
||||
|
||||
]]
|
||||
|
||||
// We don't want to require the users to write TemplatesN<...> directly,
|
||||
// as that would require them to count the length. Templates<...> is much
|
||||
// easier to write, but generates horrible messages when there is a
|
||||
// compiler error, as gcc insists on printing out each template
|
||||
// argument, even if it has the default value (this means Templates<list>
|
||||
// will appear as Templates<list, NoneT, NoneT, ..., NoneT> in the compiler
|
||||
// errors).
|
||||
//
|
||||
// Our solution is to combine the best part of the two approaches: a
|
||||
// user would write Templates<T1, ..., TN>, and Google Test will translate
|
||||
// that to TemplatesN<T1, ..., TN> internally to make error messages
|
||||
// readable. The translation is done by the 'type' member of the
|
||||
// Templates template.
|
||||
|
||||
$range i 1..n
|
||||
template <$for i, [[GTEST_TEMPLATE_ T$i = NoneT]]>
|
||||
struct Templates {
|
||||
typedef Templates$n<$for i, [[T$i]]> type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Templates<$for i, [[NoneT]]> {
|
||||
typedef Templates0 type;
|
||||
};
|
||||
|
||||
$range i 1..n-1
|
||||
$for i [[
|
||||
$range j 1..i
|
||||
$range k i+1..n
|
||||
template <$for j, [[GTEST_TEMPLATE_ T$j]]>
|
||||
struct Templates<$for j, [[T$j]]$for k[[, NoneT]]> {
|
||||
typedef Templates$i<$for j, [[T$j]]> type;
|
||||
};
|
||||
|
||||
]]
|
||||
|
||||
// The TypeList template makes it possible to use either a single type
|
||||
// or a Types<...> list in TYPED_TEST_CASE() and
|
||||
// INSTANTIATE_TYPED_TEST_CASE_P().
|
||||
|
||||
template <typename T>
|
||||
struct TypeList {
|
||||
typedef Types1<T> type;
|
||||
};
|
||||
|
||||
|
||||
$range i 1..n
|
||||
template <$for i, [[typename T$i]]>
|
||||
struct TypeList<Types<$for i, [[T$i]]> > {
|
||||
typedef typename Types<$for i, [[T$i]]>::type type;
|
||||
};
|
||||
|
||||
#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P
|
||||
|
||||
} // namespace internal
|
||||
} // namespace testing
|
||||
|
||||
#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue