Model loading and texturing

This commit is contained in:
Dane Johnson
2021-01-18 18:25:47 -06:00
parent 66bf7776c7
commit 155b572aca
1283 changed files with 533814 additions and 42 deletions

View File

@@ -0,0 +1,4 @@
# Compile internal irrXML only if system is not requested
if( NOT SYSTEM_IRRXML )
add_subdirectory(irrXML)
endif( NOT SYSTEM_IRRXML )

View File

@@ -0,0 +1,155 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_ADJACENCY_INFO_H
#define O3DGC_ADJACENCY_INFO_H
#include "o3dgcCommon.h"
namespace o3dgc
{
const long O3DGC_MIN_NEIGHBORS_SIZE = 128;
const long O3DGC_MIN_NUM_NEIGHBORS_SIZE = 16;
//!
class AdjacencyInfo
{
public:
//! Constructor.
AdjacencyInfo(long numNeighborsSize = O3DGC_MIN_NUM_NEIGHBORS_SIZE,
long neighborsSize = O3DGC_MIN_NUM_NEIGHBORS_SIZE)
{
m_numElements = 0;
m_neighborsSize = neighborsSize;
m_numNeighborsSize = numNeighborsSize;
m_numNeighbors = new long [m_numNeighborsSize];
m_neighbors = new long [m_neighborsSize ];
};
//! Destructor.
~AdjacencyInfo(void)
{
delete [] m_neighbors;
delete [] m_numNeighbors;
};
O3DGCErrorCode Allocate(long numNeighborsSize, long neighborsSize)
{
m_numElements = numNeighborsSize;
if (neighborsSize > m_neighborsSize)
{
delete [] m_numNeighbors;
m_neighborsSize = neighborsSize;
m_numNeighbors = new long [m_numNeighborsSize];
}
if (numNeighborsSize > m_numNeighborsSize)
{
delete [] m_neighbors;
m_numNeighborsSize = numNeighborsSize;
m_neighbors = new long [m_neighborsSize];
}
return O3DGC_OK;
}
O3DGCErrorCode AllocateNumNeighborsArray(long numElements)
{
if (numElements > m_numNeighborsSize)
{
delete [] m_numNeighbors;
m_numNeighborsSize = numElements;
m_numNeighbors = new long [m_numNeighborsSize];
}
m_numElements = numElements;
return O3DGC_OK;
}
O3DGCErrorCode AllocateNeighborsArray()
{
for(long i = 1; i < m_numElements; ++i)
{
m_numNeighbors[i] += m_numNeighbors[i-1];
}
if (m_numNeighbors[m_numElements-1] > m_neighborsSize)
{
delete [] m_neighbors;
m_neighborsSize = m_numNeighbors[m_numElements-1];
m_neighbors = new long [m_neighborsSize];
}
return O3DGC_OK;
}
O3DGCErrorCode ClearNumNeighborsArray()
{
memset(m_numNeighbors, 0x00, sizeof(long) * m_numElements);
return O3DGC_OK;
}
O3DGCErrorCode ClearNeighborsArray()
{
memset(m_neighbors, 0xFF, sizeof(long) * m_neighborsSize);
return O3DGC_OK;
}
O3DGCErrorCode AddNeighbor(long element, long neighbor)
{
assert(m_numNeighbors[element] <= m_numNeighbors[m_numElements-1]);
long p0 = Begin(element);
long p1 = End(element);
for(long p = p0; p < p1; p++)
{
if (m_neighbors[p] == -1)
{
m_neighbors[p] = neighbor;
return O3DGC_OK;
}
}
return O3DGC_ERROR_BUFFER_FULL;
}
long Begin(long element) const
{
assert(element < m_numElements);
assert(element >= 0);
return (element>0)?m_numNeighbors[element-1]:0;
}
long End(long element) const
{
assert(element < m_numElements);
assert(element >= 0);
return m_numNeighbors[element];
}
long GetNeighbor(long element) const
{
assert(element < m_neighborsSize);
assert(element >= 0);
return m_neighbors[element];
}
long GetNumNeighbors(long element) const
{
return End(element) - Begin(element);
}
long * GetNumNeighborsBuffer() { return m_numNeighbors;}
long * GetNeighborsBuffer() { return m_neighbors;}
private:
long m_neighborsSize; // actual allocated size for m_neighbors
long m_numNeighborsSize; // actual allocated size for m_numNeighbors
long m_numElements; // number of elements
long * m_neighbors; //
long * m_numNeighbors; //
};
}
#endif // O3DGC_ADJACENCY_INFO_H

View File

@@ -0,0 +1,865 @@
/*
Copyright (c) 2004 Amir Said (said@ieee.org) & William A. Pearlman (pearlw@ecse.rpi.edu)
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.
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 HOLDER 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.
*/
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -
// **************************** -
// ARITHMETIC CODING EXAMPLES -
// **************************** -
// -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -
// Fast arithmetic coding implementation -
// -> 32-bit variables, 32-bit product, periodic updates, table decoding -
// -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -
// Version 1.00 - April 25, 2004 -
// -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -
// WARNING -
// ========= -
// -
// The only purpose of this program is to demonstrate the basic principles -
// of arithmetic coding. It is provided as is, without any express or -
// implied warranty, without even the warranty of fitness for any particular -
// purpose, or that the implementations are correct. -
// -
// Permission to copy and redistribute this code is hereby granted, provided -
// that this warning and copyright notices are not removed or altered. -
// -
// Copyright (c) 2004 by Amir Said (said@ieee.org) & -
// William A. Pearlman (pearlw@ecse.rpi.edu) -
// -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -
// A description of the arithmetic coding method used here is available in -
// -
// Lossless Compression Handbook, ed. K. Sayood -
// Chapter 5: Arithmetic Coding (A. Said), pp. 101-152, Academic Press, 2003 -
// -
// A. Said, Introduction to Arithetic Coding Theory and Practice -
// HP Labs report HPL-2004-76 - http://www.hpl.hp.com/techreports/ -
// -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - Inclusion - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#include <stdlib.h>
#include "o3dgcArithmeticCodec.h"
namespace o3dgc
{
// - - Constants - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const unsigned AC__MinLength = 0x01000000U; // threshold for renormalization
const unsigned AC__MaxLength = 0xFFFFFFFFU; // maximum AC interval length
// Maximum values for binary models
const unsigned BM__LengthShift = 13; // length bits discarded before mult.
const unsigned BM__MaxCount = 1 << BM__LengthShift; // for adaptive models
// Maximum values for general models
const unsigned DM__LengthShift = 15; // length bits discarded before mult.
const unsigned DM__MaxCount = 1 << DM__LengthShift; // for adaptive models
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - Static functions - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void AC_Error(const char * msg)
{
fprintf(stderr, "\n\n -> Arithmetic coding error: ");
fputs(msg, stderr);
fputs("\n Execution terminated!\n", stderr);
getchar();
exit(1);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - Coding implementations - - - - - - - - - - - - - - - - - - - - - - - -
inline void Arithmetic_Codec::propagate_carry(void)
{
unsigned char * p; // carry propagation on compressed data buffer
for (p = ac_pointer - 1; *p == 0xFFU; p--) *p = 0;
++*p;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void Arithmetic_Codec::renorm_enc_interval(void)
{
do { // output and discard top byte
*ac_pointer++ = (unsigned char)(base >> 24);
base <<= 8;
} while ((length <<= 8) < AC__MinLength); // length multiplied by 256
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
inline void Arithmetic_Codec::renorm_dec_interval(void)
{
do { // read least-significant byte
value = (value << 8) | unsigned(*++ac_pointer);
} while ((length <<= 8) < AC__MinLength); // length multiplied by 256
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::put_bit(unsigned bit)
{
#ifdef _DEBUG
if (mode != 1) AC_Error("encoder not initialized");
#endif
length >>= 1; // halve interval
if (bit) {
unsigned init_base = base;
base += length; // move base
if (init_base > base) propagate_carry(); // overflow = carry
}
if (length < AC__MinLength) renorm_enc_interval(); // renormalization
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unsigned Arithmetic_Codec::get_bit(void)
{
#ifdef _DEBUG
if (mode != 2) AC_Error("decoder not initialized");
#endif
length >>= 1; // halve interval
unsigned bit = (value >= length); // decode bit
if (bit) value -= length; // move base
if (length < AC__MinLength) renorm_dec_interval(); // renormalization
return bit; // return data bit value
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::put_bits(unsigned data, unsigned bits)
{
#ifdef _DEBUG
if (mode != 1) AC_Error("encoder not initialized");
if ((bits < 1) || (bits > 20)) AC_Error("invalid number of bits");
if (data >= (1U << bits)) AC_Error("invalid data");
#endif
unsigned init_base = base;
base += data * (length >>= bits); // new interval base and length
if (init_base > base) propagate_carry(); // overflow = carry
if (length < AC__MinLength) renorm_enc_interval(); // renormalization
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unsigned Arithmetic_Codec::get_bits(unsigned bits)
{
#ifdef _DEBUG
if (mode != 2) AC_Error("decoder not initialized");
if ((bits < 1) || (bits > 20)) AC_Error("invalid number of bits");
#endif
unsigned s = value / (length >>= bits); // decode symbol, change length
value -= length * s; // update interval
if (length < AC__MinLength) renorm_dec_interval(); // renormalization
return s;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::encode(unsigned bit,
Static_Bit_Model & M)
{
#ifdef _DEBUG
if (mode != 1) AC_Error("encoder not initialized");
#endif
unsigned x = M.bit_0_prob * (length >> BM__LengthShift); // product l x p0
// update interval
if (bit == 0)
length = x;
else {
unsigned init_base = base;
base += x;
length -= x;
if (init_base > base) propagate_carry(); // overflow = carry
}
if (length < AC__MinLength) renorm_enc_interval(); // renormalization
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unsigned Arithmetic_Codec::decode(Static_Bit_Model & M)
{
#ifdef _DEBUG
if (mode != 2) AC_Error("decoder not initialized");
#endif
unsigned x = M.bit_0_prob * (length >> BM__LengthShift); // product l x p0
unsigned bit = (value >= x); // decision
// update & shift interval
if (bit == 0)
length = x;
else {
value -= x; // shifted interval base = 0
length -= x;
}
if (length < AC__MinLength) renorm_dec_interval(); // renormalization
return bit; // return data bit value
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::encode(unsigned bit,
Adaptive_Bit_Model & M)
{
#ifdef _DEBUG
if (mode != 1) AC_Error("encoder not initialized");
#endif
unsigned x = M.bit_0_prob * (length >> BM__LengthShift); // product l x p0
// update interval
if (bit == 0) {
length = x;
++M.bit_0_count;
}
else {
unsigned init_base = base;
base += x;
length -= x;
if (init_base > base) propagate_carry(); // overflow = carry
}
if (length < AC__MinLength) renorm_enc_interval(); // renormalization
if (--M.bits_until_update == 0) M.update(); // periodic model update
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unsigned Arithmetic_Codec::decode(Adaptive_Bit_Model & M)
{
#ifdef _DEBUG
if (mode != 2) AC_Error("decoder not initialized");
#endif
unsigned x = M.bit_0_prob * (length >> BM__LengthShift); // product l x p0
unsigned bit = (value >= x); // decision
// update interval
if (bit == 0) {
length = x;
++M.bit_0_count;
}
else {
value -= x;
length -= x;
}
if (length < AC__MinLength) renorm_dec_interval(); // renormalization
if (--M.bits_until_update == 0) M.update(); // periodic model update
return bit; // return data bit value
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::encode(unsigned data,
Static_Data_Model & M)
{
#ifdef _DEBUG
if (mode != 1) AC_Error("encoder not initialized");
if (data >= M.data_symbols) AC_Error("invalid data symbol");
#endif
unsigned x, init_base = base;
// compute products
if (data == M.last_symbol) {
x = M.distribution[data] * (length >> DM__LengthShift);
base += x; // update interval
length -= x; // no product needed
}
else {
x = M.distribution[data] * (length >>= DM__LengthShift);
base += x; // update interval
length = M.distribution[data+1] * length - x;
}
if (init_base > base) propagate_carry(); // overflow = carry
if (length < AC__MinLength) renorm_enc_interval(); // renormalization
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unsigned Arithmetic_Codec::decode(Static_Data_Model & M)
{
#ifdef _DEBUG
if (mode != 2) AC_Error("decoder not initialized");
#endif
unsigned n, s, x, y = length;
if (M.decoder_table) { // use table look-up for faster decoding
unsigned dv = value / (length >>= DM__LengthShift);
unsigned t = dv >> M.table_shift;
s = M.decoder_table[t]; // initial decision based on table look-up
n = M.decoder_table[t+1] + 1;
while (n > s + 1) { // finish with bisection search
unsigned m = (s + n) >> 1;
if (M.distribution[m] > dv) n = m; else s = m;
}
// compute products
x = M.distribution[s] * length;
if (s != M.last_symbol) y = M.distribution[s+1] * length;
}
else { // decode using only multiplications
x = s = 0;
length >>= DM__LengthShift;
unsigned m = (n = M.data_symbols) >> 1;
// decode via bisection search
do {
unsigned z = length * M.distribution[m];
if (z > value) {
n = m;
y = z; // value is smaller
}
else {
s = m;
x = z; // value is larger or equal
}
} while ((m = (s + n) >> 1) != s);
}
value -= x; // update interval
length = y - x;
if (length < AC__MinLength) renorm_dec_interval(); // renormalization
return s;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::encode(unsigned data,
Adaptive_Data_Model & M)
{
#ifdef _DEBUG
if (mode != 1) AC_Error("encoder not initialized");
if (data >= M.data_symbols)
{
AC_Error("invalid data symbol");
}
#endif
unsigned x, init_base = base;
// compute products
if (data == M.last_symbol) {
x = M.distribution[data] * (length >> DM__LengthShift);
base += x; // update interval
length -= x; // no product needed
}
else {
x = M.distribution[data] * (length >>= DM__LengthShift);
base += x; // update interval
length = M.distribution[data+1] * length - x;
}
if (init_base > base) propagate_carry(); // overflow = carry
if (length < AC__MinLength) renorm_enc_interval(); // renormalization
++M.symbol_count[data];
if (--M.symbols_until_update == 0) M.update(true); // periodic model update
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unsigned Arithmetic_Codec::decode(Adaptive_Data_Model & M)
{
#ifdef _DEBUG
if (mode != 2) AC_Error("decoder not initialized");
#endif
unsigned n, s, x, y = length;
if (M.decoder_table) { // use table look-up for faster decoding
unsigned dv = value / (length >>= DM__LengthShift);
unsigned t = dv >> M.table_shift;
s = M.decoder_table[t]; // initial decision based on table look-up
n = M.decoder_table[t+1] + 1;
while (n > s + 1) { // finish with bisection search
unsigned m = (s + n) >> 1;
if (M.distribution[m] > dv) n = m; else s = m;
}
// compute products
x = M.distribution[s] * length;
if (s != M.last_symbol) {
y = M.distribution[s+1] * length;
}
}
else { // decode using only multiplications
x = s = 0;
length >>= DM__LengthShift;
unsigned m = (n = M.data_symbols) >> 1;
// decode via bisection search
do {
unsigned z = length * M.distribution[m];
if (z > value) {
n = m;
y = z; // value is smaller
}
else {
s = m;
x = z; // value is larger or equal
}
} while ((m = (s + n) >> 1) != s);
}
value -= x; // update interval
length = y - x;
if (length < AC__MinLength) renorm_dec_interval(); // renormalization
++M.symbol_count[s];
if (--M.symbols_until_update == 0) M.update(false); // periodic model update
return s;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - Other Arithmetic_Codec implementations - - - - - - - - - - - - - - - -
Arithmetic_Codec::Arithmetic_Codec(void)
{
mode = buffer_size = 0;
new_buffer = code_buffer = 0;
}
Arithmetic_Codec::Arithmetic_Codec(unsigned max_code_bytes,
unsigned char * user_buffer)
{
mode = buffer_size = 0;
new_buffer = code_buffer = 0;
set_buffer(max_code_bytes, user_buffer);
}
Arithmetic_Codec::~Arithmetic_Codec(void)
{
delete [] new_buffer;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::set_buffer(unsigned max_code_bytes,
unsigned char * user_buffer)
{
// test for reasonable sizes
if (!max_code_bytes)// || (max_code_bytes > 0x10000000U)) // updated by K. Mammou
{
AC_Error("invalid codec buffer size");
}
if (mode != 0) AC_Error("cannot set buffer while encoding or decoding");
if (user_buffer != 0) { // user provides memory buffer
buffer_size = max_code_bytes;
code_buffer = user_buffer; // set buffer for compressed data
delete [] new_buffer; // free anything previously assigned
new_buffer = 0;
return;
}
if (max_code_bytes <= buffer_size) return; // enough available
buffer_size = max_code_bytes; // assign new memory
delete [] new_buffer; // free anything previously assigned
if ((new_buffer = new unsigned char[buffer_size+16]) == 0) // 16 extra bytes
AC_Error("cannot assign memory for compressed data buffer");
code_buffer = new_buffer; // set buffer for compressed data
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::start_encoder(void)
{
if (mode != 0) AC_Error("cannot start encoder");
if (buffer_size == 0) AC_Error("no code buffer set");
mode = 1;
base = 0; // initialize encoder variables: interval and pointer
length = AC__MaxLength;
ac_pointer = code_buffer; // pointer to next data byte
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::start_decoder(void)
{
if (mode != 0) AC_Error("cannot start decoder");
if (buffer_size == 0) AC_Error("no code buffer set");
// initialize decoder: interval, pointer, initial code value
mode = 2;
length = AC__MaxLength;
ac_pointer = code_buffer + 3;
value = (unsigned(code_buffer[0]) << 24)|(unsigned(code_buffer[1]) << 16) |
(unsigned(code_buffer[2]) << 8)| unsigned(code_buffer[3]);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::read_from_file(FILE * code_file)
{
unsigned shift = 0, code_bytes = 0;
int file_byte;
// read variable-length header with number of code bytes
do {
if ((file_byte = getc(code_file)) == EOF)
AC_Error("cannot read code from file");
code_bytes |= unsigned(file_byte & 0x7F) << shift;
shift += 7;
} while (file_byte & 0x80);
// read compressed data
if (code_bytes > buffer_size) AC_Error("code buffer overflow");
if (fread(code_buffer, 1, code_bytes, code_file) != code_bytes)
AC_Error("cannot read code from file");
start_decoder(); // initialize decoder
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unsigned Arithmetic_Codec::stop_encoder(void)
{
if (mode != 1) AC_Error("invalid to stop encoder");
mode = 0;
unsigned init_base = base; // done encoding: set final data bytes
if (length > 2 * AC__MinLength) {
base += AC__MinLength; // base offset
length = AC__MinLength >> 1; // set new length for 1 more byte
}
else {
base += AC__MinLength >> 1; // base offset
length = AC__MinLength >> 9; // set new length for 2 more bytes
}
if (init_base > base) propagate_carry(); // overflow = carry
renorm_enc_interval(); // renormalization = output last bytes
unsigned code_bytes = unsigned(ac_pointer - code_buffer);
if (code_bytes > buffer_size) AC_Error("code buffer overflow");
return code_bytes; // number of bytes used
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
unsigned Arithmetic_Codec::write_to_file(FILE * code_file)
{
unsigned header_bytes = 0, code_bytes = stop_encoder(), nb = code_bytes;
// write variable-length header with number of code bytes
do {
int file_byte = int(nb & 0x7FU);
if ((nb >>= 7) > 0) file_byte |= 0x80;
if (putc(file_byte, code_file) == EOF)
AC_Error("cannot write compressed data to file");
header_bytes++;
} while (nb);
// write compressed data
if (fwrite(code_buffer, 1, code_bytes, code_file) != code_bytes)
AC_Error("cannot write compressed data to file");
return code_bytes + header_bytes; // bytes used
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Arithmetic_Codec::stop_decoder(void)
{
if (mode != 2) AC_Error("invalid to stop decoder");
mode = 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - Static bit model implementation - - - - - - - - - - - - - - - - - - - - -
Static_Bit_Model::Static_Bit_Model(void)
{
bit_0_prob = 1U << (BM__LengthShift - 1); // p0 = 0.5
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Static_Bit_Model::set_probability_0(double p0)
{
if ((p0 < 0.0001)||(p0 > 0.9999)) AC_Error("invalid bit probability");
bit_0_prob = unsigned(p0 * (1 << BM__LengthShift));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - Adaptive bit model implementation - - - - - - - - - - - - - - - - - - - -
Adaptive_Bit_Model::Adaptive_Bit_Model(void)
{
reset();
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Adaptive_Bit_Model::reset(void)
{
// initialization to equiprobable model
bit_0_count = 1;
bit_count = 2;
bit_0_prob = 1U << (BM__LengthShift - 1);
update_cycle = bits_until_update = 4; // start with frequent updates
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Adaptive_Bit_Model::update(void)
{
// halve counts when a threshold is reached
if ((bit_count += update_cycle) > BM__MaxCount) {
bit_count = (bit_count + 1) >> 1;
bit_0_count = (bit_0_count + 1) >> 1;
if (bit_0_count == bit_count) ++bit_count;
}
// compute scaled bit 0 probability
unsigned scale = 0x80000000U / bit_count;
bit_0_prob = (bit_0_count * scale) >> (31 - BM__LengthShift);
// set frequency of model updates
update_cycle = (5 * update_cycle) >> 2;
if (update_cycle > 64) update_cycle = 64;
bits_until_update = update_cycle;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - Static data model implementation - - - - - - - - - - - - - - - - - - -
Static_Data_Model::Static_Data_Model(void)
{
data_symbols = 0;
distribution = 0;
}
Static_Data_Model::~Static_Data_Model(void)
{
delete [] distribution;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Static_Data_Model::set_distribution(unsigned number_of_symbols,
const double probability[])
{
if ((number_of_symbols < 2) || (number_of_symbols > (1 << 11)))
AC_Error("invalid number of data symbols");
if (data_symbols != number_of_symbols) { // assign memory for data model
data_symbols = number_of_symbols;
last_symbol = data_symbols - 1;
delete [] distribution;
// define size of table for fast decoding
if (data_symbols > 16) {
unsigned table_bits = 3;
while (data_symbols > (1U << (table_bits + 2))) ++table_bits;
table_size = 1 << table_bits;
table_shift = DM__LengthShift - table_bits;
distribution = new unsigned[data_symbols+table_size+2];
decoder_table = distribution + data_symbols;
}
else { // small alphabet: no table needed
decoder_table = 0;
table_size = table_shift = 0;
distribution = new unsigned[data_symbols];
}
if (distribution == 0) AC_Error("cannot assign model memory");
}
// compute cumulative distribution, decoder table
unsigned s = 0;
double sum = 0.0, p = 1.0 / double(data_symbols);
for (unsigned k = 0; k < data_symbols; k++) {
if (probability) p = probability[k];
if ((p < 0.0001) || (p > 0.9999)) AC_Error("invalid symbol probability");
distribution[k] = unsigned(sum * (1 << DM__LengthShift));
sum += p;
if (table_size == 0) continue;
unsigned w = distribution[k] >> table_shift;
while (s < w) decoder_table[++s] = k - 1;
}
if (table_size != 0) {
decoder_table[0] = 0;
while (s <= table_size) decoder_table[++s] = data_symbols - 1;
}
if ((sum < 0.9999) || (sum > 1.0001)) AC_Error("invalid probabilities");
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - Adaptive data model implementation - - - - - - - - - - - - - - - - - -
Adaptive_Data_Model::Adaptive_Data_Model(void)
{
data_symbols = 0;
distribution = 0;
}
Adaptive_Data_Model::Adaptive_Data_Model(unsigned number_of_symbols)
{
data_symbols = 0;
distribution = 0;
set_alphabet(number_of_symbols);
}
Adaptive_Data_Model::~Adaptive_Data_Model(void)
{
delete [] distribution;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Adaptive_Data_Model::set_alphabet(unsigned number_of_symbols)
{
if ((number_of_symbols < 2) || (number_of_symbols > (1 << 11)))
AC_Error("invalid number of data symbols");
if (data_symbols != number_of_symbols) { // assign memory for data model
data_symbols = number_of_symbols;
last_symbol = data_symbols - 1;
delete [] distribution;
// define size of table for fast decoding
if (data_symbols > 16) {
unsigned table_bits = 3;
while (data_symbols > (1U << (table_bits + 2))) ++table_bits;
table_size = 1 << table_bits;
table_shift = DM__LengthShift - table_bits;
distribution = new unsigned[2*data_symbols+table_size+2];
decoder_table = distribution + 2 * data_symbols;
}
else { // small alphabet: no table needed
decoder_table = 0;
table_size = table_shift = 0;
distribution = new unsigned[2*data_symbols];
}
symbol_count = distribution + data_symbols;
if (distribution == 0) AC_Error("cannot assign model memory");
}
reset(); // initialize model
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Adaptive_Data_Model::update(bool from_encoder)
{
// halve counts when a threshold is reached
if ((total_count += update_cycle) > DM__MaxCount) {
total_count = 0;
for (unsigned n = 0; n < data_symbols; n++)
total_count += (symbol_count[n] = (symbol_count[n] + 1) >> 1);
}
assert(total_count > 0);
// compute cumulative distribution, decoder table
unsigned k, sum = 0, s = 0;
unsigned scale = 0x80000000U / total_count;
if (from_encoder || (table_size == 0))
for (k = 0; k < data_symbols; k++) {
distribution[k] = (scale * sum) >> (31 - DM__LengthShift);
sum += symbol_count[k];
}
else {
assert(decoder_table);
for (k = 0; k < data_symbols; k++) {
distribution[k] = (scale * sum) >> (31 - DM__LengthShift);
sum += symbol_count[k];
unsigned w = distribution[k] >> table_shift;
while (s < w) decoder_table[++s] = k - 1;
}
decoder_table[0] = 0;
while (s <= table_size) decoder_table[++s] = data_symbols - 1;
}
// set frequency of model updates
update_cycle = (5 * update_cycle) >> 2;
unsigned max_cycle = (data_symbols + 6) << 3;
if (update_cycle > max_cycle) update_cycle = max_cycle;
symbols_until_update = update_cycle;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Adaptive_Data_Model::reset(void)
{
if (data_symbols == 0) return;
// restore probability estimates to uniform distribution
total_count = 0;
update_cycle = data_symbols;
for (unsigned k = 0; k < data_symbols; k++) symbol_count[k] = 1;
update(false);
symbols_until_update = update_cycle = (data_symbols + 6) >> 1;
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

View File

@@ -0,0 +1,339 @@
/*
Copyright (c) 2004 Amir Said (said@ieee.org) & William A. Pearlman (pearlw@ecse.rpi.edu)
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.
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 HOLDER 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.
*/
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -
// **************************** -
// ARITHMETIC CODING EXAMPLES -
// **************************** -
// -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -
// Fast arithmetic coding implementation -
// -> 32-bit variables, 32-bit product, periodic updates, table decoding -
// -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -
// Version 1.00 - April 25, 2004 -
// -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -
// WARNING -
// ========= -
// -
// The only purpose of this program is to demonstrate the basic principles -
// of arithmetic coding. It is provided as is, without any express or -
// implied warranty, without even the warranty of fitness for any particular -
// purpose, or that the implementations are correct. -
// -
// Permission to copy and redistribute this code is hereby granted, provided -
// that this warning and copyright notices are not removed or altered. -
// -
// Copyright (c) 2004 by Amir Said (said@ieee.org) & -
// William A. Pearlman (pearlw@ecse.rpi.edu) -
// -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// -
// A description of the arithmetic coding method used here is available in -
// -
// Lossless Compression Handbook, ed. K. Sayood -
// Chapter 5: Arithmetic Coding (A. Said), pp. 101-152, Academic Press, 2003 -
// -
// A. Said, Introduction to Arithetic Coding Theory and Practice -
// HP Labs report HPL-2004-76 - http://www.hpl.hp.com/techreports/ -
// -
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - Definitions - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#ifndef O3DGC_ARITHMETIC_CODEC
#define O3DGC_ARITHMETIC_CODEC
#include <stdio.h>
#include "o3dgcCommon.h"
namespace o3dgc
{
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - Class definitions - - - - - - - - - - - - - - - - - - - - - - - - - - -
class Static_Bit_Model // static model for binary data
{
public:
Static_Bit_Model(void);
void set_probability_0(double); // set probability of symbol '0'
private: // . . . . . . . . . . . . . . . . . . . . . .
unsigned bit_0_prob;
friend class Arithmetic_Codec;
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class Static_Data_Model // static model for general data
{
public:
Static_Data_Model(void);
~Static_Data_Model(void);
unsigned model_symbols(void) { return data_symbols; }
void set_distribution(unsigned number_of_symbols,
const double probability[] = 0); // 0 means uniform
private: // . . . . . . . . . . . . . . . . . . . . . .
unsigned * distribution, * decoder_table;
unsigned data_symbols, last_symbol, table_size, table_shift;
friend class Arithmetic_Codec;
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class Adaptive_Bit_Model // adaptive model for binary data
{
public:
Adaptive_Bit_Model(void);
void reset(void); // reset to equiprobable model
private: // . . . . . . . . . . . . . . . . . . . . . .
void update(void);
unsigned update_cycle, bits_until_update;
unsigned bit_0_prob, bit_0_count, bit_count;
friend class Arithmetic_Codec;
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
class Adaptive_Data_Model // adaptive model for binary data
{
public:
Adaptive_Data_Model(void);
Adaptive_Data_Model(unsigned number_of_symbols);
~Adaptive_Data_Model(void);
unsigned model_symbols(void) { return data_symbols; }
void reset(void); // reset to equiprobable model
void set_alphabet(unsigned number_of_symbols);
private: // . . . . . . . . . . . . . . . . . . . . . .
void update(bool);
unsigned * distribution, * symbol_count, * decoder_table;
unsigned total_count, update_cycle, symbols_until_update;
unsigned data_symbols, last_symbol, table_size, table_shift;
friend class Arithmetic_Codec;
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// - - Encoder and decoder class - - - - - - - - - - - - - - - - - - - - - - -
// Class with both the arithmetic encoder and decoder. All compressed data is
// saved to a memory buffer
class Arithmetic_Codec
{
public:
Arithmetic_Codec(void);
~Arithmetic_Codec(void);
Arithmetic_Codec(unsigned max_code_bytes,
unsigned char * user_buffer = 0); // 0 = assign new
unsigned char * buffer(void) { return code_buffer; }
void set_buffer(unsigned max_code_bytes,
unsigned char * user_buffer = 0); // 0 = assign new
void start_encoder(void);
void start_decoder(void);
void read_from_file(FILE * code_file); // read code data, start decoder
unsigned stop_encoder(void); // returns number of bytes used
unsigned write_to_file(FILE * code_file); // stop encoder, write code data
void stop_decoder(void);
void put_bit(unsigned bit);
unsigned get_bit(void);
void put_bits(unsigned data, unsigned number_of_bits);
unsigned get_bits(unsigned number_of_bits);
void encode(unsigned bit,
Static_Bit_Model &);
unsigned decode(Static_Bit_Model &);
void encode(unsigned data,
Static_Data_Model &);
unsigned decode(Static_Data_Model &);
void encode(unsigned bit,
Adaptive_Bit_Model &);
unsigned decode(Adaptive_Bit_Model &);
void encode(unsigned data,
Adaptive_Data_Model &);
unsigned decode(Adaptive_Data_Model &);
// This section was added by K. Mammou
void ExpGolombEncode(unsigned int symbol,
int k,
Static_Bit_Model & bModel0,
Adaptive_Bit_Model & bModel1)
{
while(1)
{
if (symbol >= (unsigned int)(1<<k))
{
encode(1, bModel1);
symbol = symbol - (1<<k);
k++;
}
else
{
encode(0, bModel1); // now terminated zero of unary part
while (k--) // next binary part
{
encode((signed short)((symbol>>k)&1), bModel0);
}
break;
}
}
}
unsigned ExpGolombDecode(int k,
Static_Bit_Model & bModel0,
Adaptive_Bit_Model & bModel1)
{
unsigned int l;
int symbol = 0;
int binary_symbol = 0;
do
{
l=decode(bModel1);
if (l==1)
{
symbol += (1<<k);
k++;
}
}
while (l!=0);
while (k--) //next binary part
if (decode(bModel0)==1)
{
binary_symbol |= (1<<k);
}
return (unsigned int) (symbol+binary_symbol);
}
//----------------------------------------------------------
private: // . . . . . . . . . . . . . . . . . . . . . .
void propagate_carry(void);
void renorm_enc_interval(void);
void renorm_dec_interval(void);
unsigned char * code_buffer, * new_buffer, * ac_pointer;
unsigned base, value, length; // arithmetic coding state
unsigned buffer_size, mode; // mode: 0 = undef, 1 = encoder, 2 = decoder
};
inline long DecodeIntACEGC(Arithmetic_Codec & acd,
Adaptive_Data_Model & mModelValues,
Static_Bit_Model & bModel0,
Adaptive_Bit_Model & bModel1,
const unsigned long exp_k,
const unsigned long M)
{
unsigned long uiValue = acd.decode(mModelValues);
if (uiValue == M)
{
uiValue += acd.ExpGolombDecode(exp_k, bModel0, bModel1);
}
return UIntToInt(uiValue);
}
inline unsigned long DecodeUIntACEGC(Arithmetic_Codec & acd,
Adaptive_Data_Model & mModelValues,
Static_Bit_Model & bModel0,
Adaptive_Bit_Model & bModel1,
const unsigned long exp_k,
const unsigned long M)
{
unsigned long uiValue = acd.decode(mModelValues);
if (uiValue == M)
{
uiValue += acd.ExpGolombDecode(exp_k, bModel0, bModel1);
}
return uiValue;
}
inline void EncodeIntACEGC(long predResidual,
Arithmetic_Codec & ace,
Adaptive_Data_Model & mModelValues,
Static_Bit_Model & bModel0,
Adaptive_Bit_Model & bModel1,
const unsigned long M)
{
unsigned long uiValue = IntToUInt(predResidual);
if (uiValue < M)
{
ace.encode(uiValue, mModelValues);
}
else
{
ace.encode(M, mModelValues);
ace.ExpGolombEncode(uiValue-M, 0, bModel0, bModel1);
}
}
inline void EncodeUIntACEGC(long predResidual,
Arithmetic_Codec & ace,
Adaptive_Data_Model & mModelValues,
Static_Bit_Model & bModel0,
Adaptive_Bit_Model & bModel1,
const unsigned long M)
{
unsigned long uiValue = (unsigned long) predResidual;
if (uiValue < M)
{
ace.encode(uiValue, mModelValues);
}
else
{
ace.encode(M, mModelValues);
ace.ExpGolombEncode(uiValue-M, 0, bModel0, bModel1);
}
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#endif

View File

@@ -0,0 +1,433 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_BINARY_STREAM_H
#define O3DGC_BINARY_STREAM_H
#include "o3dgcCommon.h"
#include "o3dgcVector.h"
namespace o3dgc
{
const unsigned long O3DGC_BINARY_STREAM_DEFAULT_SIZE = 4096;
const unsigned long O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0 = 7;
const unsigned long O3DGC_BINARY_STREAM_MAX_SYMBOL0 = (1 << O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0) - 1;
const unsigned long O3DGC_BINARY_STREAM_BITS_PER_SYMBOL1 = 6;
const unsigned long O3DGC_BINARY_STREAM_MAX_SYMBOL1 = (1 << O3DGC_BINARY_STREAM_BITS_PER_SYMBOL1) - 1;
const unsigned long O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32 = (32+O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0-1) /
O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0;
//!
class BinaryStream
{
public:
//! Constructor.
BinaryStream(unsigned long size = O3DGC_BINARY_STREAM_DEFAULT_SIZE)
{
m_endianness = SystemEndianness();
m_stream.Allocate(size);
};
//! Destructor.
~BinaryStream(void){};
void WriteFloat32(float value, O3DGCStreamType streamType)
{
if (streamType == O3DGC_STREAM_TYPE_ASCII)
{
WriteFloat32ASCII(value);
}
else
{
WriteFloat32Bin(value);
}
}
void WriteUInt32(unsigned long position, unsigned long value, O3DGCStreamType streamType)
{
if (streamType == O3DGC_STREAM_TYPE_ASCII)
{
WriteUInt32ASCII(position, value);
}
else
{
WriteUInt32Bin(position, value);
}
}
void WriteUInt32(unsigned long value, O3DGCStreamType streamType)
{
if (streamType == O3DGC_STREAM_TYPE_ASCII)
{
WriteUInt32ASCII(value);
}
else
{
WriteUInt32Bin(value);
}
}
void WriteUChar(unsigned int position, unsigned char value, O3DGCStreamType streamType)
{
if (streamType == O3DGC_STREAM_TYPE_ASCII)
{
WriteUInt32ASCII(position, value);
}
else
{
WriteUInt32Bin(position, value);
}
}
void WriteUChar(unsigned char value, O3DGCStreamType streamType)
{
if (streamType == O3DGC_STREAM_TYPE_ASCII)
{
WriteUCharASCII(value);
}
else
{
WriteUChar8Bin(value);
}
}
float ReadFloat32(unsigned long & position, O3DGCStreamType streamType) const
{
float value;
if (streamType == O3DGC_STREAM_TYPE_ASCII)
{
value = ReadFloat32ASCII(position);
}
else
{
value = ReadFloat32Bin(position);
}
return value;
}
unsigned long ReadUInt32(unsigned long & position, O3DGCStreamType streamType) const
{
unsigned long value;
if (streamType == O3DGC_STREAM_TYPE_ASCII)
{
value = ReadUInt32ASCII(position);
}
else
{
value = ReadUInt32Bin(position);
}
return value;
}
unsigned char ReadUChar(unsigned long & position, O3DGCStreamType streamType) const
{
unsigned char value;
if (streamType == O3DGC_STREAM_TYPE_ASCII)
{
value = ReadUCharASCII(position);
}
else
{
value = ReadUChar8Bin(position);
}
return value;
}
void WriteFloat32Bin(unsigned long position, float value)
{
assert(position < m_stream.GetSize() - 4);
unsigned char * ptr = (unsigned char *) (&value);
if (m_endianness == O3DGC_BIG_ENDIAN)
{
m_stream[position++] = ptr[3];
m_stream[position++] = ptr[2];
m_stream[position++] = ptr[1];
m_stream[position ] = ptr[0];
}
else
{
m_stream[position++] = ptr[0];
m_stream[position++] = ptr[1];
m_stream[position++] = ptr[2];
m_stream[position ] = ptr[3];
}
}
void WriteFloat32Bin(float value)
{
unsigned char * ptr = (unsigned char *) (&value);
if (m_endianness == O3DGC_BIG_ENDIAN)
{
m_stream.PushBack(ptr[3]);
m_stream.PushBack(ptr[2]);
m_stream.PushBack(ptr[1]);
m_stream.PushBack(ptr[0]);
}
else
{
m_stream.PushBack(ptr[0]);
m_stream.PushBack(ptr[1]);
m_stream.PushBack(ptr[2]);
m_stream.PushBack(ptr[3]);
}
}
void WriteUInt32Bin(unsigned long position, unsigned long value)
{
assert(position < m_stream.GetSize() - 4);
unsigned char * ptr = (unsigned char *) (&value);
if (m_endianness == O3DGC_BIG_ENDIAN)
{
m_stream[position++] = ptr[3];
m_stream[position++] = ptr[2];
m_stream[position++] = ptr[1];
m_stream[position ] = ptr[0];
}
else
{
m_stream[position++] = ptr[0];
m_stream[position++] = ptr[1];
m_stream[position++] = ptr[2];
m_stream[position ] = ptr[3];
}
}
void WriteUInt32Bin(unsigned long value)
{
unsigned char * ptr = (unsigned char *) (&value);
if (m_endianness == O3DGC_BIG_ENDIAN)
{
m_stream.PushBack(ptr[3]);
m_stream.PushBack(ptr[2]);
m_stream.PushBack(ptr[1]);
m_stream.PushBack(ptr[0]);
}
else
{
m_stream.PushBack(ptr[0]);
m_stream.PushBack(ptr[1]);
m_stream.PushBack(ptr[2]);
m_stream.PushBack(ptr[3]);
}
}
void WriteUChar8Bin(unsigned int position, unsigned char value)
{
m_stream[position] = value;
}
void WriteUChar8Bin(unsigned char value)
{
m_stream.PushBack(value);
}
float ReadFloat32Bin(unsigned long & position) const
{
unsigned long value = ReadUInt32Bin(position);
float fvalue;
memcpy(&fvalue, &value, 4);
return fvalue;
}
unsigned long ReadUInt32Bin(unsigned long & position) const
{
assert(position < m_stream.GetSize() - 4);
unsigned long value = 0;
if (m_endianness == O3DGC_BIG_ENDIAN)
{
value += (m_stream[position++]<<24);
value += (m_stream[position++]<<16);
value += (m_stream[position++]<<8);
value += (m_stream[position++]);
}
else
{
value += (m_stream[position++]);
value += (m_stream[position++]<<8);
value += (m_stream[position++]<<16);
value += (m_stream[position++]<<24);
}
return value;
}
unsigned char ReadUChar8Bin(unsigned long & position) const
{
return m_stream[position++];
}
void WriteFloat32ASCII(float value)
{
unsigned long uiValue;
memcpy(&uiValue, &value, 4);
WriteUInt32ASCII(uiValue);
}
void WriteUInt32ASCII(unsigned long position, unsigned long value)
{
assert(position < m_stream.GetSize() - O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32);
unsigned long value0 = value;
for(unsigned long i = 0; i < O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32; ++i)
{
m_stream[position++] = (value0 & O3DGC_BINARY_STREAM_MAX_SYMBOL0);
value0 >>= O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0;
}
}
void WriteUInt32ASCII(unsigned long value)
{
for(unsigned long i = 0; i < O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32; ++i)
{
m_stream.PushBack(value & O3DGC_BINARY_STREAM_MAX_SYMBOL0);
value >>= O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0;
}
}
void WriteIntASCII(long value)
{
WriteUIntASCII(IntToUInt(value));
}
void WriteUIntASCII(unsigned long value)
{
if (value >= O3DGC_BINARY_STREAM_MAX_SYMBOL0)
{
m_stream.PushBack(O3DGC_BINARY_STREAM_MAX_SYMBOL0);
value -= O3DGC_BINARY_STREAM_MAX_SYMBOL0;
unsigned char a, b;
do
{
a = ((value & O3DGC_BINARY_STREAM_MAX_SYMBOL1) << 1);
b = ( (value >>= O3DGC_BINARY_STREAM_BITS_PER_SYMBOL1) > 0);
a += b;
m_stream.PushBack(a);
} while (b);
}
else
{
m_stream.PushBack((unsigned char) value);
}
}
void WriteUCharASCII(unsigned char value)
{
assert(value <= O3DGC_BINARY_STREAM_MAX_SYMBOL0);
m_stream.PushBack(value);
}
float ReadFloat32ASCII(unsigned long & position) const
{
unsigned long value = ReadUInt32ASCII(position);
float fvalue;
memcpy(&fvalue, &value, 4);
return fvalue;
}
unsigned long ReadUInt32ASCII(unsigned long & position) const
{
assert(position < m_stream.GetSize() - O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32);
unsigned long value = 0;
unsigned long shift = 0;
for(unsigned long i = 0; i < O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32; ++i)
{
value += (m_stream[position++] << shift);
shift += O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0;
}
return value;
}
long ReadIntASCII(unsigned long & position) const
{
return UIntToInt(ReadUIntASCII(position));
}
unsigned long ReadUIntASCII(unsigned long & position) const
{
unsigned long value = m_stream[position++];
if (value == O3DGC_BINARY_STREAM_MAX_SYMBOL0)
{
long x;
unsigned long i = 0;
do
{
x = m_stream[position++];
value += ( (x>>1) << i);
i += O3DGC_BINARY_STREAM_BITS_PER_SYMBOL1;
} while (x & 1);
}
return value;
}
unsigned char ReadUCharASCII(unsigned long & position) const
{
return m_stream[position++];
}
O3DGCErrorCode Save(const char * const fileName)
{
FILE * fout = fopen(fileName, "wb");
if (!fout)
{
return O3DGC_ERROR_CREATE_FILE;
}
fwrite(m_stream.GetBuffer(), 1, m_stream.GetSize(), fout);
fclose(fout);
return O3DGC_OK;
}
O3DGCErrorCode Load(const char * const fileName)
{
FILE * fin = fopen(fileName, "rb");
if (!fin)
{
return O3DGC_ERROR_OPEN_FILE;
}
fseek(fin, 0, SEEK_END);
unsigned long size = ftell(fin);
m_stream.Allocate(size);
rewind(fin);
unsigned int nread = (unsigned int) fread((void *) m_stream.GetBuffer(), 1, size, fin);
m_stream.SetSize(size);
if (nread != size)
{
return O3DGC_ERROR_READ_FILE;
}
fclose(fin);
return O3DGC_OK;
}
O3DGCErrorCode LoadFromBuffer(unsigned char * buffer, unsigned long bufferSize)
{
m_stream.Allocate(bufferSize);
memcpy(m_stream.GetBuffer(), buffer, bufferSize);
m_stream.SetSize(bufferSize);
return O3DGC_OK;
}
unsigned long GetSize() const
{
return m_stream.GetSize();
}
const unsigned char * GetBuffer(unsigned long position) const
{
return m_stream.GetBuffer() + position;
}
unsigned char * GetBuffer(unsigned long position)
{
return (m_stream.GetBuffer() + position);
}
unsigned char * GetBuffer()
{
return m_stream.GetBuffer();
}
void GetBuffer(unsigned long position, unsigned char * & buffer) const
{
buffer = (unsigned char *) (m_stream.GetBuffer() + position); // fix me: ugly!
}
void SetSize(unsigned long size)
{
m_stream.SetSize(size);
};
void Allocate(unsigned long size)
{
m_stream.Allocate(size);
}
private:
Vector<unsigned char> m_stream;
O3DGCEndianness m_endianness;
};
}
#endif // O3DGC_BINARY_STREAM_H

View File

@@ -0,0 +1,412 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_COMMON_H
#define O3DGC_COMMON_H
#ifndef _CRT_SECURE_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <math.h>
namespace o3dgc
{
typedef float Real;
const double O3DGC_MAX_DOUBLE = 1.79769e+308;
const long O3DGC_MIN_LONG = -2147483647;
const long O3DGC_MAX_LONG = 2147483647;
const long O3DGC_MAX_UCHAR8 = 255;
const long O3DGC_MAX_TFAN_SIZE = 256;
const unsigned long O3DGC_MAX_ULONG = 4294967295;
const unsigned long O3DGC_SC3DMC_START_CODE = 0x00001F1;
const unsigned long O3DGC_DV_START_CODE = 0x00001F2;
const unsigned long O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES = 256;
const unsigned long O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES = 256;
const unsigned long O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES = 32;
const unsigned long O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS = 2;
const unsigned long O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS = 257;
enum O3DGCEndianness
{
O3DGC_BIG_ENDIAN = 0,
O3DGC_LITTLE_ENDIAN = 1
};
enum O3DGCErrorCode
{
O3DGC_OK,
O3DGC_ERROR_BUFFER_FULL,
O3DGC_ERROR_CREATE_FILE,
O3DGC_ERROR_OPEN_FILE,
O3DGC_ERROR_READ_FILE,
O3DGC_ERROR_CORRUPTED_STREAM,
O3DGC_ERROR_NON_SUPPORTED_FEATURE
};
enum O3DGCSC3DMCBinarization
{
O3DGC_SC3DMC_BINARIZATION_FL = 0, // Fixed Length (not supported)
O3DGC_SC3DMC_BINARIZATION_BP = 1, // BPC (not supported)
O3DGC_SC3DMC_BINARIZATION_FC = 2, // 4 bits Coding (not supported)
O3DGC_SC3DMC_BINARIZATION_AC = 3, // Arithmetic Coding (not supported)
O3DGC_SC3DMC_BINARIZATION_AC_EGC = 4, // Arithmetic Coding & EGCk
O3DGC_SC3DMC_BINARIZATION_ASCII = 5 // Arithmetic Coding & EGCk
};
enum O3DGCStreamType
{
O3DGC_STREAM_TYPE_UNKOWN = 0,
O3DGC_STREAM_TYPE_ASCII = 1,
O3DGC_STREAM_TYPE_BINARY = 2
};
enum O3DGCSC3DMCQuantizationMode
{
O3DGC_SC3DMC_DIAG_BB = 0, // supported
O3DGC_SC3DMC_MAX_ALL_DIMS = 1, // supported
O3DGC_SC3DMC_MAX_SEP_DIM = 2 // supported
};
enum O3DGCSC3DMCPredictionMode
{
O3DGC_SC3DMC_NO_PREDICTION = 0, // supported
O3DGC_SC3DMC_DIFFERENTIAL_PREDICTION = 1, // supported
O3DGC_SC3DMC_XOR_PREDICTION = 2, // not supported
O3DGC_SC3DMC_ADAPTIVE_DIFFERENTIAL_PREDICTION = 3, // not supported
O3DGC_SC3DMC_CIRCULAR_DIFFERENTIAL_PREDICTION = 4, // not supported
O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION = 5, // supported
O3DGC_SC3DMC_SURF_NORMALS_PREDICTION = 6 // supported
};
enum O3DGCSC3DMCEncodingMode
{
O3DGC_SC3DMC_ENCODE_MODE_QBCR = 0, // not supported
O3DGC_SC3DMC_ENCODE_MODE_SVA = 1, // not supported
O3DGC_SC3DMC_ENCODE_MODE_TFAN = 2, // supported
};
enum O3DGCDVEncodingMode
{
O3DGC_DYNAMIC_VECTOR_ENCODE_MODE_LIFT = 0
};
enum O3DGCIFSFloatAttributeType
{
O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_UNKOWN = 0,
O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_POSITION = 1,
O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_NORMAL = 2,
O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_COLOR = 3,
O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD = 4,
O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_WEIGHT = 5
};
enum O3DGCIFSIntAttributeType
{
O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN = 0,
O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX = 1,
O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID = 2,
O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID = 3
};
template<class T>
inline const T absolute(const T& a)
{
return (a < (T)(0)) ? -a : a;
}
template<class T>
inline const T min(const T& a, const T& b)
{
return (b < a) ? b : a;
}
template<class T>
inline const T max(const T& a, const T& b)
{
return (b > a) ? b : a;
}
template<class T>
inline void swap(T& a, T& b)
{
T tmp = a;
a = b;
b = tmp;
}
inline double log2( double n )
{
return log(n) / log(2.0);
}
inline O3DGCEndianness SystemEndianness()
{
unsigned long num = 1;
return ( *((char *)(&num)) == 1 )? O3DGC_LITTLE_ENDIAN : O3DGC_BIG_ENDIAN ;
}
class SC3DMCStats
{
public:
SC3DMCStats(void)
{
memset(this, 0, sizeof(SC3DMCStats));
};
~SC3DMCStats(void){};
double m_timeCoord;
double m_timeNormal;
double m_timeCoordIndex;
double m_timeFloatAttribute[O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
double m_timeIntAttribute [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES ];
double m_timeReorder;
unsigned long m_streamSizeCoord;
unsigned long m_streamSizeNormal;
unsigned long m_streamSizeCoordIndex;
unsigned long m_streamSizeFloatAttribute[O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
unsigned long m_streamSizeIntAttribute [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES ];
};
typedef struct
{
long m_a;
long m_b;
long m_c;
} SC3DMCTriplet;
typedef struct
{
SC3DMCTriplet m_id;
long m_pred[O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES];
} SC3DMCPredictor;
inline bool operator< (const SC3DMCTriplet& lhs, const SC3DMCTriplet& rhs)
{
if (lhs.m_c != rhs.m_c)
{
return (lhs.m_c < rhs.m_c);
}
else if (lhs.m_b != rhs.m_b)
{
return (lhs.m_b < rhs.m_b);
}
return (lhs.m_a < rhs.m_a);
}
inline bool operator== (const SC3DMCTriplet& lhs, const SC3DMCTriplet& rhs)
{
return (lhs.m_c == rhs.m_c && lhs.m_b == rhs.m_b && lhs.m_a == rhs.m_a);
}
// fix me: optimize this function (e.g., binary search)
inline unsigned long Insert(SC3DMCTriplet e, unsigned long & nPred, SC3DMCPredictor * const list)
{
unsigned long pos = 0xFFFFFFFF;
bool foundOrInserted = false;
for (unsigned long j = 0; j < nPred; ++j)
{
if (e == list[j].m_id)
{
foundOrInserted = true;
break;
}
else if (e < list[j].m_id)
{
if (nPred < O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS)
{
++nPred;
}
for (unsigned long h = nPred-1; h > j; --h)
{
list[h] = list[h-1];
}
list[j].m_id = e;
pos = j;
foundOrInserted = true;
break;
}
}
if (!foundOrInserted && nPred < O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS)
{
pos = nPred;
list[nPred++].m_id = e;
}
return pos;
}
template <class T>
inline void SphereToCube(const T x, const T y, const T z,
T & a, T & b, char & index)
{
T ax = absolute(x);
T ay = absolute(y);
T az = absolute(z);
if (az >= ax && az >= ay)
{
if (z >= (T)(0))
{
index = 0;
a = x;
b = y;
}
else
{
index = 1;
a = -x;
b = -y;
}
}
else if (ay >= ax && ay >= az)
{
if (y >= (T)(0))
{
index = 2;
a = z;
b = x;
}
else
{
index = 3;
a = -z;
b = -x;
}
}
else if (ax >= ay && ax >= az)
{
if (x >= (T)(0))
{
index = 4;
a = y;
b = z;
}
else
{
index = 5;
a = -y;
b = -z;
}
}
}
inline void CubeToSphere(const Real a, const Real b, const char index,
Real & x, Real & y, Real & z)
{
switch( index )
{
case 0:
x = a;
y = b;
z = (Real) sqrt(max(0.0, 1.0 - x*x-y*y));
break;
case 1:
x = -a;
y = -b;
z = -(Real) sqrt(max(0.0, 1.0 - x*x-y*y));
break;
case 2:
z = a;
x = b;
y = (Real) sqrt(max(0.0, 1.0 - x*x-z*z));
break;
case 3:
z = -a;
x = -b;
y = -(Real) sqrt(max(0.0, 1.0 - x*x-z*z));
break;
case 4:
y = a;
z = b;
x = (Real) sqrt(max(0.0, 1.0 - y*y-z*z));
break;
case 5:
y = -a;
z = -b;
x = -(Real) sqrt(max(0.0, 1.0 - y*y-z*z));
break;
}
}
inline unsigned long IntToUInt(long value)
{
return (value < 0)?(unsigned long) (-1 - (2 * value)):(unsigned long) (2 * value);
}
inline long UIntToInt(unsigned long uiValue)
{
return (uiValue & 1)?-((long) ((uiValue+1) >> 1)):((long) (uiValue >> 1));
}
inline void ComputeVectorMinMax(const Real * const tab,
unsigned long size,
unsigned long dim,
unsigned long stride,
Real * minTab,
Real * maxTab,
O3DGCSC3DMCQuantizationMode quantMode)
{
if (size == 0 || dim == 0)
{
return;
}
unsigned long p = 0;
for(unsigned long d = 0; d < dim; ++d)
{
maxTab[d] = minTab[d] = tab[p++];
}
p = stride;
for(unsigned long i = 1; i < size; ++i)
{
for(unsigned long d = 0; d < dim; ++d)
{
if (maxTab[d] < tab[p+d]) maxTab[d] = tab[p+d];
if (minTab[d] > tab[p+d]) minTab[d] = tab[p+d];
}
p += stride;
}
if (quantMode == O3DGC_SC3DMC_DIAG_BB)
{
Real diag = Real( 0.0 );
Real r;
for(unsigned long d = 0; d < dim; ++d)
{
r = (maxTab[d] - minTab[d]);
diag += r*r;
}
diag = static_cast<Real>(sqrt(diag));
for(unsigned long d = 0; d < dim; ++d)
{
maxTab[d] = minTab[d] + diag;
}
}
else if (quantMode == O3DGC_SC3DMC_MAX_ALL_DIMS)
{
Real maxr = (maxTab[0] - minTab[0]);
Real r;
for(unsigned long d = 1; d < dim; ++d)
{
r = (maxTab[d] - minTab[d]);
if ( r > maxr)
{
maxr = r;
}
}
for(unsigned long d = 0; d < dim; ++d)
{
maxTab[d] = minTab[d] + maxr;
}
}
}
}
#endif // O3DGC_COMMON_H

View File

@@ -0,0 +1,62 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_DV_ENCODE_PARAMS_H
#define O3DGC_DV_ENCODE_PARAMS_H
#include "o3dgcCommon.h"
namespace o3dgc
{
class DVEncodeParams
{
public:
//! Constructor.
DVEncodeParams(void)
{
m_quantBits = 10;
m_streamTypeMode = O3DGC_STREAM_TYPE_ASCII;
m_encodeMode = O3DGC_DYNAMIC_VECTOR_ENCODE_MODE_LIFT;
};
//! Destructor.
~DVEncodeParams(void) {};
unsigned long GetQuantBits() const { return m_quantBits;}
O3DGCStreamType GetStreamType() const { return m_streamTypeMode;}
O3DGCDVEncodingMode GetEncodeMode() const { return m_encodeMode;}
void SetQuantBits (unsigned long quantBits ) { m_quantBits = quantBits;}
void SetStreamType(O3DGCStreamType streamTypeMode) { m_streamTypeMode = streamTypeMode;}
void SetEncodeMode(O3DGCDVEncodingMode encodeMode ) { m_encodeMode = encodeMode ;}
private:
unsigned long m_quantBits;
O3DGCStreamType m_streamTypeMode;
O3DGCDVEncodingMode m_encodeMode;
};
}
#endif // O3DGC_DV_ENCODE_PARAMS_H

View File

@@ -0,0 +1,84 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_DYNAMIC_VECTOR_SET_H
#define O3DGC_DYNAMIC_VECTOR_SET_H
#include "o3dgcCommon.h"
namespace o3dgc
{
class DynamicVector
{
public:
//! Constructor.
DynamicVector(void)
{
m_num = 0;
m_dim = 0;
m_stride = 0;
m_max = 0;
m_min = 0;
m_vectors = 0;
};
//! Destructor.
~DynamicVector(void) {};
unsigned long GetNVector() const { return m_num;}
unsigned long GetDimVector() const { return m_dim;}
unsigned long GetStride() const { return m_stride;}
const Real * GetMin() const { return m_min;}
const Real * GetMax() const { return m_max;}
const Real * GetVectors() const { return m_vectors;}
Real * GetVectors() { return m_vectors;}
Real GetMin(unsigned long j) const { return m_min[j];}
Real GetMax(unsigned long j) const { return m_max[j];}
void SetNVector (unsigned long num ) { m_num = num ;}
void SetDimVector (unsigned long dim ) { m_dim = dim ;}
void SetStride (unsigned long stride ) { m_stride = stride ;}
void SetMin (Real * const min ) { m_min = min ;}
void SetMax (Real * const max ) { m_max = max ;}
void SetMin (unsigned long j, Real min) { m_min[j] = min ;}
void SetMax (unsigned long j, Real max) { m_max[j] = max ;}
void SetVectors (Real * const vectors) { m_vectors = vectors ;}
void ComputeMinMax(O3DGCSC3DMCQuantizationMode quantMode)
{
assert( m_max && m_min && m_vectors && m_stride && m_dim && m_num);
ComputeVectorMinMax(m_vectors, m_num , m_dim, m_stride, m_min , m_max , quantMode);
}
private:
unsigned long m_num;
unsigned long m_dim;
unsigned long m_stride;
Real * m_max;
Real * m_min;
Real * m_vectors;
};
}
#endif // O3DGC_DYNAMIC_VECTOR_SET_H

View File

@@ -0,0 +1,278 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#include "o3dgcDynamicVectorDecoder.h"
#include "o3dgcArithmeticCodec.h"
//#define DEBUG_VERBOSE
namespace o3dgc
{
#ifdef DEBUG_VERBOSE
FILE * g_fileDebugDVCDec = NULL;
#endif //DEBUG_VERBOSE
O3DGCErrorCode IUpdate(long * const data, const long size)
{
assert(size > 1);
const long size1 = size - 1;
long p = 2;
data[0] -= data[1] >> 1;
while(p < size1)
{
data[p] -= (data[p-1] + data[p+1] + 2) >> 2;
p += 2;
}
if ( p == size1)
{
data[p] -= data[p-1]>>1;
}
return O3DGC_OK;
}
O3DGCErrorCode IPredict(long * const data, const long size)
{
assert(size > 1);
const long size1 = size - 1;
long p = 1;
while(p < size1)
{
data[p] += (data[p-1] + data[p+1] + 1) >> 1;
p += 2;
}
if ( p == size1)
{
data[p] += data[p-1];
}
return O3DGC_OK;
}
O3DGCErrorCode Merge(long * const data, const long size)
{
assert(size > 1);
const long h = (size >> 1) + (size & 1);
long a = h-1;
long b = h;
while (a > 0)
{
for (long i = a; i < b; i += 2)
{
swap(data[i], data[i+1]);
}
--a;
++b;
}
return O3DGC_OK;
}
inline O3DGCErrorCode ITransform(long * const data, const unsigned long size)
{
unsigned long n = size;
unsigned long even = 0;
unsigned long k = 0;
even += ((n&1) << k++);
while(n > 1)
{
n = (n >> 1) + (n & 1);
even += ((n&1) << k++);
}
for(long i = k-2; i >= 0; --i)
{
n = (n << 1) - ((even>>i) & 1);
Merge (data, n);
IUpdate (data, n);
IPredict(data, n);
}
return O3DGC_OK;
}
DynamicVectorDecoder::DynamicVectorDecoder(void)
{
m_streamSize = 0;
m_maxNumVectors = 0;
m_numVectors = 0;
m_dimVectors = 0;
m_quantVectors = 0;
m_iterator = 0;
m_streamType = O3DGC_STREAM_TYPE_UNKOWN;
}
DynamicVectorDecoder::~DynamicVectorDecoder()
{
delete [] m_quantVectors;
}
O3DGCErrorCode DynamicVectorDecoder::DecodeHeader(DynamicVector & dynamicVector,
const BinaryStream & bstream)
{
unsigned long iterator0 = m_iterator;
unsigned long start_code = bstream.ReadUInt32(m_iterator, O3DGC_STREAM_TYPE_BINARY);
if (start_code != O3DGC_DV_START_CODE)
{
m_iterator = iterator0;
start_code = bstream.ReadUInt32(m_iterator, O3DGC_STREAM_TYPE_ASCII);
if (start_code != O3DGC_DV_START_CODE)
{
return O3DGC_ERROR_CORRUPTED_STREAM;
}
else
{
m_streamType = O3DGC_STREAM_TYPE_ASCII;
}
}
else
{
m_streamType = O3DGC_STREAM_TYPE_BINARY;
}
m_streamSize = bstream.ReadUInt32(m_iterator, m_streamType);
m_params.SetEncodeMode( (O3DGCDVEncodingMode) bstream.ReadUChar(m_iterator, m_streamType));
dynamicVector.SetNVector ( bstream.ReadUInt32(m_iterator, m_streamType) );
if (dynamicVector.GetNVector() > 0)
{
dynamicVector.SetDimVector( bstream.ReadUInt32(m_iterator, m_streamType) );
m_params.SetQuantBits(bstream.ReadUChar(m_iterator, m_streamType));
}
return O3DGC_OK;
}
O3DGCErrorCode DynamicVectorDecoder::DecodePlayload(DynamicVector & dynamicVector,
const BinaryStream & bstream)
{
O3DGCErrorCode ret = O3DGC_OK;
#ifdef DEBUG_VERBOSE
g_fileDebugDVCDec = fopen("dv_dec.txt", "w");
#endif //DEBUG_VERBOSE
unsigned long start = m_iterator;
unsigned long streamSize = bstream.ReadUInt32(m_iterator, m_streamType); // bitsream size
const unsigned long dim = dynamicVector.GetDimVector();
const unsigned long num = dynamicVector.GetNVector();
const unsigned long size = dim * num;
for(unsigned long j=0 ; j < dynamicVector.GetDimVector() ; ++j)
{
dynamicVector.SetMin(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
dynamicVector.SetMax(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
}
Arithmetic_Codec acd;
Static_Bit_Model bModel0;
Adaptive_Bit_Model bModel1;
unsigned char * buffer = 0;
streamSize -= (m_iterator - start);
unsigned int exp_k = 0;
unsigned int M = 0;
if (m_streamType == O3DGC_STREAM_TYPE_BINARY)
{
bstream.GetBuffer(m_iterator, buffer);
m_iterator += streamSize;
acd.set_buffer(streamSize, buffer);
acd.start_decoder();
exp_k = acd.ExpGolombDecode(0, bModel0, bModel1);
M = acd.ExpGolombDecode(0, bModel0, bModel1);
}
Adaptive_Data_Model mModelValues(M+2);
if (m_maxNumVectors < size)
{
delete [] m_quantVectors;
m_maxNumVectors = size;
m_quantVectors = new long [size];
}
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
for(unsigned long v = 0; v < num; ++v)
{
for(unsigned long d = 0; d < dim; ++d)
{
m_quantVectors[d * num + v] = bstream.ReadIntASCII(m_iterator);
}
}
}
else
{
for(unsigned long v = 0; v < num; ++v)
{
for(unsigned long d = 0; d < dim; ++d)
{
m_quantVectors[d * num + v] = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
}
}
}
#ifdef DEBUG_VERBOSE
printf("IntArray (%i, %i)\n", num, dim);
fprintf(g_fileDebugDVCDec, "IntArray (%i, %i)\n", num, dim);
for(unsigned long v = 0; v < num; ++v)
{
for(unsigned long d = 0; d < dim; ++d)
{
printf("%i\t %i \t %i\n", d * num + v, m_quantVectors[d * num + v], IntToUInt(m_quantVectors[d * num + v]));
fprintf(g_fileDebugDVCDec, "%i\t %i \t %i\n", d * num + v, m_quantVectors[d * num + v], IntToUInt(m_quantVectors[d * num + v]));
}
}
fflush(g_fileDebugDVCDec);
#endif //DEBUG_VERBOSE
for(unsigned long d = 0; d < dim; ++d)
{
ITransform(m_quantVectors + d * num, num);
}
IQuantize(dynamicVector.GetVectors(),
num,
dim,
dynamicVector.GetStride(),
dynamicVector.GetMin(),
dynamicVector.GetMax(),
m_params.GetQuantBits());
#ifdef DEBUG_VERBOSE
fclose(g_fileDebugDVCDec);
#endif //DEBUG_VERBOSE
return ret;
}
O3DGCErrorCode DynamicVectorDecoder::IQuantize(Real * const floatArray,
unsigned long numFloatArray,
unsigned long dimFloatArray,
unsigned long stride,
const Real * const minFloatArray,
const Real * const maxFloatArray,
unsigned long nQBits)
{
const unsigned long size = numFloatArray * dimFloatArray;
Real r;
if (m_maxNumVectors < size)
{
delete [] m_quantVectors;
m_maxNumVectors = size;
m_quantVectors = new long [m_maxNumVectors];
}
Real idelta;
for(unsigned long d = 0; d < dimFloatArray; ++d)
{
r = maxFloatArray[d] - minFloatArray[d];
if (r > 0.0f)
{
idelta = (float)(r) / ((1 << nQBits) - 1);
}
else
{
idelta = 1.0f;
}
for(unsigned long v = 0; v < numFloatArray; ++v)
{
floatArray[v * stride + d] = m_quantVectors[v + d * numFloatArray] * idelta + minFloatArray[d];
}
}
return O3DGC_OK;
}
}

View File

@@ -0,0 +1,76 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_DYNAMIC_VECTOR_DECODER_H
#define O3DGC_DYNAMIC_VECTOR_DECODER_H
#include "o3dgcCommon.h"
#include "o3dgcBinaryStream.h"
#include "o3dgcDVEncodeParams.h"
#include "o3dgcDynamicVector.h"
namespace o3dgc
{
//!
class DynamicVectorDecoder
{
public:
//! Constructor.
DynamicVectorDecoder(void);
//! Destructor.
~DynamicVectorDecoder(void);
//!
//!
O3DGCErrorCode DecodeHeader(DynamicVector & dynamicVector,
const BinaryStream & bstream);
//!
O3DGCErrorCode DecodePlayload(DynamicVector & dynamicVector,
const BinaryStream & bstream);
O3DGCStreamType GetStreamType() const { return m_streamType; }
void SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; }
unsigned long GetIterator() const { return m_iterator;}
O3DGCErrorCode SetIterator(unsigned long iterator) { m_iterator = iterator; return O3DGC_OK; }
private:
O3DGCErrorCode IQuantize(Real * const floatArray,
unsigned long numFloatArray,
unsigned long dimFloatArray,
unsigned long stride,
const Real * const minFloatArray,
const Real * const maxFloatArray,
unsigned long nQBits);
unsigned long m_streamSize;
unsigned long m_maxNumVectors;
unsigned long m_numVectors;
unsigned long m_dimVectors;
unsigned long m_iterator;
long * m_quantVectors;
DVEncodeParams m_params;
O3DGCStreamType m_streamType;
};
}
#endif // O3DGC_DYNAMIC_VECTOR_DECODER_H

View File

@@ -0,0 +1,295 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#include "o3dgcDVEncodeParams.h"
#include "o3dgcDynamicVectorEncoder.h"
#include "o3dgcArithmeticCodec.h"
#include "o3dgcBinaryStream.h"
//#define DEBUG_VERBOSE
namespace o3dgc
{
#ifdef DEBUG_VERBOSE
FILE * g_fileDebugDVEnc = NULL;
#endif //DEBUG_VERBOSE
inline O3DGCErrorCode Update(long * const data, const long size)
{
assert(size > 1);
const long size1 = size - 1;
long p = 2;
data[0] += data[1] >> 1;
while(p < size1)
{
data[p] += (data[p-1] + data[p+1] + 2) >> 2;
p += 2;
}
if ( p == size1)
{
data[p] += data[p-1]>>1;
}
return O3DGC_OK;
}
inline O3DGCErrorCode Predict(long * const data, const long size)
{
assert(size > 1);
const long size1 = size - 1;
long p = 1;
while(p < size1)
{
data[p] -= (data[p-1] + data[p+1] + 1) >> 1;
p += 2;
}
if ( p == size1)
{
data[p] -= data[p-1];
}
return O3DGC_OK;
}
inline O3DGCErrorCode Split(long * const data, const long size)
{
assert(size > 1);
long a = 1;
long b = size-1;
while (a < b)
{
for (long i = a; i < b; i += 2)
{
swap(data[i], data[i+1]);
}
++a;
--b;
}
return O3DGC_OK;
}
inline O3DGCErrorCode Transform(long * const data, const unsigned long size)
{
unsigned long n = size;
while(n > 1)
{
Predict(data, n);
Update (data, n);
Split(data, n);
n = (n >> 1) + (n & 1);
}
return O3DGC_OK;
}
DynamicVectorEncoder::DynamicVectorEncoder(void)
{
m_maxNumVectors = 0;
m_numVectors = 0;
m_dimVectors = 0;
m_quantVectors = 0;
m_sizeBufferAC = 0;
m_bufferAC = 0;
m_posSize = 0;
m_streamType = O3DGC_STREAM_TYPE_UNKOWN;
}
DynamicVectorEncoder::~DynamicVectorEncoder()
{
delete [] m_quantVectors;
delete [] m_bufferAC;
}
O3DGCErrorCode DynamicVectorEncoder::Encode(const DVEncodeParams & params,
const DynamicVector & dynamicVector,
BinaryStream & bstream)
{
assert(params.GetQuantBits() > 0);
assert(dynamicVector.GetNVector() > 0);
assert(dynamicVector.GetDimVector() > 0);
assert(dynamicVector.GetStride() >= dynamicVector.GetDimVector());
assert(dynamicVector.GetVectors() && dynamicVector.GetMin() && dynamicVector.GetMax());
assert(m_streamType != O3DGC_STREAM_TYPE_UNKOWN);
// Encode header
unsigned long start = bstream.GetSize();
EncodeHeader(params, dynamicVector, bstream);
// Encode payload
EncodePayload(params, dynamicVector, bstream);
bstream.WriteUInt32(m_posSize, bstream.GetSize() - start, m_streamType);
return O3DGC_OK;
}
O3DGCErrorCode DynamicVectorEncoder::EncodeHeader(const DVEncodeParams & params,
const DynamicVector & dynamicVector,
BinaryStream & bstream)
{
m_streamType = params.GetStreamType();
bstream.WriteUInt32(O3DGC_DV_START_CODE, m_streamType);
m_posSize = bstream.GetSize();
bstream.WriteUInt32(0, m_streamType); // to be filled later
bstream.WriteUChar((unsigned char) params.GetEncodeMode(), m_streamType);
bstream.WriteUInt32(dynamicVector.GetNVector() , m_streamType);
if (dynamicVector.GetNVector() > 0)
{
bstream.WriteUInt32(dynamicVector.GetDimVector(), m_streamType);
bstream.WriteUChar ((unsigned char) params.GetQuantBits(), m_streamType);
}
return O3DGC_OK;
}
O3DGCErrorCode DynamicVectorEncoder::EncodeAC(unsigned long num,
unsigned long dim,
unsigned long M,
unsigned long & encodedBytes)
{
Arithmetic_Codec ace;
Static_Bit_Model bModel0;
Adaptive_Bit_Model bModel1;
Adaptive_Data_Model mModelValues(M+2);
const unsigned int NMAX = num * dim * 8 + 100;
if ( m_sizeBufferAC < NMAX )
{
delete [] m_bufferAC;
m_sizeBufferAC = NMAX;
m_bufferAC = new unsigned char [m_sizeBufferAC];
}
ace.set_buffer(NMAX, m_bufferAC);
ace.start_encoder();
ace.ExpGolombEncode(0, 0, bModel0, bModel1);
ace.ExpGolombEncode(M, 0, bModel0, bModel1);
for(unsigned long v = 0; v < num; ++v)
{
for(unsigned long d = 0; d < dim; ++d)
{
EncodeIntACEGC(m_quantVectors[d * num + v], ace, mModelValues, bModel0, bModel1, M);
}
}
encodedBytes = ace.stop_encoder();
return O3DGC_OK;
}
O3DGCErrorCode DynamicVectorEncoder::EncodePayload(const DVEncodeParams & params,
const DynamicVector & dynamicVector,
BinaryStream & bstream)
{
#ifdef DEBUG_VERBOSE
g_fileDebugDVEnc = fopen("dv_enc.txt", "w");
#endif //DEBUG_VERBOSE
unsigned long start = bstream.GetSize();
const unsigned long dim = dynamicVector.GetDimVector();
const unsigned long num = dynamicVector.GetNVector();
bstream.WriteUInt32(0, m_streamType);
for(unsigned long j=0 ; j<dynamicVector.GetDimVector() ; ++j)
{
bstream.WriteFloat32((float) dynamicVector.GetMin(j), m_streamType);
bstream.WriteFloat32((float) dynamicVector.GetMax(j), m_streamType);
}
Quantize(dynamicVector.GetVectors(),
num,
dim,
dynamicVector.GetStride(),
dynamicVector.GetMin(),
dynamicVector.GetMax(),
params.GetQuantBits());
for(unsigned long d = 0; d < dim; ++d)
{
Transform(m_quantVectors + d * num, num);
}
#ifdef DEBUG_VERBOSE
printf("IntArray (%i, %i)\n", num, dim);
fprintf(g_fileDebugDVEnc, "IntArray (%i, %i)\n", num, dim);
for(unsigned long v = 0; v < num; ++v)
{
for(unsigned long d = 0; d < dim; ++d)
{
printf("%i\t %i \t %i\n", d * num + v, m_quantVectors[d * num + v], IntToUInt(m_quantVectors[d * num + v]));
fprintf(g_fileDebugDVEnc, "%i\t %i \t %i\n", d * num + v, m_quantVectors[d * num + v], IntToUInt(m_quantVectors[d * num + v]));
}
}
#endif //DEBUG_VERBOSE
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
for(unsigned long v = 0; v < num; ++v)
{
for(unsigned long d = 0; d < dim; ++d)
{
bstream.WriteIntASCII(m_quantVectors[d * num + v]);
}
}
}
else
{
unsigned long encodedBytes = 0;
unsigned long bestEncodedBytes = O3DGC_MAX_ULONG;
unsigned long M = 1;
unsigned long bestM = 1;
while (M < 1024)
{
EncodeAC(num, dim, M, encodedBytes);
if (encodedBytes > bestEncodedBytes)
{
break;
}
bestM = M;
bestEncodedBytes = encodedBytes;
M *= 2;
}
EncodeAC(num, dim, bestM, encodedBytes);
for(unsigned long i = 0; i < encodedBytes; ++i)
{
bstream.WriteUChar8Bin(m_bufferAC[i]);
}
}
bstream.WriteUInt32(start, bstream.GetSize() - start, m_streamType);
#ifdef DEBUG_VERBOSE
fclose(g_fileDebugDVEnc);
#endif //DEBUG_VERBOSE
return O3DGC_OK;
}
O3DGCErrorCode DynamicVectorEncoder::Quantize(const Real * const floatArray,
unsigned long numFloatArray,
unsigned long dimFloatArray,
unsigned long stride,
const Real * const minFloatArray,
const Real * const maxFloatArray,
unsigned long nQBits)
{
const unsigned long size = numFloatArray * dimFloatArray;
Real r;
if (m_maxNumVectors < size)
{
delete [] m_quantVectors;
m_maxNumVectors = size;
m_quantVectors = new long [m_maxNumVectors];
}
Real delta;
for(unsigned long d = 0; d < dimFloatArray; ++d)
{
r = maxFloatArray[d] - minFloatArray[d];
if (r > 0.0f)
{
delta = (float)((1 << nQBits) - 1) / r;
}
else
{
delta = 1.0f;
}
for(unsigned long v = 0; v < numFloatArray; ++v)
{
m_quantVectors[v + d * numFloatArray] = (long)((floatArray[v * stride + d]-minFloatArray[d]) * delta + 0.5f);
}
}
return O3DGC_OK;
}
}

View File

@@ -0,0 +1,79 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_DYNAMIC_VECTOR_ENCODER_H
#define O3DGC_DYNAMIC_VECTOR_ENCODER_H
#include "o3dgcCommon.h"
#include "o3dgcBinaryStream.h"
#include "o3dgcDynamicVector.h"
namespace o3dgc
{
//!
class DynamicVectorEncoder
{
public:
//! Constructor.
DynamicVectorEncoder(void);
//! Destructor.
~DynamicVectorEncoder(void);
//!
O3DGCErrorCode Encode(const DVEncodeParams & params,
const DynamicVector & dynamicVector,
BinaryStream & bstream);
O3DGCStreamType GetStreamType() const { return m_streamType; }
void SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; }
private:
O3DGCErrorCode EncodeHeader(const DVEncodeParams & params,
const DynamicVector & dynamicVector,
BinaryStream & bstream);
O3DGCErrorCode EncodePayload(const DVEncodeParams & params,
const DynamicVector & dynamicVector,
BinaryStream & bstream);
O3DGCErrorCode Quantize(const Real * const floatArray,
unsigned long numFloatArray,
unsigned long dimFloatArray,
unsigned long stride,
const Real * const minFloatArray,
const Real * const maxFloatArray,
unsigned long nQBits);
O3DGCErrorCode EncodeAC(unsigned long num,
unsigned long dim,
unsigned long M,
unsigned long & encodedBytes);
unsigned long m_posSize;
unsigned long m_sizeBufferAC;
unsigned long m_maxNumVectors;
unsigned long m_numVectors;
unsigned long m_dimVectors;
unsigned char * m_bufferAC;
long * m_quantVectors;
O3DGCStreamType m_streamType;
};
}
#endif // O3DGC_DYNAMIC_VECTOR_ENCODER_H

View File

@@ -0,0 +1,97 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_FIFO_H
#define O3DGC_FIFO_H
#include "o3dgcCommon.h"
namespace o3dgc
{
//!
template < typename T > class FIFO
{
public:
//! Constructor.
FIFO()
{
m_buffer = 0;
m_allocated = 0;
m_size = 0;
m_start = 0;
m_end = 0;
};
//! Destructor.
~FIFO(void)
{
delete [] m_buffer;
};
O3DGCErrorCode Allocate(unsigned long size)
{
assert(size > 0);
if (size > m_allocated)
{
delete [] m_buffer;
m_allocated = size;
m_buffer = new T [m_allocated];
}
Clear();
return O3DGC_OK;
}
const T & PopFirst()
{
assert(m_size > 0);
--m_size;
unsigned long current = m_start++;
if (m_start == m_allocated)
{
m_end = 0;
}
return m_buffer[current];
};
void PushBack(const T & value)
{
assert( m_size < m_allocated);
m_buffer[m_end] = value;
++m_size;
++m_end;
if (m_end == m_allocated)
{
m_end = 0;
}
}
unsigned long GetSize() const { return m_size;};
unsigned long GetAllocatedSize() const { return m_allocated;};
void Clear() { m_start = m_end = m_size = 0;};
private:
T * m_buffer;
unsigned long m_allocated;
unsigned long m_size;
unsigned long m_start;
unsigned long m_end;
};
}
#endif // O3DGC_FIFO_H

View File

@@ -0,0 +1,263 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_INDEXED_FACE_SET_H
#define O3DGC_INDEXED_FACE_SET_H
#include "o3dgcCommon.h"
namespace o3dgc
{
template<class T>
class IndexedFaceSet
{
public:
//! Constructor.
IndexedFaceSet(void)
{
memset(this, 0, sizeof(IndexedFaceSet));
m_ccw = true;
m_solid = true;
m_convex = true;
m_isTriangularMesh = true;
m_creaseAngle = 30;
};
//! Destructor.
~IndexedFaceSet(void) {};
unsigned long GetNCoordIndex() const { return m_nCoordIndex ;}
// only coordIndex is supported
unsigned long GetNCoord() const { return m_nCoord ;}
unsigned long GetNNormal() const { return m_nNormal ;}
unsigned long GetNFloatAttribute(unsigned long a) const
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
return m_nFloatAttribute[a];
}
unsigned long GetNIntAttribute(unsigned long a) const
{
assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
return m_nIntAttribute[a];
}
unsigned long GetNumFloatAttributes() const { return m_numFloatAttributes;}
unsigned long GetNumIntAttributes() const { return m_numIntAttributes ;}
const Real * GetCoordMin () const { return m_coordMin;}
const Real * GetCoordMax () const { return m_coordMax;}
const Real * GetNormalMin () const { return m_normalMin;}
const Real * GetNormalMax () const { return m_normalMax;}
Real GetCoordMin (int j) const { return m_coordMin[j] ;}
Real GetCoordMax (int j) const { return m_coordMax[j] ;}
Real GetNormalMin (int j) const { return m_normalMin[j] ;}
Real GetNormalMax (int j) const { return m_normalMax[j] ;}
O3DGCIFSFloatAttributeType GetFloatAttributeType(unsigned long a) const
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
return m_typeFloatAttribute[a];
}
O3DGCIFSIntAttributeType GetIntAttributeType(unsigned long a) const
{
assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
return m_typeIntAttribute[a];
}
unsigned long GetFloatAttributeDim(unsigned long a) const
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
return m_dimFloatAttribute[a];
}
unsigned long GetIntAttributeDim(unsigned long a) const
{
assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
return m_dimIntAttribute[a];
}
const Real * GetFloatAttributeMin(unsigned long a) const
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
return &(m_minFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]);
}
const Real * GetFloatAttributeMax(unsigned long a) const
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
return &(m_maxFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]);
}
Real GetFloatAttributeMin(unsigned long a, unsigned long dim) const
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
assert(dim < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
return m_minFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES + dim];
}
Real GetFloatAttributeMax(unsigned long a, unsigned long dim) const
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
assert(dim < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
return m_maxFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES + dim];
}
Real GetCreaseAngle() const { return m_creaseAngle ;}
bool GetCCW() const { return m_ccw ;}
bool GetSolid() const { return m_solid ;}
bool GetConvex() const { return m_convex ;}
bool GetIsTriangularMesh() const { return m_isTriangularMesh;}
const unsigned long * GetIndexBufferID() const { return m_indexBufferID ;}
const T * GetCoordIndex() const { return m_coordIndex;}
T * GetCoordIndex() { return m_coordIndex;}
Real * GetCoord() const { return m_coord ;}
Real * GetNormal() const { return m_normal ;}
Real * GetFloatAttribute(unsigned long a) const
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
return m_floatAttribute[a];
}
long * GetIntAttribute(unsigned long a) const
{
assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
return m_intAttribute[a] ;
}
// only coordIndex is supported
void SetNNormalIndex(unsigned long) {}
void SetNTexCoordIndex(unsigned long) {}
void SetNFloatAttributeIndex(int, unsigned long) {}
void SetNIntAttributeIndex (int, unsigned long) {}
// per triangle attributes not supported
void SetNormalPerVertex(bool) {}
void SetColorPerVertex(bool) {}
void SetFloatAttributePerVertex(int, bool){}
void SetIntAttributePerVertex (int, bool){}
void SetNCoordIndex (unsigned long nCoordIndex) { m_nCoordIndex = nCoordIndex;}
void SetNCoord (unsigned long nCoord) { m_nCoord = nCoord ;}
void SetNNormal (unsigned long nNormal) { m_nNormal = nNormal ;}
void SetNumFloatAttributes(unsigned long numFloatAttributes)
{
assert(numFloatAttributes < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
m_numFloatAttributes = numFloatAttributes;
}
void SetNumIntAttributes (unsigned long numIntAttributes)
{
assert(numIntAttributes < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
m_numIntAttributes = numIntAttributes;
}
void SetCreaseAngle (Real creaseAngle) { m_creaseAngle = creaseAngle ;}
void SetCCW (bool ccw) { m_ccw = ccw ;}
void SetSolid (bool solid) { m_solid = solid ;}
void SetConvex (bool convex) { m_convex = convex ;}
void SetIsTriangularMesh (bool isTriangularMesh) { m_isTriangularMesh = isTriangularMesh;}
void SetCoordMin (int j, Real min) { m_coordMin[j] = min;}
void SetCoordMax (int j, Real max) { m_coordMax[j] = max;}
void SetNormalMin (int j, Real min) { m_normalMin[j] = min;}
void SetNormalMax (int j, Real max) { m_normalMax[j] = max;}
void SetNFloatAttribute(unsigned long a, unsigned long nFloatAttribute)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
m_nFloatAttribute[a] = nFloatAttribute;
}
void SetNIntAttribute(unsigned long a, unsigned long nIntAttribute)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
m_nIntAttribute[a] = nIntAttribute;
}
void SetFloatAttributeDim(unsigned long a, unsigned long d)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
m_dimFloatAttribute[a] = d;
}
void SetIntAttributeDim(unsigned long a, unsigned long d)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
m_dimIntAttribute[a] = d;
}
void SetFloatAttributeType(unsigned long a, O3DGCIFSFloatAttributeType t)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
m_typeFloatAttribute[a] = t;
}
void SetIntAttributeType(unsigned long a, O3DGCIFSIntAttributeType t)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
m_typeIntAttribute[a] = t;
}
void SetFloatAttributeMin(unsigned long a, unsigned long dim, Real min)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
assert(dim < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
m_minFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES + dim] = min;
}
void SetFloatAttributeMax(unsigned long a, unsigned long dim, Real max)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
assert(dim < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
m_maxFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES + dim] = max;
}
void SetIndexBufferID (unsigned long * const indexBufferID) { m_indexBufferID = indexBufferID;}
void SetCoordIndex (T * const coordIndex) { m_coordIndex = coordIndex;}
void SetCoord (Real * const coord ) { m_coord = coord ;}
void SetNormal (Real * const normal ) { m_normal = normal ;}
void SetFloatAttribute (unsigned long a, Real * const floatAttribute)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
m_floatAttribute[a] = floatAttribute;
}
void SetIntAttribute (unsigned long a, long * const intAttribute)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
m_intAttribute[a] = intAttribute ;
}
void ComputeMinMax(O3DGCSC3DMCQuantizationMode quantMode);
private:
// triangles list
unsigned long m_nCoordIndex;
T * m_coordIndex;
unsigned long * m_indexBufferID;
// coord, normals, texcoord and color
unsigned long m_nCoord;
unsigned long m_nNormal;
Real m_coordMin [3];
Real m_coordMax [3];
Real m_normalMin [3];
Real m_normalMax [3];
Real * m_coord;
Real * m_normal;
// other attributes
unsigned long m_numFloatAttributes;
unsigned long m_numIntAttributes;
O3DGCIFSFloatAttributeType m_typeFloatAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
O3DGCIFSIntAttributeType m_typeIntAttribute [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES ];
unsigned long m_nFloatAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
unsigned long m_nIntAttribute [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES ];
unsigned long m_dimFloatAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
unsigned long m_dimIntAttribute [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES ];
Real m_minFloatAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES];
Real m_maxFloatAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES];
Real * m_floatAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
long * m_intAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
// mesh info
Real m_creaseAngle;
bool m_ccw;
bool m_solid;
bool m_convex;
bool m_isTriangularMesh;
};
}
#include "o3dgcIndexedFaceSet.inl" // template implementation
#endif // O3DGC_INDEXED_FACE_SET_H

View File

@@ -0,0 +1,47 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_INDEXED_FACE_SET_INL
#define O3DGC_INDEXED_FACE_SET_INL
#include <math.h>
namespace o3dgc
{
template <class T>
void IndexedFaceSet<T>::ComputeMinMax(O3DGCSC3DMCQuantizationMode quantMode)
{
ComputeVectorMinMax(m_coord , m_nCoord , 3, 3, m_coordMin , m_coordMax , quantMode);
ComputeVectorMinMax(m_normal , m_nNormal , 3, 3, m_normalMin , m_normalMax , quantMode);
unsigned long numFloatAttributes = GetNumFloatAttributes();
for(unsigned long a = 0; a < numFloatAttributes; ++a)
{
ComputeVectorMinMax(m_floatAttribute[a],
m_nFloatAttribute[a],
m_dimFloatAttribute[a],
m_dimFloatAttribute[a], // stride
m_minFloatAttribute + (a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES),
m_maxFloatAttribute + (a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES), quantMode);
}
}
}
#endif // O3DGC_INDEXED_FACE_SET_INL

View File

@@ -0,0 +1,111 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_SC3DMC_DECODER_H
#define O3DGC_SC3DMC_DECODER_H
#include "o3dgcCommon.h"
#include "o3dgcBinaryStream.h"
#include "o3dgcIndexedFaceSet.h"
#include "o3dgcSC3DMCEncodeParams.h"
#include "o3dgcTriangleListDecoder.h"
namespace o3dgc
{
//!
template <class T>
class SC3DMCDecoder
{
public:
//! Constructor.
SC3DMCDecoder(void)
{
m_iterator = 0;
m_streamSize = 0;
m_quantFloatArray = 0;
m_quantFloatArraySize = 0;
m_normals = 0;
m_normalsSize = 0;
m_streamType = O3DGC_STREAM_TYPE_UNKOWN;
};
//! Destructor.
~SC3DMCDecoder(void)
{
delete [] m_normals;
delete [] m_quantFloatArray;
}
//!
O3DGCErrorCode DecodeHeader(IndexedFaceSet<T> & ifs,
const BinaryStream & bstream);
//!
O3DGCErrorCode DecodePayload(IndexedFaceSet<T> & ifs,
const BinaryStream & bstream);
const SC3DMCStats & GetStats() const { return m_stats;}
unsigned long GetIterator() const { return m_iterator;}
O3DGCErrorCode SetIterator(unsigned long iterator) { m_iterator = iterator; return O3DGC_OK; }
private:
O3DGCErrorCode DecodeFloatArray(Real * const floatArray,
unsigned long numfloatArraySize,
unsigned long dimfloatArraySize,
unsigned long stride,
const Real * const minfloatArray,
const Real * const maxfloatArray,
unsigned long nQBits,
const IndexedFaceSet<T> & ifs,
O3DGCSC3DMCPredictionMode & predMode,
const BinaryStream & bstream);
O3DGCErrorCode IQuantizeFloatArray(Real * const floatArray,
unsigned long numfloatArraySize,
unsigned long dimfloatArraySize,
unsigned long stride,
const Real * const minfloatArray,
const Real * const maxfloatArray,
unsigned long nQBits);
O3DGCErrorCode DecodeIntArray(long * const intArray,
unsigned long numIntArraySize,
unsigned long dimIntArraySize,
unsigned long stride,
const IndexedFaceSet<T> & ifs,
O3DGCSC3DMCPredictionMode & predMode,
const BinaryStream & bstream);
O3DGCErrorCode ProcessNormals(const IndexedFaceSet<T> & ifs);
unsigned long m_iterator;
unsigned long m_streamSize;
SC3DMCEncodeParams m_params;
TriangleListDecoder<T> m_triangleListDecoder;
long * m_quantFloatArray;
unsigned long m_quantFloatArraySize;
Vector<char> m_orientation;
Real * m_normals;
unsigned long m_normalsSize;
SC3DMCStats m_stats;
O3DGCStreamType m_streamType;
};
}
#include "o3dgcSC3DMCDecoder.inl" // template implementation
#endif // O3DGC_SC3DMC_DECODER_H

View File

@@ -0,0 +1,850 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_SC3DMC_DECODER_INL
#define O3DGC_SC3DMC_DECODER_INL
#include "o3dgcArithmeticCodec.h"
#include "o3dgcTimer.h"
//#define DEBUG_VERBOSE
namespace o3dgc
{
#ifdef DEBUG_VERBOSE
FILE * g_fileDebugSC3DMCDec = NULL;
#endif //DEBUG_VERBOSE
template<class T>
O3DGCErrorCode SC3DMCDecoder<T>::DecodeHeader(IndexedFaceSet<T> & ifs,
const BinaryStream & bstream)
{
unsigned long iterator0 = m_iterator;
unsigned long start_code = bstream.ReadUInt32(m_iterator, O3DGC_STREAM_TYPE_BINARY);
if (start_code != O3DGC_SC3DMC_START_CODE)
{
m_iterator = iterator0;
start_code = bstream.ReadUInt32(m_iterator, O3DGC_STREAM_TYPE_ASCII);
if (start_code != O3DGC_SC3DMC_START_CODE)
{
return O3DGC_ERROR_CORRUPTED_STREAM;
}
else
{
m_streamType = O3DGC_STREAM_TYPE_ASCII;
}
}
else
{
m_streamType = O3DGC_STREAM_TYPE_BINARY;
}
m_streamSize = bstream.ReadUInt32(m_iterator, m_streamType);
m_params.SetEncodeMode( (O3DGCSC3DMCEncodingMode) bstream.ReadUChar(m_iterator, m_streamType));
ifs.SetCreaseAngle((Real) bstream.ReadFloat32(m_iterator, m_streamType));
unsigned char mask = bstream.ReadUChar(m_iterator, m_streamType);
ifs.SetCCW ((mask & 1) == 1);
ifs.SetSolid ((mask & 2) == 1);
ifs.SetConvex ((mask & 4) == 1);
ifs.SetIsTriangularMesh((mask & 8) == 1);
//bool markerBit0 = (mask & 16 ) == 1;
//bool markerBit1 = (mask & 32 ) == 1;
//bool markerBit2 = (mask & 64 ) == 1;
//bool markerBit3 = (mask & 128) == 1;
ifs.SetNCoord (bstream.ReadUInt32(m_iterator, m_streamType));
ifs.SetNNormal (bstream.ReadUInt32(m_iterator, m_streamType));
ifs.SetNumFloatAttributes(bstream.ReadUInt32(m_iterator, m_streamType));
ifs.SetNumIntAttributes (bstream.ReadUInt32(m_iterator, m_streamType));
if (ifs.GetNCoord() > 0)
{
ifs.SetNCoordIndex(bstream.ReadUInt32(m_iterator, m_streamType));
for(int j=0 ; j<3 ; ++j)
{
ifs.SetCoordMin(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
ifs.SetCoordMax(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
}
m_params.SetCoordQuantBits( bstream.ReadUChar(m_iterator, m_streamType) );
}
if (ifs.GetNNormal() > 0)
{
ifs.SetNNormalIndex(bstream.ReadUInt32(m_iterator, m_streamType));
for(int j=0 ; j<3 ; ++j)
{
ifs.SetNormalMin(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
ifs.SetNormalMax(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
}
ifs.SetNormalPerVertex(bstream.ReadUChar(m_iterator, m_streamType) == 1);
m_params.SetNormalQuantBits(bstream.ReadUChar(m_iterator, m_streamType));
}
for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a)
{
ifs.SetNFloatAttribute(a, bstream.ReadUInt32(m_iterator, m_streamType));
if (ifs.GetNFloatAttribute(a) > 0)
{
ifs.SetNFloatAttributeIndex(a, bstream.ReadUInt32(m_iterator, m_streamType));
unsigned char d = bstream.ReadUChar(m_iterator, m_streamType);
ifs.SetFloatAttributeDim(a, d);
for(unsigned char j = 0 ; j < d ; ++j)
{
ifs.SetFloatAttributeMin(a, j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
ifs.SetFloatAttributeMax(a, j, (Real) bstream.ReadFloat32(m_iterator, m_streamType));
}
ifs.SetFloatAttributePerVertex(a, bstream.ReadUChar(m_iterator, m_streamType) == 1);
ifs.SetFloatAttributeType(a, (O3DGCIFSFloatAttributeType) bstream.ReadUChar(m_iterator, m_streamType));
m_params.SetFloatAttributeQuantBits(a, bstream.ReadUChar(m_iterator, m_streamType));
}
}
for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a)
{
ifs.SetNIntAttribute(a, bstream.ReadUInt32(m_iterator, m_streamType));
if (ifs.GetNIntAttribute(a) > 0)
{
ifs.SetNIntAttributeIndex(a, bstream.ReadUInt32(m_iterator, m_streamType));
ifs.SetIntAttributeDim(a, bstream.ReadUChar(m_iterator, m_streamType));
ifs.SetIntAttributePerVertex(a, bstream.ReadUChar(m_iterator, m_streamType) == 1);
ifs.SetIntAttributeType(a, (O3DGCIFSIntAttributeType) bstream.ReadUChar(m_iterator, m_streamType));
}
}
return O3DGC_OK;
}
template<class T>
O3DGCErrorCode SC3DMCDecoder<T>::DecodePayload(IndexedFaceSet<T> & ifs,
const BinaryStream & bstream)
{
O3DGCErrorCode ret = O3DGC_OK;
#ifdef DEBUG_VERBOSE
g_fileDebugSC3DMCDec = fopen("tfans_dec_main.txt", "w");
#endif //DEBUG_VERBOSE
m_triangleListDecoder.SetStreamType(m_streamType);
m_stats.m_streamSizeCoordIndex = m_iterator;
Timer timer;
timer.Tic();
m_triangleListDecoder.Decode(ifs.GetCoordIndex(), ifs.GetNCoordIndex(), ifs.GetNCoord(), bstream, m_iterator);
timer.Toc();
m_stats.m_timeCoordIndex = timer.GetElapsedTime();
m_stats.m_streamSizeCoordIndex = m_iterator - m_stats.m_streamSizeCoordIndex;
// decode coord
m_stats.m_streamSizeCoord = m_iterator;
timer.Tic();
if (ifs.GetNCoord() > 0)
{
ret = DecodeFloatArray(ifs.GetCoord(), ifs.GetNCoord(), 3, 3, ifs.GetCoordMin(), ifs.GetCoordMax(),
m_params.GetCoordQuantBits(), ifs, m_params.GetCoordPredMode(), bstream);
}
if (ret != O3DGC_OK)
{
return ret;
}
timer.Toc();
m_stats.m_timeCoord = timer.GetElapsedTime();
m_stats.m_streamSizeCoord = m_iterator - m_stats.m_streamSizeCoord;
// decode Normal
m_stats.m_streamSizeNormal = m_iterator;
timer.Tic();
if (ifs.GetNNormal() > 0)
{
DecodeFloatArray(ifs.GetNormal(), ifs.GetNNormal(), 3, 3, ifs.GetNormalMin(), ifs.GetNormalMax(),
m_params.GetNormalQuantBits(), ifs, m_params.GetNormalPredMode(), bstream);
}
if (ret != O3DGC_OK)
{
return ret;
}
timer.Toc();
m_stats.m_timeNormal = timer.GetElapsedTime();
m_stats.m_streamSizeNormal = m_iterator - m_stats.m_streamSizeNormal;
// decode FloatAttributes
for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a)
{
m_stats.m_streamSizeFloatAttribute[a] = m_iterator;
timer.Tic();
DecodeFloatArray(ifs.GetFloatAttribute(a), ifs.GetNFloatAttribute(a), ifs.GetFloatAttributeDim(a), ifs.GetFloatAttributeDim(a),
ifs.GetFloatAttributeMin(a), ifs.GetFloatAttributeMax(a),
m_params.GetFloatAttributeQuantBits(a), ifs, m_params.GetFloatAttributePredMode(a), bstream);
timer.Toc();
m_stats.m_timeFloatAttribute[a] = timer.GetElapsedTime();
m_stats.m_streamSizeFloatAttribute[a] = m_iterator - m_stats.m_streamSizeFloatAttribute[a];
}
if (ret != O3DGC_OK)
{
return ret;
}
// decode IntAttributes
for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a)
{
m_stats.m_streamSizeIntAttribute[a] = m_iterator;
timer.Tic();
DecodeIntArray(ifs.GetIntAttribute(a), ifs.GetNIntAttribute(a), ifs.GetIntAttributeDim(a), ifs.GetIntAttributeDim(a),
ifs, m_params.GetIntAttributePredMode(a), bstream);
timer.Toc();
m_stats.m_timeIntAttribute[a] = timer.GetElapsedTime();
m_stats.m_streamSizeIntAttribute[a] = m_iterator - m_stats.m_streamSizeIntAttribute[a];
}
if (ret != O3DGC_OK)
{
return ret;
}
timer.Tic();
m_triangleListDecoder.Reorder();
timer.Toc();
m_stats.m_timeReorder = timer.GetElapsedTime();
#ifdef DEBUG_VERBOSE
fclose(g_fileDebugSC3DMCDec);
#endif //DEBUG_VERBOSE
return ret;
}
template<class T>
O3DGCErrorCode SC3DMCDecoder<T>::DecodeIntArray(long * const intArray,
unsigned long numIntArray,
unsigned long dimIntArray,
unsigned long stride,
const IndexedFaceSet<T> & ifs,
O3DGCSC3DMCPredictionMode & predMode,
const BinaryStream & bstream)
{
assert(dimIntArray < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
long predResidual;
SC3DMCPredictor m_neighbors [O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS];
Arithmetic_Codec acd;
Static_Bit_Model bModel0;
Adaptive_Bit_Model bModel1;
Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1);
unsigned long nPred;
const AdjacencyInfo & v2T = m_triangleListDecoder.GetVertexToTriangle();
const T * const triangles = ifs.GetCoordIndex();
const long nvert = (long) numIntArray;
unsigned char * buffer = 0;
unsigned long start = m_iterator;
unsigned long streamSize = bstream.ReadUInt32(m_iterator, m_streamType); // bitsream size
unsigned char mask = bstream.ReadUChar(m_iterator, m_streamType);
O3DGCSC3DMCBinarization binarization = (O3DGCSC3DMCBinarization)((mask >> 4) & 7);
predMode = (O3DGCSC3DMCPredictionMode)(mask & 7);
streamSize -= (m_iterator - start);
unsigned long iteratorPred = m_iterator + streamSize;
unsigned int exp_k = 0;
unsigned int M = 0;
if (m_streamType != O3DGC_STREAM_TYPE_ASCII)
{
if (binarization != O3DGC_SC3DMC_BINARIZATION_AC_EGC)
{
return O3DGC_ERROR_CORRUPTED_STREAM;
}
bstream.GetBuffer(m_iterator, buffer);
m_iterator += streamSize;
acd.set_buffer(streamSize, buffer);
acd.start_decoder();
exp_k = acd.ExpGolombDecode(0, bModel0, bModel1);
M = acd.ExpGolombDecode(0, bModel0, bModel1);
}
else
{
if (binarization != O3DGC_SC3DMC_BINARIZATION_ASCII)
{
return O3DGC_ERROR_CORRUPTED_STREAM;
}
bstream.ReadUInt32(iteratorPred, m_streamType); // predictors bitsream size
}
Adaptive_Data_Model mModelValues(M+2);
#ifdef DEBUG_VERBOSE
printf("IntArray (%i, %i)\n", numIntArray, dimIntArray);
fprintf(g_fileDebugSC3DMCDec, "IntArray (%i, %i)\n", numIntArray, dimIntArray);
#endif //DEBUG_VERBOSE
for (long v=0; v < nvert; ++v)
{
nPred = 0;
if ( v2T.GetNumNeighbors(v) > 0 &&
predMode != O3DGC_SC3DMC_NO_PREDICTION)
{
int u0 = v2T.Begin(v);
int u1 = v2T.End(v);
for (long u = u0; u < u1; u++)
{
long ta = v2T.GetNeighbor(u);
if (ta < 0)
{
break;
}
for(long k = 0; k < 3; ++k)
{
long w = triangles[ta*3 + k];
if ( w < v )
{
SC3DMCTriplet id = {-1, -1, w};
unsigned long p = Insert(id, nPred, m_neighbors);
if (p != 0xFFFFFFFF)
{
for (unsigned long i = 0; i < dimIntArray; i++)
{
m_neighbors[p].m_pred[i] = intArray[w*stride+i];
}
}
}
}
}
}
if (nPred > 1)
{
#ifdef DEBUG_VERBOSE1
printf("\t\t vm %i\n", v);
fprintf(g_fileDebugSC3DMCDec, "\t\t vm %i\n", v);
for (unsigned long p = 0; p < nPred; ++p)
{
printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
fprintf(g_fileDebugSC3DMCDec, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
for (unsigned long i = 0; i < dimIntArray; ++i)
{
printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]);
fprintf(g_fileDebugSC3DMCDec, "\t\t\t %i\n", m_neighbors[p].m_pred[i]);
}
}
#endif //DEBUG_VERBOSE
unsigned long bestPred;
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
bestPred = bstream.ReadUCharASCII(iteratorPred);
}
else
{
bestPred = acd.decode(mModelPreds);
}
#ifdef DEBUG_VERBOSE1
printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
fprintf(g_fileDebugSC3DMCDec, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
#endif //DEBUG_VERBOSE
for (unsigned long i = 0; i < dimIntArray; i++)
{
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
predResidual = bstream.ReadIntASCII(m_iterator);
}
else
{
predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
}
intArray[v*stride+i] = predResidual + m_neighbors[bestPred].m_pred[i];
#ifdef DEBUG_VERBOSE
printf("%i \t %i \t [%i]\n", v*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
fprintf(g_fileDebugSC3DMCDec, "%i \t %i \t [%i]\n", v*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
#endif //DEBUG_VERBOSE
}
}
else if (v > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION)
{
for (unsigned long i = 0; i < dimIntArray; i++)
{
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
predResidual = bstream.ReadIntASCII(m_iterator);
}
else
{
predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
}
intArray[v*stride+i] = predResidual + intArray[(v-1)*stride+i];
#ifdef DEBUG_VERBOSE
printf("%i \t %i\n", v*dimIntArray+i, predResidual);
fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimIntArray+i, predResidual);
#endif //DEBUG_VERBOSE
}
}
else
{
for (unsigned long i = 0; i < dimIntArray; i++)
{
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
predResidual = bstream.ReadUIntASCII(m_iterator);
}
else
{
predResidual = DecodeUIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
}
intArray[v*stride+i] = predResidual;
#ifdef DEBUG_VERBOSE
printf("%i \t %i\n", v*dimIntArray+i, predResidual);
fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimIntArray+i, predResidual);
#endif //DEBUG_VERBOSE
}
}
}
m_iterator = iteratorPred;
#ifdef DEBUG_VERBOSE
fflush(g_fileDebugSC3DMCDec);
#endif //DEBUG_VERBOSE
return O3DGC_OK;
}
template <class T>
O3DGCErrorCode SC3DMCDecoder<T>::ProcessNormals(const IndexedFaceSet<T> & ifs)
{
const long nvert = (long) ifs.GetNNormal();
const unsigned long normalSize = ifs.GetNNormal() * 2;
if (m_normalsSize < normalSize)
{
delete [] m_normals;
m_normalsSize = normalSize;
m_normals = new Real [normalSize];
}
const AdjacencyInfo & v2T = m_triangleListDecoder.GetVertexToTriangle();
const T * const triangles = ifs.GetCoordIndex();
Vec3<long> p1, p2, p3, n0, nt;
long na0 = 0, nb0 = 0;
Real rna0, rnb0, norm0;
char ni0 = 0, ni1 = 0;
long a, b, c;
for (long v=0; v < nvert; ++v)
{
n0.X() = 0;
n0.Y() = 0;
n0.Z() = 0;
int u0 = v2T.Begin(v);
int u1 = v2T.End(v);
for (long u = u0; u < u1; u++)
{
long ta = v2T.GetNeighbor(u);
if (ta == -1)
{
break;
}
a = triangles[ta*3 + 0];
b = triangles[ta*3 + 1];
c = triangles[ta*3 + 2];
p1.X() = m_quantFloatArray[3*a];
p1.Y() = m_quantFloatArray[3*a+1];
p1.Z() = m_quantFloatArray[3*a+2];
p2.X() = m_quantFloatArray[3*b];
p2.Y() = m_quantFloatArray[3*b+1];
p2.Z() = m_quantFloatArray[3*b+2];
p3.X() = m_quantFloatArray[3*c];
p3.Y() = m_quantFloatArray[3*c+1];
p3.Z() = m_quantFloatArray[3*c+2];
nt = (p2-p1)^(p3-p1);
n0 += nt;
}
norm0 = (Real) n0.GetNorm();
if (norm0 == 0.0)
{
norm0 = 1.0;
}
SphereToCube(n0.X(), n0.Y(), n0.Z(), na0, nb0, ni0);
rna0 = na0 / norm0;
rnb0 = nb0 / norm0;
ni1 = ni0 + m_orientation[v];
m_orientation[v] = ni1;
if ( (ni1 >> 1) != (ni0 >> 1) )
{
rna0 = Real(0.0);
rnb0 = Real(0.0);
}
m_normals[2*v] = rna0;
m_normals[2*v+1] = rnb0;
#ifdef DEBUG_VERBOSE1
printf("n0 \t %i \t %i \t %i \t %i (%f, %f)\n", v, n0.X(), n0.Y(), n0.Z(), rna0, rnb0);
fprintf(g_fileDebugSC3DMCDec, "n0 \t %i \t %i \t %i \t %i (%f, %f)\n", v, n0.X(), n0.Y(), n0.Z(), rna0, rnb0);
#endif //DEBUG_VERBOSE
}
return O3DGC_OK;
}
template<class T>
O3DGCErrorCode SC3DMCDecoder<T>::DecodeFloatArray(Real * const floatArray,
unsigned long numFloatArray,
unsigned long dimFloatArray,
unsigned long stride,
const Real * const minFloatArray,
const Real * const maxFloatArray,
unsigned long nQBits,
const IndexedFaceSet<T> & ifs,
O3DGCSC3DMCPredictionMode & predMode,
const BinaryStream & bstream)
{
assert(dimFloatArray < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
long predResidual;
SC3DMCPredictor m_neighbors [O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS];
Arithmetic_Codec acd;
Static_Bit_Model bModel0;
Adaptive_Bit_Model bModel1;
Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1);
unsigned long nPred;
const AdjacencyInfo & v2T = m_triangleListDecoder.GetVertexToTriangle();
const T * const triangles = ifs.GetCoordIndex();
const long nvert = (long) numFloatArray;
const unsigned long size = numFloatArray * dimFloatArray;
unsigned char * buffer = 0;
unsigned long start = m_iterator;
unsigned long streamSize = bstream.ReadUInt32(m_iterator, m_streamType); // bitsream size
unsigned char mask = bstream.ReadUChar(m_iterator, m_streamType);
O3DGCSC3DMCBinarization binarization = (O3DGCSC3DMCBinarization)((mask >> 4) & 7);
predMode = (O3DGCSC3DMCPredictionMode)(mask & 7);
streamSize -= (m_iterator - start);
unsigned long iteratorPred = m_iterator + streamSize;
unsigned int exp_k = 0;
unsigned int M = 0;
if (m_streamType != O3DGC_STREAM_TYPE_ASCII)
{
if (binarization != O3DGC_SC3DMC_BINARIZATION_AC_EGC)
{
return O3DGC_ERROR_CORRUPTED_STREAM;
}
bstream.GetBuffer(m_iterator, buffer);
m_iterator += streamSize;
acd.set_buffer(streamSize, buffer);
acd.start_decoder();
exp_k = acd.ExpGolombDecode(0, bModel0, bModel1);
M = acd.ExpGolombDecode(0, bModel0, bModel1);
}
else
{
if (binarization != O3DGC_SC3DMC_BINARIZATION_ASCII)
{
return O3DGC_ERROR_CORRUPTED_STREAM;
}
bstream.ReadUInt32(iteratorPred, m_streamType); // predictors bitsream size
}
Adaptive_Data_Model mModelValues(M+2);
if (predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION)
{
m_orientation.Allocate(size);
m_orientation.Clear();
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
for(unsigned long i = 0; i < numFloatArray; ++i)
{
m_orientation.PushBack((unsigned char) bstream.ReadIntASCII(m_iterator));
}
}
else
{
Adaptive_Data_Model dModel(12);
for(unsigned long i = 0; i < numFloatArray; ++i)
{
m_orientation.PushBack((unsigned char) UIntToInt(acd.decode(dModel)));
}
}
ProcessNormals(ifs);
dimFloatArray = 2;
}
#ifdef DEBUG_VERBOSE
printf("FloatArray (%i, %i)\n", numFloatArray, dimFloatArray);
fprintf(g_fileDebugSC3DMCDec, "FloatArray (%i, %i)\n", numFloatArray, dimFloatArray);
#endif //DEBUG_VERBOSE
if (m_quantFloatArraySize < size)
{
delete [] m_quantFloatArray;
m_quantFloatArraySize = size;
m_quantFloatArray = new long [size];
}
for (long v=0; v < nvert; ++v)
{
nPred = 0;
if ( v2T.GetNumNeighbors(v) > 0 &&
predMode != O3DGC_SC3DMC_NO_PREDICTION)
{
int u0 = v2T.Begin(v);
int u1 = v2T.End(v);
for (long u = u0; u < u1; u++)
{
long ta = v2T.GetNeighbor(u);
if (ta < 0)
{
break;
}
if (predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION)
{
long a,b;
if ((long) triangles[ta*3] == v)
{
a = triangles[ta*3 + 1];
b = triangles[ta*3 + 2];
}
else if ((long)triangles[ta*3 + 1] == v)
{
a = triangles[ta*3 + 0];
b = triangles[ta*3 + 2];
}
else
{
a = triangles[ta*3 + 0];
b = triangles[ta*3 + 1];
}
if ( a < v && b < v)
{
int u0 = v2T.Begin(a);
int u1 = v2T.End(a);
for (long u = u0; u < u1; u++)
{
long tb = v2T.GetNeighbor(u);
if (tb < 0)
{
break;
}
long c = -1;
bool foundB = false;
for(long k = 0; k < 3; ++k)
{
long x = triangles[tb*3 + k];
if (x == b)
{
foundB = true;
}
if (x < v && x != a && x != b)
{
c = x;
}
}
if (c != -1 && foundB)
{
SC3DMCTriplet id = {min(a, b), max(a, b), -c-1};
unsigned long p = Insert(id, nPred, m_neighbors);
if (p != 0xFFFFFFFF)
{
for (unsigned long i = 0; i < dimFloatArray; i++)
{
m_neighbors[p].m_pred[i] = m_quantFloatArray[a*stride+i] +
m_quantFloatArray[b*stride+i] -
m_quantFloatArray[c*stride+i];
}
}
}
}
}
}
if ( predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION ||
predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION ||
predMode == O3DGC_SC3DMC_DIFFERENTIAL_PREDICTION )
{
for(long k = 0; k < 3; ++k)
{
long w = triangles[ta*3 + k];
if ( w < v )
{
SC3DMCTriplet id = {-1, -1, w};
unsigned long p = Insert(id, nPred, m_neighbors);
if (p != 0xFFFFFFFF)
{
for (unsigned long i = 0; i < dimFloatArray; i++)
{
m_neighbors[p].m_pred[i] = m_quantFloatArray[w*stride+i];
}
}
}
}
}
}
}
if (nPred > 1)
{
#ifdef DEBUG_VERBOSE1
printf("\t\t vm %i\n", v);
fprintf(g_fileDebugSC3DMCDec, "\t\t vm %i\n", v);
for (unsigned long p = 0; p < nPred; ++p)
{
printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
fprintf(g_fileDebugSC3DMCDec, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
for (unsigned long i = 0; i < dimFloatArray; ++i)
{
printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]);
fprintf(g_fileDebugSC3DMCDec, "\t\t\t %i\n", m_neighbors[p].m_pred[i]);
}
}
#endif //DEBUG_VERBOSE
unsigned long bestPred;
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
bestPred = bstream.ReadUCharASCII(iteratorPred);
}
else
{
bestPred = acd.decode(mModelPreds);
}
#ifdef DEBUG_VERBOSE1
printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
fprintf(g_fileDebugSC3DMCDec, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
#endif //DEBUG_VERBOSE
for (unsigned long i = 0; i < dimFloatArray; i++)
{
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
predResidual = bstream.ReadIntASCII(m_iterator);
}
else
{
predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
}
m_quantFloatArray[v*stride+i] = predResidual + m_neighbors[bestPred].m_pred[i];
#ifdef DEBUG_VERBOSE
printf("%i \t %i \t [%i]\n", v*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
fprintf(g_fileDebugSC3DMCDec, "%i \t %i \t [%i]\n", v*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
#endif //DEBUG_VERBOSE
}
}
else if (v > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION)
{
for (unsigned long i = 0; i < dimFloatArray; i++)
{
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
predResidual = bstream.ReadIntASCII(m_iterator);
}
else
{
predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
}
m_quantFloatArray[v*stride+i] = predResidual + m_quantFloatArray[(v-1)*stride+i];
#ifdef DEBUG_VERBOSE
printf("%i \t %i\n", v*dimFloatArray+i, predResidual);
fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimFloatArray+i, predResidual);
#endif //DEBUG_VERBOSE
}
}
else
{
for (unsigned long i = 0; i < dimFloatArray; i++)
{
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
predResidual = bstream.ReadUIntASCII(m_iterator);
}
else
{
predResidual = DecodeUIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M);
}
m_quantFloatArray[v*stride+i] = predResidual;
#ifdef DEBUG_VERBOSE
printf("%i \t %i\n", v*dimFloatArray+i, predResidual);
fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimFloatArray+i, predResidual);
#endif //DEBUG_VERBOSE
}
}
}
m_iterator = iteratorPred;
if (predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION)
{
const Real minNormal[2] = {(Real)(-2),(Real)(-2)};
const Real maxNormal[2] = {(Real)(2),(Real)(2)};
Real na1, nb1;
Real na0, nb0;
char ni1;
IQuantizeFloatArray(floatArray, numFloatArray, dimFloatArray, stride, minNormal, maxNormal, nQBits+1);
for (long v=0; v < nvert; ++v)
{
na0 = m_normals[2*v];
nb0 = m_normals[2*v+1];
na1 = floatArray[stride*v] + na0;
nb1 = floatArray[stride*v+1] + nb0;
ni1 = m_orientation[v];
CubeToSphere(na1, nb1, ni1,
floatArray[stride*v],
floatArray[stride*v+1],
floatArray[stride*v+2]);
#ifdef DEBUG_VERBOSE1
printf("normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n",
v,
floatArray[stride*v],
floatArray[stride*v+1],
floatArray[stride*v+2],
ni1, na1, nb1,
na0, nb0);
fprintf(g_fileDebugSC3DMCDec, "normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n",
v,
floatArray[stride*v],
floatArray[stride*v+1],
floatArray[stride*v+2],
ni1, na1, nb1,
na0, nb0);
#endif //DEBUG_VERBOSE
}
}
else
{
IQuantizeFloatArray(floatArray, numFloatArray, dimFloatArray, stride, minFloatArray, maxFloatArray, nQBits);
}
#ifdef DEBUG_VERBOSE
fflush(g_fileDebugSC3DMCDec);
#endif //DEBUG_VERBOSE
return O3DGC_OK;
}
template<class T>
O3DGCErrorCode SC3DMCDecoder<T>::IQuantizeFloatArray(Real * const floatArray,
unsigned long numFloatArray,
unsigned long dimFloatArray,
unsigned long stride,
const Real * const minFloatArray,
const Real * const maxFloatArray,
unsigned long nQBits)
{
Real idelta[O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES];
Real r;
for(unsigned long d = 0; d < dimFloatArray; d++)
{
r = maxFloatArray[d] - minFloatArray[d];
if (r > 0.0f)
{
idelta[d] = r/(float)((1 << nQBits) - 1);
}
else
{
idelta[d] = 1.0f;
}
}
for(unsigned long v = 0; v < numFloatArray; ++v)
{
for(unsigned long d = 0; d < dimFloatArray; ++d)
{
// floatArray[v * stride + d] = m_quantFloatArray[v * stride + d];
floatArray[v * stride + d] = m_quantFloatArray[v * stride + d] * idelta[d] + minFloatArray[d];
}
}
return O3DGC_OK;
}
}
#endif // O3DGC_SC3DMC_DECODER_INL

View File

@@ -0,0 +1,140 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_SC3DMC_ENCODE_PARAMS_H
#define O3DGC_SC3DMC_ENCODE_PARAMS_H
#include "o3dgcCommon.h"
namespace o3dgc
{
class SC3DMCEncodeParams
{
public:
//! Constructor.
SC3DMCEncodeParams(void)
{
memset(this, 0, sizeof(SC3DMCEncodeParams));
m_encodeMode = O3DGC_SC3DMC_ENCODE_MODE_TFAN;
m_streamTypeMode = O3DGC_STREAM_TYPE_ASCII;
m_coordQuantBits = 14;
m_normalQuantBits = 8;
m_coordPredMode = O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION;
m_normalPredMode = O3DGC_SC3DMC_SURF_NORMALS_PREDICTION;
for(unsigned long a = 0; a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES; ++a)
{
m_floatAttributePredMode[a] = O3DGC_SC3DMC_DIFFERENTIAL_PREDICTION;
}
for(unsigned long a = 0; a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES; ++a)
{
m_intAttributePredMode[a] = O3DGC_SC3DMC_NO_PREDICTION;
}
};
//! Destructor.
~SC3DMCEncodeParams(void) {};
O3DGCStreamType GetStreamType() const { return m_streamTypeMode;}
O3DGCSC3DMCEncodingMode GetEncodeMode() const { return m_encodeMode;}
unsigned long GetNumFloatAttributes() const { return m_numFloatAttributes;}
unsigned long GetNumIntAttributes() const { return m_numIntAttributes;}
unsigned long GetCoordQuantBits() const { return m_coordQuantBits;}
unsigned long GetNormalQuantBits() const { return m_normalQuantBits;}
unsigned long GetFloatAttributeQuantBits(unsigned long a) const
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
return m_floatAttributeQuantBits[a];
}
O3DGCSC3DMCPredictionMode GetCoordPredMode() const { return m_coordPredMode; }
O3DGCSC3DMCPredictionMode GetNormalPredMode() const { return m_normalPredMode; }
O3DGCSC3DMCPredictionMode GetFloatAttributePredMode(unsigned long a) const
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
return m_floatAttributePredMode[a];
}
O3DGCSC3DMCPredictionMode GetIntAttributePredMode(unsigned long a) const
{
assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
return m_intAttributePredMode[a];
}
O3DGCSC3DMCPredictionMode & GetCoordPredMode() { return m_coordPredMode; }
O3DGCSC3DMCPredictionMode & GetNormalPredMode() { return m_normalPredMode; }
O3DGCSC3DMCPredictionMode & GetFloatAttributePredMode(unsigned long a)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
return m_floatAttributePredMode[a];
}
O3DGCSC3DMCPredictionMode & GetIntAttributePredMode(unsigned long a)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
return m_intAttributePredMode[a];
}
void SetStreamType(O3DGCStreamType streamTypeMode) { m_streamTypeMode = streamTypeMode;}
void SetEncodeMode(O3DGCSC3DMCEncodingMode encodeMode) { m_encodeMode = encodeMode;}
void SetNumFloatAttributes(unsigned long numFloatAttributes)
{
assert(numFloatAttributes < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
m_numFloatAttributes = numFloatAttributes;
}
void SetNumIntAttributes (unsigned long numIntAttributes)
{
assert(numIntAttributes < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
m_numIntAttributes = numIntAttributes;
}
void SetCoordQuantBits (unsigned int coordQuantBits ) { m_coordQuantBits = coordQuantBits ; }
void SetNormalQuantBits (unsigned int normalQuantBits ) { m_normalQuantBits = normalQuantBits ; }
void SetFloatAttributeQuantBits(unsigned long a, unsigned long q)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
m_floatAttributeQuantBits[a] = q;
}
void SetCoordPredMode (O3DGCSC3DMCPredictionMode coordPredMode ) { m_coordPredMode = coordPredMode ; }
void SetNormalPredMode (O3DGCSC3DMCPredictionMode normalPredMode ) { m_normalPredMode = normalPredMode ; }
void SetFloatAttributePredMode(unsigned long a, O3DGCSC3DMCPredictionMode p)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES);
m_floatAttributePredMode[a] = p;
}
void SetIntAttributePredMode(unsigned long a, O3DGCSC3DMCPredictionMode p)
{
assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES);
m_intAttributePredMode[a] = p;
}
private:
unsigned long m_numFloatAttributes;
unsigned long m_numIntAttributes;
unsigned long m_coordQuantBits;
unsigned long m_normalQuantBits;
unsigned long m_floatAttributeQuantBits[O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
O3DGCSC3DMCPredictionMode m_coordPredMode;
O3DGCSC3DMCPredictionMode m_normalPredMode;
O3DGCSC3DMCPredictionMode m_floatAttributePredMode[O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES];
O3DGCSC3DMCPredictionMode m_intAttributePredMode [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES];
O3DGCStreamType m_streamTypeMode;
O3DGCSC3DMCEncodingMode m_encodeMode;
};
}
#endif // O3DGC_SC3DMC_ENCODE_PARAMS_H

View File

@@ -0,0 +1,116 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_SC3DMC_ENCODER_H
#define O3DGC_SC3DMC_ENCODER_H
#include "o3dgcCommon.h"
#include "o3dgcBinaryStream.h"
#include "o3dgcIndexedFaceSet.h"
#include "o3dgcSC3DMCEncodeParams.h"
#include "o3dgcTriangleListEncoder.h"
namespace o3dgc
{
//!
template<class T>
class SC3DMCEncoder
{
public:
//! Constructor.
SC3DMCEncoder(void)
{
m_posSize = 0;
m_quantFloatArray = 0;
m_quantFloatArraySize = 0;
m_sizeBufferAC = 0;
m_bufferAC = 0;
m_normals = 0;
m_normalsSize = 0;
m_streamType = O3DGC_STREAM_TYPE_UNKOWN;
};
//! Destructor.
~SC3DMCEncoder(void)
{
delete [] m_normals;
delete [] m_quantFloatArray;
delete [] m_bufferAC;
}
//!
O3DGCErrorCode Encode(const SC3DMCEncodeParams & params,
const IndexedFaceSet<T> & ifs,
BinaryStream & bstream);
const SC3DMCStats & GetStats() const { return m_stats;}
private:
O3DGCErrorCode EncodeHeader(const SC3DMCEncodeParams & params,
const IndexedFaceSet<T> & ifs,
BinaryStream & bstream);
O3DGCErrorCode EncodePayload(const SC3DMCEncodeParams & params,
const IndexedFaceSet<T> & ifs,
BinaryStream & bstream);
O3DGCErrorCode EncodeFloatArray(const Real * const floatArray,
unsigned long numfloatArray,
unsigned long dimfloatArray,
unsigned long stride,
const Real * const minfloatArray,
const Real * const maxfloatArray,
unsigned long nQBits,
const IndexedFaceSet<T> & ifs,
O3DGCSC3DMCPredictionMode predMode,
BinaryStream & bstream);
O3DGCErrorCode QuantizeFloatArray(const Real * const floatArray,
unsigned long numFloatArray,
unsigned long dimFloatArray,
unsigned long stride,
const Real * const minfloatArray,
const Real * const maxfloatArray,
unsigned long nQBits);
O3DGCErrorCode EncodeIntArray(const long * const intArray,
unsigned long numIntArray,
unsigned long dimIntArray,
unsigned long stride,
const IndexedFaceSet<T> & ifs,
O3DGCSC3DMCPredictionMode predMode,
BinaryStream & bstream);
O3DGCErrorCode ProcessNormals(const IndexedFaceSet<T> & ifs);
TriangleListEncoder<T> m_triangleListEncoder;
long * m_quantFloatArray;
unsigned long m_posSize;
unsigned long m_quantFloatArraySize;
unsigned char * m_bufferAC;
unsigned long m_sizeBufferAC;
SC3DMCPredictor m_neighbors [O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS];
unsigned long m_freqSymbols[O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS];
unsigned long m_freqPreds [O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS];
Vector<long> m_predictors;
Real * m_normals;
unsigned long m_normalsSize;
SC3DMCStats m_stats;
O3DGCStreamType m_streamType;
};
}
#include "o3dgcSC3DMCEncoder.inl" // template implementation
#endif // O3DGC_SC3DMC_ENCODER_H

View File

@@ -0,0 +1,927 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_SC3DMC_ENCODER_INL
#define O3DGC_SC3DMC_ENCODER_INL
#include "o3dgcArithmeticCodec.h"
#include "o3dgcTimer.h"
#include "o3dgcVector.h"
#include "o3dgcBinaryStream.h"
#include "o3dgcCommon.h"
//#define DEBUG_VERBOSE
namespace o3dgc
{
#ifdef DEBUG_VERBOSE
FILE * g_fileDebugSC3DMCEnc = NULL;
#endif //DEBUG_VERBOSE
template <class T>
O3DGCErrorCode SC3DMCEncoder<T>::Encode(const SC3DMCEncodeParams & params,
const IndexedFaceSet<T> & ifs,
BinaryStream & bstream)
{
// Encode header
unsigned long start = bstream.GetSize();
EncodeHeader(params, ifs, bstream);
// Encode payload
EncodePayload(params, ifs, bstream);
bstream.WriteUInt32(m_posSize, bstream.GetSize() - start, m_streamType);
return O3DGC_OK;
}
template <class T>
O3DGCErrorCode SC3DMCEncoder<T>::EncodeHeader(const SC3DMCEncodeParams & params,
const IndexedFaceSet<T> & ifs,
BinaryStream & bstream)
{
m_streamType = params.GetStreamType();
bstream.WriteUInt32(O3DGC_SC3DMC_START_CODE, m_streamType);
m_posSize = bstream.GetSize();
bstream.WriteUInt32(0, m_streamType); // to be filled later
bstream.WriteUChar(O3DGC_SC3DMC_ENCODE_MODE_TFAN, m_streamType);
bstream.WriteFloat32((float)ifs.GetCreaseAngle(), m_streamType);
unsigned char mask = 0;
bool markerBit0 = false;
bool markerBit1 = false;
bool markerBit2 = false;
bool markerBit3 = false;
mask += (ifs.GetCCW() );
mask += (ifs.GetSolid() << 1);
mask += (ifs.GetConvex() << 2);
mask += (ifs.GetIsTriangularMesh() << 3);
mask += (markerBit0 << 4);
mask += (markerBit1 << 5);
mask += (markerBit2 << 6);
mask += (markerBit3 << 7);
bstream.WriteUChar(mask, m_streamType);
bstream.WriteUInt32(ifs.GetNCoord(), m_streamType);
bstream.WriteUInt32(ifs.GetNNormal(), m_streamType);
bstream.WriteUInt32(ifs.GetNumFloatAttributes(), m_streamType);
bstream.WriteUInt32(ifs.GetNumIntAttributes(), m_streamType);
if (ifs.GetNCoord() > 0)
{
bstream.WriteUInt32(ifs.GetNCoordIndex(), m_streamType);
for(int j=0 ; j<3 ; ++j)
{
bstream.WriteFloat32((float) ifs.GetCoordMin(j), m_streamType);
bstream.WriteFloat32((float) ifs.GetCoordMax(j), m_streamType);
}
bstream.WriteUChar((unsigned char) params.GetCoordQuantBits(), m_streamType);
}
if (ifs.GetNNormal() > 0)
{
bstream.WriteUInt32(0, m_streamType);
for(int j=0 ; j<3 ; ++j)
{
bstream.WriteFloat32((float) ifs.GetNormalMin(j), m_streamType);
bstream.WriteFloat32((float) ifs.GetNormalMax(j), m_streamType);
}
bstream.WriteUChar(true, m_streamType); //(unsigned char) ifs.GetNormalPerVertex()
bstream.WriteUChar((unsigned char) params.GetNormalQuantBits(), m_streamType);
}
for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a)
{
bstream.WriteUInt32(ifs.GetNFloatAttribute(a), m_streamType);
if (ifs.GetNFloatAttribute(a) > 0)
{
assert(ifs.GetFloatAttributeDim(a) < (unsigned long) O3DGC_MAX_UCHAR8);
bstream.WriteUInt32(0, m_streamType);
unsigned char d = (unsigned char) ifs.GetFloatAttributeDim(a);
bstream.WriteUChar(d, m_streamType);
for(unsigned char j = 0 ; j < d ; ++j)
{
bstream.WriteFloat32((float) ifs.GetFloatAttributeMin(a, j), m_streamType);
bstream.WriteFloat32((float) ifs.GetFloatAttributeMax(a, j), m_streamType);
}
bstream.WriteUChar(true, m_streamType); //(unsigned char) ifs.GetFloatAttributePerVertex(a)
bstream.WriteUChar((unsigned char) ifs.GetFloatAttributeType(a), m_streamType);
bstream.WriteUChar((unsigned char) params.GetFloatAttributeQuantBits(a), m_streamType);
}
}
for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a)
{
bstream.WriteUInt32(ifs.GetNIntAttribute(a), m_streamType);
if (ifs.GetNIntAttribute(a) > 0)
{
assert(ifs.GetFloatAttributeDim(a) < (unsigned long) O3DGC_MAX_UCHAR8);
bstream.WriteUInt32(0, m_streamType);
bstream.WriteUChar((unsigned char) ifs.GetIntAttributeDim(a), m_streamType);
bstream.WriteUChar(true, m_streamType); // (unsigned char) ifs.GetIntAttributePerVertex(a)
bstream.WriteUChar((unsigned char) ifs.GetIntAttributeType(a), m_streamType);
}
}
return O3DGC_OK;
}
template <class T>
O3DGCErrorCode SC3DMCEncoder<T>::QuantizeFloatArray(const Real * const floatArray,
unsigned long numFloatArray,
unsigned long dimFloatArray,
unsigned long stride,
const Real * const minFloatArray,
const Real * const maxFloatArray,
unsigned long nQBits)
{
const unsigned long size = numFloatArray * dimFloatArray;
Real delta[O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES];
Real r;
for(unsigned long d = 0; d < dimFloatArray; d++)
{
r = maxFloatArray[d] - minFloatArray[d];
if (r > 0.0f)
{
delta[d] = (float)((1 << nQBits) - 1) / r;
}
else
{
delta[d] = 1.0f;
}
}
if (m_quantFloatArraySize < size)
{
delete [] m_quantFloatArray;
m_quantFloatArraySize = size;
m_quantFloatArray = new long [size];
}
for(unsigned long v = 0; v < numFloatArray; ++v)
{
for(unsigned long d = 0; d < dimFloatArray; ++d)
{
m_quantFloatArray[v * stride + d] = (long)((floatArray[v * stride + d]-minFloatArray[d]) * delta[d] + 0.5f);
}
}
return O3DGC_OK;
}
template <class T>
O3DGCErrorCode SC3DMCEncoder<T>::EncodeFloatArray(const Real * const floatArray,
unsigned long numFloatArray,
unsigned long dimFloatArray,
unsigned long stride,
const Real * const minFloatArray,
const Real * const maxFloatArray,
unsigned long nQBits,
const IndexedFaceSet<T> & ifs,
O3DGCSC3DMCPredictionMode predMode,
BinaryStream & bstream)
{
assert(dimFloatArray < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
long predResidual, v, uPredResidual;
unsigned long nPred;
Arithmetic_Codec ace;
Static_Bit_Model bModel0;
Adaptive_Bit_Model bModel1;
const AdjacencyInfo & v2T = m_triangleListEncoder.GetVertexToTriangle();
const long * const vmap = m_triangleListEncoder.GetVMap();
const long * const invVMap = m_triangleListEncoder.GetInvVMap();
const T * const triangles = ifs.GetCoordIndex();
const long nvert = (long) numFloatArray;
unsigned long start = bstream.GetSize();
unsigned char mask = predMode & 7;
const unsigned long M = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS - 1;
unsigned long nSymbols = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS;
unsigned long nPredictors = O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS;
Adaptive_Data_Model mModelValues(M+2);
Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1);
memset(m_freqSymbols, 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS);
memset(m_freqPreds , 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS);
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
mask += (O3DGC_SC3DMC_BINARIZATION_ASCII & 7)<<4;
m_predictors.Allocate(nvert);
m_predictors.Clear();
}
else
{
mask += (O3DGC_SC3DMC_BINARIZATION_AC_EGC & 7)<<4;
const unsigned int NMAX = numFloatArray * dimFloatArray * 8 + 100;
if ( m_sizeBufferAC < NMAX )
{
delete [] m_bufferAC;
m_sizeBufferAC = NMAX;
m_bufferAC = new unsigned char [m_sizeBufferAC];
}
ace.set_buffer(NMAX, m_bufferAC);
ace.start_encoder();
ace.ExpGolombEncode(0, 0, bModel0, bModel1);
ace.ExpGolombEncode(M, 0, bModel0, bModel1);
}
bstream.WriteUInt32(0, m_streamType);
bstream.WriteUChar(mask, m_streamType);
#ifdef DEBUG_VERBOSE
printf("FloatArray (%i, %i)\n", numFloatArray, dimFloatArray);
fprintf(g_fileDebugSC3DMCEnc, "FloatArray (%i, %i)\n", numFloatArray, dimFloatArray);
#endif //DEBUG_VERBOSE
if (predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION)
{
const Real minFloatArray[2] = {(Real)(-2.0),(Real)(-2.0)};
const Real maxFloatArray[2] = {(Real)(2.0),(Real)(2.0)};
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
for(unsigned long i = 0; i < numFloatArray; ++i)
{
bstream.WriteIntASCII(m_predictors[i]);
}
}
else
{
Adaptive_Data_Model dModel(12);
for(unsigned long i = 0; i < numFloatArray; ++i)
{
ace.encode(IntToUInt(m_predictors[i]), dModel);
}
}
QuantizeFloatArray(floatArray, numFloatArray, dimFloatArray, stride, minFloatArray, maxFloatArray, nQBits+1);
}
else
{
QuantizeFloatArray(floatArray, numFloatArray, dimFloatArray, stride, minFloatArray, maxFloatArray, nQBits);
}
for (long vm=0; vm < nvert; ++vm)
{
nPred = 0;
v = invVMap[vm];
assert( v >= 0 && v < nvert);
if ( v2T.GetNumNeighbors(v) > 0 &&
predMode != O3DGC_SC3DMC_NO_PREDICTION)
{
int u0 = v2T.Begin(v);
int u1 = v2T.End(v);
for (long u = u0; u < u1; u++)
{
long ta = v2T.GetNeighbor(u);
if ( predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION )
{
long a,b;
if ((long) triangles[ta*3] == v)
{
a = triangles[ta*3 + 1];
b = triangles[ta*3 + 2];
}
else if ((long) triangles[ta*3 + 1] == v)
{
a = triangles[ta*3 + 0];
b = triangles[ta*3 + 2];
}
else
{
a = triangles[ta*3 + 0];
b = triangles[ta*3 + 1];
}
if ( vmap[a] < vm && vmap[b] < vm)
{
int u0 = v2T.Begin(a);
int u1 = v2T.End(a);
for (long u = u0; u < u1; u++)
{
long tb = v2T.GetNeighbor(u);
long c = -1;
bool foundB = false;
for(long k = 0; k < 3; ++k)
{
long x = triangles[tb*3 + k];
if (x == b)
{
foundB = true;
}
if (vmap[x] < vm && x != a && x != b)
{
c = x;
}
}
if (c != -1 && foundB)
{
SC3DMCTriplet id = {min(vmap[a], vmap[b]), max(vmap[a], vmap[b]), -vmap[c]-1};
unsigned long p = Insert(id, nPred, m_neighbors);
if (p != 0xFFFFFFFF)
{
for (unsigned long i = 0; i < dimFloatArray; i++)
{
m_neighbors[p].m_pred[i] = m_quantFloatArray[a*stride+i] +
m_quantFloatArray[b*stride+i] -
m_quantFloatArray[c*stride+i];
}
}
}
}
}
}
if ( predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION ||
predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION ||
predMode == O3DGC_SC3DMC_DIFFERENTIAL_PREDICTION )
{
for(long k = 0; k < 3; ++k)
{
long w = triangles[ta*3 + k];
if ( vmap[w] < vm )
{
SC3DMCTriplet id = {-1, -1, vmap[w]};
unsigned long p = Insert(id, nPred, m_neighbors);
if (p != 0xFFFFFFFF)
{
for (unsigned long i = 0; i < dimFloatArray; i++)
{
m_neighbors[p].m_pred[i] = m_quantFloatArray[w*stride+i];
}
}
}
}
}
}
}
if (nPred > 1)
{
// find best predictor
unsigned long bestPred = 0xFFFFFFFF;
double bestCost = O3DGC_MAX_DOUBLE;
double cost;
#ifdef DEBUG_VERBOSE1
printf("\t\t vm %i\n", vm);
fprintf(g_fileDebugSC3DMCEnc, "\t\t vm %i\n", vm);
#endif //DEBUG_VERBOSE
for (unsigned long p = 0; p < nPred; ++p)
{
#ifdef DEBUG_VERBOSE1
printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
fprintf(g_fileDebugSC3DMCEnc, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
#endif //DEBUG_VERBOSE
cost = -log2((m_freqPreds[p]+1.0) / nPredictors );
for (unsigned long i = 0; i < dimFloatArray; ++i)
{
#ifdef DEBUG_VERBOSE1
printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]);
fprintf(g_fileDebugSC3DMCEnc, "\t\t\t %i\n", m_neighbors[p].m_pred[i]);
#endif //DEBUG_VERBOSE
predResidual = (long) IntToUInt(m_quantFloatArray[v*stride+i] - m_neighbors[p].m_pred[i]);
if (predResidual < (long) M)
{
cost += -log2((m_freqSymbols[predResidual]+1.0) / nSymbols );
}
else
{
cost += -log2((m_freqSymbols[M] + 1.0) / nSymbols ) + log2((double) (predResidual-M));
}
}
if (cost < bestCost)
{
bestCost = cost;
bestPred = p;
}
}
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
m_predictors.PushBack((unsigned char) bestPred);
}
else
{
ace.encode(bestPred, mModelPreds);
}
#ifdef DEBUG_VERBOSE1
printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
fprintf(g_fileDebugSC3DMCEnc, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
#endif //DEBUG_VERBOSE
// use best predictor
for (unsigned long i = 0; i < dimFloatArray; ++i)
{
predResidual = m_quantFloatArray[v*stride+i] - m_neighbors[bestPred].m_pred[i];
uPredResidual = IntToUInt(predResidual);
++m_freqSymbols[(uPredResidual < (long) M)? uPredResidual : M];
#ifdef DEBUG_VERBOSE
printf("%i \t %i \t [%i]\n", vm*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
fprintf(g_fileDebugSC3DMCEnc, "%i \t %i \t [%i]\n", vm*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
#endif //DEBUG_VERBOSE
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
bstream.WriteIntASCII(predResidual);
}
else
{
EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M);
}
}
++m_freqPreds[bestPred];
nSymbols += dimFloatArray;
++nPredictors;
}
else if ( vm > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION)
{
long prev = invVMap[vm-1];
for (unsigned long i = 0; i < dimFloatArray; i++)
{
predResidual = m_quantFloatArray[v*stride+i] - m_quantFloatArray[prev*stride+i];
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
bstream.WriteIntASCII(predResidual);
}
else
{
EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M);
}
#ifdef DEBUG_VERBOSE
printf("%i \t %i\n", vm*dimFloatArray+i, predResidual);
fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimFloatArray+i, predResidual);
#endif //DEBUG_VERBOSE
}
}
else
{
for (unsigned long i = 0; i < dimFloatArray; i++)
{
predResidual = m_quantFloatArray[v*stride+i];
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
bstream.WriteUIntASCII(predResidual);
}
else
{
EncodeUIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M);
}
#ifdef DEBUG_VERBOSE
printf("%i \t %i\n", vm*dimFloatArray+i, predResidual);
fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimFloatArray+i, predResidual);
#endif //DEBUG_VERBOSE
}
}
}
if (m_streamType != O3DGC_STREAM_TYPE_ASCII)
{
unsigned long encodedBytes = ace.stop_encoder();
for(unsigned long i = 0; i < encodedBytes; ++i)
{
bstream.WriteUChar8Bin(m_bufferAC[i]);
}
}
bstream.WriteUInt32(start, bstream.GetSize() - start, m_streamType);
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
unsigned long start = bstream.GetSize();
bstream.WriteUInt32ASCII(0);
const unsigned long size = m_predictors.GetSize();
for(unsigned long i = 0; i < size; ++i)
{
bstream.WriteUCharASCII((unsigned char) m_predictors[i]);
}
bstream.WriteUInt32ASCII(start, bstream.GetSize() - start);
}
#ifdef DEBUG_VERBOSE
fflush(g_fileDebugSC3DMCEnc);
#endif //DEBUG_VERBOSE
return O3DGC_OK;
}
template <class T>
O3DGCErrorCode SC3DMCEncoder<T>::EncodeIntArray(const long * const intArray,
unsigned long numIntArray,
unsigned long dimIntArray,
unsigned long stride,
const IndexedFaceSet<T> & ifs,
O3DGCSC3DMCPredictionMode predMode,
BinaryStream & bstream)
{
assert(dimIntArray < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES);
long predResidual, v, uPredResidual;
unsigned long nPred;
Arithmetic_Codec ace;
Static_Bit_Model bModel0;
Adaptive_Bit_Model bModel1;
const AdjacencyInfo & v2T = m_triangleListEncoder.GetVertexToTriangle();
const long * const vmap = m_triangleListEncoder.GetVMap();
const long * const invVMap = m_triangleListEncoder.GetInvVMap();
const T * const triangles = ifs.GetCoordIndex();
const long nvert = (long) numIntArray;
unsigned long start = bstream.GetSize();
unsigned char mask = predMode & 7;
const unsigned long M = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS - 1;
unsigned long nSymbols = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS;
unsigned long nPredictors = O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS;
Adaptive_Data_Model mModelValues(M+2);
Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1);
memset(m_freqSymbols, 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS);
memset(m_freqPreds , 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS);
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
mask += (O3DGC_SC3DMC_BINARIZATION_ASCII & 7)<<4;
m_predictors.Allocate(nvert);
m_predictors.Clear();
}
else
{
mask += (O3DGC_SC3DMC_BINARIZATION_AC_EGC & 7)<<4;
const unsigned int NMAX = numIntArray * dimIntArray * 8 + 100;
if ( m_sizeBufferAC < NMAX )
{
delete [] m_bufferAC;
m_sizeBufferAC = NMAX;
m_bufferAC = new unsigned char [m_sizeBufferAC];
}
ace.set_buffer(NMAX, m_bufferAC);
ace.start_encoder();
ace.ExpGolombEncode(0, 0, bModel0, bModel1);
ace.ExpGolombEncode(M, 0, bModel0, bModel1);
}
bstream.WriteUInt32(0, m_streamType);
bstream.WriteUChar(mask, m_streamType);
#ifdef DEBUG_VERBOSE
printf("IntArray (%i, %i)\n", numIntArray, dimIntArray);
fprintf(g_fileDebugSC3DMCEnc, "IntArray (%i, %i)\n", numIntArray, dimIntArray);
#endif //DEBUG_VERBOSE
for (long vm=0; vm < nvert; ++vm)
{
nPred = 0;
v = invVMap[vm];
assert( v >= 0 && v < nvert);
if ( v2T.GetNumNeighbors(v) > 0 &&
predMode != O3DGC_SC3DMC_NO_PREDICTION)
{
int u0 = v2T.Begin(v);
int u1 = v2T.End(v);
for (long u = u0; u < u1; u++)
{
long ta = v2T.GetNeighbor(u);
for(long k = 0; k < 3; ++k)
{
long w = triangles[ta*3 + k];
if ( vmap[w] < vm )
{
SC3DMCTriplet id = {-1, -1, vmap[w]};
unsigned long p = Insert(id, nPred, m_neighbors);
if (p != 0xFFFFFFFF)
{
for (unsigned long i = 0; i < dimIntArray; i++)
{
m_neighbors[p].m_pred[i] = intArray[w*stride+i];
}
}
}
}
}
}
if (nPred > 1)
{
// find best predictor
unsigned long bestPred = 0xFFFFFFFF;
double bestCost = O3DGC_MAX_DOUBLE;
double cost;
#ifdef DEBUG_VERBOSE1
printf("\t\t vm %i\n", vm);
fprintf(g_fileDebugSC3DMCEnc, "\t\t vm %i\n", vm);
#endif //DEBUG_VERBOSE
for (unsigned long p = 0; p < nPred; ++p)
{
#ifdef DEBUG_VERBOSE1
printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
fprintf(g_fileDebugSC3DMCEnc, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c);
#endif //DEBUG_VERBOSE
cost = -log2((m_freqPreds[p]+1.0) / nPredictors );
for (unsigned long i = 0; i < dimIntArray; ++i)
{
#ifdef DEBUG_VERBOSE1
printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]);
fprintf(g_fileDebugSC3DMCEnc, "\t\t\t %i\n", m_neighbors[p].m_pred[i]);
#endif //DEBUG_VERBOSE
predResidual = (long) IntToUInt(intArray[v*stride+i] - m_neighbors[p].m_pred[i]);
if (predResidual < (long) M)
{
cost += -log2((m_freqSymbols[predResidual]+1.0) / nSymbols );
}
else
{
cost += -log2((m_freqSymbols[M] + 1.0) / nSymbols ) + log2((double) (predResidual-M));
}
}
if (cost < bestCost)
{
bestCost = cost;
bestPred = p;
}
}
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
m_predictors.PushBack((unsigned char) bestPred);
}
else
{
ace.encode(bestPred, mModelPreds);
}
#ifdef DEBUG_VERBOSE1
printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
fprintf(g_fileDebugSC3DMCEnc, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred);
#endif //DEBUG_VERBOSE
// use best predictor
for (unsigned long i = 0; i < dimIntArray; ++i)
{
predResidual = intArray[v*stride+i] - m_neighbors[bestPred].m_pred[i];
uPredResidual = IntToUInt(predResidual);
++m_freqSymbols[(uPredResidual < (long) M)? uPredResidual : M];
#ifdef DEBUG_VERBOSE
printf("%i \t %i \t [%i]\n", vm*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
fprintf(g_fileDebugSC3DMCEnc, "%i \t %i \t [%i]\n", vm*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]);
#endif //DEBUG_VERBOSE
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
bstream.WriteIntASCII(predResidual);
}
else
{
EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M);
}
}
++m_freqPreds[bestPred];
nSymbols += dimIntArray;
++nPredictors;
}
else if ( vm > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION)
{
long prev = invVMap[vm-1];
for (unsigned long i = 0; i < dimIntArray; i++)
{
predResidual = intArray[v*stride+i] - intArray[prev*stride+i];
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
bstream.WriteIntASCII(predResidual);
}
else
{
EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M);
}
#ifdef DEBUG_VERBOSE
printf("%i \t %i\n", vm*dimIntArray+i, predResidual);
fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimIntArray+i, predResidual);
#endif //DEBUG_VERBOSE
}
}
else
{
for (unsigned long i = 0; i < dimIntArray; i++)
{
predResidual = intArray[v*stride+i];
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
bstream.WriteUIntASCII(predResidual);
}
else
{
EncodeUIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M);
}
#ifdef DEBUG_VERBOSE
printf("%i \t %i\n", vm*dimIntArray+i, predResidual);
fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimIntArray+i, predResidual);
#endif //DEBUG_VERBOSE
}
}
}
if (m_streamType != O3DGC_STREAM_TYPE_ASCII)
{
unsigned long encodedBytes = ace.stop_encoder();
for(unsigned long i = 0; i < encodedBytes; ++i)
{
bstream.WriteUChar8Bin(m_bufferAC[i]);
}
}
bstream.WriteUInt32(start, bstream.GetSize() - start, m_streamType);
if (m_streamType == O3DGC_STREAM_TYPE_ASCII)
{
unsigned long start = bstream.GetSize();
bstream.WriteUInt32ASCII(0);
const unsigned long size = m_predictors.GetSize();
for(unsigned long i = 0; i < size; ++i)
{
bstream.WriteUCharASCII((unsigned char) m_predictors[i]);
}
bstream.WriteUInt32ASCII(start, bstream.GetSize() - start);
}
#ifdef DEBUG_VERBOSE
fflush(g_fileDebugSC3DMCEnc);
#endif //DEBUG_VERBOSE
return O3DGC_OK;
}
template <class T>
O3DGCErrorCode SC3DMCEncoder<T>::ProcessNormals(const IndexedFaceSet<T> & ifs)
{
const long nvert = (long) ifs.GetNNormal();
const unsigned long normalSize = ifs.GetNNormal() * 2;
if (m_normalsSize < normalSize)
{
delete [] m_normals;
m_normalsSize = normalSize;
m_normals = new Real [normalSize];
}
const AdjacencyInfo & v2T = m_triangleListEncoder.GetVertexToTriangle();
const long * const invVMap = m_triangleListEncoder.GetInvVMap();
const T * const triangles = ifs.GetCoordIndex();
const Real * const originalNormals = ifs.GetNormal();
Vec3<long> p1, p2, p3, n0, nt;
Vec3<Real> n1;
long na0 = 0, nb0 = 0;
Real rna0, rnb0, na1 = 0, nb1 = 0, norm0, norm1;
char ni0 = 0, ni1 = 0;
long a, b, c, v;
m_predictors.Clear();
for (long i=0; i < nvert; ++i)
{
v = invVMap[i];
n0.X() = 0;
n0.Y() = 0;
n0.Z() = 0;
int u0 = v2T.Begin(v);
int u1 = v2T.End(v);
for (long u = u0; u < u1; u++)
{
long ta = v2T.GetNeighbor(u);
a = triangles[ta*3 + 0];
b = triangles[ta*3 + 1];
c = triangles[ta*3 + 2];
p1.X() = m_quantFloatArray[3*a];
p1.Y() = m_quantFloatArray[3*a+1];
p1.Z() = m_quantFloatArray[3*a+2];
p2.X() = m_quantFloatArray[3*b];
p2.Y() = m_quantFloatArray[3*b+1];
p2.Z() = m_quantFloatArray[3*b+2];
p3.X() = m_quantFloatArray[3*c];
p3.Y() = m_quantFloatArray[3*c+1];
p3.Z() = m_quantFloatArray[3*c+2];
nt = (p2-p1)^(p3-p1);
n0 += nt;
}
norm0 = (Real) n0.GetNorm();
if (norm0 == 0.0)
{
norm0 = 1.0;
}
SphereToCube(n0.X(), n0.Y(), n0.Z(), na0, nb0, ni0);
rna0 = na0 / norm0;
rnb0 = nb0 / norm0;
n1.X() = originalNormals[3*v];
n1.Y() = originalNormals[3*v+1];
n1.Z() = originalNormals[3*v+2];
norm1 = (Real) n1.GetNorm();
if (norm1 != 0.0)
{
n1.X() /= norm1;
n1.Y() /= norm1;
n1.Z() /= norm1;
}
SphereToCube(n1.X(), n1.Y(), n1.Z(), na1, nb1, ni1);
m_predictors.PushBack(ni1 - ni0);
if ( (ni1 >> 1) != (ni0 >> 1) )
{
rna0 = (Real)0.0;
rnb0 = (Real)0.0;
}
m_normals[2*v] = na1 - rna0;
m_normals[2*v+1] = nb1 - rnb0;
#ifdef DEBUG_VERBOSE1
printf("n0 \t %i \t %i \t %i \t %i (%f, %f)\n", i, n0.X(), n0.Y(), n0.Z(), rna0, rnb0);
fprintf(g_fileDebugSC3DMCEnc,"n0 \t %i \t %i \t %i \t %i (%f, %f)\n", i, n0.X(), n0.Y(), n0.Z(), rna0, rnb0);
#endif //DEBUG_VERBOSE
#ifdef DEBUG_VERBOSE1
printf("normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n", i, n1.X(), n1.Y(), n1.Z(), ni1, na1, nb1, rna0, rnb0);
fprintf(g_fileDebugSC3DMCEnc, "normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n", i, n1.X(), n1.Y(), n1.Z(), ni1, na1, nb1, rna0, rnb0);
#endif //DEBUG_VERBOSE
}
return O3DGC_OK;
}
template <class T>
O3DGCErrorCode SC3DMCEncoder<T>::EncodePayload(const SC3DMCEncodeParams & params,
const IndexedFaceSet<T> & ifs,
BinaryStream & bstream)
{
#ifdef DEBUG_VERBOSE
g_fileDebugSC3DMCEnc = fopen("tfans_enc_main.txt", "w");
#endif //DEBUG_VERBOSE
// encode triangle list
m_triangleListEncoder.SetStreamType(params.GetStreamType());
m_stats.m_streamSizeCoordIndex = bstream.GetSize();
Timer timer;
timer.Tic();
m_triangleListEncoder.Encode(ifs.GetCoordIndex(), ifs.GetIndexBufferID(), ifs.GetNCoordIndex(), ifs.GetNCoord(), bstream);
timer.Toc();
m_stats.m_timeCoordIndex = timer.GetElapsedTime();
m_stats.m_streamSizeCoordIndex = bstream.GetSize() - m_stats.m_streamSizeCoordIndex;
// encode coord
m_stats.m_streamSizeCoord = bstream.GetSize();
timer.Tic();
if (ifs.GetNCoord() > 0)
{
EncodeFloatArray(ifs.GetCoord(), ifs.GetNCoord(), 3, 3, ifs.GetCoordMin(), ifs.GetCoordMax(),
params.GetCoordQuantBits(), ifs, params.GetCoordPredMode(), bstream);
}
timer.Toc();
m_stats.m_timeCoord = timer.GetElapsedTime();
m_stats.m_streamSizeCoord = bstream.GetSize() - m_stats.m_streamSizeCoord;
// encode Normal
m_stats.m_streamSizeNormal = bstream.GetSize();
timer.Tic();
if (ifs.GetNNormal() > 0)
{
if (params.GetNormalPredMode() == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION)
{
ProcessNormals(ifs);
EncodeFloatArray(m_normals, ifs.GetNNormal(), 2, 2, ifs.GetNormalMin(), ifs.GetNormalMax(),
params.GetNormalQuantBits(), ifs, params.GetNormalPredMode(), bstream);
}
else
{
EncodeFloatArray(ifs.GetNormal(), ifs.GetNNormal(), 3, 3, ifs.GetNormalMin(), ifs.GetNormalMax(),
params.GetNormalQuantBits(), ifs, params.GetNormalPredMode(), bstream);
}
}
timer.Toc();
m_stats.m_timeNormal = timer.GetElapsedTime();
m_stats.m_streamSizeNormal = bstream.GetSize() - m_stats.m_streamSizeNormal;
// encode FloatAttribute
for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a)
{
m_stats.m_streamSizeFloatAttribute[a] = bstream.GetSize();
timer.Tic();
EncodeFloatArray(ifs.GetFloatAttribute(a), ifs.GetNFloatAttribute(a),
ifs.GetFloatAttributeDim(a), ifs.GetFloatAttributeDim(a),
ifs.GetFloatAttributeMin(a), ifs.GetFloatAttributeMax(a),
params.GetFloatAttributeQuantBits(a), ifs,
params.GetFloatAttributePredMode(a), bstream);
timer.Toc();
m_stats.m_timeFloatAttribute[a] = timer.GetElapsedTime();
m_stats.m_streamSizeFloatAttribute[a] = bstream.GetSize() - m_stats.m_streamSizeFloatAttribute[a];
}
// encode IntAttribute
for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a)
{
m_stats.m_streamSizeIntAttribute[a] = bstream.GetSize();
timer.Tic();
EncodeIntArray(ifs.GetIntAttribute(a), ifs.GetNIntAttribute(a), ifs.GetIntAttributeDim(a),
ifs.GetIntAttributeDim(a), ifs, params.GetIntAttributePredMode(a), bstream);
timer.Toc();
m_stats.m_timeIntAttribute[a] = timer.GetElapsedTime();
m_stats.m_streamSizeIntAttribute[a] = bstream.GetSize() - m_stats.m_streamSizeIntAttribute[a];
}
#ifdef DEBUG_VERBOSE
fclose(g_fileDebugSC3DMCEnc);
#endif //DEBUG_VERBOSE
return O3DGC_OK;
}
}
#endif // O3DGC_SC3DMC_ENCODER_INL

View File

@@ -0,0 +1,134 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_TIMER_H
#define O3DGC_TIMER_H
#include "o3dgcCommon.h"
#ifdef _WIN32
/* Thank you, Microsoft, for file WinDef.h with min/max redefinition. */
#define NOMINMAX
#include <windows.h>
#elif __APPLE__
#include <mach/clock.h>
#include <mach/mach.h>
#else
#include <time.h>
#include <sys/time.h>
#endif
namespace o3dgc
{
#ifdef _WIN32
class Timer
{
public:
Timer(void)
{
m_start.QuadPart = 0;
m_stop.QuadPart = 0;
QueryPerformanceFrequency( &m_freq ) ;
};
~Timer(void){};
void Tic()
{
QueryPerformanceCounter(&m_start) ;
}
void Toc()
{
QueryPerformanceCounter(&m_stop);
}
double GetElapsedTime() // in ms
{
LARGE_INTEGER delta;
delta.QuadPart = m_stop.QuadPart - m_start.QuadPart;
return (1000.0 * delta.QuadPart) / (double)m_freq.QuadPart;
}
private:
LARGE_INTEGER m_start;
LARGE_INTEGER m_stop;
LARGE_INTEGER m_freq;
};
#elif __APPLE__
class Timer
{
public:
Timer(void)
{
memset(this, 0, sizeof(Timer));
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, & m_cclock);
};
~Timer(void)
{
mach_port_deallocate(mach_task_self(), m_cclock);
};
void Tic()
{
clock_get_time( m_cclock, &m_start);
}
void Toc()
{
clock_get_time( m_cclock, &m_stop);
}
double GetElapsedTime() // in ms
{
return 1000.0 * (m_stop.tv_sec - m_start.tv_sec + (1.0E-9) * (m_stop.tv_nsec - m_start.tv_nsec));
}
private:
clock_serv_t m_cclock;
mach_timespec_t m_start;
mach_timespec_t m_stop;
};
#else
class Timer
{
public:
Timer(void)
{
memset(this, 0, sizeof(Timer));
};
~Timer(void){};
void Tic()
{
clock_gettime(CLOCK_REALTIME, &m_start);
}
void Toc()
{
clock_gettime(CLOCK_REALTIME, &m_stop);
}
double GetElapsedTime() // in ms
{
return 1000.0 * (m_stop.tv_sec - m_start.tv_sec + (1.0E-9) * (m_stop.tv_nsec - m_start.tv_nsec));
}
private:
struct timespec m_start;
struct timespec m_stop;
};
#endif
}
#endif // O3DGC_TIMER_H

View File

@@ -0,0 +1,22 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

View File

@@ -0,0 +1,475 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#include "o3dgcTriangleFans.h"
#include "o3dgcArithmeticCodec.h"
//#define DEBUG_VERBOSE
namespace o3dgc
{
#ifdef DEBUG_VERBOSE
FILE* g_fileDebugTF = NULL;
#endif //DEBUG_VERBOSE
O3DGCErrorCode SaveUIntData(const Vector<long> & data,
BinaryStream & bstream)
{
unsigned long start = bstream.GetSize();
bstream.WriteUInt32ASCII(0);
const unsigned long size = data.GetSize();
bstream.WriteUInt32ASCII(size);
for(unsigned long i = 0; i < size; ++i)
{
bstream.WriteUIntASCII(data[i]);
}
bstream.WriteUInt32ASCII(start, bstream.GetSize() - start);
return O3DGC_OK;
}
O3DGCErrorCode SaveIntData(const Vector<long> & data,
BinaryStream & bstream)
{
unsigned long start = bstream.GetSize();
bstream.WriteUInt32ASCII(0);
const unsigned long size = data.GetSize();
bstream.WriteUInt32ASCII(size);
for(unsigned long i = 0; i < size; ++i)
{
bstream.WriteIntASCII(data[i]);
}
bstream.WriteUInt32ASCII(start, bstream.GetSize() - start);
return O3DGC_OK;
}
O3DGCErrorCode SaveBinData(const Vector<long> & data,
BinaryStream & bstream)
{
unsigned long start = bstream.GetSize();
bstream.WriteUInt32ASCII(0);
const unsigned long size = data.GetSize();
long symbol;
bstream.WriteUInt32ASCII(size);
for(unsigned long i = 0; i < size; )
{
symbol = 0;
for(unsigned long h = 0; h < O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0 && i < size; ++h)
{
symbol += (data[i] << h);
++i;
}
bstream.WriteUCharASCII((unsigned char) symbol);
}
bstream.WriteUInt32ASCII(start, bstream.GetSize() - start);
return O3DGC_OK;
}
O3DGCErrorCode CompressedTriangleFans::SaveUIntAC(const Vector<long> & data,
const unsigned long M,
BinaryStream & bstream)
{
unsigned long start = bstream.GetSize();
const unsigned int NMAX = data.GetSize() * 8 + 100;
const unsigned long size = data.GetSize();
long minValue = O3DGC_MAX_LONG;
bstream.WriteUInt32Bin(0);
bstream.WriteUInt32Bin(size);
if (size > 0)
{
#ifdef DEBUG_VERBOSE
printf("-----------\nsize %i, start %i\n", size, start);
fprintf(g_fileDebugTF, "-----------\nsize %i, start %i\n", size, start);
#endif //DEBUG_VERBOSE
for(unsigned long i = 0; i < size; ++i)
{
if (minValue > data[i])
{
minValue = data[i];
}
#ifdef DEBUG_VERBOSE
printf("%i\t%i\n", i, data[i]);
fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]);
#endif //DEBUG_VERBOSE
}
bstream.WriteUInt32Bin(minValue);
if ( m_sizeBufferAC < NMAX )
{
delete [] m_bufferAC;
m_sizeBufferAC = NMAX;
m_bufferAC = new unsigned char [m_sizeBufferAC];
}
Arithmetic_Codec ace;
ace.set_buffer(NMAX, m_bufferAC);
ace.start_encoder();
Adaptive_Data_Model mModelValues(M+1);
for(unsigned long i = 0; i < size; ++i)
{
ace.encode(data[i]-minValue, mModelValues);
}
unsigned long encodedBytes = ace.stop_encoder();
for(unsigned long i = 0; i < encodedBytes; ++i)
{
bstream.WriteUChar8Bin(m_bufferAC[i]);
}
}
bstream.WriteUInt32Bin(start, bstream.GetSize() - start);
return O3DGC_OK;
}
O3DGCErrorCode CompressedTriangleFans::SaveBinAC(const Vector<long> & data,
BinaryStream & bstream)
{
unsigned long start = bstream.GetSize();
const unsigned int NMAX = data.GetSize() * 8 + 100;
const unsigned long size = data.GetSize();
bstream.WriteUInt32Bin(0);
bstream.WriteUInt32Bin(size);
if (size > 0)
{
if ( m_sizeBufferAC < NMAX )
{
delete [] m_bufferAC;
m_sizeBufferAC = NMAX;
m_bufferAC = new unsigned char [m_sizeBufferAC];
}
Arithmetic_Codec ace;
ace.set_buffer(NMAX, m_bufferAC);
ace.start_encoder();
Adaptive_Bit_Model bModel;
#ifdef DEBUG_VERBOSE
printf("-----------\nsize %i, start %i\n", size, start);
fprintf(g_fileDebugTF, "-----------\nsize %i, start %i\n", size, start);
#endif //DEBUG_VERBOSE
for(unsigned long i = 0; i < size; ++i)
{
ace.encode(data[i], bModel);
#ifdef DEBUG_VERBOSE
printf("%i\t%i\n", i, data[i]);
fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]);
#endif //DEBUG_VERBOSE
}
unsigned long encodedBytes = ace.stop_encoder();
for(unsigned long i = 0; i < encodedBytes; ++i)
{
bstream.WriteUChar8Bin(m_bufferAC[i]);
}
}
bstream.WriteUInt32Bin(start, bstream.GetSize() - start);
return O3DGC_OK;
}
O3DGCErrorCode CompressedTriangleFans::SaveIntACEGC(const Vector<long> & data,
const unsigned long M,
BinaryStream & bstream)
{
unsigned long start = bstream.GetSize();
const unsigned int NMAX = data.GetSize() * 8 + 100;
const unsigned long size = data.GetSize();
long minValue = 0;
bstream.WriteUInt32Bin(0);
bstream.WriteUInt32Bin(size);
if (size > 0)
{
#ifdef DEBUG_VERBOSE
printf("-----------\nsize %i, start %i\n", size, start);
fprintf(g_fileDebugTF, "-----------\nsize %i, start %i\n", size, start);
#endif //DEBUG_VERBOSE
for(unsigned long i = 0; i < size; ++i)
{
if (minValue > data[i])
{
minValue = data[i];
}
#ifdef DEBUG_VERBOSE
printf("%i\t%i\n", i, data[i]);
fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]);
#endif //DEBUG_VERBOSE
}
bstream.WriteUInt32Bin(minValue + O3DGC_MAX_LONG);
if ( m_sizeBufferAC < NMAX )
{
delete [] m_bufferAC;
m_sizeBufferAC = NMAX;
m_bufferAC = new unsigned char [m_sizeBufferAC];
}
Arithmetic_Codec ace;
ace.set_buffer(NMAX, m_bufferAC);
ace.start_encoder();
Adaptive_Data_Model mModelValues(M+2);
Static_Bit_Model bModel0;
Adaptive_Bit_Model bModel1;
unsigned long value;
for(unsigned long i = 0; i < size; ++i)
{
value = data[i]-minValue;
if (value < M)
{
ace.encode(value, mModelValues);
}
else
{
ace.encode(M, mModelValues);
ace.ExpGolombEncode(value-M, 0, bModel0, bModel1);
}
}
unsigned long encodedBytes = ace.stop_encoder();
for(unsigned long i = 0; i < encodedBytes; ++i)
{
bstream.WriteUChar8Bin(m_bufferAC[i]);
}
}
bstream.WriteUInt32Bin(start, bstream.GetSize() - start);
return O3DGC_OK;
}
O3DGCErrorCode CompressedTriangleFans::Save(BinaryStream & bstream, bool encodeTrianglesOrder, O3DGCStreamType streamType)
{
#ifdef DEBUG_VERBOSE
g_fileDebugTF = fopen("SaveIntACEGC_new.txt", "w");
#endif //DEBUG_VERBOSE
if (streamType == O3DGC_STREAM_TYPE_ASCII)
{
SaveUIntData(m_numTFANs , bstream);
SaveUIntData(m_degrees , bstream);
SaveUIntData(m_configs , bstream);
SaveBinData (m_operations, bstream);
SaveIntData (m_indices , bstream);
if (encodeTrianglesOrder)
{
SaveUIntData(m_trianglesOrder, bstream);
}
}
else
{
SaveIntACEGC(m_numTFANs , 4 , bstream);
SaveIntACEGC(m_degrees , 16, bstream);
SaveUIntAC (m_configs , 10, bstream);
SaveBinAC (m_operations, bstream);
SaveIntACEGC(m_indices , 8 , bstream);
if (encodeTrianglesOrder)
{
SaveIntACEGC(m_trianglesOrder , 16, bstream);
}
}
#ifdef DEBUG_VERBOSE
fclose(g_fileDebugTF);
#endif //DEBUG_VERBOSE
return O3DGC_OK;
}
O3DGCErrorCode LoadUIntData(Vector<long> & data,
const BinaryStream & bstream,
unsigned long & iterator)
{
bstream.ReadUInt32ASCII(iterator);
const unsigned long size = bstream.ReadUInt32ASCII(iterator);
data.Allocate(size);
data.Clear();
for(unsigned long i = 0; i < size; ++i)
{
data.PushBack(bstream.ReadUIntASCII(iterator));
}
return O3DGC_OK;
}
O3DGCErrorCode LoadIntData(Vector<long> & data,
const BinaryStream & bstream,
unsigned long & iterator)
{
bstream.ReadUInt32ASCII(iterator);
const unsigned long size = bstream.ReadUInt32ASCII(iterator);
data.Allocate(size);
data.Clear();
for(unsigned long i = 0; i < size; ++i)
{
data.PushBack(bstream.ReadIntASCII(iterator));
}
return O3DGC_OK;
}
O3DGCErrorCode LoadBinData(Vector<long> & data,
const BinaryStream & bstream,
unsigned long & iterator)
{
bstream.ReadUInt32ASCII(iterator);
const unsigned long size = bstream.ReadUInt32ASCII(iterator);
long symbol;
data.Allocate(size * O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0);
data.Clear();
for(unsigned long i = 0; i < size;)
{
symbol = bstream.ReadUCharASCII(iterator);
for(unsigned long h = 0; h < O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0; ++h)
{
data.PushBack(symbol & 1);
symbol >>= 1;
++i;
}
}
return O3DGC_OK;
}
O3DGCErrorCode LoadUIntAC(Vector<long> & data,
const unsigned long M,
const BinaryStream & bstream,
unsigned long & iterator)
{
unsigned long sizeSize = bstream.ReadUInt32Bin(iterator) - 12;
unsigned long size = bstream.ReadUInt32Bin(iterator);
if (size == 0)
{
return O3DGC_OK;
}
long minValue = bstream.ReadUInt32Bin(iterator);
unsigned char * buffer = 0;
bstream.GetBuffer(iterator, buffer);
iterator += sizeSize;
data.Allocate(size);
Arithmetic_Codec acd;
acd.set_buffer(sizeSize, buffer);
acd.start_decoder();
Adaptive_Data_Model mModelValues(M+1);
#ifdef DEBUG_VERBOSE
printf("-----------\nsize %i\n", size);
fprintf(g_fileDebugTF, "size %i\n", size);
#endif //DEBUG_VERBOSE
for(unsigned long i = 0; i < size; ++i)
{
data.PushBack(acd.decode(mModelValues)+minValue);
#ifdef DEBUG_VERBOSE
printf("%i\t%i\n", i, data[i]);
fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]);
#endif //DEBUG_VERBOSE
}
return O3DGC_OK;
}
O3DGCErrorCode LoadIntACEGC(Vector<long> & data,
const unsigned long M,
const BinaryStream & bstream,
unsigned long & iterator)
{
unsigned long sizeSize = bstream.ReadUInt32Bin(iterator) - 12;
unsigned long size = bstream.ReadUInt32Bin(iterator);
if (size == 0)
{
return O3DGC_OK;
}
long minValue = bstream.ReadUInt32Bin(iterator) - O3DGC_MAX_LONG;
unsigned char * buffer = 0;
bstream.GetBuffer(iterator, buffer);
iterator += sizeSize;
data.Allocate(size);
Arithmetic_Codec acd;
acd.set_buffer(sizeSize, buffer);
acd.start_decoder();
Adaptive_Data_Model mModelValues(M+2);
Static_Bit_Model bModel0;
Adaptive_Bit_Model bModel1;
unsigned long value;
#ifdef DEBUG_VERBOSE
printf("-----------\nsize %i\n", size);
fprintf(g_fileDebugTF, "size %i\n", size);
#endif //DEBUG_VERBOSE
for(unsigned long i = 0; i < size; ++i)
{
value = acd.decode(mModelValues);
if ( value == M)
{
value += acd.ExpGolombDecode(0, bModel0, bModel1);
}
data.PushBack(value + minValue);
#ifdef DEBUG_VERBOSE
printf("%i\t%i\n", i, data[i]);
fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]);
#endif //DEBUG_VERBOSE
}
#ifdef DEBUG_VERBOSE
fflush(g_fileDebugTF);
#endif //DEBUG_VERBOSE
return O3DGC_OK;
}
O3DGCErrorCode LoadBinAC(Vector<long> & data,
const BinaryStream & bstream,
unsigned long & iterator)
{
unsigned long sizeSize = bstream.ReadUInt32Bin(iterator) - 8;
unsigned long size = bstream.ReadUInt32Bin(iterator);
if (size == 0)
{
return O3DGC_OK;
}
unsigned char * buffer = 0;
bstream.GetBuffer(iterator, buffer);
iterator += sizeSize;
data.Allocate(size);
Arithmetic_Codec acd;
acd.set_buffer(sizeSize, buffer);
acd.start_decoder();
Adaptive_Bit_Model bModel;
#ifdef DEBUG_VERBOSE
printf("-----------\nsize %i\n", size);
fprintf(g_fileDebugTF, "size %i\n", size);
#endif //DEBUG_VERBOSE
for(unsigned long i = 0; i < size; ++i)
{
data.PushBack(acd.decode(bModel));
#ifdef DEBUG_VERBOSE
printf("%i\t%i\n", i, data[i]);
fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]);
#endif //DEBUG_VERBOSE
}
return O3DGC_OK;
}
O3DGCErrorCode CompressedTriangleFans::Load(const BinaryStream & bstream,
unsigned long & iterator,
bool decodeTrianglesOrder,
O3DGCStreamType streamType)
{
#ifdef DEBUG_VERBOSE
g_fileDebugTF = fopen("Load_new.txt", "w");
#endif //DEBUG_VERBOSE
if (streamType == O3DGC_STREAM_TYPE_ASCII)
{
LoadUIntData(m_numTFANs , bstream, iterator);
LoadUIntData(m_degrees , bstream, iterator);
LoadUIntData(m_configs , bstream, iterator);
LoadBinData (m_operations, bstream, iterator);
LoadIntData (m_indices , bstream, iterator);
if (decodeTrianglesOrder)
{
LoadUIntData(m_trianglesOrder , bstream, iterator);
}
}
else
{
LoadIntACEGC(m_numTFANs , 4 , bstream, iterator);
LoadIntACEGC(m_degrees , 16, bstream, iterator);
LoadUIntAC (m_configs , 10, bstream, iterator);
LoadBinAC (m_operations, bstream, iterator);
LoadIntACEGC(m_indices , 8 , bstream, iterator);
if (decodeTrianglesOrder)
{
LoadIntACEGC(m_trianglesOrder , 16, bstream, iterator);
}
}
#ifdef DEBUG_VERBOSE
fclose(g_fileDebugTF);
#endif //DEBUG_VERBOSE
return O3DGC_OK;
}
}

View File

@@ -0,0 +1,291 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_TRIANGLE_FANS_H
#define O3DGC_TRIANGLE_FANS_H
#include "o3dgcCommon.h"
#include "o3dgcVector.h"
#include "o3dgcBinaryStream.h"
namespace o3dgc
{
const long O3DGC_TFANS_MIN_SIZE_ALLOCATED_VERTICES_BUFFER = 128;
const long O3DGC_TFANS_MIN_SIZE_TFAN_SIZE_BUFFER = 8;
class CompressedTriangleFans
{
public:
//! Constructor.
CompressedTriangleFans(void)
{
m_streamType = O3DGC_STREAM_TYPE_UNKOWN;
m_bufferAC = 0;
m_sizeBufferAC = 0;
};
//! Destructor.
~CompressedTriangleFans(void)
{
delete [] m_bufferAC;
};
O3DGCStreamType GetStreamType() const { return m_streamType; }
void SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; }
O3DGCErrorCode Allocate(long numVertices, long numTriangles)
{
assert(numVertices > 0);
m_numTFANs.Allocate(numVertices);
m_degrees.Allocate(2*numVertices);
m_configs.Allocate(2*numVertices);
m_operations.Allocate(2*numVertices);
m_indices.Allocate(2*numVertices);
m_trianglesOrder.Allocate(numTriangles);
Clear();
return O3DGC_OK;
}
O3DGCErrorCode PushNumTFans(long numTFans)
{
m_numTFANs.PushBack(numTFans);
return O3DGC_OK;
}
long ReadNumTFans(unsigned long & iterator) const
{
assert(iterator < m_numTFANs.GetSize());
return m_numTFANs[iterator++];
}
O3DGCErrorCode PushDegree(long degree)
{
m_degrees.PushBack(degree);
return O3DGC_OK;
}
long ReadDegree(unsigned long & iterator) const
{
assert(iterator < m_degrees.GetSize());
return m_degrees[iterator++];
}
O3DGCErrorCode PushConfig(long config)
{
m_configs.PushBack(config);
return O3DGC_OK;
}
long ReadConfig(unsigned long & iterator) const
{
assert(iterator < m_configs.GetSize());
return m_configs[iterator++];
}
O3DGCErrorCode PushOperation(long op)
{
m_operations.PushBack(op);
return O3DGC_OK;
}
long ReadOperation(unsigned long & iterator) const
{
assert(iterator < m_operations.GetSize());
return m_operations[iterator++];
}
O3DGCErrorCode PushIndex(long index)
{
m_indices.PushBack(index);
return O3DGC_OK;
}
long ReadIndex(unsigned long & iterator) const
{
assert(iterator < m_indices.GetSize());
return m_indices[iterator++];
}
O3DGCErrorCode PushTriangleIndex(long index)
{
m_trianglesOrder.PushBack(IntToUInt(index));
return O3DGC_OK;
}
long ReadTriangleIndex(unsigned long & iterator) const
{
assert(iterator < m_trianglesOrder.GetSize());
return UIntToInt(m_trianglesOrder[iterator++]);
}
O3DGCErrorCode Clear()
{
m_numTFANs.Clear();
m_degrees.Clear();
m_configs.Clear();
m_operations.Clear();
m_indices.Clear();
return O3DGC_OK;
}
O3DGCErrorCode Save(BinaryStream & bstream,
bool encodeTrianglesOrder,
O3DGCStreamType streamType);
O3DGCErrorCode Load(const BinaryStream & bstream,
unsigned long & iterator,
bool decodeTrianglesOrder,
O3DGCStreamType streamType);
private:
O3DGCErrorCode SaveBinAC(const Vector<long> & data,
BinaryStream & bstream);
O3DGCErrorCode SaveUIntAC(const Vector<long> & data,
const unsigned long M,
BinaryStream & bstream);
O3DGCErrorCode SaveIntACEGC(const Vector<long> & data,
const unsigned long M,
BinaryStream & bstream);
Vector<long> m_numTFANs;
Vector<long> m_degrees;
Vector<long> m_configs;
Vector<long> m_operations;
Vector<long> m_indices;
Vector<long> m_trianglesOrder;
unsigned char * m_bufferAC;
unsigned long m_sizeBufferAC;
O3DGCStreamType m_streamType;
};
//!
class TriangleFans
{
public:
//! Constructor.
TriangleFans(long sizeTFAN = O3DGC_TFANS_MIN_SIZE_TFAN_SIZE_BUFFER,
long verticesSize = O3DGC_TFANS_MIN_SIZE_ALLOCATED_VERTICES_BUFFER)
{
assert(sizeTFAN > 0);
assert(verticesSize > 0);
m_numTFANs = 0;
m_numVertices = 0;
m_verticesAllocatedSize = verticesSize;
m_sizeTFANAllocatedSize = sizeTFAN;
m_sizeTFAN = new long [m_sizeTFANAllocatedSize];
m_vertices = new long [m_verticesAllocatedSize];
};
//! Destructor.
~TriangleFans(void)
{
delete [] m_vertices;
delete [] m_sizeTFAN;
};
O3DGCErrorCode Allocate(long sizeTFAN, long verticesSize)
{
assert(sizeTFAN > 0);
assert(verticesSize > 0);
m_numTFANs = 0;
m_numVertices = 0;
if (m_verticesAllocatedSize < verticesSize)
{
delete [] m_vertices;
m_verticesAllocatedSize = verticesSize;
m_vertices = new long [m_verticesAllocatedSize];
}
if (m_sizeTFANAllocatedSize < sizeTFAN)
{
delete [] m_sizeTFAN;
m_sizeTFANAllocatedSize = sizeTFAN;
m_sizeTFAN = new long [m_sizeTFANAllocatedSize];
}
return O3DGC_OK;
};
O3DGCErrorCode Clear()
{
m_numTFANs = 0;
m_numVertices = 0;
return O3DGC_OK;
}
O3DGCErrorCode AddVertex(long vertex)
{
assert(m_numTFANs >= 0);
assert(m_numTFANs < m_sizeTFANAllocatedSize);
assert(m_numVertices >= 0);
++m_numVertices;
if (m_numVertices == m_verticesAllocatedSize)
{
m_verticesAllocatedSize *= 2;
long * tmp = m_vertices;
m_vertices = new long [m_verticesAllocatedSize];
memcpy(m_vertices, tmp, sizeof(long) * m_numVertices);
delete [] tmp;
}
m_vertices[m_numVertices-1] = vertex;
++m_sizeTFAN[m_numTFANs-1];
return O3DGC_OK;
}
O3DGCErrorCode AddTFAN()
{
assert(m_numTFANs >= 0);
++m_numTFANs;
if (m_numTFANs == m_sizeTFANAllocatedSize)
{
m_sizeTFANAllocatedSize *= 2;
long * tmp = m_sizeTFAN;
m_sizeTFAN = new long [m_sizeTFANAllocatedSize];
memcpy(m_sizeTFAN, tmp, sizeof(long) * m_numTFANs);
delete [] tmp;
}
m_sizeTFAN[m_numTFANs-1] = (m_numTFANs > 1) ? m_sizeTFAN[m_numTFANs-2] : 0;
return O3DGC_OK;
}
long Begin(long tfan) const
{
assert(tfan < m_numTFANs);
assert(tfan >= 0);
return (tfan>0)?m_sizeTFAN[tfan-1]:0;
}
long End(long tfan) const
{
assert(tfan < m_numTFANs);
assert(tfan >= 0);
return m_sizeTFAN[tfan];
}
long GetVertex(long vertex) const
{
assert(vertex < m_numVertices);
assert(vertex >= 0);
return m_vertices[vertex];
}
long GetTFANSize(long tfan) const
{
return End(tfan) - Begin(tfan);
}
long GetNumTFANs() const
{
return m_numTFANs;
}
long GetNumVertices() const
{
return m_numVertices;
}
private:
long m_verticesAllocatedSize;
long m_sizeTFANAllocatedSize;
long m_numTFANs;
long m_numVertices;
long * m_vertices;
long * m_sizeTFAN;
};
}
#endif // O3DGC_TRIANGLE_FANS_H

View File

@@ -0,0 +1,133 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_TRIANGLE_LIST_DECODER_H
#define O3DGC_TRIANGLE_LIST_DECODER_H
#include "o3dgcCommon.h"
#include "o3dgcTriangleFans.h"
#include "o3dgcBinaryStream.h"
#include "o3dgcAdjacencyInfo.h"
namespace o3dgc
{
//!
template <class T>
class TriangleListDecoder
{
public:
//! Constructor.
TriangleListDecoder(void)
{
m_vertexCount = 0;
m_triangleCount = 0;
m_numTriangles = 0;
m_numVertices = 0;
m_triangles = 0;
m_numConqueredTriangles = 0;
m_numVisitedVertices = 0;
m_visitedVertices = 0;
m_visitedVerticesValence = 0;
m_maxNumVertices = 0;
m_maxNumTriangles = 0;
m_itNumTFans = 0;
m_itDegree = 0;
m_itConfig = 0;
m_itOperation = 0;
m_itIndex = 0;
m_tempTriangles = 0;
m_tempTrianglesSize = 0;
m_decodeTrianglesOrder = false;
m_decodeVerticesOrder = false;
};
//! Destructor.
~TriangleListDecoder(void)
{
delete [] m_tempTriangles;
};
O3DGCStreamType GetStreamType() const { return m_streamType; }
bool GetReorderTriangles() const { return m_decodeTrianglesOrder; }
bool GetReorderVertices() const { return m_decodeVerticesOrder; }
void SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; }
const AdjacencyInfo & GetVertexToTriangle() const { return m_vertexToTriangle;}
O3DGCErrorCode Decode(T * const triangles,
const long numTriangles,
const long numVertices,
const BinaryStream & bstream,
unsigned long & iterator)
{
unsigned char compressionMask = bstream.ReadUChar(iterator, m_streamType);
m_decodeTrianglesOrder = ( (compressionMask&2) != 0);
m_decodeVerticesOrder = ( (compressionMask&1) != 0);
if (m_decodeVerticesOrder) // vertices reordering not supported
{
return O3DGC_ERROR_NON_SUPPORTED_FEATURE;
}
unsigned long maxSizeV2T = bstream.ReadUInt32(iterator, m_streamType);
Init(triangles, numTriangles, numVertices, maxSizeV2T);
m_ctfans.Load(bstream, iterator, m_decodeTrianglesOrder, m_streamType);
Decompress();
return O3DGC_OK;
}
O3DGCErrorCode Reorder();
private:
O3DGCErrorCode Init(T * const triangles,
const long numTriangles,
const long numVertices,
const long maxSizeV2T);
O3DGCErrorCode Decompress();
O3DGCErrorCode CompueLocalConnectivityInfo(const long focusVertex);
O3DGCErrorCode DecompressTFAN(const long focusVertex);
unsigned long m_itNumTFans;
unsigned long m_itDegree;
unsigned long m_itConfig;
unsigned long m_itOperation;
unsigned long m_itIndex;
long m_maxNumVertices;
long m_maxNumTriangles;
long m_numTriangles;
long m_numVertices;
long m_tempTrianglesSize;
T * m_triangles;
T * m_tempTriangles;
long m_vertexCount;
long m_triangleCount;
long m_numConqueredTriangles;
long m_numVisitedVertices;
long * m_visitedVertices;
long * m_visitedVerticesValence;
AdjacencyInfo m_vertexToTriangle;
CompressedTriangleFans m_ctfans;
TriangleFans m_tfans;
O3DGCStreamType m_streamType;
bool m_decodeTrianglesOrder;
bool m_decodeVerticesOrder;
};
}
#include "o3dgcTriangleListDecoder.inl" // template implementation
#endif // O3DGC_TRIANGLE_LIST_DECODER_H

View File

@@ -0,0 +1,364 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_TRIANGLE_LIST_DECODER_INL
#define O3DGC_TRIANGLE_LIST_DECODER_INL
namespace o3dgc
{
template<class T>
O3DGCErrorCode TriangleListDecoder<T>::Init(T * const triangles,
const long numTriangles,
const long numVertices,
const long maxSizeV2T)
{
assert(numVertices > 0);
assert(numTriangles > 0);
m_numTriangles = numTriangles;
m_numVertices = numVertices;
m_triangles = triangles;
m_vertexCount = 0;
m_triangleCount = 0;
m_itNumTFans = 0;
m_itDegree = 0;
m_itConfig = 0;
m_itOperation = 0;
m_itIndex = 0;
if (m_numVertices > m_maxNumVertices)
{
m_maxNumVertices = m_numVertices;
delete [] m_visitedVerticesValence;
delete [] m_visitedVertices;
m_visitedVerticesValence = new long [m_numVertices];
m_visitedVertices = new long [m_numVertices];
}
if (m_decodeTrianglesOrder && m_tempTrianglesSize < m_numTriangles)
{
delete [] m_tempTriangles;
m_tempTrianglesSize = m_numTriangles;
m_tempTriangles = new T [3*m_tempTrianglesSize];
}
m_ctfans.SetStreamType(m_streamType);
m_ctfans.Allocate(m_numVertices, m_numTriangles);
m_tfans.Allocate(2 * m_numVertices, 8 * m_numVertices);
// compute vertex-to-triangle adjacency information
m_vertexToTriangle.AllocateNumNeighborsArray(numVertices);
long * numNeighbors = m_vertexToTriangle.GetNumNeighborsBuffer();
for(long i = 0; i < numVertices; ++i)
{
numNeighbors[i] = maxSizeV2T;
}
m_vertexToTriangle.AllocateNeighborsArray();
m_vertexToTriangle.ClearNeighborsArray();
return O3DGC_OK;
}
template<class T>
O3DGCErrorCode TriangleListDecoder<T>::Decompress()
{
for(long focusVertex = 0; focusVertex < m_numVertices; ++focusVertex)
{
if (focusVertex == m_vertexCount)
{
m_vertexCount++; // insert focusVertex
}
CompueLocalConnectivityInfo(focusVertex);
DecompressTFAN(focusVertex);
}
return O3DGC_OK;
}
template<class T>
O3DGCErrorCode TriangleListDecoder<T>::Reorder()
{
if (m_decodeTrianglesOrder)
{
unsigned long itTriangleIndex = 0;
long prevTriangleIndex = 0;
long t;
memcpy(m_tempTriangles, m_triangles, m_numTriangles * 3 * sizeof(T));
for(long i = 0; i < m_numTriangles; ++i)
{
t = m_ctfans.ReadTriangleIndex(itTriangleIndex) + prevTriangleIndex;
assert( t >= 0 && t < m_numTriangles);
memcpy(m_triangles + 3 * t, m_tempTriangles + 3 * i, sizeof(T) * 3);
prevTriangleIndex = t + 1;
}
}
return O3DGC_OK;
}
template<class T>
O3DGCErrorCode TriangleListDecoder<T>::CompueLocalConnectivityInfo(const long focusVertex)
{
long t = 0;
long p, v;
m_numConqueredTriangles = 0;
m_numVisitedVertices = 0;
for(long i = m_vertexToTriangle.Begin(focusVertex); (t >= 0) && (i < m_vertexToTriangle.End(focusVertex)); ++i)
{
t = m_vertexToTriangle.GetNeighbor(i);
if ( t >= 0)
{
++m_numConqueredTriangles;
p = 3*t;
// extract visited vertices
for(long k = 0; k < 3; ++k)
{
v = m_triangles[p+k];
if (v > focusVertex) // vertices are insertices by increasing traversal order
{
bool foundOrInserted = false;
for (long j = 0; j < m_numVisitedVertices; ++j)
{
if (v == m_visitedVertices[j])
{
m_visitedVerticesValence[j]++;
foundOrInserted = true;
break;
}
else if (v < m_visitedVertices[j])
{
++m_numVisitedVertices;
for (long h = m_numVisitedVertices-1; h > j; --h)
{
m_visitedVertices[h] = m_visitedVertices[h-1];
m_visitedVerticesValence[h] = m_visitedVerticesValence[h-1];
}
m_visitedVertices[j] = v;
m_visitedVerticesValence[j] = 1;
foundOrInserted = true;
break;
}
}
if (!foundOrInserted)
{
m_visitedVertices[m_numVisitedVertices] = v;
m_visitedVerticesValence[m_numVisitedVertices] = 1;
m_numVisitedVertices++;
}
}
}
}
}
// re-order visited vertices by taking into account their valence (i.e., # of conquered triangles incident to each vertex)
// in order to avoid config. 9
if (m_numVisitedVertices > 2)
{
long y;
for(long x = 1; x < m_numVisitedVertices; ++x)
{
if (m_visitedVerticesValence[x] == 1)
{
y = x;
while( (y > 0) && (m_visitedVerticesValence[y] < m_visitedVerticesValence[y-1]) )
{
swap(m_visitedVerticesValence[y], m_visitedVerticesValence[y-1]);
swap(m_visitedVertices[y], m_visitedVertices[y-1]);
--y;
}
}
}
}
return O3DGC_OK;
}
template<class T>
O3DGCErrorCode TriangleListDecoder<T>::DecompressTFAN(const long focusVertex)
{
long ntfans;
long degree, config;
long op;
long index;
long k0, k1;
long b, c, t;
ntfans = m_ctfans.ReadNumTFans(m_itNumTFans);
if (ntfans > 0)
{
for(long f = 0; f != ntfans; f++)
{
m_tfans.AddTFAN();
degree = m_ctfans.ReadDegree(m_itDegree) +2 - m_numConqueredTriangles;
config = m_ctfans.ReadConfig(m_itConfig);
k0 = m_tfans.GetNumVertices();
m_tfans.AddVertex(focusVertex);
switch(config)
{
case 0:// ops: 1000001 vertices: -1 -2
m_tfans.AddVertex(m_visitedVertices[0]);
for(long u = 1; u < degree-1; u++)
{
m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
m_tfans.AddVertex(m_vertexCount++);
}
m_tfans.AddVertex(m_visitedVertices[1]);
break;
case 1: // ops: 1xxxxxx1 vertices: -1 x x x x x -2
m_tfans.AddVertex(m_visitedVertices[0]);
for(long u = 1; u < degree-1; u++)
{
op = m_ctfans.ReadOperation(m_itOperation);
if (op == 1)
{
index = m_ctfans.ReadIndex(m_itIndex);
if ( index < 0)
{
m_tfans.AddVertex(m_visitedVertices[-index-1]);
}
else
{
m_tfans.AddVertex(index + focusVertex);
}
}
else
{
m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
m_tfans.AddVertex(m_vertexCount++);
}
}
m_tfans.AddVertex(m_visitedVertices[1]);
break;
case 2: // ops: 00000001 vertices: -1
for(long u = 0; u < degree-1; u++)
{
m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
m_tfans.AddVertex(m_vertexCount++);
}
m_tfans.AddVertex(m_visitedVertices[0]);
break;
case 3: // ops: 00000001 vertices: -2
for(long u=0; u < degree-1; u++)
{
m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
m_tfans.AddVertex(m_vertexCount++);
}
m_tfans.AddVertex(m_visitedVertices[1]);
break;
case 4: // ops: 10000000 vertices: -1
m_tfans.AddVertex(m_visitedVertices[0]);
for(long u = 1; u < degree; u++)
{
m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
m_tfans.AddVertex(m_vertexCount++);
}
break;
case 5: // ops: 10000000 vertices: -2
m_tfans.AddVertex(m_visitedVertices[1]);
for(long u = 1; u < degree; u++)
{
m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
m_tfans.AddVertex(m_vertexCount++);
}
break;
case 6:// ops: 00000000 vertices:
for(long u = 0; u < degree; u++)
{
m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
m_tfans.AddVertex(m_vertexCount++);
}
break;
case 7: // ops: 1000001 vertices: -2 -1
m_tfans.AddVertex(m_visitedVertices[1]);
for(long u = 1; u < degree-1; u++)
{
m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
m_tfans.AddVertex(m_vertexCount++);
}
m_tfans.AddVertex(m_visitedVertices[0]);
break;
case 8: // ops: 1xxxxxx1 vertices: -2 x x x x x -1
m_tfans.AddVertex(m_visitedVertices[1]);
for(long u = 1; u < degree-1; u++)
{
op = m_ctfans.ReadOperation(m_itOperation);
if (op == 1)
{
index = m_ctfans.ReadIndex(m_itIndex);
if ( index < 0)
{
m_tfans.AddVertex(m_visitedVertices[-index-1]);
}
else
{
m_tfans.AddVertex(index + focusVertex);
}
}
else
{
m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
m_tfans.AddVertex(m_vertexCount++);
}
}
m_tfans.AddVertex(m_visitedVertices[0]);
break;
case 9: // general case
for(long u = 0; u < degree; u++)
{
op = m_ctfans.ReadOperation(m_itOperation);
if (op == 1)
{
index = m_ctfans.ReadIndex(m_itIndex);
if ( index < 0)
{
m_tfans.AddVertex(m_visitedVertices[-index-1]);
}
else
{
m_tfans.AddVertex(index + focusVertex);
}
}
else
{
m_visitedVertices[m_numVisitedVertices++] = m_vertexCount;
m_tfans.AddVertex(m_vertexCount++);
}
}
break;
}
//logger.write_2_log("\t degree=%i \t cas = %i\n", degree, cas);
k1 = m_tfans.GetNumVertices();
b = m_tfans.GetVertex(k0+1);
for (long k = k0+2; k < k1; k++)
{
c = m_tfans.GetVertex(k);
t = m_triangleCount*3;
m_triangles[t++] = (T) focusVertex;
m_triangles[t++] = (T) b;
m_triangles[t ] = (T) c;
m_vertexToTriangle.AddNeighbor(focusVertex, m_triangleCount);
m_vertexToTriangle.AddNeighbor(b , m_triangleCount);
m_vertexToTriangle.AddNeighbor(c , m_triangleCount);
b=c;
m_triangleCount++;
}
}
}
return O3DGC_OK;
}
}
#endif //O3DGC_TRIANGLE_LIST_DECODER_INL

View File

@@ -0,0 +1,101 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_TRIANGLE_LIST_ENCODER_H
#define O3DGC_TRIANGLE_LIST_ENCODER_H
#include "o3dgcCommon.h"
#include "o3dgcAdjacencyInfo.h"
#include "o3dgcBinaryStream.h"
#include "o3dgcFIFO.h"
#include "o3dgcTriangleFans.h"
namespace o3dgc
{
//!
template <class T>
class TriangleListEncoder
{
public:
//! Constructor.
TriangleListEncoder(void);
//! Destructor.
~TriangleListEncoder(void);
//!
O3DGCErrorCode Encode(const T * const triangles,
const unsigned long * const indexBufferIDs,
const long numTriangles,
const long numVertices,
BinaryStream & bstream);
O3DGCStreamType GetStreamType() const { return m_streamType; }
void SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; }
const long * GetInvVMap() const { return m_invVMap;}
const long * GetInvTMap() const { return m_invTMap;}
const long * GetVMap() const { return m_vmap;}
const long * GetTMap() const { return m_tmap;}
const AdjacencyInfo & GetVertexToTriangle() const { return m_vertexToTriangle;}
private:
O3DGCErrorCode Init(const T * const triangles,
long numTriangles,
long numVertices);
O3DGCErrorCode CompueLocalConnectivityInfo(const long focusVertex);
O3DGCErrorCode ProcessVertex( long focusVertex);
O3DGCErrorCode ComputeTFANDecomposition(const long focusVertex);
O3DGCErrorCode CompressTFAN(const long focusVertex);
long m_vertexCount;
long m_triangleCount;
long m_maxNumVertices;
long m_maxNumTriangles;
long m_numNonConqueredTriangles;
long m_numConqueredTriangles;
long m_numVisitedVertices;
long m_numTriangles;
long m_numVertices;
long m_maxSizeVertexToTriangle;
T const * m_triangles;
long * m_vtags;
long * m_ttags;
long * m_vmap;
long * m_invVMap;
long * m_tmap;
long * m_invTMap;
long * m_count;
long * m_nonConqueredTriangles;
long * m_nonConqueredEdges;
long * m_visitedVertices;
long * m_visitedVerticesValence;
FIFO<long> m_vfifo;
AdjacencyInfo m_vertexToTriangle;
AdjacencyInfo m_triangleToTriangle;
AdjacencyInfo m_triangleToTriangleInv;
TriangleFans m_tfans;
CompressedTriangleFans m_ctfans;
O3DGCStreamType m_streamType;
};
}
#include "o3dgcTriangleListEncoder.inl" // template implementation
#endif // O3DGC_TRIANGLE_LIST_ENCODER_H

View File

@@ -0,0 +1,719 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_TRIANGLE_LIST_ENCODER_INL
#define O3DGC_TRIANGLE_LIST_ENCODER_INL
namespace o3dgc
{
// extract opposite edge
template <class T>
inline void CompueOppositeEdge(const long focusVertex,
const T * triangle,
long & a, long & b)
{
if ((long) triangle[0] == focusVertex)
{
a = triangle[1];
b = triangle[2];
}
else if ((long) triangle[1] == focusVertex)
{
a = triangle[2];
b = triangle[0];
}
else
{
a = triangle[0];
b = triangle[1];
}
}
inline bool IsCase0(long degree, long numIndices, const long * const ops, const long * const indices)
{
// ops: 1000001 vertices: -1 -2
if ((numIndices != 2) || (degree < 2)) {
return false;
}
if ((indices[0] != -1) ||(indices[1] != -2) ||
(ops[0] != 1) ||(ops[degree-1] != 1) ) return false;
for (long u = 1; u < degree-1; u++) {
if (ops[u] != 0) return false;
}
return true;
}
inline bool IsCase1(long degree, long numIndices, const long * const ops, const long * const indices)
{
// ops: 1xxxxxx1 indices: -1 x x x x x -2
if ((degree < 2) || (numIndices < 1))
{
return false;
}
if ((indices[0] != -1) ||(indices[numIndices-1] != -2) ||
(ops[0] != 1) ||(ops[degree-1] != 1) ) return false;
return true;
}
inline bool IsCase2(long degree, long numIndices, const long * const ops, const long * const indices)
{
// ops: 00000001 indices: -1
if ((degree < 2) || (numIndices!= 1))
{
return false;
}
if ((indices[0] != -1) || (ops[degree-1] != 1) ) return false;
for (long u = 0; u < degree-1; u++) {
if (ops[u] != 0) return false;
}
return true;
}
inline bool IsCase3(long degree, long numIndices, const long * const ops, const long * const indices)
{
// ops: 00000001 indices: -2
if ((degree < 2) || (numIndices!= 1))
{
return false;
}
if ((indices[0] != -2) || (ops[degree-1] != 1) ) return false;
for (long u = 0; u < degree-1; u++) {
if (ops[u] != 0) return false;
}
return true;
}
inline bool IsCase4(long degree, long numIndices, const long * const ops, const long * const indices)
{
// ops: 10000000 indices: -1
if ((degree < 2) || (numIndices!= 1))
{
return false;
}
if ((indices[0] != -1) || (ops[0] != 1) ) return false;
for (long u = 1; u < degree; u++)
{
if (ops[u] != 0) return false;
}
return true;
}
inline bool IsCase5(long degree, long numIndices, const long * const ops, const long * const indices)
{
// ops: 10000000 indices: -2
if ((degree < 2) || (numIndices!= 1))
{
return false;
}
if ((indices[0] != -2) || (ops[0] != 1) ) return false;
for (long u = 1; u < degree; u++) {
if (ops[u] != 0) return false;
}
return true;
}
inline bool IsCase6(long degree, long numIndices, const long * const ops, const long * const /*indices*/)
{
// ops: 0000000 indices:
if (numIndices!= 0)
{
return false;
}
for (long u = 0; u < degree; u++)
{
if (ops[u] != 0) return false;
}
return true;
}
inline bool IsCase7(long degree, long numIndices, const long * const ops, const long * const indices)
{
// ops: 1000001 indices: -2 -1
if ((numIndices!= 2) || (degree < 2))
{
return false;
}
if ((indices[0] != -2) ||(indices[1] != -1) ||
(ops[0] != 1) ||(ops[degree-1] != 1) ) return false;
for (long u = 1; u < degree-1; u++)
{
if (ops[u] != 0) return false;
}
return true;
}
inline bool IsCase8(long degree, long numIndices, const long * const ops, const long * const indices)
{
// ops: 1xxxxxx1 indices: -1 x x x x x -2
if ((degree < 2) || (numIndices < 1))
{
return false;
}
if ((indices[0] != -2) ||(indices[numIndices-1] != -1) ||
(ops[0] != 1) ||(ops[degree-1] != 1) ) return false;
return true;
}
template <class T>
TriangleListEncoder<T>::TriangleListEncoder(void)
{
m_vtags = 0;
m_ttags = 0;
m_tmap = 0;
m_vmap = 0;
m_count = 0;
m_invVMap = 0;
m_invTMap = 0;
m_nonConqueredTriangles = 0;
m_nonConqueredEdges = 0;
m_visitedVertices = 0;
m_visitedVerticesValence = 0;
m_vertexCount = 0;
m_triangleCount = 0;
m_maxNumVertices = 0;
m_maxNumTriangles = 0;
m_numTriangles = 0;
m_numVertices = 0;
m_triangles = 0;
m_maxSizeVertexToTriangle = 0;
m_streamType = O3DGC_STREAM_TYPE_UNKOWN;
}
template <class T>
TriangleListEncoder<T>::~TriangleListEncoder()
{
delete [] m_vtags;
delete [] m_vmap;
delete [] m_invVMap;
delete [] m_invTMap;
delete [] m_visitedVerticesValence;
delete [] m_visitedVertices;
delete [] m_ttags;
delete [] m_tmap;
delete [] m_count;
delete [] m_nonConqueredTriangles;
delete [] m_nonConqueredEdges;
}
template <class T>
O3DGCErrorCode TriangleListEncoder<T>::Init(const T * const triangles,
long numTriangles,
long numVertices)
{
assert(numVertices > 0);
assert(numTriangles > 0);
m_numTriangles = numTriangles;
m_numVertices = numVertices;
m_triangles = triangles;
m_vertexCount = 0;
m_triangleCount = 0;
if (m_numVertices > m_maxNumVertices)
{
delete [] m_vtags;
delete [] m_vmap;
delete [] m_invVMap;
delete [] m_visitedVerticesValence;
delete [] m_visitedVertices;
m_maxNumVertices = m_numVertices;
m_vtags = new long [m_numVertices];
m_vmap = new long [m_numVertices];
m_invVMap = new long [m_numVertices];
m_visitedVerticesValence = new long [m_numVertices];
m_visitedVertices = new long [m_numVertices];
}
if (m_numTriangles > m_maxNumTriangles)
{
delete [] m_ttags;
delete [] m_tmap;
delete [] m_invTMap;
delete [] m_nonConqueredTriangles;
delete [] m_nonConqueredEdges;
delete [] m_count;
m_maxNumTriangles = m_numTriangles;
m_ttags = new long [m_numTriangles];
m_tmap = new long [m_numTriangles];
m_invTMap = new long [m_numTriangles];
m_count = new long [m_numTriangles+1];
m_nonConqueredTriangles = new long [m_numTriangles];
m_nonConqueredEdges = new long [2*m_numTriangles];
}
memset(m_vtags , 0x00, sizeof(long) * m_numVertices );
memset(m_vmap , 0xFF, sizeof(long) * m_numVertices );
memset(m_invVMap, 0xFF, sizeof(long) * m_numVertices );
memset(m_ttags , 0x00, sizeof(long) * m_numTriangles);
memset(m_tmap , 0xFF, sizeof(long) * m_numTriangles);
memset(m_invTMap, 0xFF, sizeof(long) * m_numTriangles);
memset(m_count , 0x00, sizeof(long) * (m_numTriangles+1));
m_vfifo.Allocate(m_numVertices);
m_ctfans.SetStreamType(m_streamType);
m_ctfans.Allocate(m_numVertices, m_numTriangles);
// compute vertex-to-triangle adjacency information
m_vertexToTriangle.AllocateNumNeighborsArray(numVertices);
m_vertexToTriangle.ClearNumNeighborsArray();
long * numNeighbors = m_vertexToTriangle.GetNumNeighborsBuffer();
for(long i = 0, t = 0; i < m_numTriangles; ++i, t+=3)
{
++numNeighbors[ triangles[t ] ];
++numNeighbors[ triangles[t+1] ];
++numNeighbors[ triangles[t+2] ];
}
m_maxSizeVertexToTriangle = 0;
for(long i = 0; i < numVertices; ++i)
{
if (m_maxSizeVertexToTriangle < numNeighbors[i])
{
m_maxSizeVertexToTriangle = numNeighbors[i];
}
}
m_vertexToTriangle.AllocateNeighborsArray();
m_vertexToTriangle.ClearNeighborsArray();
for(long i = 0, t = 0; i < m_numTriangles; ++i, t+=3)
{
m_vertexToTriangle.AddNeighbor(triangles[t ], i);
m_vertexToTriangle.AddNeighbor(triangles[t+1], i);
m_vertexToTriangle.AddNeighbor(triangles[t+2], i);
}
return O3DGC_OK;
}
template <class T>
O3DGCErrorCode TriangleListEncoder<T>::Encode(const T * const triangles,
const unsigned long * const indexBufferIDs,
const long numTriangles,
const long numVertices,
BinaryStream & bstream)
{
assert(numVertices > 0);
assert(numTriangles > 0);
Init(triangles, numTriangles, numVertices);
unsigned char mask = 0;
bool encodeTrianglesOrder = (indexBufferIDs != 0);
if (encodeTrianglesOrder)
{
long numBufferIDs = 0;
for (long t = 0; t < numTriangles; t++)
{
if (numBufferIDs <= (long) indexBufferIDs[t])
{
++numBufferIDs;
assert(numBufferIDs <= numTriangles);
}
++m_count[indexBufferIDs[t]+1];
}
for (long i = 2; i <= numBufferIDs; i++)
{
m_count[i] += m_count[i-1];
}
mask += 2; // preserved triangles order
}
bstream.WriteUChar(mask, m_streamType);
bstream.WriteUInt32(m_maxSizeVertexToTriangle, m_streamType);
long v0;
for (long v = 0; v < m_numVertices; v++)
{
if (!m_vtags[v])
{
m_vfifo.PushBack(v);
m_vtags[v] = 1;
m_vmap[v] = m_vertexCount++;
m_invVMap[m_vmap[v]] = v;
while (m_vfifo.GetSize() > 0 )
{
v0 = m_vfifo.PopFirst();
ProcessVertex(v0);
}
}
}
if (encodeTrianglesOrder)
{
long t, prev = 0;
long pred;
for (long i = 0; i < numTriangles; ++i)
{
t = m_invTMap[i];
m_tmap[t] = m_count[ indexBufferIDs[t] ]++;
pred = m_tmap[t] - prev;
m_ctfans.PushTriangleIndex(pred);
prev = m_tmap[t] + 1;
}
for (long t = 0; t < numTriangles; ++t)
{
m_invTMap[m_tmap[t]] = t;
}
}
m_ctfans.Save(bstream, encodeTrianglesOrder, m_streamType);
return O3DGC_OK;
}
template <class T>
O3DGCErrorCode TriangleListEncoder<T>::CompueLocalConnectivityInfo(const long focusVertex)
{
long t, v, p;
m_numNonConqueredTriangles = 0;
m_numConqueredTriangles = 0;
m_numVisitedVertices = 0;
for(long i = m_vertexToTriangle.Begin(focusVertex); i < m_vertexToTriangle.End(focusVertex); ++i)
{
t = m_vertexToTriangle.GetNeighbor(i);
if ( m_ttags[t] == 0) // non-processed triangle
{
m_nonConqueredTriangles[m_numNonConqueredTriangles] = t;
CompueOppositeEdge( focusVertex,
m_triangles + (3*t),
m_nonConqueredEdges[m_numNonConqueredTriangles*2],
m_nonConqueredEdges[m_numNonConqueredTriangles*2+1]);
++m_numNonConqueredTriangles;
}
else // triangle already processed
{
m_numConqueredTriangles++;
p = 3*t;
// extract visited vertices
for(long k = 0; k < 3; ++k)
{
v = m_triangles[p+k];
if (m_vmap[v] > m_vmap[focusVertex]) // vertices are insertices by increasing traversal order
{
bool foundOrInserted = false;
for (long j = 0; j < m_numVisitedVertices; ++j)
{
if (m_vmap[v] == m_visitedVertices[j])
{
m_visitedVerticesValence[j]++;
foundOrInserted = true;
break;
}
else if (m_vmap[v] < m_visitedVertices[j])
{
++m_numVisitedVertices;
for (long h = m_numVisitedVertices-1; h > j; --h)
{
m_visitedVertices[h] = m_visitedVertices[h-1];
m_visitedVerticesValence[h] = m_visitedVerticesValence[h-1];
}
m_visitedVertices[j] = m_vmap[v];
m_visitedVerticesValence[j] = 1;
foundOrInserted = true;
break;
}
}
if (!foundOrInserted)
{
m_visitedVertices[m_numVisitedVertices] = m_vmap[v];
m_visitedVerticesValence[m_numVisitedVertices] = 1;
m_numVisitedVertices++;
}
}
}
}
}
// re-order visited vertices by taking into account their valence (i.e., # of conquered triangles incident to each vertex)
// in order to avoid config. 9
if (m_numVisitedVertices > 2)
{
long y;
for(long x = 1; x < m_numVisitedVertices; ++x)
{
if (m_visitedVerticesValence[x] == 1)
{
y = x;
while( (y > 0) && (m_visitedVerticesValence[y] < m_visitedVerticesValence[y-1]) )
{
swap(m_visitedVerticesValence[y], m_visitedVerticesValence[y-1]);
swap(m_visitedVertices[y], m_visitedVertices[y-1]);
--y;
}
}
}
}
if (m_numNonConqueredTriangles > 0)
{
// compute triangle-to-triangle adjacency information
m_triangleToTriangle.AllocateNumNeighborsArray(m_numNonConqueredTriangles);
m_triangleToTriangle.ClearNumNeighborsArray();
m_triangleToTriangleInv.AllocateNumNeighborsArray(m_numNonConqueredTriangles);
m_triangleToTriangleInv.ClearNumNeighborsArray();
long * const numNeighbors = m_triangleToTriangle.GetNumNeighborsBuffer();
long * const invNumNeighbors = m_triangleToTriangleInv.GetNumNeighborsBuffer();
for(long i = 0; i < m_numNonConqueredTriangles; ++i)
{
for(long j = i+1; j < m_numNonConqueredTriangles; ++j)
{
if (m_nonConqueredEdges[2*i+1] == m_nonConqueredEdges[2*j]) // edge i is connected to edge j
{
++numNeighbors[i];
++invNumNeighbors[j];
}
if (m_nonConqueredEdges[2*i] == m_nonConqueredEdges[2*j+1]) // edge i is connected to edge j
{
++numNeighbors[j];
++invNumNeighbors[i];
}
}
}
m_triangleToTriangle.AllocateNeighborsArray();
m_triangleToTriangle.ClearNeighborsArray();
m_triangleToTriangleInv.AllocateNeighborsArray();
m_triangleToTriangleInv.ClearNeighborsArray();
for(long i = 0; i < m_numNonConqueredTriangles; ++i)
{
for(long j = 1; j < m_numNonConqueredTriangles; ++j)
{
if (m_nonConqueredEdges[2*i+1] == m_nonConqueredEdges[2*j]) // edge i is connected to edge j
{
m_triangleToTriangle.AddNeighbor(i, j);
m_triangleToTriangleInv.AddNeighbor(j, i);
}
if (m_nonConqueredEdges[2*i] == m_nonConqueredEdges[2*j+1]) // edge i is connected to edge j
{
m_triangleToTriangle.AddNeighbor(j, i);
m_triangleToTriangleInv.AddNeighbor(i, j);
}
}
}
}
return O3DGC_OK;
}
template <class T>
O3DGCErrorCode TriangleListEncoder<T>::ComputeTFANDecomposition(const long focusVertex)
{
long processedTriangles = 0;
long minNumInputEdges;
long numInputEdges;
long indexSeedTriangle;
long seedTriangle;
long currentIndex;
long currentTriangle;
long i0, i1, index;
m_tfans.Clear();
while (processedTriangles != m_numNonConqueredTriangles)
{
// find non processed triangle with lowest number of inputs
minNumInputEdges = m_numTriangles;
indexSeedTriangle = -1;
for(long i = 0; i < m_numNonConqueredTriangles; ++i)
{
numInputEdges = m_triangleToTriangleInv.GetNumNeighbors(i);
if ( !m_ttags[m_nonConqueredTriangles[i]] &&
numInputEdges < minNumInputEdges )
{
minNumInputEdges = numInputEdges;
indexSeedTriangle = i;
if (minNumInputEdges == 0) // found boundary triangle
{
break;
}
}
}
assert(indexSeedTriangle >= 0);
seedTriangle = m_nonConqueredTriangles[indexSeedTriangle];
m_tfans.AddTFAN();
m_tfans.AddVertex( focusVertex );
m_tfans.AddVertex( m_nonConqueredEdges[indexSeedTriangle*2] );
m_tfans.AddVertex( m_nonConqueredEdges[indexSeedTriangle*2 + 1] );
m_ttags[ seedTriangle ] = 1; // mark triangle as processed
m_tmap[seedTriangle] = m_triangleCount++;
m_invTMap[m_tmap[seedTriangle]] = seedTriangle;
++processedTriangles;
currentIndex = indexSeedTriangle;
currentTriangle = seedTriangle;
do
{
// find next triangle
i0 = m_triangleToTriangle.Begin(currentIndex);
i1 = m_triangleToTriangle.End(currentIndex);
currentIndex = -1;
for(long i = i0; i < i1; ++i)
{
index = m_triangleToTriangle.GetNeighbor(i);
currentTriangle = m_nonConqueredTriangles[index];
if ( !m_ttags[currentTriangle] )
{
currentIndex = index;
m_tfans.AddVertex( m_nonConqueredEdges[currentIndex*2+1] );
m_ttags[currentTriangle] = 1; // mark triangle as processed
m_tmap [currentTriangle] = m_triangleCount++;
m_invTMap[m_tmap [currentTriangle]] = currentTriangle;
++processedTriangles;
break;
}
}
} while (currentIndex != -1);
}
return O3DGC_OK;
}
template <class T>
O3DGCErrorCode TriangleListEncoder<T>::CompressTFAN(const long focusVertex)
{
m_ctfans.PushNumTFans(m_tfans.GetNumTFANs());
const long ntfans = m_tfans.GetNumTFANs();
long degree;
long k0, k1;
long v0;
long ops[O3DGC_MAX_TFAN_SIZE];
long indices[O3DGC_MAX_TFAN_SIZE];
long numOps;
long numIndices;
long pos;
long found;
if (m_tfans.GetNumTFANs() > 0)
{
for(long f = 0; f != ntfans; f++)
{
degree = m_tfans.GetTFANSize(f) - 1;
m_ctfans.PushDegree(degree-2+ m_numConqueredTriangles);
numOps = 0;
numIndices = 0;
k0 = 1 + m_tfans.Begin(f);
k1 = m_tfans.End(f);
for(long k = k0; k < k1; k++)
{
v0 = m_tfans.GetVertex(k);
if (m_vtags[v0] == 0)
{
ops[numOps++] = 0;
m_vtags[v0] = 1;
m_vmap[v0] = m_vertexCount++;
m_invVMap[m_vmap[v0]] = v0;
m_vfifo.PushBack(v0);
m_visitedVertices[m_numVisitedVertices++] = m_vmap[v0];
}
else
{
ops[numOps++] = 1;
pos = 0;
found = 0;
for(long u=0; u < m_numVisitedVertices; ++u)
{
pos++;
if (m_visitedVertices[u] == m_vmap[v0])
{
found = 1;
break;
}
}
if (found == 1)
{
indices[numIndices++] = -pos;
}
else
{
indices[numIndices++] = m_vmap[v0] - m_vmap[focusVertex];
}
}
}
//-----------------------------------------------
if (IsCase0(degree, numIndices, ops, indices))
{
// ops: 1000001 vertices: -1 -2
m_ctfans.PushConfig(0);
}
else if (IsCase1(degree, numIndices, ops, indices))
{
// ops: 1xxxxxx1 vertices: -1 x x x x x -2
long u = 1;
for(u = 1; u < degree-1; u++)
{
m_ctfans.PushOperation(ops[u]);
}
for(u =1; u < numIndices-1; u++)
{
m_ctfans.PushIndex(indices[u]);
}
m_ctfans.PushConfig(1);
}
else if (IsCase2(degree, numIndices, ops, indices))
{
// ops: 00000001 vertices: -1
m_ctfans.PushConfig(2);
}
else if (IsCase3(degree, numIndices, ops, indices))
{
// ops: 00000001 vertices: -2
m_ctfans.PushConfig(3);
}
else if (IsCase4(degree, numIndices, ops, indices))
{
// ops: 10000000 vertices: -1
m_ctfans.PushConfig(4);
}
else if (IsCase5(degree, numIndices, ops, indices))
{
// ops: 10000000 vertices: -2
m_ctfans.PushConfig(5);
}
else if (IsCase6(degree, numIndices, ops, indices))
{
// ops: 00000000 vertices:
m_ctfans.PushConfig(6);
}
else if (IsCase7(degree, numIndices, ops, indices))
{
// ops: 1000001 vertices: -1 -2
m_ctfans.PushConfig(7);
}
else if (IsCase8(degree, numIndices, ops, indices))
{
// ops: 1xxxxxx1 vertices: -2 x x x x x -1
long u = 1;
for(u =1; u < degree-1; u++)
{
m_ctfans.PushOperation(ops[u]);
}
for(u =1; u < numIndices-1; u++)
{
m_ctfans.PushIndex(indices[u]);
}
m_ctfans.PushConfig(8);
}
else
{
long u = 0;
for(u =0; u < degree; u++)
{
m_ctfans.PushOperation(ops[u]);
}
for(u =0; u < numIndices; u++)
{
m_ctfans.PushIndex(indices[u]);
}
m_ctfans.PushConfig(9);
}
}
}
return O3DGC_OK;
}
template <class T>
O3DGCErrorCode TriangleListEncoder<T>::ProcessVertex(const long focusVertex)
{
CompueLocalConnectivityInfo(focusVertex);
ComputeTFANDecomposition(focusVertex);
CompressTFAN(focusVertex);
return O3DGC_OK;
}
}
#endif //O3DGC_TRIANGLE_LIST_ENCODER_INL

View File

@@ -0,0 +1,184 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_VECTOR_H
#define O3DGC_VECTOR_H
#include "o3dgcCommon.h"
namespace o3dgc
{
const unsigned long O3DGC_DEFAULT_VECTOR_SIZE = 32;
//!
template < typename T > class Vector
{
public:
//! Constructor.
Vector()
{
m_allocated = 0;
m_size = 0;
m_buffer = 0;
};
//! Destructor.
~Vector(void)
{
delete [] m_buffer;
};
T & operator[](unsigned long i)
{
return m_buffer[i];
}
const T & operator[](unsigned long i) const
{
return m_buffer[i];
}
void Allocate(unsigned long size)
{
if (size > m_allocated)
{
m_allocated = size;
T * tmp = new T [m_allocated];
if (m_size > 0)
{
memcpy(tmp, m_buffer, m_size * sizeof(T) );
delete [] m_buffer;
}
m_buffer = tmp;
}
};
void PushBack(const T & value)
{
if (m_size == m_allocated)
{
m_allocated *= 2;
if (m_allocated < O3DGC_DEFAULT_VECTOR_SIZE)
{
m_allocated = O3DGC_DEFAULT_VECTOR_SIZE;
}
T * tmp = new T [m_allocated];
if (m_size > 0)
{
memcpy(tmp, m_buffer, m_size * sizeof(T) );
delete [] m_buffer;
}
m_buffer = tmp;
}
assert(m_size < m_allocated);
m_buffer[m_size++] = value;
}
const T * GetBuffer() const { return m_buffer;};
T * GetBuffer() { return m_buffer;};
unsigned long GetSize() const { return m_size;};
void SetSize(unsigned long size)
{
assert(size <= m_allocated);
m_size = size;
};
unsigned long GetAllocatedSize() const { return m_allocated;};
void Clear(){ m_size = 0;};
private:
T * m_buffer;
unsigned long m_allocated;
unsigned long m_size;
};
//! Vector dim 3.
template < typename T > class Vec3
{
public:
T & operator[](unsigned long i) { return m_data[i];}
const T & operator[](unsigned long i) const { return m_data[i];}
T & X();
T & Y();
T & Z();
const T & X() const;
const T & Y() const;
const T & Z() const;
double GetNorm() const;
void operator= (const Vec3 & rhs);
void operator+=(const Vec3 & rhs);
void operator-=(const Vec3 & rhs);
void operator-=(T a);
void operator+=(T a);
void operator/=(T a);
void operator*=(T a);
Vec3 operator^ (const Vec3 & rhs) const;
T operator* (const Vec3 & rhs) const;
Vec3 operator+ (const Vec3 & rhs) const;
Vec3 operator- (const Vec3 & rhs) const;
Vec3 operator- () const;
Vec3 operator* (T rhs) const;
Vec3 operator/ (T rhs) const;
Vec3();
Vec3(T a);
Vec3(T x, T y, T z);
Vec3(const Vec3 & rhs);
~Vec3(void);
private:
T m_data[3];
};
//! Vector dim 2.
template < typename T > class Vec2
{
public:
T & operator[](unsigned long i) { return m_data[i];}
const T & operator[](unsigned long i) const { return m_data[i];}
T & X();
T & Y();
const T & X() const;
const T & Y() const;
double GetNorm() const;
void operator= (const Vec2 & rhs);
void operator+=(const Vec2 & rhs);
void operator-=(const Vec2 & rhs);
void operator-=(T a);
void operator+=(T a);
void operator/=(T a);
void operator*=(T a);
T operator^ (const Vec2 & rhs) const;
T operator* (const Vec2 & rhs) const;
Vec2 operator+ (const Vec2 & rhs) const;
Vec2 operator- (const Vec2 & rhs) const;
Vec2 operator- () const;
Vec2 operator* (T rhs) const;
Vec2 operator/ (T rhs) const;
Vec2();
Vec2(T a);
Vec2(T x, T y);
Vec2(const Vec2 & rhs);
~Vec2(void);
private:
T m_data[2];
};
}
#include "o3dgcVector.inl" // template implementation
#endif // O3DGC_VECTOR_H

View File

@@ -0,0 +1,317 @@
/*
Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc.
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.
*/
#pragma once
#ifndef O3DGC_VECTOR_INL
#define O3DGC_VECTOR_INL
namespace o3dgc
{
template <typename T>
inline Vec3<T> operator*(T lhs, const Vec3<T> & rhs)
{
return Vec3<T>(lhs * rhs.X(), lhs * rhs.Y(), lhs * rhs.Z());
}
template <typename T>
inline T & Vec3<T>::X()
{
return m_data[0];
}
template <typename T>
inline T & Vec3<T>::Y()
{
return m_data[1];
}
template <typename T>
inline T & Vec3<T>::Z()
{
return m_data[2];
}
template <typename T>
inline const T & Vec3<T>::X() const
{
return m_data[0];
}
template <typename T>
inline const T & Vec3<T>::Y() const
{
return m_data[1];
}
template <typename T>
inline const T & Vec3<T>::Z() const
{
return m_data[2];
}
template <typename T>
inline double Vec3<T>::GetNorm() const
{
double a = (double) (m_data[0]);
double b = (double) (m_data[1]);
double c = (double) (m_data[2]);
return sqrt(a*a+b*b+c*c);
}
template <typename T>
inline void Vec3<T>::operator= (const Vec3 & rhs)
{
this->m_data[0] = rhs.m_data[0];
this->m_data[1] = rhs.m_data[1];
this->m_data[2] = rhs.m_data[2];
}
template <typename T>
inline void Vec3<T>::operator+=(const Vec3 & rhs)
{
this->m_data[0] += rhs.m_data[0];
this->m_data[1] += rhs.m_data[1];
this->m_data[2] += rhs.m_data[2];
}
template <typename T>
inline void Vec3<T>::operator-=(const Vec3 & rhs)
{
this->m_data[0] -= rhs.m_data[0];
this->m_data[1] -= rhs.m_data[1];
this->m_data[2] -= rhs.m_data[2];
}
template <typename T>
inline void Vec3<T>::operator-=(T a)
{
this->m_data[0] -= a;
this->m_data[1] -= a;
this->m_data[2] -= a;
}
template <typename T>
inline void Vec3<T>::operator+=(T a)
{
this->m_data[0] += a;
this->m_data[1] += a;
this->m_data[2] += a;
}
template <typename T>
inline void Vec3<T>::operator/=(T a)
{
this->m_data[0] /= a;
this->m_data[1] /= a;
this->m_data[2] /= a;
}
template <typename T>
inline void Vec3<T>::operator*=(T a)
{
this->m_data[0] *= a;
this->m_data[1] *= a;
this->m_data[2] *= a;
}
template <typename T>
inline Vec3<T> Vec3<T>::operator^ (const Vec3<T> & rhs) const
{
return Vec3<T>(m_data[1] * rhs.m_data[2] - m_data[2] * rhs.m_data[1],
m_data[2] * rhs.m_data[0] - m_data[0] * rhs.m_data[2],
m_data[0] * rhs.m_data[1] - m_data[1] * rhs.m_data[0]);
}
template <typename T>
inline T Vec3<T>::operator*(const Vec3<T> & rhs) const
{
return (m_data[0] * rhs.m_data[0] + m_data[1] * rhs.m_data[1] + m_data[2] * rhs.m_data[2]);
}
template <typename T>
inline Vec3<T> Vec3<T>::operator+(const Vec3<T> & rhs) const
{
return Vec3<T>(m_data[0] + rhs.m_data[0],m_data[1] + rhs.m_data[1],m_data[2] + rhs.m_data[2]);
}
template <typename T>
inline Vec3<T> Vec3<T>::operator-(const Vec3<T> & rhs) const
{
return Vec3<T>(m_data[0] - rhs.m_data[0],m_data[1] - rhs.m_data[1],m_data[2] - rhs.m_data[2]);
}
template <typename T>
inline Vec3<T> Vec3<T>::operator-() const
{
return Vec3<T>(-m_data[0],-m_data[1],-m_data[2]);
}
template <typename T>
inline Vec3<T> Vec3<T>::operator*(T rhs) const
{
return Vec3<T>(rhs * this->m_data[0], rhs * this->m_data[1], rhs * this->m_data[2]);
}
template <typename T>
inline Vec3<T> Vec3<T>::operator/ (T rhs) const
{
return Vec3<T>(m_data[0] / rhs, m_data[1] / rhs, m_data[2] / rhs);
}
template <typename T>
inline Vec3<T>::Vec3(T a)
{
m_data[0] = m_data[1] = m_data[2] = a;
}
template <typename T>
inline Vec3<T>::Vec3(T x, T y, T z)
{
m_data[0] = x;
m_data[1] = y;
m_data[2] = z;
}
template <typename T>
inline Vec3<T>::Vec3(const Vec3 & rhs)
{
m_data[0] = rhs.m_data[0];
m_data[1] = rhs.m_data[1];
m_data[2] = rhs.m_data[2];
}
template <typename T>
inline Vec3<T>::~Vec3(void){};
template <typename T>
inline Vec3<T>::Vec3() {}
template <typename T>
inline Vec2<T> operator*(T lhs, const Vec2<T> & rhs)
{
return Vec2<T>(lhs * rhs.X(), lhs * rhs.Y());
}
template <typename T>
inline T & Vec2<T>::X()
{
return m_data[0];
}
template <typename T>
inline T & Vec2<T>::Y()
{
return m_data[1];
}
template <typename T>
inline const T & Vec2<T>::X() const
{
return m_data[0];
}
template <typename T>
inline const T & Vec2<T>::Y() const
{
return m_data[1];
}
template <typename T>
inline double Vec2<T>::GetNorm() const
{
double a = (double) (m_data[0]);
double b = (double) (m_data[1]);
return sqrt(a*a+b*b);
}
template <typename T>
inline void Vec2<T>::operator= (const Vec2 & rhs)
{
this->m_data[0] = rhs.m_data[0];
this->m_data[1] = rhs.m_data[1];
}
template <typename T>
inline void Vec2<T>::operator+=(const Vec2 & rhs)
{
this->m_data[0] += rhs.m_data[0];
this->m_data[1] += rhs.m_data[1];
}
template <typename T>
inline void Vec2<T>::operator-=(const Vec2 & rhs)
{
this->m_data[0] -= rhs.m_data[0];
this->m_data[1] -= rhs.m_data[1];
}
template <typename T>
inline void Vec2<T>::operator-=(T a)
{
this->m_data[0] -= a;
this->m_data[1] -= a;
}
template <typename T>
inline void Vec2<T>::operator+=(T a)
{
this->m_data[0] += a;
this->m_data[1] += a;
}
template <typename T>
inline void Vec2<T>::operator/=(T a)
{
this->m_data[0] /= a;
this->m_data[1] /= a;
}
template <typename T>
inline void Vec2<T>::operator*=(T a)
{
this->m_data[0] *= a;
this->m_data[1] *= a;
}
template <typename T>
inline T Vec2<T>::operator^ (const Vec2<T> & rhs) const
{
return m_data[0] * rhs.m_data[1] - m_data[1] * rhs.m_data[0];
}
template <typename T>
inline T Vec2<T>::operator*(const Vec2<T> & rhs) const
{
return (m_data[0] * rhs.m_data[0] + m_data[1] * rhs.m_data[1]);
}
template <typename T>
inline Vec2<T> Vec2<T>::operator+(const Vec2<T> & rhs) const
{
return Vec2<T>(m_data[0] + rhs.m_data[0],m_data[1] + rhs.m_data[1]);
}
template <typename T>
inline Vec2<T> Vec2<T>::operator-(const Vec2<T> & rhs) const
{
return Vec2<T>(m_data[0] - rhs.m_data[0],m_data[1] - rhs.m_data[1]);
}
template <typename T>
inline Vec2<T> Vec2<T>::operator-() const
{
return Vec2<T>(-m_data[0],-m_data[1]) ;
}
template <typename T>
inline Vec2<T> Vec2<T>::operator*(T rhs) const
{
return Vec2<T>(rhs * this->m_data[0], rhs * this->m_data[1]);
}
template <typename T>
inline Vec2<T> Vec2<T>::operator/ (T rhs) const
{
return Vec2<T>(m_data[0] / rhs, m_data[1] / rhs);
}
template <typename T>
inline Vec2<T>::Vec2(T a)
{
m_data[0] = m_data[1] = a;
}
template <typename T>
inline Vec2<T>::Vec2(T x, T y)
{
m_data[0] = x;
m_data[1] = y;
}
template <typename T>
inline Vec2<T>::Vec2(const Vec2 & rhs)
{
m_data[0] = rhs.m_data[0];
m_data[1] = rhs.m_data[1];
}
template <typename T>
inline Vec2<T>::~Vec2(void){};
template <typename T>
inline Vec2<T>::Vec2() {}
}
#endif //O3DGC_VECTOR_INL

View File

@@ -0,0 +1,96 @@
# Copyright (c) 2014, Pavel Rojtberg
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE 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 HOLDER 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.
# ------------------------------------------------------------------------------
# Usage:
# 1. place AndroidNdkGdb.cmake somewhere inside ${CMAKE_MODULE_PATH}
# 2. inside your project add
#
# include(AndroidNdkGdb)
# android_ndk_gdb_enable()
# # for each target
# add_library(MyLibrary ...)
# android_ndk_gdb_debuggable(MyLibrary)
# add gdbserver and general gdb configuration to project
# also create a mininal NDK skeleton so ndk-gdb finds the paths
#
# the optional parameter defines the path to the android project.
# uses PROJECT_SOURCE_DIR by default.
macro(android_ndk_gdb_enable)
if(ANDROID)
# create custom target that depends on the real target so it gets executed afterwards
add_custom_target(NDK_GDB ALL)
if(${ARGC})
set(ANDROID_PROJECT_DIR ${ARGV0})
else()
set(ANDROID_PROJECT_DIR ${PROJECT_SOURCE_DIR})
endif()
set(NDK_GDB_SOLIB_PATH ${ANDROID_PROJECT_DIR}/obj/local/${ANDROID_NDK_ABI_NAME}/)
file(MAKE_DIRECTORY ${NDK_GDB_SOLIB_PATH})
# 1. generate essential Android Makefiles
file(MAKE_DIRECTORY ${ANDROID_PROJECT_DIR}/jni)
if(NOT EXISTS ${ANDROID_PROJECT_DIR}/jni/Android.mk)
file(WRITE ${ANDROID_PROJECT_DIR}/jni/Android.mk "APP_ABI := ${ANDROID_NDK_ABI_NAME}\n")
endif()
if(NOT EXISTS ${ANDROID_PROJECT_DIR}/jni/Application.mk)
file(WRITE ${ANDROID_PROJECT_DIR}/jni/Application.mk "APP_ABI := ${ANDROID_NDK_ABI_NAME}\n")
endif()
# 2. generate gdb.setup
get_directory_property(PROJECT_INCLUDES DIRECTORY ${PROJECT_SOURCE_DIR} INCLUDE_DIRECTORIES)
string(REGEX REPLACE ";" " " PROJECT_INCLUDES "${PROJECT_INCLUDES}")
file(WRITE ${LIBRARY_OUTPUT_PATH}/gdb.setup "set solib-search-path ${NDK_GDB_SOLIB_PATH}\n")
file(APPEND ${LIBRARY_OUTPUT_PATH}/gdb.setup "directory ${PROJECT_INCLUDES}\n")
# 3. copy gdbserver executable
file(COPY ${ANDROID_NDK}/prebuilt/android-${ANDROID_ARCH_NAME}/gdbserver/gdbserver DESTINATION ${LIBRARY_OUTPUT_PATH})
endif()
endmacro()
# register a target for remote debugging
# copies the debug version to NDK_GDB_SOLIB_PATH then strips symbols of original
macro(android_ndk_gdb_debuggable TARGET_NAME)
if(ANDROID)
get_property(TARGET_LOCATION TARGET ${TARGET_NAME} PROPERTY LOCATION)
# create custom target that depends on the real target so it gets executed afterwards
add_dependencies(NDK_GDB ${TARGET_NAME})
# 4. copy lib to obj
add_custom_command(TARGET NDK_GDB POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${TARGET_LOCATION} ${NDK_GDB_SOLIB_PATH})
# 5. strip symbols
add_custom_command(TARGET NDK_GDB POST_BUILD COMMAND ${CMAKE_STRIP} ${TARGET_LOCATION})
endif()
endmacro()

View File

@@ -0,0 +1,58 @@
# Copyright (c) 2014, Pavel Rojtberg
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from this
# software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE 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 HOLDER 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.
macro(android_ndk_import_module_cpufeatures)
if(ANDROID)
include_directories(${ANDROID_NDK}/sources/android/cpufeatures)
add_library(cpufeatures ${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c)
target_link_libraries(cpufeatures dl)
endif()
endmacro()
macro(android_ndk_import_module_native_app_glue)
if(ANDROID)
include_directories(${ANDROID_NDK}/sources/android/native_app_glue)
add_library(native_app_glue ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c)
target_link_libraries(native_app_glue log)
endif()
endmacro()
macro(android_ndk_import_module_ndk_helper)
if(ANDROID)
android_ndk_import_module_cpufeatures()
android_ndk_import_module_native_app_glue()
include_directories(${ANDROID_NDK}/sources/android/ndk_helper)
file(GLOB _NDK_HELPER_SRCS ${ANDROID_NDK}/sources/android/ndk_helper/*.cpp ${ANDROID_NDK}/sources/android/ndk_helper/gl3stub.c)
add_library(ndk_helper ${_NDK_HELPER_SRCS})
target_link_libraries(ndk_helper log android EGL GLESv2 cpufeatures native_app_glue)
unset(_NDK_HELPER_SRCS)
endif()
endmacro()

View File

@@ -0,0 +1,240 @@
# android-cmake
CMake is great, and so is Android. This is a collection of CMake scripts that may be useful to the Android NDK community. It is based on experience from porting OpenCV library to Android: http://opencv.org/platforms/android.html
Main goal is to share these scripts so that devs that use CMake as their build system may easily compile native code for Android.
## TL;DR
cmake -DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake \
-DANDROID_NDK=<ndk_path> \
-DCMAKE_BUILD_TYPE=Release \
-DANDROID_ABI="armeabi-v7a with NEON" \
<source_path>
cmake --build .
One-liner:
cmake -DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake -DANDROID_NDK=<ndk_path> -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="armeabi-v7a with NEON" <source_path> && cmake --build .
_android-cmake_ will search for your NDK install in the following order:
1. Value of `ANDROID_NDK` CMake variable;
1. Value of `ANDROID_NDK` environment variable;
1. Search under paths from `ANDROID_NDK_SEARCH_PATHS` CMake variable;
1. Search platform specific locations (home folder, Windows "Program Files", etc).
So if you have installed the NDK as `~/android-ndk-r10d` then _android-cmake_ will locate it automatically.
## Getting started
To build a cmake-based C/C++ project for Android you need:
* Android NDK (>= r5) http://developer.android.com/tools/sdk/ndk/index.html
* CMake (>= v2.6.3, >= v2.8.9 recommended) http://www.cmake.org/download
The _android-cmake_ is also capable to build with NDK from AOSP or Linaro Android source tree, but you may be required to manually specify path to `libm` binary to link with.
## Difference from traditional CMake
Folowing the _ndk-build_ the _android-cmake_ supports **only two build targets**:
* `-DCMAKE_BUILD_TYPE=Release`
* `-DCMAKE_BUILD_TYPE=Debug`
So don't even try other targets that can be found in CMake documentation and don't forget to explicitly specify `Release` or `Debug` because CMake builds without a build configuration by default.
## Difference from _ndk-build_
* Latest GCC available in NDK is used as the default compiler;
* `Release` builds with `-O3` instead of `-Os`;
* `Release` builds without debug info (without `-g`) (because _ndk-build_ always creates a stripped version but cmake delays this for `install/strip` target);
* `-fsigned-char` is added to compiler flags to make `char` signed by default as it is on x86/x86_64;
* GCC's stack protector is not used neither in `Debug` nor `Release` configurations;
* No builds for multiple platforms (e.g. building for both arm and x86 require to run cmake twice with different parameters);
* No file level Neon via `.neon` suffix;
The following features of _ndk-build_ are not supported by the _android-cmake_ yet:
* `armeabi-v7a-hard` ABI
* `libc++_static`/`libc++_shared` STL runtime
## Basic options
Similarly to the NDK build system _android-cmake_ allows to select between several compiler toolchains and target platforms. Most of the options can be set either as cmake arguments: `-D<NAME>=<VALUE>` or as environment variables:
* **ANDROID_NDK** - path to the Android NDK. If not set then _android-cmake_ will search for the most recent version of supported NDK in commonly used locations;
* **ANDROID_ABI** - specifies the target Application Binary Interface (ABI). This option nearly matches to the APP_ABI variable used by ndk-build tool from Android NDK. If not specified then set to `armeabi-v7a`. Possible target names are:
* `armeabi` - ARMv5TE based CPU with software floating point operations;
* **`armeabi-v7a`** - ARMv7 based devices with hardware FPU instructions (VFPv3_D16);
* `armeabi-v7a with NEON` - same as armeabi-v7a, but sets NEON as floating-point unit;
* `armeabi-v7a with VFPV3` - same as armeabi-v7a, but sets VFPv3_D32 as floating-point unit;
* `armeabi-v6 with VFP` - tuned for ARMv6 processors having VFP;
* `x86` - IA-32 instruction set
* `mips` - MIPS32 instruction set
* `arm64-v8a` - ARMv8 AArch64 instruction set - only for NDK r10 and newer
* `x86_64` - Intel64 instruction set (r1) - only for NDK r10 and newer
* `mips64` - MIPS64 instruction set (r6) - only for NDK r10 and newer
* **ANDROID_NATIVE_API_LEVEL** - level of android API to build for. Can be set either to full name (example: `android-8`) or a numeric value (example: `17`). The default API level depends on the target ABI:
* `android-8` for ARM;
* `android-9` for x86 and MIPS;
* `android-21` for 64-bit ABIs.
Building for `android-L` is possible only when it is explicitly selected.
* **ANDROID_TOOLCHAIN_NAME** - the name of compiler toolchain to be used. This option allows to select between different GCC and Clang versions. The list of possible values depends on the NDK version and will be printed by toolchain file if an invalid value is set. By default _android-cmake_ selects the most recent version of GCC which can build for specified `ANDROID_ABI`.
Example values are:
* `aarch64-linux-android-4.9`
* `aarch64-linux-android-clang3.5`
* `arm-linux-androideabi-4.8`
* `arm-linux-androideabi-4.9`
* `arm-linux-androideabi-clang3.5`
* `mips64el-linux-android-4.9`
* `mipsel-linux-android-4.8`
* `x86-4.9`
* `x86_64-4.9`
* etc.
* **ANDROID_STL** - the name of C++ runtime to use. The default is `gnustl_static`.
* `none` - do not configure the runtime.
* `system` - use the default minimal system C++ runtime library.
* Implies `-fno-rtti -fno-exceptions`.
* `system_re` - use the default minimal system C++ runtime library.
* Implies `-frtti -fexceptions`.
* `gabi++_static` - use the GAbi++ runtime as a static library.
* Implies `-frtti -fno-exceptions`.
* Available for NDK r7 and newer.
* `gabi++_shared` - use the GAbi++ runtime as a shared library.
* Implies `-frtti -fno-exceptions`.
* Available for NDK r7 and newer.
* `stlport_static` - use the STLport runtime as a static library.
* Implies `-fno-rtti -fno-exceptions` for NDK before r7.
* Implies `-frtti -fno-exceptions` for NDK r7 and newer.
* `stlport_shared` - use the STLport runtime as a shared library.
* Implies `-fno-rtti -fno-exceptions` for NDK before r7.
* Implies `-frtti -fno-exceptions` for NDK r7 and newer.
* **`gnustl_static`** - use the GNU STL as a static library.
* Implies `-frtti -fexceptions`.
* `gnustl_shared` - use the GNU STL as a shared library.
* Implies `-frtti -fno-exceptions`.
* Available for NDK r7b and newer.
* Silently degrades to `gnustl_static` if not available.
* **NDK_CCACHE** - path to `ccache` executable. If not set then initialized from `NDK_CCACHE` environment variable.
## Advanced _android-cmake_ options
Normally _android-cmake_ users are not supposed to touch these variables but they might be useful to workaround some build issues:
* **ANDROID_FORCE_ARM_BUILD** = `OFF` - generate 32-bit ARM instructions instead of Thumb. Applicable only for arm ABIs and is forced to be `ON` for `armeabi-v6 with VFP`;
* **ANDROID_NO_UNDEFINED** = `ON` - show all undefined symbols as linker errors;
* **ANDROID_SO_UNDEFINED** = `OFF` - allow undefined symbols in shared libraries;
* actually it is turned `ON` by default for NDK older than `r7`
* **ANDROID_STL_FORCE_FEATURES** = `ON` - automatically configure rtti and exceptions support based on C++ runtime;
* **ANDROID_NDK_LAYOUT** = `RELEASE` - inner layout of Android NDK, should be detected automatically. Possible values are:
* `RELEASE` - public releases from Google;
* `LINARO` - NDK from Linaro project;
* `ANDROID` - NDK from AOSP.
* **ANDROID_FUNCTION_LEVEL_LINKING** = `ON` - enables saparate putting each function and data items into separate sections and enable garbage collection of unused input sections at link time (`-fdata-sections -ffunction-sections -Wl,--gc-sections`);
* **ANDROID_GOLD_LINKER** = `ON` - use gold linker with GCC 4.6 for NDK r8b and newer (only for ARM and x86);
* **ANDROID_NOEXECSTACK** = `ON` - enables or disables stack execution protection code (`-Wl,-z,noexecstack`);
* **ANDROID_RELRO** = `ON` - Enables RELRO - a memory corruption mitigation technique (`-Wl,-z,relro -Wl,-z,now`);
* **ANDROID_LIBM_PATH** - path to `libm.so` (set to something like `$(TOP)/out/target/product/<product_name>/obj/lib/libm.so`) to workaround unresolved `sincos`.
## Fine-tuning `CMakeLists.txt` for _android-cmake_
### Recognizing Android build
_android-cmake_ defines `ANDROID` CMake variable which can be used to add Android-specific stuff:
if (ANDROID)
message(STATUS "Hello from Android build!")
endif()
The recommended way to identify ARM/MIPS/x86 architecture is examining `CMAKE_SYSTEM_PROCESSOR` which is set to the appropriate value:
* `armv5te` - for `armeabi` ABI
* `armv6` - for `armeabi-v6 with VFP` ABI
* `armv7-a` - for `armeabi-v7a`, `armeabi-v7a with VFPV3` and `armeabi-v7a with NEON` ABIs
* `aarch64` - for `arm64-v8a` ABI
* `i686` - for `x86` ABI
* `x86_64` - for `x86_64` ABI
* `mips` - for `mips` ABI
* `mips64` - for `mips64` ABI
Other variables that are set by _android-cmake_ and can be used for the fine-grained build configuration are:
* `NEON` - set if target ABI supports Neon;
* `ANDROID_NATIVE_API_LEVEL` - native Android API level we are building for (note: Java part of Andoid application can be built for another API level)
* `ANDROID_NDK_RELEASE` - version of the Android NDK
* `ANDROID_NDK_HOST_SYSTEM_NAME` - "windows", "linux-x86" or "darwin-x86" depending on the host platform
* `ANDROID_RTTI` - set if rtti is enabled by the runtime
* `ANDROID_EXCEPTIONS` - set if exceptions are enabled by the runtime
### Finding packages
When crosscompiling CMake `find_*` commands are normally expected to find libraries and packages belonging to the same build target. So _android-cmake_ configures CMake to search in Android-specific paths only and ignore your host system locations. So
find_package(ZLIB)
will surely find libz.so within the Android NDK.
However sometimes you need to locate a host package even when cross-compiling. For example you can be searching for your documentation generator. The _android-cmake_ recommends you to use `find_host_package` and `find_host_program` macro defined in the `android.toolchain.cmake`:
find_host_package(Doxygen)
find_host_program(PDFLATEX pdflatex)
However this will break regular builds so instead of wrapping package search into platform-specific logic you can copy the following snippet into your project (put it after your top-level `project()` command):
# Search packages for host system instead of packages for target system
# in case of cross compilation these macro should be defined by toolchain file
if(NOT COMMAND find_host_package)
macro(find_host_package)
find_package(${ARGN})
endmacro()
endif()
if(NOT COMMAND find_host_program)
macro(find_host_program)
find_program(${ARGN})
endmacro()
endif()
### Compiler flags recycling
Make sure to do the following in your scripts:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${my_cxx_flags}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${my_cxx_flags}")
The flags will be prepopulated with critical flags, so don't loose them. Also be aware that _android-cmake_ also sets configuration-specific compiler and linker flags.
## Troubleshooting
### Building on Windows
First of all `cygwin` builds are **NOT supported** and will not be supported by _android-cmake_. To build natively on Windows you need a port of make but I recommend http://martine.github.io/ninja/ instead.
To build with Ninja you need:
* Ensure you are using CMake newer than 2.8.9;
* Download the latest Ninja from https://github.com/martine/ninja/releases;
* Put the `ninja.exe` into your PATH (or add path to `ninja.exe` to your PATH environment variable);
* Pass `-GNinja` to `cmake` alongside with other arguments (or choose Ninja generator in `cmake-gui`).
* Enjoy the fast native multithreaded build :)
But if you still want to stick to old make then:
* Get a Windows port of GNU Make:
* Android NDK r7 (and newer) already has `make.exe` on board;
* `mingw-make` should work as fine;
* Download some other port. For example, this one: http://gnuwin32.sourceforge.net/packages/make.htm.
* Add path to your `make.exe` to system PATH or always use full path;
* Pass `-G"MinGW Makefiles"` and `-DCMAKE_MAKE_PROGRAM="<full/path/to/>make.exe"`
* It must be `MinGW Makefiles` and not `Unix Makefiles` even if your `make.exe` is not a MinGW's make.
* Run `make.exe` or `cmake --build .` for single-threaded build.
### Projects with assembler files
The _android-cmake_ should correctly handle projects with assembler sources (`*.s` or `*.S`). But if you still facing problems with assembler then try to upgrade your CMake to version newer than 2.8.5
## Copying
_android-cmake_ is distributed under the terms of [BSD 3-Clause License](http://opensource.org/licenses/BSD-3-Clause)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,211 @@
============== r1 ============== (dead links)
* http://dl.google.com/android/ndk/android-ndk-1.5_r1-windows.zip
* http://dl.google.com/android/ndk/android-ndk-1.5_r1-darwin-x86.zip
* http://dl.google.com/android/ndk/android-ndk-1.5_r1-linux-x86.zip
============== r2 ==============
* http://dl.google.com/android/ndk/android-ndk-1.6_r1-windows.zip
* http://dl.google.com/android/ndk/android-ndk-1.6_r1-darwin-x86.zip
* http://dl.google.com/android/ndk/android-ndk-1.6_r1-linux-x86.zip
============== r3 ==============
* http://dl.google.com/android/ndk/android-ndk-r3-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r3-darwin-x86.zip
* http://dl.google.com/android/ndk/android-ndk-r3-linux-x86.zip
============== r4 ==============
* http://dl.google.com/android/ndk/android-ndk-r4-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r4-darwin-x86.zip
* http://dl.google.com/android/ndk/android-ndk-r4-linux-x86.zip
============== r4b ==============
* http://dl.google.com/android/ndk/android-ndk-r4b-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r4b-darwin-x86.zip
* http://dl.google.com/android/ndk/android-ndk-r4b-linux-x86.zip
============== r5 ==============
* http://dl.google.com/android/ndk/android-ndk-r5-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r5-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r5-linux-x86.tar.bz2
============== r5b ==============
* http://dl.google.com/android/ndk/android-ndk-r5b-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r5b-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r5b-linux-x86.tar.bz2
============== r5c ==============
* http://dl.google.com/android/ndk/android-ndk-r5c-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r5c-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r5c-linux-x86.tar.bz2
============== r6 ==============
* http://dl.google.com/android/ndk/android-ndk-r6-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r6-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r6-linux-x86.tar.bz2
============== r6b ==============
* http://dl.google.com/android/ndk/android-ndk-r6b-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r6b-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r6b-linux-x86.tar.bz2
============== r7 ==============
* http://dl.google.com/android/ndk/android-ndk-r7-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r7-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r7-linux-x86.tar.bz2
============== r7b ==============
* http://dl.google.com/android/ndk/android-ndk-r7b-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r7b-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r7b-linux-x86.tar.bz2
============== r7c ==============
* http://dl.google.com/android/ndk/android-ndk-r7c-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r7c-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r7c-linux-x86.tar.bz2
============== r8 ==============
* http://dl.google.com/android/ndk/android-ndk-r8-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r8-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r8-linux-x86.tar.bz2
============== r8b ==============
* http://dl.google.com/android/ndk/android-ndk-r8b-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r8b-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r8b-linux-x86.tar.bz2
============== r8c ==============
* http://dl.google.com/android/ndk/android-ndk-r8c-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r8c-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r8c-linux-x86.tar.bz2
============== r8d ==============
* http://dl.google.com/android/ndk/android-ndk-r8d-windows.zip
* http://dl.google.com/android/ndk/android-ndk-r8d-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r8d-linux-x86.tar.bz2
============== r8e ==============
* http://dl.google.com/android/ndk/android-ndk-r8e-windows-x86.zip
* http://dl.google.com/android/ndk/android-ndk-r8e-windows-x86_64.zip
* http://dl.google.com/android/ndk/android-ndk-r8e-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r8e-darwin-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r8e-linux-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r8e-linux-x86_64.tar.bz2
============== r9 ==============
* http://dl.google.com/android/ndk/android-ndk-r9-windows-x86.zip
* http://dl.google.com/android/ndk/android-ndk-r9-windows-x86-legacy-toolchains.zip
* http://dl.google.com/android/ndk/android-ndk-r9-windows-x86_64.zip
* http://dl.google.com/android/ndk/android-ndk-r9-windows-x86_64-legacy-toolchains.zip
* http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86-legacy-toolchains.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86_64-legacy-toolchains.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9-linux-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9-linux-x86-legacy-toolchains.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9-linux-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9-linux-x86_64-legacy-toolchains.tar.bz2
============== r9b ==============
* http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86.zip
* http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86-legacy-toolchains.zip
* http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86_64.zip
* http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86_64-legacy-toolchains.zip
* http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86-legacy-toolchains.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86_64-legacy-toolchains.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86-legacy-toolchains.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86_64-legacy-toolchains.tar.bz2
============== r9c ==============
* http://dl.google.com/android/ndk/android-ndk-r9c-windows-x86.zip
* http://dl.google.com/android/ndk/android-ndk-r9c-windows-x86_64.zip
* http://dl.google.com/android/ndk/android-ndk-r9c-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9c-darwin-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9c-linux-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9c-linux-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9c-cxx-stl-libs-with-debugging-info.zip
============== r9d ==============
* http://dl.google.com/android/ndk/android-ndk-r9d-windows-x86.zip
* http://dl.google.com/android/ndk/android-ndk-r9d-windows-x86_64.zip
* http://dl.google.com/android/ndk/android-ndk-r9d-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9d-darwin-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9d-linux-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9d-linux-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r9d-cxx-stl-libs-with-debug-info.zip
============== r10 ==============
* http://dl.google.com/android/ndk/android-ndk32-r10-windows-x86.zip
* http://dl.google.com/android/ndk/android-ndk32-r10-windows-x86_64.zip
* http://dl.google.com/android/ndk/android-ndk32-r10-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk32-r10-darwin-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk32-r10-linux-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk32-r10-linux-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk64-r10-windows-x86.zip
* http://dl.google.com/android/ndk/android-ndk64-r10-windows-x86_64.zip
* http://dl.google.com/android/ndk/android-ndk64-r10-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk64-r10-darwin-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk64-r10-linux-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk64-r10-linux-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r10-cxx-stl-libs-with-debug-info.zip
============== r10b ==============
* http://dl.google.com/android/ndk/android-ndk32-r10b-windows-x86.zip
* http://dl.google.com/android/ndk/android-ndk32-r10b-windows-x86_64.zip
* http://dl.google.com/android/ndk/android-ndk32-r10b-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk32-r10b-darwin-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk32-r10b-linux-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk32-r10b-linux-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk64-r10b-windows-x86.zip
* http://dl.google.com/android/ndk/android-ndk64-r10b-windows-x86_64.zip
* http://dl.google.com/android/ndk/android-ndk64-r10b-darwin-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk64-r10b-darwin-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk64-r10b-linux-x86.tar.bz2
* http://dl.google.com/android/ndk/android-ndk64-r10b-linux-x86_64.tar.bz2
* http://dl.google.com/android/ndk/android-ndk-r10b-cxx-stl-libs-with-debug-info.zip
============== r10c ==============
* http://dl.google.com/android/ndk/android-ndk-r10c-windows-x86.exe
* http://dl.google.com/android/ndk/android-ndk-r10c-windows-x86_64.exe
* http://dl.google.com/android/ndk/android-ndk-r10c-darwin-x86.bin
* http://dl.google.com/android/ndk/android-ndk-r10c-darwin-x86_64.bin
* http://dl.google.com/android/ndk/android-ndk-r10c-linux-x86.bin
* http://dl.google.com/android/ndk/android-ndk-r10c-linux-x86_64.bin
============== r10d ==============
* http://dl.google.com/android/ndk/android-ndk-r10d-windows-x86.exe
* http://dl.google.com/android/ndk/android-ndk-r10d-windows-x86_64.exe
* http://dl.google.com/android/ndk/android-ndk-r10d-darwin-x86.bin
* http://dl.google.com/android/ndk/android-ndk-r10d-darwin-x86_64.bin
* http://dl.google.com/android/ndk/android-ndk-r10d-linux-x86.bin
* http://dl.google.com/android/ndk/android-ndk-r10d-linux-x86_64.bin

View File

@@ -0,0 +1,29 @@
The Clipper code library, the "Software" (that includes Delphi, C++ & C#
source code, accompanying samples and documentation), has been released
under the following license, terms and conditions:
Boost Software License - Version 1.0 - August 17th, 2003
http://www.boost.org/LICENSE_1_0.txt
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,306 @@
/*******************************************************************************
* *
* Author : Angus Johnson *
* Version : 4.8.8 *
* Date : 30 August 2012 *
* Website : http://www.angusj.com *
* Copyright : Angus Johnson 2010-2012 *
* *
* License: *
* Use, modification & distribution is subject to Boost Software License Ver 1. *
* http://www.boost.org/LICENSE_1_0.txt *
* *
* Attributions: *
* The code in this library is an extension of Bala Vatti's clipping algorithm: *
* "A generic solution to polygon clipping" *
* Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. *
* http://portal.acm.org/citation.cfm?id=129906 *
* *
* Computer graphics and geometric modeling: implementation and algorithms *
* By Max K. Agoston *
* Springer; 1 edition (January 4, 2005) *
* http://books.google.com/books?q=vatti+clipping+agoston *
* *
* See also: *
* "Polygon Offsetting by Computing Winding Numbers" *
* Paper no. DETC2005-85513 pp. 565-575 *
* ASME 2005 International Design Engineering Technical Conferences *
* and Computers and Information in Engineering Conference (IDETC/CIE2005) *
* September 24-28, 2005 , Long Beach, California, USA *
* http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf *
* *
*******************************************************************************/
#ifndef clipper_hpp
#define clipper_hpp
#include <vector>
#include <stdexcept>
#include <cstring>
#include <cstdlib>
#include <ostream>
namespace ClipperLib {
enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor };
enum PolyType { ptSubject, ptClip };
//By far the most widely used winding rules for polygon filling are
//EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32)
//Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL)
//see http://glprogramming.com/red/chapter11.html
enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative };
typedef signed long long long64;
typedef unsigned long long ulong64;
struct IntPoint {
public:
long64 X;
long64 Y;
IntPoint(long64 x = 0, long64 y = 0): X(x), Y(y) {};
friend std::ostream& operator <<(std::ostream &s, IntPoint &p);
};
typedef std::vector< IntPoint > Polygon;
typedef std::vector< Polygon > Polygons;
std::ostream& operator <<(std::ostream &s, Polygon &p);
std::ostream& operator <<(std::ostream &s, Polygons &p);
struct ExPolygon {
Polygon outer;
Polygons holes;
};
typedef std::vector< ExPolygon > ExPolygons;
enum JoinType { jtSquare, jtRound, jtMiter };
bool Orientation(const Polygon &poly);
double Area(const Polygon &poly);
void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys,
double delta, JoinType jointype = jtSquare, double MiterLimit = 2);
void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys, PolyFillType fillType = pftEvenOdd);
void SimplifyPolygons(Polygons &polys, PolyFillType fillType = pftEvenOdd);
void ReversePolygon(Polygon& p);
void ReversePolygons(Polygons& p);
//used internally ...
enum EdgeSide { esNeither = 0, esLeft = 1, esRight = 2, esBoth = 3 };
enum IntersectProtects { ipNone = 0, ipLeft = 1, ipRight = 2, ipBoth = 3 };
struct TEdge {
long64 xbot;
long64 ybot;
long64 xcurr;
long64 ycurr;
long64 xtop;
long64 ytop;
double dx;
long64 tmpX;
PolyType polyType;
EdgeSide side;
int windDelta; //1 or -1 depending on winding direction
int windCnt;
int windCnt2; //winding count of the opposite polytype
int outIdx;
TEdge *next;
TEdge *prev;
TEdge *nextInLML;
TEdge *nextInAEL;
TEdge *prevInAEL;
TEdge *nextInSEL;
TEdge *prevInSEL;
};
struct IntersectNode {
TEdge *edge1;
TEdge *edge2;
IntPoint pt;
IntersectNode *next;
};
struct LocalMinima {
long64 Y;
TEdge *leftBound;
TEdge *rightBound;
LocalMinima *next;
};
struct Scanbeam {
long64 Y;
Scanbeam *next;
};
struct OutPt; //forward declaration
struct OutRec {
int idx;
bool isHole;
OutRec *FirstLeft;
OutRec *AppendLink;
OutPt *pts;
OutPt *bottomPt;
OutPt *bottomFlag;
EdgeSide sides;
};
struct OutPt {
int idx;
IntPoint pt;
OutPt *next;
OutPt *prev;
};
struct JoinRec {
IntPoint pt1a;
IntPoint pt1b;
int poly1Idx;
IntPoint pt2a;
IntPoint pt2b;
int poly2Idx;
};
struct HorzJoinRec {
TEdge *edge;
int savedIdx;
};
struct IntRect { long64 left; long64 top; long64 right; long64 bottom; };
typedef std::vector < OutRec* > PolyOutList;
typedef std::vector < TEdge* > EdgeList;
typedef std::vector < JoinRec* > JoinList;
typedef std::vector < HorzJoinRec* > HorzJoinList;
//ClipperBase is the ancestor to the Clipper class. It should not be
//instantiated directly. This class simply abstracts the conversion of sets of
//polygon coordinates into edge objects that are stored in a LocalMinima list.
class ClipperBase
{
public:
ClipperBase();
virtual ~ClipperBase();
bool AddPolygon(const Polygon &pg, PolyType polyType);
bool AddPolygons( const Polygons &ppg, PolyType polyType);
virtual void Clear();
IntRect GetBounds();
protected:
void DisposeLocalMinimaList();
TEdge* AddBoundsToLML(TEdge *e);
void PopLocalMinima();
virtual void Reset();
void InsertLocalMinima(LocalMinima *newLm);
LocalMinima *m_CurrentLM;
LocalMinima *m_MinimaList;
bool m_UseFullRange;
EdgeList m_edges;
};
class Clipper : public virtual ClipperBase
{
public:
Clipper();
~Clipper();
bool Execute(ClipType clipType,
Polygons &solution,
PolyFillType subjFillType = pftEvenOdd,
PolyFillType clipFillType = pftEvenOdd);
bool Execute(ClipType clipType,
ExPolygons &solution,
PolyFillType subjFillType = pftEvenOdd,
PolyFillType clipFillType = pftEvenOdd);
void Clear();
bool ReverseSolution() {return m_ReverseOutput;};
void ReverseSolution(bool value) {m_ReverseOutput = value;};
protected:
void Reset();
virtual bool ExecuteInternal(bool fixHoleLinkages);
private:
PolyOutList m_PolyOuts;
JoinList m_Joins;
HorzJoinList m_HorizJoins;
ClipType m_ClipType;
Scanbeam *m_Scanbeam;
TEdge *m_ActiveEdges;
TEdge *m_SortedEdges;
IntersectNode *m_IntersectNodes;
bool m_ExecuteLocked;
PolyFillType m_ClipFillType;
PolyFillType m_SubjFillType;
bool m_ReverseOutput;
void DisposeScanbeamList();
void SetWindingCount(TEdge& edge);
bool IsEvenOddFillType(const TEdge& edge) const;
bool IsEvenOddAltFillType(const TEdge& edge) const;
void InsertScanbeam(const long64 Y);
long64 PopScanbeam();
void InsertLocalMinimaIntoAEL(const long64 botY);
void InsertEdgeIntoAEL(TEdge *edge);
void AddEdgeToSEL(TEdge *edge);
void CopyAELToSEL();
void DeleteFromSEL(TEdge *e);
void DeleteFromAEL(TEdge *e);
void UpdateEdgeIntoAEL(TEdge *&e);
void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2);
bool IsContributing(const TEdge& edge) const;
bool IsTopHorz(const long64 XPos);
void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2);
void DoMaxima(TEdge *e, long64 topY);
void ProcessHorizontals();
void ProcessHorizontal(TEdge *horzEdge);
void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
void AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt);
void AppendPolygon(TEdge *e1, TEdge *e2);
void DoEdge1(TEdge *edge1, TEdge *edge2, const IntPoint &pt);
void DoEdge2(TEdge *edge1, TEdge *edge2, const IntPoint &pt);
void DoBothEdges(TEdge *edge1, TEdge *edge2, const IntPoint &pt);
void IntersectEdges(TEdge *e1, TEdge *e2,
const IntPoint &pt, IntersectProtects protects);
OutRec* CreateOutRec();
void AddOutPt(TEdge *e, const IntPoint &pt);
void DisposeBottomPt(OutRec &outRec);
void DisposeAllPolyPts();
void DisposeOutRec(PolyOutList::size_type index);
bool ProcessIntersections(const long64 botY, const long64 topY);
void AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt);
void BuildIntersectList(const long64 botY, const long64 topY);
void ProcessIntersectList();
void ProcessEdgesAtTopOfScanbeam(const long64 topY);
void BuildResult(Polygons& polys);
void BuildResultEx(ExPolygons& polys);
void SetHoleState(TEdge *e, OutRec *OutRec);
void DisposeIntersectNodes();
bool FixupIntersections();
void FixupOutPolygon(OutRec &outRec);
bool IsHole(TEdge *e);
void FixHoleLinkage(OutRec *outRec);
void CheckHoleLinkages1(OutRec *outRec1, OutRec *outRec2);
void CheckHoleLinkages2(OutRec *outRec1, OutRec *outRec2);
void AddJoin(TEdge *e1, TEdge *e2, int e1OutIdx = -1, int e2OutIdx = -1);
void ClearJoins();
void AddHorzJoin(TEdge *e, int idx);
void ClearHorzJoins();
void JoinCommonEdges(bool fixHoleLinkages);
};
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
class clipperException : public std::exception
{
public:
clipperException(const char* description): m_descr(description) {}
virtual ~clipperException() throw() {}
virtual const char* what() const throw() {return m_descr.c_str();}
private:
std::string m_descr;
};
//------------------------------------------------------------------------------
} //ClipperLib namespace
#endif //clipper_hpp

157
thirdparty/assimp/contrib/gtest/CHANGES vendored Normal file
View File

@@ -0,0 +1,157 @@
Changes for 1.7.0:
* New feature: death tests are supported on OpenBSD and in iOS
simulator now.
* New feature: Google Test now implements a protocol to allow
a test runner to detect that a test program has exited
prematurely and report it as a failure (before it would be
falsely reported as a success if the exit code is 0).
* 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

View File

@@ -0,0 +1,286 @@
########################################################################
# 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)
option(
gtest_hide_internal_symbols
"Build gtest with internal symbols hidden in shared libraries."
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()
if (gtest_hide_internal_symbols)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)
set(CMAKE_VISIBILITY_INLINES_HIDDEN 1)
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)
# Summary of tuple support for Microsoft Visual Studio:
# Compiler version(MS) version(cmake) Support
# ---------- ----------- -------------- -----------------------------
# <= VS 2010 <= 10 <= 1600 Use Google Tests's own tuple.
# VS 2012 11 1700 std::tr1::tuple + _VARIADIC_MAX=10
# VS 2013 12 1800 std::tr1::tuple
if (MSVC AND MSVC_VERSION EQUAL 1700)
add_definitions(/D _VARIADIC_MAX=10)
endif()
########################################################################
#
# 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)
# If the CMake version supports it, attach header directory information
# to the targets for when we are part of a parent build (ie being pulled
# in via add_subdirectory() rather than being a standalone build).
if (DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11")
target_include_directories(gtest INTERFACE "${gtest_SOURCE_DIR}/include")
target_include_directories(gtest_main INTERFACE "${gtest_SOURCE_DIR}/include")
endif()
########################################################################
#
# Install rules
install(TARGETS gtest gtest_main
DESTINATION lib)
install(DIRECTORY ${gtest_SOURCE_DIR}/include/gtest
DESTINATION include)
########################################################################
#
# 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_premature_exit_test gtest
test/gtest_premature_exit_test.cc)
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 MSVC_VERSION LESS 1600) # 1600 is Visual Studio 2010.
# Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that
# conflict with our own definitions. Therefore using our own tuple does not
# work on those compilers.
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)
# Visual Studio .NET 2003 does not support STL with exceptions disabled.
if (NOT MSVC OR MSVC_VERSION GREATER 1310) # 1310 is Visual Studio .NET 2003
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()

View File

@@ -0,0 +1,37 @@
# 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>

28
thirdparty/assimp/contrib/gtest/LICENSE vendored Normal file
View File

@@ -0,0 +1,28 @@
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.

View File

@@ -0,0 +1,310 @@
# 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_premature_exit_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-port-arch.h \
include/gtest/internal/gtest-string.h \
include/gtest/internal/gtest-tuple.h \
include/gtest/internal/gtest-type-util.h \
include/gtest/internal/custom/gtest.h \
include/gtest/internal/custom/gtest-port.h \
include/gtest/internal/custom/gtest-printers.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

View File

@@ -0,0 +1,280 @@
### Generic Build Instructions ###
#### Setup ####
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.
#### Build ####
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](CMakeLists.txt)) that can be used on a wide range of platforms ("C" stands for
cross-platform.). 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 Visual 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](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.
## 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.
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/](scripts/) directory.
Read the [Pump manual](docs/PumpManual.md) for how to use it.

View File

View File

@@ -0,0 +1,254 @@
# 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 -wd4251 -wd4275 -nologo -J -Zi")
if (MSVC_VERSION LESS 1400) # 1400 is Visual Studio 2005
# 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()
if (MSVC_VERSION LESS 1500) # 1500 is Visual Studio 2008
# Conditional expression is constant.
# When compiling with /W4, we get several instances of C4127
# (Conditional expression is constant). In our code, we disable that
# warning on a case-by-case basis. However, on Visual Studio 2005,
# the warning fires on std::list. Therefore on that compiler and earlier,
# we disable the warning project-wide.
set(cxx_base_flags "${cxx_base_flags} -wd4127")
endif()
if (NOT (MSVC_VERSION LESS 1700)) # 1700 is Visual Studio 2012.
# Suppress "unreachable code" warning on VS 2012 and later.
# http://stackoverflow.com/questions/3232669 explains the issue.
set(cxx_base_flags "${cxx_base_flags} -wd4702")
endif()
if (NOT (MSVC_VERSION GREATER 1900)) # 1900 is Visual Studio 2015
# BigObj required for tests.
set(cxx_base_flags "${cxx_base_flags} -bigobj")
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-")
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) # 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.
if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.1)
add_test(
NAME ${name}
COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py
--build_dir=${CMAKE_CURRENT_BINARY_DIR}/$<CONFIGURATION>)
else (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.1)
add_test(
${name}
${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py
--build_dir=${CMAKE_CURRENT_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE})
endif (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.1)
endif()
endfunction()

View File

@@ -0,0 +1,138 @@
<?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>

View File

@@ -0,0 +1,54 @@
<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>

View File

@@ -0,0 +1,38 @@
// 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"

View File

@@ -0,0 +1,40 @@
// 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"

View File

@@ -0,0 +1,82 @@
<?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>

View File

@@ -0,0 +1,88 @@
<?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>

View File

@@ -0,0 +1,68 @@
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

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,126 @@
If you are interested in understanding the internals of Google Test,
building from source, or contributing ideas or modifications to the
project, then this document is for you.
# Introduction #
First, let's give you some background of the project.
## Licensing ##
All Google Test source and pre-built packages are provided under the [New BSD License](http://www.opensource.org/licenses/bsd-license.php).
## The Google Test Community ##
The Google Test community exists primarily through the [discussion group](http://groups.google.com/group/googletestframework) and the GitHub repository.
You are definitely encouraged to contribute to the
discussion and you can also help us to keep the effectiveness of the
group high by following and promoting the guidelines listed here.
### Please Be Friendly ###
Showing courtesy and respect to others is a vital part of the Google
culture, and we strongly encourage everyone participating in Google
Test development to join us in accepting nothing less. Of course,
being courteous is not the same as failing to constructively disagree
with each other, but it does mean that we should be respectful of each
other when enumerating the 42 technical reasons that a particular
proposal may not be the best choice. There's never a reason to be
antagonistic or dismissive toward anyone who is sincerely trying to
contribute to a discussion.
Sure, C++ testing is serious business and all that, but it's also
a lot of fun. Let's keep it that way. Let's strive to be one of the
friendliest communities in all of open source.
As always, discuss Google Test in the official GoogleTest discussion group.
You don't have to actually submit code in order to sign up. Your participation
itself is a valuable contribution.
# Working with the Code #
If you want to get your hands dirty with the code inside Google Test,
this is the section for you.
## Compiling from Source ##
Once you check out the code, you can find instructions on how to
compile it in the [README](../README.md) file.
## Testing ##
A testing framework is of no good if itself is not thoroughly tested.
Tests should be written for any new code, and changes should be
verified to not break existing tests before they are submitted for
review. To perform the tests, follow the instructions in
[README](../README.md) and verify that there are no failures.
# Contributing Code #
We are excited that Google Test is now open source, and hope to get
great patches from the community. Before you fire up your favorite IDE
and begin hammering away at that new feature, though, please take the
time to read this section and understand the process. While it seems
rigorous, we want to keep a high standard of quality in the code
base.
## Contributor License Agreements ##
You must sign a Contributor License Agreement (CLA) before we can
accept any code. The CLA protects you and us.
* If you are an individual writing original source code and you're sure you own the intellectual property, then you'll need to sign an [individual CLA](http://code.google.com/legal/individual-cla-v1.0.html).
* If you work for a company that wants to allow you to contribute your work to Google Test, then you'll need to sign a [corporate CLA](http://code.google.com/legal/corporate-cla-v1.0.html).
Follow either of the two links above to access the appropriate CLA and
instructions for how to sign and return it.
## Coding Style ##
To keep the source consistent, readable, diffable and easy to merge,
we use a fairly rigid coding style, as defined by the [google-styleguide](http://code.google.com/p/google-styleguide/) project. All patches will be expected
to conform to the style outlined [here](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml).
## Updating Generated Code ##
Some of Google Test's source files are generated by the Pump tool (a
Python script). If you need to update such files, please modify the
source (`foo.h.pump`) and re-generate the C++ file using Pump. You
can read the PumpManual for details.
## Submitting Patches ##
Please do submit code. Here's what you need to do:
1. A submission should be a set of changes that addresses one issue in the [issue tracker](https://github.com/google/googletest/issues). Please don't mix more than one logical change per submittal, because it makes the history hard to follow. If you want to make a change that doesn't have a corresponding issue in the issue tracker, please create one.
1. Also, coordinate with team members that are listed on the issue in question. This ensures that work isn't being duplicated and communicating your plan early also generally leads to better patches.
1. Ensure that your code adheres to the [Google Test source code style](#Coding_Style.md).
1. Ensure that there are unit tests for your code.
1. Sign a Contributor License Agreement.
1. Create a Pull Request in the usual way.
## Google Test Committers ##
The current members of the Google Test engineering team are the only
committers at present. In the great tradition of eating one's own
dogfood, we will be requiring each new Google Test engineering team
member to earn the right to become a committer by following the
procedures in this document, writing consistently great code, and
demonstrating repeatedly that he or she truly gets the zen of Google
Test.
# Release Process #
We follow a typical release process:
1. A release branch named `release-X.Y` is created.
1. Bugs are fixed and features are added in trunk; those individual patches are merged into the release branch until it's stable.
1. An individual point release (the `Z` in `X.Y.Z`) is made by creating a tag from the branch.
1. Repeat steps 2 and 3 throughout one release cycle (as determined by features or time).
1. Go back to step 1 to create another release branch and so on.
---
This page is based on the [Making GWT Better](http://code.google.com/webtoolkit/makinggwtbetter.html) guide from the [Google Web Toolkit](http://code.google.com/webtoolkit/) project. Except as otherwise [noted](http://code.google.com/policies.html#restrictions), the content of this page is licensed under the [Creative Commons Attribution 2.5 License](http://creativecommons.org/licenses/by/2.5/).

View File

@@ -0,0 +1,14 @@
This page lists all documentation wiki pages for Google Test **(the SVN trunk version)**
-- **if you use a released version of Google Test, please read the
documentation for that specific version instead.**
* [Primer](Primer.md) -- start here if you are new to Google Test.
* [Samples](Samples.md) -- learn from examples.
* [AdvancedGuide](AdvancedGuide.md) -- learn more about Google Test.
* [XcodeGuide](XcodeGuide.md) -- how to use Google Test in Xcode on Mac.
* [Frequently-Asked Questions](FAQ.md) -- check here before asking a question on the mailing list.
To contribute code to Google Test, read:
* [DevGuide](DevGuide.md) -- read this _before_ writing your first patch.
* [PumpManual](PumpManual.md) -- how we generate some of Google Test's source files.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,502 @@
# Introduction: Why Google C++ Testing Framework? #
_Google C++ Testing Framework_ helps you write better C++ tests.
No matter whether you work on Linux, Windows, or a Mac, if you write C++ code,
Google Test can help you.
So what makes a good test, and how does Google C++ Testing Framework fit in? We believe:
1. Tests should be _independent_ and _repeatable_. It's a pain to debug a test that succeeds or fails as a result of other tests. Google C++ Testing Framework isolates the tests by running each of them on a different object. When a test fails, Google C++ Testing Framework allows you to run it in isolation for quick debugging.
1. Tests should be well _organized_ and reflect the structure of the tested code. Google C++ Testing Framework groups related tests into test cases that can share data and subroutines. This common pattern is easy to recognize and makes tests easy to maintain. Such consistency is especially helpful when people switch projects and start to work on a new code base.
1. Tests should be _portable_ and _reusable_. The open-source community has a lot of code that is platform-neutral, its tests should also be platform-neutral. Google C++ Testing Framework works on different OSes, with different compilers (gcc, MSVC, and others), with or without exceptions, so Google C++ Testing Framework tests can easily work with a variety of configurations. (Note that the current release only contains build scripts for Linux - we are actively working on scripts for other platforms.)
1. When tests fail, they should provide as much _information_ about the problem as possible. Google C++ Testing Framework doesn't stop at the first test failure. Instead, it only stops the current test and continues with the next. You can also set up tests that report non-fatal failures after which the current test continues. Thus, you can detect and fix multiple bugs in a single run-edit-compile cycle.
1. The testing framework should liberate test writers from housekeeping chores and let them focus on the test _content_. Google C++ Testing Framework automatically keeps track of all tests defined, and doesn't require the user to enumerate them in order to run them.
1. Tests should be _fast_. With Google C++ Testing Framework, you can reuse shared resources across tests and pay for the set-up/tear-down only once, without making tests depend on each other.
Since Google C++ Testing Framework is based on the popular xUnit
architecture, you'll feel right at home if you've used JUnit or PyUnit before.
If not, it will take you about 10 minutes to learn the basics and get started.
So let's go!
_Note:_ We sometimes refer to Google C++ Testing Framework informally
as _Google Test_.
# Setting up a New Test Project #
To write a test program using Google Test, you need to compile Google
Test into a library and link your test with it. We provide build
files for some popular build systems: `msvc/` for Visual Studio,
`xcode/` for Mac Xcode, `make/` for GNU make, `codegear/` for Borland
C++ Builder, and the autotools script (deprecated) and
`CMakeLists.txt` for CMake (recommended) in the Google Test root
directory. If your build system is not on this list, you can take a
look at `make/Makefile` to learn how Google Test should be compiled
(basically you want to compile `src/gtest-all.cc` with `GTEST_ROOT`
and `GTEST_ROOT/include` in the header search path, where `GTEST_ROOT`
is the Google Test root directory).
Once you are able to compile the Google Test library, you should
create a project or build target for your test program. Make sure you
have `GTEST_ROOT/include` in the header search path so that the
compiler can find `"gtest/gtest.h"` when compiling your test. Set up
your test project to link with the Google Test library (for example,
in Visual Studio, this is done by adding a dependency on
`gtest.vcproj`).
If you still have questions, take a look at how Google Test's own
tests are built and use them as examples.
# Basic Concepts #
When using Google Test, you start by writing _assertions_, which are statements
that check whether a condition is true. An assertion's result can be _success_,
_nonfatal failure_, or _fatal failure_. If a fatal failure occurs, it aborts
the current function; otherwise the program continues normally.
_Tests_ use assertions to verify the tested code's behavior. If a test crashes
or has a failed assertion, then it _fails_; otherwise it _succeeds_.
A _test case_ contains one or many tests. You should group your tests into test
cases that reflect the structure of the tested code. When multiple tests in a
test case need to share common objects and subroutines, you can put them into a
_test fixture_ class.
A _test program_ can contain multiple test cases.
We'll now explain how to write a test program, starting at the individual
assertion level and building up to tests and test cases.
# Assertions #
Google Test assertions are macros that resemble function calls. You test a
class or function by making assertions about its behavior. When an assertion
fails, Google Test prints the assertion's source file and line number location,
along with a failure message. You may also supply a custom failure message
which will be appended to Google Test's message.
The assertions come in pairs that test the same thing but have different
effects on the current function. `ASSERT_*` versions generate fatal failures
when they fail, and **abort the current function**. `EXPECT_*` versions generate
nonfatal failures, which don't abort the current function. Usually `EXPECT_*`
are preferred, as they allow more than one failures to be reported in a test.
However, you should use `ASSERT_*` if it doesn't make sense to continue when
the assertion in question fails.
Since a failed `ASSERT_*` returns from the current function immediately,
possibly skipping clean-up code that comes after it, it may cause a space leak.
Depending on the nature of the leak, it may or may not be worth fixing - so
keep this in mind if you get a heap checker error in addition to assertion
errors.
To provide a custom failure message, simply stream it into the macro using the
`<<` operator, or a sequence of such operators. An example:
```
ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length";
for (int i = 0; i < x.size(); ++i) {
EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i;
}
```
Anything that can be streamed to an `ostream` can be streamed to an assertion
macro--in particular, C strings and `string` objects. If a wide string
(`wchar_t*`, `TCHAR*` in `UNICODE` mode on Windows, or `std::wstring`) is
streamed to an assertion, it will be translated to UTF-8 when printed.
## Basic Assertions ##
These assertions do basic true/false condition testing.
| **Fatal assertion** | **Nonfatal assertion** | **Verifies** |
|:--------------------|:-----------------------|:-------------|
| `ASSERT_TRUE(`_condition_`)`; | `EXPECT_TRUE(`_condition_`)`; | _condition_ is true |
| `ASSERT_FALSE(`_condition_`)`; | `EXPECT_FALSE(`_condition_`)`; | _condition_ is false |
Remember, when they fail, `ASSERT_*` yields a fatal failure and
returns from the current function, while `EXPECT_*` yields a nonfatal
failure, allowing the function to continue running. In either case, an
assertion failure means its containing test fails.
_Availability_: Linux, Windows, Mac.
## Binary Comparison ##
This section describes assertions that compare two values.
| **Fatal assertion** | **Nonfatal assertion** | **Verifies** |
|:--------------------|:-----------------------|:-------------|
|`ASSERT_EQ(`_val1_`, `_val2_`);`|`EXPECT_EQ(`_val1_`, `_val2_`);`| _val1_ `==` _val2_ |
|`ASSERT_NE(`_val1_`, `_val2_`);`|`EXPECT_NE(`_val1_`, `_val2_`);`| _val1_ `!=` _val2_ |
|`ASSERT_LT(`_val1_`, `_val2_`);`|`EXPECT_LT(`_val1_`, `_val2_`);`| _val1_ `<` _val2_ |
|`ASSERT_LE(`_val1_`, `_val2_`);`|`EXPECT_LE(`_val1_`, `_val2_`);`| _val1_ `<=` _val2_ |
|`ASSERT_GT(`_val1_`, `_val2_`);`|`EXPECT_GT(`_val1_`, `_val2_`);`| _val1_ `>` _val2_ |
|`ASSERT_GE(`_val1_`, `_val2_`);`|`EXPECT_GE(`_val1_`, `_val2_`);`| _val1_ `>=` _val2_ |
In the event of a failure, Google Test prints both _val1_ and _val2_.
Value arguments must be comparable by the assertion's comparison
operator or you'll get a compiler error. We used to require the
arguments to support the `<<` operator for streaming to an `ostream`,
but it's no longer necessary since v1.6.0 (if `<<` is supported, it
will be called to print the arguments when the assertion fails;
otherwise Google Test will attempt to print them in the best way it
can. For more details and how to customize the printing of the
arguments, see this Google Mock [recipe](../../googlemock/docs/CookBook.md#teaching-google-mock-how-to-print-your-values).).
These assertions can work with a user-defined type, but only if you define the
corresponding comparison operator (e.g. `==`, `<`, etc). If the corresponding
operator is defined, prefer using the `ASSERT_*()` macros because they will
print out not only the result of the comparison, but the two operands as well.
Arguments are always evaluated exactly once. Therefore, it's OK for the
arguments to have side effects. However, as with any ordinary C/C++ function,
the arguments' evaluation order is undefined (i.e. the compiler is free to
choose any order) and your code should not depend on any particular argument
evaluation order.
`ASSERT_EQ()` does pointer equality on pointers. If used on two C strings, it
tests if they are in the same memory location, not if they have the same value.
Therefore, if you want to compare C strings (e.g. `const char*`) by value, use
`ASSERT_STREQ()` , which will be described later on. In particular, to assert
that a C string is `NULL`, use `ASSERT_STREQ(NULL, c_string)` . However, to
compare two `string` objects, you should use `ASSERT_EQ`.
Macros in this section work with both narrow and wide string objects (`string`
and `wstring`).
_Availability_: Linux, Windows, Mac.
_Historical note_: Before February 2016 `*_EQ` had a convention of calling it as
`ASSERT_EQ(expected, actual)`, so lots of existing code uses this order.
Now `*_EQ` treats both parameters in the same way.
## String Comparison ##
The assertions in this group compare two **C strings**. If you want to compare
two `string` objects, use `EXPECT_EQ`, `EXPECT_NE`, and etc instead.
| **Fatal assertion** | **Nonfatal assertion** | **Verifies** |
|:--------------------|:-----------------------|:-------------|
| `ASSERT_STREQ(`_str1_`, `_str2_`);` | `EXPECT_STREQ(`_str1_`, `_str_2`);` | the two C strings have the same content |
| `ASSERT_STRNE(`_str1_`, `_str2_`);` | `EXPECT_STRNE(`_str1_`, `_str2_`);` | the two C strings have different content |
| `ASSERT_STRCASEEQ(`_str1_`, `_str2_`);`| `EXPECT_STRCASEEQ(`_str1_`, `_str2_`);` | the two C strings have the same content, ignoring case |
| `ASSERT_STRCASENE(`_str1_`, `_str2_`);`| `EXPECT_STRCASENE(`_str1_`, `_str2_`);` | the two C strings have different content, ignoring case |
Note that "CASE" in an assertion name means that case is ignored.
`*STREQ*` and `*STRNE*` also accept wide C strings (`wchar_t*`). If a
comparison of two wide strings fails, their values will be printed as UTF-8
narrow strings.
A `NULL` pointer and an empty string are considered _different_.
_Availability_: Linux, Windows, Mac.
See also: For more string comparison tricks (substring, prefix, suffix, and
regular expression matching, for example), see the [Advanced Google Test Guide](AdvancedGuide.md).
# Simple Tests #
To create a test:
1. Use the `TEST()` macro to define and name a test function, These are ordinary C++ functions that don't return a value.
1. In this function, along with any valid C++ statements you want to include, use the various Google Test assertions to check values.
1. The test's result is determined by the assertions; if any assertion in the test fails (either fatally or non-fatally), or if the test crashes, the entire test fails. Otherwise, it succeeds.
```
TEST(test_case_name, test_name) {
... test body ...
}
```
`TEST()` arguments go from general to specific. The _first_ argument is the
name of the test case, and the _second_ argument is the test's name within the
test case. Both names must be valid C++ identifiers, and they should not contain underscore (`_`). A test's _full name_ consists of its containing test case and its
individual name. Tests from different test cases can have the same individual
name.
For example, let's take a simple integer function:
```
int Factorial(int n); // Returns the factorial of n
```
A test case for this function might look like:
```
// Tests factorial of 0.
TEST(FactorialTest, HandlesZeroInput) {
EXPECT_EQ(1, Factorial(0));
}
// Tests factorial of positive numbers.
TEST(FactorialTest, HandlesPositiveInput) {
EXPECT_EQ(1, Factorial(1));
EXPECT_EQ(2, Factorial(2));
EXPECT_EQ(6, Factorial(3));
EXPECT_EQ(40320, Factorial(8));
}
```
Google Test groups the test results by test cases, so logically-related tests
should be in the same test case; in other words, the first argument to their
`TEST()` should be the same. In the above example, we have two tests,
`HandlesZeroInput` and `HandlesPositiveInput`, that belong to the same test
case `FactorialTest`.
_Availability_: Linux, Windows, Mac.
# Test Fixtures: Using the Same Data Configuration for Multiple Tests #
If you find yourself writing two or more tests that operate on similar data,
you can use a _test fixture_. It allows you to reuse the same configuration of
objects for several different tests.
To create a fixture, just:
1. Derive a class from `::testing::Test` . Start its body with `protected:` or `public:` as we'll want to access fixture members from sub-classes.
1. Inside the class, declare any objects you plan to use.
1. If necessary, write a default constructor or `SetUp()` function to prepare the objects for each test. A common mistake is to spell `SetUp()` as `Setup()` with a small `u` - don't let that happen to you.
1. If necessary, write a destructor or `TearDown()` function to release any resources you allocated in `SetUp()` . To learn when you should use the constructor/destructor and when you should use `SetUp()/TearDown()`, read this [FAQ entry](FAQ.md#should-i-use-the-constructordestructor-of-the-test-fixture-or-the-set-uptear-down-function).
1. If needed, define subroutines for your tests to share.
When using a fixture, use `TEST_F()` instead of `TEST()` as it allows you to
access objects and subroutines in the test fixture:
```
TEST_F(test_case_name, test_name) {
... test body ...
}
```
Like `TEST()`, the first argument is the test case name, but for `TEST_F()`
this must be the name of the test fixture class. You've probably guessed: `_F`
is for fixture.
Unfortunately, the C++ macro system does not allow us to create a single macro
that can handle both types of tests. Using the wrong macro causes a compiler
error.
Also, you must first define a test fixture class before using it in a
`TEST_F()`, or you'll get the compiler error "`virtual outside class
declaration`".
For each test defined with `TEST_F()`, Google Test will:
1. Create a _fresh_ test fixture at runtime
1. Immediately initialize it via `SetUp()` ,
1. Run the test
1. Clean up by calling `TearDown()`
1. Delete the test fixture. Note that different tests in the same test case have different test fixture objects, and Google Test always deletes a test fixture before it creates the next one. Google Test does not reuse the same test fixture for multiple tests. Any changes one test makes to the fixture do not affect other tests.
As an example, let's write tests for a FIFO queue class named `Queue`, which
has the following interface:
```
template <typename E> // E is the element type.
class Queue {
public:
Queue();
void Enqueue(const E& element);
E* Dequeue(); // Returns NULL if the queue is empty.
size_t size() const;
...
};
```
First, define a fixture class. By convention, you should give it the name
`FooTest` where `Foo` is the class being tested.
```
class QueueTest : public ::testing::Test {
protected:
virtual void SetUp() {
q1_.Enqueue(1);
q2_.Enqueue(2);
q2_.Enqueue(3);
}
// virtual void TearDown() {}
Queue<int> q0_;
Queue<int> q1_;
Queue<int> q2_;
};
```
In this case, `TearDown()` is not needed since we don't have to clean up after
each test, other than what's already done by the destructor.
Now we'll write tests using `TEST_F()` and this fixture.
```
TEST_F(QueueTest, IsEmptyInitially) {
EXPECT_EQ(0, q0_.size());
}
TEST_F(QueueTest, DequeueWorks) {
int* n = q0_.Dequeue();
EXPECT_EQ(NULL, n);
n = q1_.Dequeue();
ASSERT_TRUE(n != NULL);
EXPECT_EQ(1, *n);
EXPECT_EQ(0, q1_.size());
delete n;
n = q2_.Dequeue();
ASSERT_TRUE(n != NULL);
EXPECT_EQ(2, *n);
EXPECT_EQ(1, q2_.size());
delete n;
}
```
The above uses both `ASSERT_*` and `EXPECT_*` assertions. The rule of thumb is
to use `EXPECT_*` when you want the test to continue to reveal more errors
after the assertion failure, and use `ASSERT_*` when continuing after failure
doesn't make sense. For example, the second assertion in the `Dequeue` test is
`ASSERT_TRUE(n != NULL)`, as we need to dereference the pointer `n` later,
which would lead to a segfault when `n` is `NULL`.
When these tests run, the following happens:
1. Google Test constructs a `QueueTest` object (let's call it `t1` ).
1. `t1.SetUp()` initializes `t1` .
1. The first test ( `IsEmptyInitially` ) runs on `t1` .
1. `t1.TearDown()` cleans up after the test finishes.
1. `t1` is destructed.
1. The above steps are repeated on another `QueueTest` object, this time running the `DequeueWorks` test.
_Availability_: Linux, Windows, Mac.
_Note_: Google Test automatically saves all _Google Test_ flags when a test
object is constructed, and restores them when it is destructed.
# Invoking the Tests #
`TEST()` and `TEST_F()` implicitly register their tests with Google Test. So, unlike with many other C++ testing frameworks, you don't have to re-list all your defined tests in order to run them.
After defining your tests, you can run them with `RUN_ALL_TESTS()` , which returns `0` if all the tests are successful, or `1` otherwise. Note that `RUN_ALL_TESTS()` runs _all tests_ in your link unit -- they can be from different test cases, or even different source files.
When invoked, the `RUN_ALL_TESTS()` macro:
1. Saves the state of all Google Test flags.
1. Creates a test fixture object for the first test.
1. Initializes it via `SetUp()`.
1. Runs the test on the fixture object.
1. Cleans up the fixture via `TearDown()`.
1. Deletes the fixture.
1. Restores the state of all Google Test flags.
1. Repeats the above steps for the next test, until all tests have run.
In addition, if the text fixture's constructor generates a fatal failure in
step 2, there is no point for step 3 - 5 and they are thus skipped. Similarly,
if step 3 generates a fatal failure, step 4 will be skipped.
_Important_: You must not ignore the return value of `RUN_ALL_TESTS()`, or `gcc`
will give you a compiler error. The rationale for this design is that the
automated testing service determines whether a test has passed based on its
exit code, not on its stdout/stderr output; thus your `main()` function must
return the value of `RUN_ALL_TESTS()`.
Also, you should call `RUN_ALL_TESTS()` only **once**. Calling it more than once
conflicts with some advanced Google Test features (e.g. thread-safe death
tests) and thus is not supported.
_Availability_: Linux, Windows, Mac.
# Writing the main() Function #
You can start from this boilerplate:
```
#include "this/package/foo.h"
#include "gtest/gtest.h"
namespace {
// The fixture for testing class Foo.
class FooTest : public ::testing::Test {
protected:
// You can remove any or all of the following functions if its body
// is empty.
FooTest() {
// You can do set-up work for each test here.
}
virtual ~FooTest() {
// You can do clean-up work that doesn't throw exceptions here.
}
// If the constructor and destructor are not enough for setting up
// and cleaning up each test, you can define the following methods:
virtual void SetUp() {
// Code here will be called immediately after the constructor (right
// before each test).
}
virtual void TearDown() {
// Code here will be called immediately after each test (right
// before the destructor).
}
// Objects declared here can be used by all tests in the test case for Foo.
};
// Tests that the Foo::Bar() method does Abc.
TEST_F(FooTest, MethodBarDoesAbc) {
const string input_filepath = "this/package/testdata/myinputfile.dat";
const string output_filepath = "this/package/testdata/myoutputfile.dat";
Foo f;
EXPECT_EQ(0, f.Bar(input_filepath, output_filepath));
}
// Tests that Foo does Xyz.
TEST_F(FooTest, DoesXyz) {
// Exercises the Xyz feature of Foo.
}
} // namespace
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
```
The `::testing::InitGoogleTest()` function parses the command line for Google
Test flags, and removes all recognized flags. This allows the user to control a
test program's behavior via various flags, which we'll cover in [AdvancedGuide](AdvancedGuide.md).
You must call this function before calling `RUN_ALL_TESTS()`, or the flags
won't be properly initialized.
On Windows, `InitGoogleTest()` also works with wide strings, so it can be used
in programs compiled in `UNICODE` mode as well.
But maybe you think that writing all those main() functions is too much work? We agree with you completely and that's why Google Test provides a basic implementation of main(). If it fits your needs, then just link your test with gtest\_main library and you are good to go.
## Important note for Visual C++ users ##
If you put your tests into a library and your `main()` function is in a different library or in your .exe file, those tests will not run. The reason is a [bug](https://connect.microsoft.com/feedback/viewfeedback.aspx?FeedbackID=244410&siteid=210) in Visual C++. When you define your tests, Google Test creates certain static objects to register them. These objects are not referenced from elsewhere but their constructors are still supposed to run. When Visual C++ linker sees that nothing in the library is referenced from other places it throws the library out. You have to reference your library with tests from your main program to keep the linker from discarding it. Here is how to do it. Somewhere in your library code declare a function:
```
__declspec(dllexport) int PullInMyLibrary() { return 0; }
```
If you put your tests in a static library (not DLL) then `__declspec(dllexport)` is not required. Now, in your main program, write a code that invokes that function:
```
int PullInMyLibrary();
static int dummy = PullInMyLibrary();
```
This will keep your tests referenced and will make them register themselves at startup.
In addition, if you define your tests in a static library, add `/OPT:NOREF` to your main program linker options. If you use MSVC++ IDE, go to your .exe project properties/Configuration Properties/Linker/Optimization and set References setting to `Keep Unreferenced Data (/OPT:NOREF)`. This will keep Visual C++ linker from discarding individual symbols generated by your tests from the final executable.
There is one more pitfall, though. If you use Google Test as a static library (that's how it is defined in gtest.vcproj) your tests must also reside in a static library. If you have to have them in a DLL, you _must_ change Google Test to build into a DLL as well. Otherwise your tests will not run correctly or will not run at all. The general conclusion here is: make your life easier - do not write your tests in libraries!
# Where to Go from Here #
Congratulations! You've learned the Google Test basics. You can start writing
and running Google Test tests, read some [samples](Samples.md), or continue with
[AdvancedGuide](AdvancedGuide.md), which describes many more useful Google Test features.
# Known Limitations #
Google Test is designed to be thread-safe. The implementation is
thread-safe on systems where the `pthreads` library is available. It
is currently _unsafe_ to use Google Test assertions from two threads
concurrently on other systems (e.g. Windows). In most tests this is
not an issue as usually the assertions are done in the main thread. If
you want to help, you can volunteer to implement the necessary
synchronization primitives in `gtest-port.h` for your platform.

View File

@@ -0,0 +1,177 @@
<b>P</b>ump is <b>U</b>seful for <b>M</b>eta <b>P</b>rogramming.
# The Problem #
Template and macro libraries often need to define many classes,
functions, or macros that vary only (or almost only) in the number of
arguments they take. It's a lot of repetitive, mechanical, and
error-prone work.
Variadic templates and variadic macros can alleviate the problem.
However, while both are being considered by the C++ committee, neither
is in the standard yet or widely supported by compilers. Thus they
are often not a good choice, especially when your code needs to be
portable. And their capabilities are still limited.
As a result, authors of such libraries often have to write scripts to
generate their implementation. However, our experience is that it's
tedious to write such scripts, which tend to reflect the structure of
the generated code poorly and are often hard to read and edit. For
example, a small change needed in the generated code may require some
non-intuitive, non-trivial changes in the script. This is especially
painful when experimenting with the code.
# Our Solution #
Pump (for Pump is Useful for Meta Programming, Pretty Useful for Meta
Programming, or Practical Utility for Meta Programming, whichever you
prefer) is a simple meta-programming tool for C++. The idea is that a
programmer writes a `foo.pump` file which contains C++ code plus meta
code that manipulates the C++ code. The meta code can handle
iterations over a range, nested iterations, local meta variable
definitions, simple arithmetic, and conditional expressions. You can
view it as a small Domain-Specific Language. The meta language is
designed to be non-intrusive (s.t. it won't confuse Emacs' C++ mode,
for example) and concise, making Pump code intuitive and easy to
maintain.
## Highlights ##
* The implementation is in a single Python script and thus ultra portable: no build or installation is needed and it works cross platforms.
* Pump tries to be smart with respect to [Google's style guide](http://code.google.com/p/google-styleguide/): it breaks long lines (easy to have when they are generated) at acceptable places to fit within 80 columns and indent the continuation lines correctly.
* The format is human-readable and more concise than XML.
* The format works relatively well with Emacs' C++ mode.
## Examples ##
The following Pump code (where meta keywords start with `$`, `[[` and `]]` are meta brackets, and `$$` starts a meta comment that ends with the line):
```
$var n = 3 $$ Defines a meta variable n.
$range i 0..n $$ Declares the range of meta iterator i (inclusive).
$for i [[
$$ Meta loop.
// Foo$i does blah for $i-ary predicates.
$range j 1..i
template <size_t N $for j [[, typename A$j]]>
class Foo$i {
$if i == 0 [[
blah a;
]] $elif i <= 2 [[
blah b;
]] $else [[
blah c;
]]
};
]]
```
will be translated by the Pump compiler to:
```
// Foo0 does blah for 0-ary predicates.
template <size_t N>
class Foo0 {
blah a;
};
// Foo1 does blah for 1-ary predicates.
template <size_t N, typename A1>
class Foo1 {
blah b;
};
// Foo2 does blah for 2-ary predicates.
template <size_t N, typename A1, typename A2>
class Foo2 {
blah b;
};
// Foo3 does blah for 3-ary predicates.
template <size_t N, typename A1, typename A2, typename A3>
class Foo3 {
blah c;
};
```
In another example,
```
$range i 1..n
Func($for i + [[a$i]]);
$$ The text between i and [[ is the separator between iterations.
```
will generate one of the following lines (without the comments), depending on the value of `n`:
```
Func(); // If n is 0.
Func(a1); // If n is 1.
Func(a1 + a2); // If n is 2.
Func(a1 + a2 + a3); // If n is 3.
// And so on...
```
## Constructs ##
We support the following meta programming constructs:
| `$var id = exp` | Defines a named constant value. `$id` is valid util the end of the current meta lexical block. |
|:----------------|:-----------------------------------------------------------------------------------------------|
| `$range id exp..exp` | Sets the range of an iteration variable, which can be reused in multiple loops later. |
| `$for id sep [[ code ]]` | Iteration. The range of `id` must have been defined earlier. `$id` is valid in `code`. |
| `$($)` | Generates a single `$` character. |
| `$id` | Value of the named constant or iteration variable. |
| `$(exp)` | Value of the expression. |
| `$if exp [[ code ]] else_branch` | Conditional. |
| `[[ code ]]` | Meta lexical block. |
| `cpp_code` | Raw C++ code. |
| `$$ comment` | Meta comment. |
**Note:** To give the user some freedom in formatting the Pump source
code, Pump ignores a new-line character if it's right after `$for foo`
or next to `[[` or `]]`. Without this rule you'll often be forced to write
very long lines to get the desired output. Therefore sometimes you may
need to insert an extra new-line in such places for a new-line to show
up in your output.
## Grammar ##
```
code ::= atomic_code*
atomic_code ::= $var id = exp
| $var id = [[ code ]]
| $range id exp..exp
| $for id sep [[ code ]]
| $($)
| $id
| $(exp)
| $if exp [[ code ]] else_branch
| [[ code ]]
| cpp_code
sep ::= cpp_code | empty_string
else_branch ::= $else [[ code ]]
| $elif exp [[ code ]] else_branch
| empty_string
exp ::= simple_expression_in_Python_syntax
```
## Code ##
You can find the source code of Pump in [scripts/pump.py](../scripts/pump.py). It is still
very unpolished and lacks automated tests, although it has been
successfully used many times. If you find a chance to use it in your
project, please let us know what you think! We also welcome help on
improving Pump.
## Real Examples ##
You can find real-world applications of Pump in [Google Test](http://www.google.com/codesearch?q=file%3A\.pump%24+package%3Ahttp%3A%2F%2Fgoogletest\.googlecode\.com) and [Google Mock](http://www.google.com/codesearch?q=file%3A\.pump%24+package%3Ahttp%3A%2F%2Fgooglemock\.googlecode\.com). The source file `foo.h.pump` generates `foo.h`.
## Tips ##
* If a meta variable is followed by a letter or digit, you can separate them using `[[]]`, which inserts an empty string. For example `Foo$j[[]]Helper` generate `Foo1Helper` when `j` is 1.
* To avoid extra-long Pump source lines, you can break a line anywhere you want by inserting `[[]]` followed by a new line. Since any new-line character next to `[[` or `]]` is ignored, the generated code won't contain this new line.

View File

@@ -0,0 +1,14 @@
If you're like us, you'd like to look at some Google Test sample code. The
[samples folder](../samples) has a number of well-commented samples showing how to use a
variety of Google Test features.
* [Sample #1](../samples/sample1_unittest.cc) shows the basic steps of using Google Test to test C++ functions.
* [Sample #2](../samples/sample2_unittest.cc) shows a more complex unit test for a class with multiple member functions.
* [Sample #3](../samples/sample3_unittest.cc) uses a test fixture.
* [Sample #4](../samples/sample4_unittest.cc) is another basic example of using Google Test.
* [Sample #5](../samples/sample5_unittest.cc) teaches how to reuse a test fixture in multiple test cases by deriving sub-fixtures from it.
* [Sample #6](../samples/sample6_unittest.cc) demonstrates type-parameterized tests.
* [Sample #7](../samples/sample7_unittest.cc) teaches the basics of value-parameterized tests.
* [Sample #8](../samples/sample8_unittest.cc) shows using `Combine()` in value-parameterized tests.
* [Sample #9](../samples/sample9_unittest.cc) shows use of the listener API to modify Google Test's console output and the use of its reflection API to inspect test results.
* [Sample #10](../samples/sample10_unittest.cc) shows use of the listener API to implement a primitive memory leak checker.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
This page lists all official documentation wiki pages for Google Test **1.5.0** -- **if you use a different version of Google Test, make sure to read the documentation for that version instead.**
* [Primer](V1_5_Primer.md) -- start here if you are new to Google Test.
* [Samples](Samples.md) -- learn from examples.
* [AdvancedGuide](V1_5_AdvancedGuide.md) -- learn more about Google Test.
* [XcodeGuide](V1_5_XcodeGuide.md) -- how to use Google Test in Xcode on Mac.
* [Frequently-Asked Questions](V1_5_FAQ.md) -- check here before asking a question on the mailing list.
To contribute code to Google Test, read:
* DevGuide -- read this _before_ writing your first patch.
* [PumpManual](V1_5_PumpManual.md) -- how we generate some of Google Test's source files.

View File

@@ -0,0 +1,886 @@
If you cannot find the answer to your question here, and you have read
[Primer](V1_5_Primer.md) and [AdvancedGuide](V1_5_AdvancedGuide.md), send it to
googletestframework@googlegroups.com.
## Why should I use Google Test instead of my favorite C++ testing framework? ##
First, let's say clearly that we don't want to get into the debate of
which C++ testing framework is **the best**. There exist many fine
frameworks for writing C++ tests, and we have tremendous respect for
the developers and users of them. We don't think there is (or will
be) a single best framework - you have to pick the right tool for the
particular task you are tackling.
We created Google Test because we couldn't find the right combination
of features and conveniences in an existing framework to satisfy _our_
needs. The following is a list of things that _we_ like about Google
Test. We don't claim them to be unique to Google Test - rather, the
combination of them makes Google Test the choice for us. We hope this
list can help you decide whether it is for you too.
* Google Test is designed to be portable. It works where many STL types (e.g. `std::string` and `std::vector`) don't compile. It doesn't require exceptions or RTTI. As a result, it runs on Linux, Mac OS X, Windows and several embedded operating systems.
* Nonfatal assertions (`EXPECT_*`) have proven to be great time savers, as they allow a test to report multiple failures in a single edit-compile-test cycle.
* It's easy to write assertions that generate informative messages: you just use the stream syntax to append any additional information, e.g. `ASSERT_EQ(5, Foo(i)) << " where i = " << i;`. It doesn't require a new set of macros or special functions.
* Google Test automatically detects your tests and doesn't require you to enumerate them in order to run them.
* No framework can anticipate all your needs, so Google Test provides `EXPECT_PRED*` to make it easy to extend your assertion vocabulary. For a nicer syntax, you can define your own assertion macros trivially in terms of `EXPECT_PRED*`.
* Death tests are pretty handy for ensuring that your asserts in production code are triggered by the right conditions.
* `SCOPED_TRACE` helps you understand the context of an assertion failure when it comes from inside a sub-routine or loop.
* You can decide which tests to run using name patterns. This saves time when you want to quickly reproduce a test failure.
## How do I generate 64-bit binaries on Windows (using Visual Studio 2008)? ##
(Answered by Trevor Robinson)
Load the supplied Visual Studio solution file, either `msvc\gtest-md.sln` or
`msvc\gtest.sln`. Go through the migration wizard to migrate the
solution and project files to Visual Studio 2008. Select
`Configuration Manager...` from the `Build` menu. Select `<New...>` from
the `Active solution platform` dropdown. Select `x64` from the new
platform dropdown, leave `Copy settings from` set to `Win32` and
`Create new project platforms` checked, then click `OK`. You now have
`Win32` and `x64` platform configurations, selectable from the
`Standard` toolbar, which allow you to toggle between building 32-bit or
64-bit binaries (or both at once using Batch Build).
In order to prevent build output files from overwriting one another,
you'll need to change the `Intermediate Directory` settings for the
newly created platform configuration across all the projects. To do
this, multi-select (e.g. using shift-click) all projects (but not the
solution) in the `Solution Explorer`. Right-click one of them and
select `Properties`. In the left pane, select `Configuration Properties`,
and from the `Configuration` dropdown, select `All Configurations`.
Make sure the selected platform is `x64`. For the
`Intermediate Directory` setting, change the value from
`$(PlatformName)\$(ConfigurationName)` to
`$(OutDir)\$(ProjectName)`. Click `OK` and then build the
solution. When the build is complete, the 64-bit binaries will be in
the `msvc\x64\Debug` directory.
## Can I use Google Test on MinGW? ##
We haven't tested this ourselves, but Per Abrahamsen reported that he
was able to compile and install Google Test successfully when using
MinGW from Cygwin. You'll need to configure it with:
`PATH/TO/configure CC="gcc -mno-cygwin" CXX="g++ -mno-cygwin"`
You should be able to replace the `-mno-cygwin` option with direct links
to the real MinGW binaries, but we haven't tried that.
Caveats:
* There are many warnings when compiling.
* `make check` will produce some errors as not all tests for Google Test itself are compatible with MinGW.
We also have reports on successful cross compilation of Google Test MinGW binaries on Linux using [these instructions](http://wiki.wxwidgets.org/Cross-Compiling_Under_Linux#Cross-compiling_under_Linux_for_MS_Windows) on the WxWidgets site.
Please contact `googletestframework@googlegroups.com` if you are
interested in improving the support for MinGW.
## Why does Google Test support EXPECT\_EQ(NULL, ptr) and ASSERT\_EQ(NULL, ptr) but not EXPECT\_NE(NULL, ptr) and ASSERT\_NE(NULL, ptr)? ##
Due to some peculiarity of C++, it requires some non-trivial template
meta programming tricks to support using `NULL` as an argument of the
`EXPECT_XX()` and `ASSERT_XX()` macros. Therefore we only do it where
it's most needed (otherwise we make the implementation of Google Test
harder to maintain and more error-prone than necessary).
The `EXPECT_EQ()` macro takes the _expected_ value as its first
argument and the _actual_ value as the second. It's reasonable that
someone wants to write `EXPECT_EQ(NULL, some_expression)`, and this
indeed was requested several times. Therefore we implemented it.
The need for `EXPECT_NE(NULL, ptr)` isn't nearly as strong. When the
assertion fails, you already know that `ptr` must be `NULL`, so it
doesn't add any information to print ptr in this case. That means
`EXPECT_TRUE(ptr ! NULL)` works just as well.
If we were to support `EXPECT_NE(NULL, ptr)`, for consistency we'll
have to support `EXPECT_NE(ptr, NULL)` as well, as unlike `EXPECT_EQ`,
we don't have a convention on the order of the two arguments for
`EXPECT_NE`. This means using the template meta programming tricks
twice in the implementation, making it even harder to understand and
maintain. We believe the benefit doesn't justify the cost.
Finally, with the growth of Google Mock's [matcher](../../CookBook.md#using-matchers-in-google-test-assertions) library, we are
encouraging people to use the unified `EXPECT_THAT(value, matcher)`
syntax more often in tests. One significant advantage of the matcher
approach is that matchers can be easily combined to form new matchers,
while the `EXPECT_NE`, etc, macros cannot be easily
combined. Therefore we want to invest more in the matchers than in the
`EXPECT_XX()` macros.
## Does Google Test support running tests in parallel? ##
Test runners tend to be tightly coupled with the build/test
environment, and Google Test doesn't try to solve the problem of
running tests in parallel. Instead, we tried to make Google Test work
nicely with test runners. For example, Google Test's XML report
contains the time spent on each test, and its `gtest_list_tests` and
`gtest_filter` flags can be used for splitting the execution of test
methods into multiple processes. These functionalities can help the
test runner run the tests in parallel.
## Why don't Google Test run the tests in different threads to speed things up? ##
It's difficult to write thread-safe code. Most tests are not written
with thread-safety in mind, and thus may not work correctly in a
multi-threaded setting.
If you think about it, it's already hard to make your code work when
you know what other threads are doing. It's much harder, and
sometimes even impossible, to make your code work when you don't know
what other threads are doing (remember that test methods can be added,
deleted, or modified after your test was written). If you want to run
the tests in parallel, you'd better run them in different processes.
## Why aren't Google Test assertions implemented using exceptions? ##
Our original motivation was to be able to use Google Test in projects
that disable exceptions. Later we realized some additional benefits
of this approach:
1. Throwing in a destructor is undefined behavior in C++. Not using exceptions means Google Test's assertions are safe to use in destructors.
1. The `EXPECT_*` family of macros will continue even after a failure, allowing multiple failures in a `TEST` to be reported in a single run. This is a popular feature, as in C++ the edit-compile-test cycle is usually quite long and being able to fixing more than one thing at a time is a blessing.
1. If assertions are implemented using exceptions, a test may falsely ignore a failure if it's caught by user code:
```
try { ... ASSERT_TRUE(...) ... }
catch (...) { ... }
```
The above code will pass even if the `ASSERT_TRUE` throws. While it's unlikely for someone to write this in a test, it's possible to run into this pattern when you write assertions in callbacks that are called by the code under test.
The downside of not using exceptions is that `ASSERT_*` (implemented
using `return`) will only abort the current function, not the current
`TEST`.
## Why do we use two different macros for tests with and without fixtures? ##
Unfortunately, C++'s macro system doesn't allow us to use the same
macro for both cases. One possibility is to provide only one macro
for tests with fixtures, and require the user to define an empty
fixture sometimes:
```
class FooTest : public ::testing::Test {};
TEST_F(FooTest, DoesThis) { ... }
```
or
```
typedef ::testing::Test FooTest;
TEST_F(FooTest, DoesThat) { ... }
```
Yet, many people think this is one line too many. :-) Our goal was to
make it really easy to write tests, so we tried to make simple tests
trivial to create. That means using a separate macro for such tests.
We think neither approach is ideal, yet either of them is reasonable.
In the end, it probably doesn't matter much either way.
## Why don't we use structs as test fixtures? ##
We like to use structs only when representing passive data. This
distinction between structs and classes is good for documenting the
intent of the code's author. Since test fixtures have logic like
`SetUp()` and `TearDown()`, they are better defined as classes.
## Why are death tests implemented as assertions instead of using a test runner? ##
Our goal was to make death tests as convenient for a user as C++
possibly allows. In particular:
* The runner-style requires to split the information into two pieces: the definition of the death test itself, and the specification for the runner on how to run the death test and what to expect. The death test would be written in C++, while the runner spec may or may not be. A user needs to carefully keep the two in sync. `ASSERT_DEATH(statement, expected_message)` specifies all necessary information in one place, in one language, without boilerplate code. It is very declarative.
* `ASSERT_DEATH` has a similar syntax and error-reporting semantics as other Google Test assertions, and thus is easy to learn.
* `ASSERT_DEATH` can be mixed with other assertions and other logic at your will. You are not limited to one death test per test method. For example, you can write something like:
```
if (FooCondition()) {
ASSERT_DEATH(Bar(), "blah");
} else {
ASSERT_EQ(5, Bar());
}
```
If you prefer one death test per test method, you can write your tests in that style too, but we don't want to impose that on the users. The fewer artificial limitations the better.
* `ASSERT_DEATH` can reference local variables in the current function, and you can decide how many death tests you want based on run-time information. For example,
```
const int count = GetCount(); // Only known at run time.
for (int i = 1; i <= count; i++) {
ASSERT_DEATH({
double* buffer = new double[i];
... initializes buffer ...
Foo(buffer, i)
}, "blah blah");
}
```
The runner-based approach tends to be more static and less flexible, or requires more user effort to get this kind of flexibility.
Another interesting thing about `ASSERT_DEATH` is that it calls `fork()`
to create a child process to run the death test. This is lightening
fast, as `fork()` uses copy-on-write pages and incurs almost zero
overhead, and the child process starts from the user-supplied
statement directly, skipping all global and local initialization and
any code leading to the given statement. If you launch the child
process from scratch, it can take seconds just to load everything and
start running if the test links to many libraries dynamically.
## My death test modifies some state, but the change seems lost after the death test finishes. Why? ##
Death tests (`EXPECT_DEATH`, etc) are executed in a sub-process s.t. the
expected crash won't kill the test program (i.e. the parent process). As a
result, any in-memory side effects they incur are observable in their
respective sub-processes, but not in the parent process. You can think of them
as running in a parallel universe, more or less.
## The compiler complains about "undefined references" to some static const member variables, but I did define them in the class body. What's wrong? ##
If your class has a static data member:
```
// foo.h
class Foo {
...
static const int kBar = 100;
};
```
You also need to define it _outside_ of the class body in `foo.cc`:
```
const int Foo::kBar; // No initializer here.
```
Otherwise your code is **invalid C++**, and may break in unexpected ways. In
particular, using it in Google Test comparison assertions (`EXPECT_EQ`, etc)
will generate an "undefined reference" linker error.
## I have an interface that has several implementations. Can I write a set of tests once and repeat them over all the implementations? ##
Google Test doesn't yet have good support for this kind of tests, or
data-driven tests in general. We hope to be able to make improvements in this
area soon.
## Can I derive a test fixture from another? ##
Yes.
Each test fixture has a corresponding and same named test case. This means only
one test case can use a particular fixture. Sometimes, however, multiple test
cases may want to use the same or slightly different fixtures. For example, you
may want to make sure that all of a GUI library's test cases don't leak
important system resources like fonts and brushes.
In Google Test, you share a fixture among test cases by putting the shared
logic in a base test fixture, then deriving from that base a separate fixture
for each test case that wants to use this common logic. You then use `TEST_F()`
to write tests using each derived fixture.
Typically, your code looks like this:
```
// Defines a base test fixture.
class BaseTest : public ::testing::Test {
protected:
...
};
// Derives a fixture FooTest from BaseTest.
class FooTest : public BaseTest {
protected:
virtual void SetUp() {
BaseTest::SetUp(); // Sets up the base fixture first.
... additional set-up work ...
}
virtual void TearDown() {
... clean-up work for FooTest ...
BaseTest::TearDown(); // Remember to tear down the base fixture
// after cleaning up FooTest!
}
... functions and variables for FooTest ...
};
// Tests that use the fixture FooTest.
TEST_F(FooTest, Bar) { ... }
TEST_F(FooTest, Baz) { ... }
... additional fixtures derived from BaseTest ...
```
If necessary, you can continue to derive test fixtures from a derived fixture.
Google Test has no limit on how deep the hierarchy can be.
For a complete example using derived test fixtures, see
`samples/sample5_unittest.cc`.
## My compiler complains "void value not ignored as it ought to be." What does this mean? ##
You're probably using an `ASSERT_*()` in a function that doesn't return `void`.
`ASSERT_*()` can only be used in `void` functions.
## My death test hangs (or seg-faults). How do I fix it? ##
In Google Test, death tests are run in a child process and the way they work is
delicate. To write death tests you really need to understand how they work.
Please make sure you have read this.
In particular, death tests don't like having multiple threads in the parent
process. So the first thing you can try is to eliminate creating threads
outside of `EXPECT_DEATH()`.
Sometimes this is impossible as some library you must use may be creating
threads before `main()` is even reached. In this case, you can try to minimize
the chance of conflicts by either moving as many activities as possible inside
`EXPECT_DEATH()` (in the extreme case, you want to move everything inside), or
leaving as few things as possible in it. Also, you can try to set the death
test style to `"threadsafe"`, which is safer but slower, and see if it helps.
If you go with thread-safe death tests, remember that they rerun the test
program from the beginning in the child process. Therefore make sure your
program can run side-by-side with itself and is deterministic.
In the end, this boils down to good concurrent programming. You have to make
sure that there is no race conditions or dead locks in your program. No silver
bullet - sorry!
## Should I use the constructor/destructor of the test fixture or the set-up/tear-down function? ##
The first thing to remember is that Google Test does not reuse the
same test fixture object across multiple tests. For each `TEST_F`,
Google Test will create a fresh test fixture object, _immediately_
call `SetUp()`, run the test, call `TearDown()`, and then
_immediately_ delete the test fixture object. Therefore, there is no
need to write a `SetUp()` or `TearDown()` function if the constructor
or destructor already does the job.
You may still want to use `SetUp()/TearDown()` in the following cases:
* If the tear-down operation could throw an exception, you must use `TearDown()` as opposed to the destructor, as throwing in a destructor leads to undefined behavior and usually will kill your program right away. Note that many standard libraries (like STL) may throw when exceptions are enabled in the compiler. Therefore you should prefer `TearDown()` if you want to write portable tests that work with or without exceptions.
* The Google Test team is considering making the assertion macros throw on platforms where exceptions are enabled (e.g. Windows, Mac OS, and Linux client-side), which will eliminate the need for the user to propagate failures from a subroutine to its caller. Therefore, you shouldn't use Google Test assertions in a destructor if your code could run on such a platform.
* In a constructor or destructor, you cannot make a virtual function call on this object. (You can call a method declared as virtual, but it will be statically bound.) Therefore, if you need to call a method that will be overriden in a derived class, you have to use `SetUp()/TearDown()`.
## The compiler complains "no matching function to call" when I use ASSERT\_PREDn. How do I fix it? ##
If the predicate function you use in `ASSERT_PRED*` or `EXPECT_PRED*` is
overloaded or a template, the compiler will have trouble figuring out which
overloaded version it should use. `ASSERT_PRED_FORMAT*` and
`EXPECT_PRED_FORMAT*` don't have this problem.
If you see this error, you might want to switch to
`(ASSERT|EXPECT)_PRED_FORMAT*`, which will also give you a better failure
message. If, however, that is not an option, you can resolve the problem by
explicitly telling the compiler which version to pick.
For example, suppose you have
```
bool IsPositive(int n) {
return n > 0;
}
bool IsPositive(double x) {
return x > 0;
}
```
you will get a compiler error if you write
```
EXPECT_PRED1(IsPositive, 5);
```
However, this will work:
```
EXPECT_PRED1(*static_cast<bool (*)(int)>*(IsPositive), 5);
```
(The stuff inside the angled brackets for the `static_cast` operator is the
type of the function pointer for the `int`-version of `IsPositive()`.)
As another example, when you have a template function
```
template <typename T>
bool IsNegative(T x) {
return x < 0;
}
```
you can use it in a predicate assertion like this:
```
ASSERT_PRED1(IsNegative*<int>*, -5);
```
Things are more interesting if your template has more than one parameters. The
following won't compile:
```
ASSERT_PRED2(*GreaterThan<int, int>*, 5, 0);
```
as the C++ pre-processor thinks you are giving `ASSERT_PRED2` 4 arguments,
which is one more than expected. The workaround is to wrap the predicate
function in parentheses:
```
ASSERT_PRED2(*(GreaterThan<int, int>)*, 5, 0);
```
## My compiler complains about "ignoring return value" when I call RUN\_ALL\_TESTS(). Why? ##
Some people had been ignoring the return value of `RUN_ALL_TESTS()`. That is,
instead of
```
return RUN_ALL_TESTS();
```
they write
```
RUN_ALL_TESTS();
```
This is wrong and dangerous. A test runner needs to see the return value of
`RUN_ALL_TESTS()` in order to determine if a test has passed. If your `main()`
function ignores it, your test will be considered successful even if it has a
Google Test assertion failure. Very bad.
To help the users avoid this dangerous bug, the implementation of
`RUN_ALL_TESTS()` causes gcc to raise this warning, when the return value is
ignored. If you see this warning, the fix is simple: just make sure its value
is used as the return value of `main()`.
## My compiler complains that a constructor (or destructor) cannot return a value. What's going on? ##
Due to a peculiarity of C++, in order to support the syntax for streaming
messages to an `ASSERT_*`, e.g.
```
ASSERT_EQ(1, Foo()) << "blah blah" << foo;
```
we had to give up using `ASSERT*` and `FAIL*` (but not `EXPECT*` and
`ADD_FAILURE*`) in constructors and destructors. The workaround is to move the
content of your constructor/destructor to a private void member function, or
switch to `EXPECT_*()` if that works. This section in the user's guide explains
it.
## My set-up function is not called. Why? ##
C++ is case-sensitive. It should be spelled as `SetUp()`. Did you
spell it as `Setup()`?
Similarly, sometimes people spell `SetUpTestCase()` as `SetupTestCase()` and
wonder why it's never called.
## How do I jump to the line of a failure in Emacs directly? ##
Google Test's failure message format is understood by Emacs and many other
IDEs, like acme and XCode. If a Google Test message is in a compilation buffer
in Emacs, then it's clickable. You can now hit `enter` on a message to jump to
the corresponding source code, or use `C-x `` to jump to the next failure.
## I have several test cases which share the same test fixture logic, do I have to define a new test fixture class for each of them? This seems pretty tedious. ##
You don't have to. Instead of
```
class FooTest : public BaseTest {};
TEST_F(FooTest, Abc) { ... }
TEST_F(FooTest, Def) { ... }
class BarTest : public BaseTest {};
TEST_F(BarTest, Abc) { ... }
TEST_F(BarTest, Def) { ... }
```
you can simply `typedef` the test fixtures:
```
typedef BaseTest FooTest;
TEST_F(FooTest, Abc) { ... }
TEST_F(FooTest, Def) { ... }
typedef BaseTest BarTest;
TEST_F(BarTest, Abc) { ... }
TEST_F(BarTest, Def) { ... }
```
## The Google Test output is buried in a whole bunch of log messages. What do I do? ##
The Google Test output is meant to be a concise and human-friendly report. If
your test generates textual output itself, it will mix with the Google Test
output, making it hard to read. However, there is an easy solution to this
problem.
Since most log messages go to stderr, we decided to let Google Test output go
to stdout. This way, you can easily separate the two using redirection. For
example:
```
./my_test > googletest_output.txt
```
## Why should I prefer test fixtures over global variables? ##
There are several good reasons:
1. It's likely your test needs to change the states of its global variables. This makes it difficult to keep side effects from escaping one test and contaminating others, making debugging difficult. By using fixtures, each test has a fresh set of variables that's different (but with the same names). Thus, tests are kept independent of each other.
1. Global variables pollute the global namespace.
1. Test fixtures can be reused via subclassing, which cannot be done easily with global variables. This is useful if many test cases have something in common.
## How do I test private class members without writing FRIEND\_TEST()s? ##
You should try to write testable code, which means classes should be easily
tested from their public interface. One way to achieve this is the Pimpl idiom:
you move all private members of a class into a helper class, and make all
members of the helper class public.
You have several other options that don't require using `FRIEND_TEST`:
* Write the tests as members of the fixture class:
```
class Foo {
friend class FooTest;
...
};
class FooTest : public ::testing::Test {
protected:
...
void Test1() {...} // This accesses private members of class Foo.
void Test2() {...} // So does this one.
};
TEST_F(FooTest, Test1) {
Test1();
}
TEST_F(FooTest, Test2) {
Test2();
}
```
* In the fixture class, write accessors for the tested class' private members, then use the accessors in your tests:
```
class Foo {
friend class FooTest;
...
};
class FooTest : public ::testing::Test {
protected:
...
T1 get_private_member1(Foo* obj) {
return obj->private_member1_;
}
};
TEST_F(FooTest, Test1) {
...
get_private_member1(x)
...
}
```
* If the methods are declared **protected**, you can change their access level in a test-only subclass:
```
class YourClass {
...
protected: // protected access for testability.
int DoSomethingReturningInt();
...
};
// in the your_class_test.cc file:
class TestableYourClass : public YourClass {
...
public: using YourClass::DoSomethingReturningInt; // changes access rights
...
};
TEST_F(YourClassTest, DoSomethingTest) {
TestableYourClass obj;
assertEquals(expected_value, obj.DoSomethingReturningInt());
}
```
## How do I test private class static members without writing FRIEND\_TEST()s? ##
We find private static methods clutter the header file. They are
implementation details and ideally should be kept out of a .h. So often I make
them free functions instead.
Instead of:
```
// foo.h
class Foo {
...
private:
static bool Func(int n);
};
// foo.cc
bool Foo::Func(int n) { ... }
// foo_test.cc
EXPECT_TRUE(Foo::Func(12345));
```
You probably should better write:
```
// foo.h
class Foo {
...
};
// foo.cc
namespace internal {
bool Func(int n) { ... }
}
// foo_test.cc
namespace internal {
bool Func(int n);
}
EXPECT_TRUE(internal::Func(12345));
```
## I would like to run a test several times with different parameters. Do I need to write several similar copies of it? ##
No. You can use a feature called [value-parameterized tests](V1_5_AdvancedGuide.md#Value_Parameterized_Tests) which
lets you repeat your tests with different parameters, without defining it more than once.
## How do I test a file that defines main()? ##
To test a `foo.cc` file, you need to compile and link it into your unit test
program. However, when the file contains a definition for the `main()`
function, it will clash with the `main()` of your unit test, and will result in
a build error.
The right solution is to split it into three files:
1. `foo.h` which contains the declarations,
1. `foo.cc` which contains the definitions except `main()`, and
1. `foo_main.cc` which contains nothing but the definition of `main()`.
Then `foo.cc` can be easily tested.
If you are adding tests to an existing file and don't want an intrusive change
like this, there is a hack: just include the entire `foo.cc` file in your unit
test. For example:
```
// File foo_unittest.cc
// The headers section
...
// Renames main() in foo.cc to make room for the unit test main()
#define main FooMain
#include "a/b/foo.cc"
// The tests start here.
...
```
However, please remember this is a hack and should only be used as the last
resort.
## What can the statement argument in ASSERT\_DEATH() be? ##
`ASSERT_DEATH(_statement_, _regex_)` (or any death assertion macro) can be used
wherever `_statement_` is valid. So basically `_statement_` can be any C++
statement that makes sense in the current context. In particular, it can
reference global and/or local variables, and can be:
* a simple function call (often the case),
* a complex expression, or
* a compound statement.
> Some examples are shown here:
```
// A death test can be a simple function call.
TEST(MyDeathTest, FunctionCall) {
ASSERT_DEATH(Xyz(5), "Xyz failed");
}
// Or a complex expression that references variables and functions.
TEST(MyDeathTest, ComplexExpression) {
const bool c = Condition();
ASSERT_DEATH((c ? Func1(0) : object2.Method("test")),
"(Func1|Method) failed");
}
// Death assertions can be used any where in a function. In
// particular, they can be inside a loop.
TEST(MyDeathTest, InsideLoop) {
// Verifies that Foo(0), Foo(1), ..., and Foo(4) all die.
for (int i = 0; i < 5; i++) {
EXPECT_DEATH_M(Foo(i), "Foo has \\d+ errors",
::testing::Message() << "where i is " << i);
}
}
// A death assertion can contain a compound statement.
TEST(MyDeathTest, CompoundStatement) {
// Verifies that at lease one of Bar(0), Bar(1), ..., and
// Bar(4) dies.
ASSERT_DEATH({
for (int i = 0; i < 5; i++) {
Bar(i);
}
},
"Bar has \\d+ errors");}
```
`googletest_unittest.cc` contains more examples if you are interested.
## What syntax does the regular expression in ASSERT\_DEATH use? ##
On POSIX systems, Google Test uses the POSIX Extended regular
expression syntax
(http://en.wikipedia.org/wiki/Regular_expression#POSIX_Extended_Regular_Expressions). On
Windows, it uses a limited variant of regular expression syntax. For
more details, see the [regular expression syntax](V1_5_AdvancedGuide.md#Regular_Expression_Syntax).
## I have a fixture class Foo, but TEST\_F(Foo, Bar) gives me error "no matching function for call to Foo::Foo()". Why? ##
Google Test needs to be able to create objects of your test fixture class, so
it must have a default constructor. Normally the compiler will define one for
you. However, there are cases where you have to define your own:
* If you explicitly declare a non-default constructor for class `Foo`, then you need to define a default constructor, even if it would be empty.
* If `Foo` has a const non-static data member, then you have to define the default constructor _and_ initialize the const member in the initializer list of the constructor. (Early versions of `gcc` doesn't force you to initialize the const member. It's a bug that has been fixed in `gcc 4`.)
## Why does ASSERT\_DEATH complain about previous threads that were already joined? ##
With the Linux pthread library, there is no turning back once you cross the
line from single thread to multiple threads. The first time you create a
thread, a manager thread is created in addition, so you get 3, not 2, threads.
Later when the thread you create joins the main thread, the thread count
decrements by 1, but the manager thread will never be killed, so you still have
2 threads, which means you cannot safely run a death test.
The new NPTL thread library doesn't suffer from this problem, as it doesn't
create a manager thread. However, if you don't control which machine your test
runs on, you shouldn't depend on this.
## Why does Google Test require the entire test case, instead of individual tests, to be named FOODeathTest when it uses ASSERT\_DEATH? ##
Google Test does not interleave tests from different test cases. That is, it
runs all tests in one test case first, and then runs all tests in the next test
case, and so on. Google Test does this because it needs to set up a test case
before the first test in it is run, and tear it down afterwords. Splitting up
the test case would require multiple set-up and tear-down processes, which is
inefficient and makes the semantics unclean.
If we were to determine the order of tests based on test name instead of test
case name, then we would have a problem with the following situation:
```
TEST_F(FooTest, AbcDeathTest) { ... }
TEST_F(FooTest, Uvw) { ... }
TEST_F(BarTest, DefDeathTest) { ... }
TEST_F(BarTest, Xyz) { ... }
```
Since `FooTest.AbcDeathTest` needs to run before `BarTest.Xyz`, and we don't
interleave tests from different test cases, we need to run all tests in the
`FooTest` case before running any test in the `BarTest` case. This contradicts
with the requirement to run `BarTest.DefDeathTest` before `FooTest.Uvw`.
## But I don't like calling my entire test case FOODeathTest when it contains both death tests and non-death tests. What do I do? ##
You don't have to, but if you like, you may split up the test case into
`FooTest` and `FooDeathTest`, where the names make it clear that they are
related:
```
class FooTest : public ::testing::Test { ... };
TEST_F(FooTest, Abc) { ... }
TEST_F(FooTest, Def) { ... }
typedef FooTest FooDeathTest;
TEST_F(FooDeathTest, Uvw) { ... EXPECT_DEATH(...) ... }
TEST_F(FooDeathTest, Xyz) { ... ASSERT_DEATH(...) ... }
```
## The compiler complains about "no match for 'operator<<'" when I use an assertion. What gives? ##
If you use a user-defined type `FooType` in an assertion, you must make sure
there is an `std::ostream& operator<<(std::ostream&, const FooType&)` function
defined such that we can print a value of `FooType`.
In addition, if `FooType` is declared in a name space, the `<<` operator also
needs to be defined in the _same_ name space.
## How do I suppress the memory leak messages on Windows? ##
Since the statically initialized Google Test singleton requires allocations on
the heap, the Visual C++ memory leak detector will report memory leaks at the
end of the program run. The easiest way to avoid this is to use the
`_CrtMemCheckpoint` and `_CrtMemDumpAllObjectsSince` calls to not report any
statically initialized heap objects. See MSDN for more details and additional
heap check/debug routines.
## I am building my project with Google Test in Visual Studio and all I'm getting is a bunch of linker errors (or warnings). Help! ##
You may get a number of the following linker error or warnings if you
attempt to link your test project with the Google Test library when
your project and the are not built using the same compiler settings.
* LNK2005: symbol already defined in object
* LNK4217: locally defined symbol 'symbol' imported in function 'function'
* LNK4049: locally defined symbol 'symbol' imported
The Google Test project (gtest.vcproj) has the Runtime Library option
set to /MT (use multi-threaded static libraries, /MTd for debug). If
your project uses something else, for example /MD (use multi-threaded
DLLs, /MDd for debug), you need to change the setting in the Google
Test project to match your project's.
To update this setting open the project properties in the Visual
Studio IDE then select the branch Configuration Properties | C/C++ |
Code Generation and change the option "Runtime Library". You may also try
using gtest-md.vcproj instead of gtest.vcproj.
## I put my tests in a library and Google Test doesn't run them. What's happening? ##
Have you read a
[warning](V1_5_Primer.md#important-note-for-visual-c-users) on
the Google Test Primer page?
## I want to use Google Test with Visual Studio but don't know where to start. ##
Many people are in your position and one of the posted his solution to
our mailing list. Here is his link:
http://hassanjamilahmad.blogspot.com/2009/07/gtest-starters-help.html.
## My question is not covered in your FAQ! ##
If you cannot find the answer to your question in this FAQ, there are
some other resources you can use:
1. read other [wiki pages](http://code.google.com/p/googletest/w/list),
1. search the mailing list [archive](http://groups.google.com/group/googletestframework/topics),
1. ask it on [googletestframework@googlegroups.com](mailto:googletestframework@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googletestframework) before you can post.).
Please note that creating an issue in the
[issue tracker](http://code.google.com/p/googletest/issues/list) is _not_
a good way to get your answer, as it is monitored infrequently by a
very small number of people.
When asking a question, it's helpful to provide as much of the
following information as possible (people cannot help you if there's
not enough information in your question):
* the version (or the revision number if you check out from SVN directly) of Google Test you use (Google Test is under active development, so it's possible that your problem has been solved in a later version),
* your operating system,
* the name and version of your compiler,
* the complete command line flags you give to your compiler,
* the complete compiler error messages (if the question is about compilation),
* the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter.

View File

@@ -0,0 +1,497 @@
# Introduction: Why Google C++ Testing Framework? #
_Google C++ Testing Framework_ helps you write better C++ tests.
No matter whether you work on Linux, Windows, or a Mac, if you write C++ code,
Google Test can help you.
So what makes a good test, and how does Google C++ Testing Framework fit in? We believe:
1. Tests should be _independent_ and _repeatable_. It's a pain to debug a test that succeeds or fails as a result of other tests. Google C++ Testing Framework isolates the tests by running each of them on a different object. When a test fails, Google C++ Testing Framework allows you to run it in isolation for quick debugging.
1. Tests should be well _organized_ and reflect the structure of the tested code. Google C++ Testing Framework groups related tests into test cases that can share data and subroutines. This common pattern is easy to recognize and makes tests easy to maintain. Such consistency is especially helpful when people switch projects and start to work on a new code base.
1. Tests should be _portable_ and _reusable_. The open-source community has a lot of code that is platform-neutral, its tests should also be platform-neutral. Google C++ Testing Framework works on different OSes, with different compilers (gcc, MSVC, and others), with or without exceptions, so Google C++ Testing Framework tests can easily work with a variety of configurations. (Note that the current release only contains build scripts for Linux - we are actively working on scripts for other platforms.)
1. When tests fail, they should provide as much _information_ about the problem as possible. Google C++ Testing Framework doesn't stop at the first test failure. Instead, it only stops the current test and continues with the next. You can also set up tests that report non-fatal failures after which the current test continues. Thus, you can detect and fix multiple bugs in a single run-edit-compile cycle.
1. The testing framework should liberate test writers from housekeeping chores and let them focus on the test _content_. Google C++ Testing Framework automatically keeps track of all tests defined, and doesn't require the user to enumerate them in order to run them.
1. Tests should be _fast_. With Google C++ Testing Framework, you can reuse shared resources across tests and pay for the set-up/tear-down only once, without making tests depend on each other.
Since Google C++ Testing Framework is based on the popular xUnit
architecture, you'll feel right at home if you've used JUnit or PyUnit before.
If not, it will take you about 10 minutes to learn the basics and get started.
So let's go!
_Note:_ We sometimes refer to Google C++ Testing Framework informally
as _Google Test_.
# Setting up a New Test Project #
To write a test program using Google Test, you need to compile Google
Test into a library and link your test with it. We provide build
files for some popular build systems (`msvc/` for Visual Studio,
`xcode/` for Mac Xcode, `make/` for GNU make, `codegear/` for Borland
C++ Builder, and the autotools script in the
Google Test root directory). If your build system is not on this
list, you can take a look at `make/Makefile` to learn how Google Test
should be compiled (basically you want to compile `src/gtest-all.cc`
with `GTEST_ROOT` and `GTEST_ROOT/include` in the header search path,
where `GTEST_ROOT` is the Google Test root directory).
Once you are able to compile the Google Test library, you should
create a project or build target for your test program. Make sure you
have `GTEST_ROOT/include` in the header search path so that the
compiler can find `<gtest/gtest.h>` when compiling your test. Set up
your test project to link with the Google Test library (for example,
in Visual Studio, this is done by adding a dependency on
`gtest.vcproj`).
If you still have questions, take a look at how Google Test's own
tests are built and use them as examples.
# Basic Concepts #
When using Google Test, you start by writing _assertions_, which are statements
that check whether a condition is true. An assertion's result can be _success_,
_nonfatal failure_, or _fatal failure_. If a fatal failure occurs, it aborts
the current function; otherwise the program continues normally.
_Tests_ use assertions to verify the tested code's behavior. If a test crashes
or has a failed assertion, then it _fails_; otherwise it _succeeds_.
A _test case_ contains one or many tests. You should group your tests into test
cases that reflect the structure of the tested code. When multiple tests in a
test case need to share common objects and subroutines, you can put them into a
_test fixture_ class.
A _test program_ can contain multiple test cases.
We'll now explain how to write a test program, starting at the individual
assertion level and building up to tests and test cases.
# Assertions #
Google Test assertions are macros that resemble function calls. You test a
class or function by making assertions about its behavior. When an assertion
fails, Google Test prints the assertion's source file and line number location,
along with a failure message. You may also supply a custom failure message
which will be appended to Google Test's message.
The assertions come in pairs that test the same thing but have different
effects on the current function. `ASSERT_*` versions generate fatal failures
when they fail, and **abort the current function**. `EXPECT_*` versions generate
nonfatal failures, which don't abort the current function. Usually `EXPECT_*`
are preferred, as they allow more than one failures to be reported in a test.
However, you should use `ASSERT_*` if it doesn't make sense to continue when
the assertion in question fails.
Since a failed `ASSERT_*` returns from the current function immediately,
possibly skipping clean-up code that comes after it, it may cause a space leak.
Depending on the nature of the leak, it may or may not be worth fixing - so
keep this in mind if you get a heap checker error in addition to assertion
errors.
To provide a custom failure message, simply stream it into the macro using the
`<<` operator, or a sequence of such operators. An example:
```
ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length";
for (int i = 0; i < x.size(); ++i) {
EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i;
}
```
Anything that can be streamed to an `ostream` can be streamed to an assertion
macro--in particular, C strings and `string` objects. If a wide string
(`wchar_t*`, `TCHAR*` in `UNICODE` mode on Windows, or `std::wstring`) is
streamed to an assertion, it will be translated to UTF-8 when printed.
## Basic Assertions ##
These assertions do basic true/false condition testing.
| **Fatal assertion** | **Nonfatal assertion** | **Verifies** |
|:--------------------|:-----------------------|:-------------|
| `ASSERT_TRUE(`_condition_`)`; | `EXPECT_TRUE(`_condition_`)`; | _condition_ is true |
| `ASSERT_FALSE(`_condition_`)`; | `EXPECT_FALSE(`_condition_`)`; | _condition_ is false |
Remember, when they fail, `ASSERT_*` yields a fatal failure and
returns from the current function, while `EXPECT_*` yields a nonfatal
failure, allowing the function to continue running. In either case, an
assertion failure means its containing test fails.
_Availability_: Linux, Windows, Mac.
## Binary Comparison ##
This section describes assertions that compare two values.
| **Fatal assertion** | **Nonfatal assertion** | **Verifies** |
|:--------------------|:-----------------------|:-------------|
|`ASSERT_EQ(`_expected_`, `_actual_`);`|`EXPECT_EQ(`_expected_`, `_actual_`);`| _expected_ `==` _actual_ |
|`ASSERT_NE(`_val1_`, `_val2_`);` |`EXPECT_NE(`_val1_`, `_val2_`);` | _val1_ `!=` _val2_ |
|`ASSERT_LT(`_val1_`, `_val2_`);` |`EXPECT_LT(`_val1_`, `_val2_`);` | _val1_ `<` _val2_ |
|`ASSERT_LE(`_val1_`, `_val2_`);` |`EXPECT_LE(`_val1_`, `_val2_`);` | _val1_ `<=` _val2_ |
|`ASSERT_GT(`_val1_`, `_val2_`);` |`EXPECT_GT(`_val1_`, `_val2_`);` | _val1_ `>` _val2_ |
|`ASSERT_GE(`_val1_`, `_val2_`);` |`EXPECT_GE(`_val1_`, `_val2_`);` | _val1_ `>=` _val2_ |
In the event of a failure, Google Test prints both _val1_ and _val2_
. In `ASSERT_EQ*` and `EXPECT_EQ*` (and all other equality assertions
we'll introduce later), you should put the expression you want to test
in the position of _actual_, and put its expected value in _expected_,
as Google Test's failure messages are optimized for this convention.
Value arguments must be comparable by the assertion's comparison operator or
you'll get a compiler error. Values must also support the `<<` operator for
streaming to an `ostream`. All built-in types support this.
These assertions can work with a user-defined type, but only if you define the
corresponding comparison operator (e.g. `==`, `<`, etc). If the corresponding
operator is defined, prefer using the `ASSERT_*()` macros because they will
print out not only the result of the comparison, but the two operands as well.
Arguments are always evaluated exactly once. Therefore, it's OK for the
arguments to have side effects. However, as with any ordinary C/C++ function,
the arguments' evaluation order is undefined (i.e. the compiler is free to
choose any order) and your code should not depend on any particular argument
evaluation order.
`ASSERT_EQ()` does pointer equality on pointers. If used on two C strings, it
tests if they are in the same memory location, not if they have the same value.
Therefore, if you want to compare C strings (e.g. `const char*`) by value, use
`ASSERT_STREQ()` , which will be described later on. In particular, to assert
that a C string is `NULL`, use `ASSERT_STREQ(NULL, c_string)` . However, to
compare two `string` objects, you should use `ASSERT_EQ`.
Macros in this section work with both narrow and wide string objects (`string`
and `wstring`).
_Availability_: Linux, Windows, Mac.
## String Comparison ##
The assertions in this group compare two **C strings**. If you want to compare
two `string` objects, use `EXPECT_EQ`, `EXPECT_NE`, and etc instead.
| **Fatal assertion** | **Nonfatal assertion** | **Verifies** |
|:--------------------|:-----------------------|:-------------|
| `ASSERT_STREQ(`_expected\_str_`, `_actual\_str_`);` | `EXPECT_STREQ(`_expected\_str_`, `_actual\_str_`);` | the two C strings have the same content |
| `ASSERT_STRNE(`_str1_`, `_str2_`);` | `EXPECT_STRNE(`_str1_`, `_str2_`);` | the two C strings have different content |
| `ASSERT_STRCASEEQ(`_expected\_str_`, `_actual\_str_`);`| `EXPECT_STRCASEEQ(`_expected\_str_`, `_actual\_str_`);` | the two C strings have the same content, ignoring case |
| `ASSERT_STRCASENE(`_str1_`, `_str2_`);`| `EXPECT_STRCASENE(`_str1_`, `_str2_`);` | the two C strings have different content, ignoring case |
Note that "CASE" in an assertion name means that case is ignored.
`*STREQ*` and `*STRNE*` also accept wide C strings (`wchar_t*`). If a
comparison of two wide strings fails, their values will be printed as UTF-8
narrow strings.
A `NULL` pointer and an empty string are considered _different_.
_Availability_: Linux, Windows, Mac.
See also: For more string comparison tricks (substring, prefix, suffix, and
regular expression matching, for example), see the [AdvancedGuide Advanced
Google Test Guide].
# Simple Tests #
To create a test:
1. Use the `TEST()` macro to define and name a test function, These are ordinary C++ functions that don't return a value.
1. In this function, along with any valid C++ statements you want to include, use the various Google Test assertions to check values.
1. The test's result is determined by the assertions; if any assertion in the test fails (either fatally or non-fatally), or if the test crashes, the entire test fails. Otherwise, it succeeds.
```
TEST(test_case_name, test_name) {
... test body ...
}
```
`TEST()` arguments go from general to specific. The _first_ argument is the
name of the test case, and the _second_ argument is the test's name within the
test case. Remember that a test case can contain any number of individual
tests. A test's _full name_ consists of its containing test case and its
individual name. Tests from different test cases can have the same individual
name.
For example, let's take a simple integer function:
```
int Factorial(int n); // Returns the factorial of n
```
A test case for this function might look like:
```
// Tests factorial of 0.
TEST(FactorialTest, HandlesZeroInput) {
EXPECT_EQ(1, Factorial(0));
}
// Tests factorial of positive numbers.
TEST(FactorialTest, HandlesPositiveInput) {
EXPECT_EQ(1, Factorial(1));
EXPECT_EQ(2, Factorial(2));
EXPECT_EQ(6, Factorial(3));
EXPECT_EQ(40320, Factorial(8));
}
```
Google Test groups the test results by test cases, so logically-related tests
should be in the same test case; in other words, the first argument to their
`TEST()` should be the same. In the above example, we have two tests,
`HandlesZeroInput` and `HandlesPositiveInput`, that belong to the same test
case `FactorialTest`.
_Availability_: Linux, Windows, Mac.
# Test Fixtures: Using the Same Data Configuration for Multiple Tests #
If you find yourself writing two or more tests that operate on similar data,
you can use a _test fixture_. It allows you to reuse the same configuration of
objects for several different tests.
To create a fixture, just:
1. Derive a class from `::testing::Test` . Start its body with `protected:` or `public:` as we'll want to access fixture members from sub-classes.
1. Inside the class, declare any objects you plan to use.
1. If necessary, write a default constructor or `SetUp()` function to prepare the objects for each test. A common mistake is to spell `SetUp()` as `Setup()` with a small `u` - don't let that happen to you.
1. If necessary, write a destructor or `TearDown()` function to release any resources you allocated in `SetUp()` . To learn when you should use the constructor/destructor and when you should use `SetUp()/TearDown()`, read this [FAQ entry](V1_5_FAQ.md#should-i-use-the-constructordestructor-of-the-test-fixture-or-the-set-uptear-down-function).
1. If needed, define subroutines for your tests to share.
When using a fixture, use `TEST_F()` instead of `TEST()` as it allows you to
access objects and subroutines in the test fixture:
```
TEST_F(test_case_name, test_name) {
... test body ...
}
```
Like `TEST()`, the first argument is the test case name, but for `TEST_F()`
this must be the name of the test fixture class. You've probably guessed: `_F`
is for fixture.
Unfortunately, the C++ macro system does not allow us to create a single macro
that can handle both types of tests. Using the wrong macro causes a compiler
error.
Also, you must first define a test fixture class before using it in a
`TEST_F()`, or you'll get the compiler error "`virtual outside class
declaration`".
For each test defined with `TEST_F()`, Google Test will:
1. Create a _fresh_ test fixture at runtime
1. Immediately initialize it via `SetUp()` ,
1. Run the test
1. Clean up by calling `TearDown()`
1. Delete the test fixture. Note that different tests in the same test case have different test fixture objects, and Google Test always deletes a test fixture before it creates the next one. Google Test does not reuse the same test fixture for multiple tests. Any changes one test makes to the fixture do not affect other tests.
As an example, let's write tests for a FIFO queue class named `Queue`, which
has the following interface:
```
template <typename E> // E is the element type.
class Queue {
public:
Queue();
void Enqueue(const E& element);
E* Dequeue(); // Returns NULL if the queue is empty.
size_t size() const;
...
};
```
First, define a fixture class. By convention, you should give it the name
`FooTest` where `Foo` is the class being tested.
```
class QueueTest : public ::testing::Test {
protected:
virtual void SetUp() {
q1_.Enqueue(1);
q2_.Enqueue(2);
q2_.Enqueue(3);
}
// virtual void TearDown() {}
Queue<int> q0_;
Queue<int> q1_;
Queue<int> q2_;
};
```
In this case, `TearDown()` is not needed since we don't have to clean up after
each test, other than what's already done by the destructor.
Now we'll write tests using `TEST_F()` and this fixture.
```
TEST_F(QueueTest, IsEmptyInitially) {
EXPECT_EQ(0, q0_.size());
}
TEST_F(QueueTest, DequeueWorks) {
int* n = q0_.Dequeue();
EXPECT_EQ(NULL, n);
n = q1_.Dequeue();
ASSERT_TRUE(n != NULL);
EXPECT_EQ(1, *n);
EXPECT_EQ(0, q1_.size());
delete n;
n = q2_.Dequeue();
ASSERT_TRUE(n != NULL);
EXPECT_EQ(2, *n);
EXPECT_EQ(1, q2_.size());
delete n;
}
```
The above uses both `ASSERT_*` and `EXPECT_*` assertions. The rule of thumb is
to use `EXPECT_*` when you want the test to continue to reveal more errors
after the assertion failure, and use `ASSERT_*` when continuing after failure
doesn't make sense. For example, the second assertion in the `Dequeue` test is
`ASSERT_TRUE(n != NULL)`, as we need to dereference the pointer `n` later,
which would lead to a segfault when `n` is `NULL`.
When these tests run, the following happens:
1. Google Test constructs a `QueueTest` object (let's call it `t1` ).
1. `t1.SetUp()` initializes `t1` .
1. The first test ( `IsEmptyInitially` ) runs on `t1` .
1. `t1.TearDown()` cleans up after the test finishes.
1. `t1` is destructed.
1. The above steps are repeated on another `QueueTest` object, this time running the `DequeueWorks` test.
_Availability_: Linux, Windows, Mac.
_Note_: Google Test automatically saves all _Google Test_ flags when a test
object is constructed, and restores them when it is destructed.
# Invoking the Tests #
`TEST()` and `TEST_F()` implicitly register their tests with Google Test. So, unlike with many other C++ testing frameworks, you don't have to re-list all your defined tests in order to run them.
After defining your tests, you can run them with `RUN_ALL_TESTS()` , which returns `0` if all the tests are successful, or `1` otherwise. Note that `RUN_ALL_TESTS()` runs _all tests_ in your link unit -- they can be from different test cases, or even different source files.
When invoked, the `RUN_ALL_TESTS()` macro:
1. Saves the state of all Google Test flags.
1. Creates a test fixture object for the first test.
1. Initializes it via `SetUp()`.
1. Runs the test on the fixture object.
1. Cleans up the fixture via `TearDown()`.
1. Deletes the fixture.
1. Restores the state of all Google Test flags.
1. Repeats the above steps for the next test, until all tests have run.
In addition, if the text fixture's constructor generates a fatal failure in
step 2, there is no point for step 3 - 5 and they are thus skipped. Similarly,
if step 3 generates a fatal failure, step 4 will be skipped.
_Important_: You must not ignore the return value of `RUN_ALL_TESTS()`, or `gcc`
will give you a compiler error. The rationale for this design is that the
automated testing service determines whether a test has passed based on its
exit code, not on its stdout/stderr output; thus your `main()` function must
return the value of `RUN_ALL_TESTS()`.
Also, you should call `RUN_ALL_TESTS()` only **once**. Calling it more than once
conflicts with some advanced Google Test features (e.g. thread-safe death
tests) and thus is not supported.
_Availability_: Linux, Windows, Mac.
# Writing the main() Function #
You can start from this boilerplate:
```
#include "this/package/foo.h"
#include <gtest/gtest.h>
namespace {
// The fixture for testing class Foo.
class FooTest : public ::testing::Test {
protected:
// You can remove any or all of the following functions if its body
// is empty.
FooTest() {
// You can do set-up work for each test here.
}
virtual ~FooTest() {
// You can do clean-up work that doesn't throw exceptions here.
}
// If the constructor and destructor are not enough for setting up
// and cleaning up each test, you can define the following methods:
virtual void SetUp() {
// Code here will be called immediately after the constructor (right
// before each test).
}
virtual void TearDown() {
// Code here will be called immediately after each test (right
// before the destructor).
}
// Objects declared here can be used by all tests in the test case for Foo.
};
// Tests that the Foo::Bar() method does Abc.
TEST_F(FooTest, MethodBarDoesAbc) {
const string input_filepath = "this/package/testdata/myinputfile.dat";
const string output_filepath = "this/package/testdata/myoutputfile.dat";
Foo f;
EXPECT_EQ(0, f.Bar(input_filepath, output_filepath));
}
// Tests that Foo does Xyz.
TEST_F(FooTest, DoesXyz) {
// Exercises the Xyz feature of Foo.
}
} // namespace
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
```
The `::testing::InitGoogleTest()` function parses the command line for Google
Test flags, and removes all recognized flags. This allows the user to control a
test program's behavior via various flags, which we'll cover in [AdvancedGuide](V1_5_AdvancedGuide.md).
You must call this function before calling `RUN_ALL_TESTS()`, or the flags
won't be properly initialized.
On Windows, `InitGoogleTest()` also works with wide strings, so it can be used
in programs compiled in `UNICODE` mode as well.
But maybe you think that writing all those main() functions is too much work? We agree with you completely and that's why Google Test provides a basic implementation of main(). If it fits your needs, then just link your test with gtest\_main library and you are good to go.
## Important note for Visual C++ users ##
If you put your tests into a library and your `main()` function is in a different library or in your .exe file, those tests will not run. The reason is a [bug](https://connect.microsoft.com/feedback/viewfeedback.aspx?FeedbackID=244410&siteid=210) in Visual C++. When you define your tests, Google Test creates certain static objects to register them. These objects are not referenced from elsewhere but their constructors are still supposed to run. When Visual C++ linker sees that nothing in the library is referenced from other places it throws the library out. You have to reference your library with tests from your main program to keep the linker from discarding it. Here is how to do it. Somewhere in your library code declare a function:
```
__declspec(dllexport) int PullInMyLibrary() { return 0; }
```
If you put your tests in a static library (not DLL) then `__declspec(dllexport)` is not required. Now, in your main program, write a code that invokes that function:
```
int PullInMyLibrary();
static int dummy = PullInMyLibrary();
```
This will keep your tests referenced and will make them register themselves at startup.
In addition, if you define your tests in a static library, add `/OPT:NOREF` to your main program linker options. If you use MSVC++ IDE, go to your .exe project properties/Configuration Properties/Linker/Optimization and set References setting to `Keep Unreferenced Data (/OPT:NOREF)`. This will keep Visual C++ linker from discarding individual symbols generated by your tests from the final executable.
There is one more pitfall, though. If you use Google Test as a static library (that's how it is defined in gtest.vcproj) your tests must also reside in a static library. If you have to have them in a DLL, you _must_ change Google Test to build into a DLL as well. Otherwise your tests will not run correctly or will not run at all. The general conclusion here is: make your life easier - do not write your tests in libraries!
# Where to Go from Here #
Congratulations! You've learned the Google Test basics. You can start writing
and running Google Test tests, read some [samples](Samples.md), or continue with
[AdvancedGuide](V1_5_AdvancedGuide.md), which describes many more useful Google Test features.
# Known Limitations #
Google Test is designed to be thread-safe. The implementation is
thread-safe on systems where the `pthreads` library is available. It
is currently _unsafe_ to use Google Test assertions from two threads
concurrently on other systems (e.g. Windows). In most tests this is
not an issue as usually the assertions are done in the main thread. If
you want to help, you can volunteer to implement the necessary
synchronization primitives in `gtest-port.h` for your platform.

View File

@@ -0,0 +1,177 @@
<b>P</b>ump is <b>U</b>seful for <b>M</b>eta <b>P</b>rogramming.
# The Problem #
Template and macro libraries often need to define many classes,
functions, or macros that vary only (or almost only) in the number of
arguments they take. It's a lot of repetitive, mechanical, and
error-prone work.
Variadic templates and variadic macros can alleviate the problem.
However, while both are being considered by the C++ committee, neither
is in the standard yet or widely supported by compilers. Thus they
are often not a good choice, especially when your code needs to be
portable. And their capabilities are still limited.
As a result, authors of such libraries often have to write scripts to
generate their implementation. However, our experience is that it's
tedious to write such scripts, which tend to reflect the structure of
the generated code poorly and are often hard to read and edit. For
example, a small change needed in the generated code may require some
non-intuitive, non-trivial changes in the script. This is especially
painful when experimenting with the code.
# Our Solution #
Pump (for Pump is Useful for Meta Programming, Pretty Useful for Meta
Programming, or Practical Utility for Meta Programming, whichever you
prefer) is a simple meta-programming tool for C++. The idea is that a
programmer writes a `foo.pump` file which contains C++ code plus meta
code that manipulates the C++ code. The meta code can handle
iterations over a range, nested iterations, local meta variable
definitions, simple arithmetic, and conditional expressions. You can
view it as a small Domain-Specific Language. The meta language is
designed to be non-intrusive (s.t. it won't confuse Emacs' C++ mode,
for example) and concise, making Pump code intuitive and easy to
maintain.
## Highlights ##
* The implementation is in a single Python script and thus ultra portable: no build or installation is needed and it works cross platforms.
* Pump tries to be smart with respect to [Google's style guide](http://code.google.com/p/google-styleguide/): it breaks long lines (easy to have when they are generated) at acceptable places to fit within 80 columns and indent the continuation lines correctly.
* The format is human-readable and more concise than XML.
* The format works relatively well with Emacs' C++ mode.
## Examples ##
The following Pump code (where meta keywords start with `$`, `[[` and `]]` are meta brackets, and `$$` starts a meta comment that ends with the line):
```
$var n = 3 $$ Defines a meta variable n.
$range i 0..n $$ Declares the range of meta iterator i (inclusive).
$for i [[
$$ Meta loop.
// Foo$i does blah for $i-ary predicates.
$range j 1..i
template <size_t N $for j [[, typename A$j]]>
class Foo$i {
$if i == 0 [[
blah a;
]] $elif i <= 2 [[
blah b;
]] $else [[
blah c;
]]
};
]]
```
will be translated by the Pump compiler to:
```
// Foo0 does blah for 0-ary predicates.
template <size_t N>
class Foo0 {
blah a;
};
// Foo1 does blah for 1-ary predicates.
template <size_t N, typename A1>
class Foo1 {
blah b;
};
// Foo2 does blah for 2-ary predicates.
template <size_t N, typename A1, typename A2>
class Foo2 {
blah b;
};
// Foo3 does blah for 3-ary predicates.
template <size_t N, typename A1, typename A2, typename A3>
class Foo3 {
blah c;
};
```
In another example,
```
$range i 1..n
Func($for i + [[a$i]]);
$$ The text between i and [[ is the separator between iterations.
```
will generate one of the following lines (without the comments), depending on the value of `n`:
```
Func(); // If n is 0.
Func(a1); // If n is 1.
Func(a1 + a2); // If n is 2.
Func(a1 + a2 + a3); // If n is 3.
// And so on...
```
## Constructs ##
We support the following meta programming constructs:
| `$var id = exp` | Defines a named constant value. `$id` is valid util the end of the current meta lexical block. |
|:----------------|:-----------------------------------------------------------------------------------------------|
| $range id exp..exp | Sets the range of an iteration variable, which can be reused in multiple loops later. |
| $for id sep [[code ](.md)] | Iteration. The range of `id` must have been defined earlier. `$id` is valid in `code`. |
| `$($)` | Generates a single `$` character. |
| `$id` | Value of the named constant or iteration variable. |
| `$(exp)` | Value of the expression. |
| `$if exp [[ code ]] else_branch` | Conditional. |
| `[[ code ]]` | Meta lexical block. |
| `cpp_code` | Raw C++ code. |
| `$$ comment` | Meta comment. |
**Note:** To give the user some freedom in formatting the Pump source
code, Pump ignores a new-line character if it's right after `$for foo`
or next to `[[` or `]]`. Without this rule you'll often be forced to write
very long lines to get the desired output. Therefore sometimes you may
need to insert an extra new-line in such places for a new-line to show
up in your output.
## Grammar ##
```
code ::= atomic_code*
atomic_code ::= $var id = exp
| $var id = [[ code ]]
| $range id exp..exp
| $for id sep [[ code ]]
| $($)
| $id
| $(exp)
| $if exp [[ code ]] else_branch
| [[ code ]]
| cpp_code
sep ::= cpp_code | empty_string
else_branch ::= $else [[ code ]]
| $elif exp [[ code ]] else_branch
| empty_string
exp ::= simple_expression_in_Python_syntax
```
## Code ##
You can find the source code of Pump in [scripts/pump.py](http://code.google.com/p/googletest/source/browse/trunk/scripts/pump.py). It is still
very unpolished and lacks automated tests, although it has been
successfully used many times. If you find a chance to use it in your
project, please let us know what you think! We also welcome help on
improving Pump.
## Real Examples ##
You can find real-world applications of Pump in [Google Test](http://www.google.com/codesearch?q=file%3A\.pump%24+package%3Ahttp%3A%2F%2Fgoogletest\.googlecode\.com) and [Google Mock](http://www.google.com/codesearch?q=file%3A\.pump%24+package%3Ahttp%3A%2F%2Fgooglemock\.googlecode\.com). The source file `foo.h.pump` generates `foo.h`.
## Tips ##
* If a meta variable is followed by a letter or digit, you can separate them using `[[]]`, which inserts an empty string. For example `Foo$j[[]]Helper` generate `Foo1Helper` when `j` is 1.
* To avoid extra-long Pump source lines, you can break a line anywhere you want by inserting `[[]]` followed by a new line. Since any new-line character next to `[[` or `]]` is ignored, the generated code won't contain this new line.

View File

@@ -0,0 +1,93 @@
This guide will explain how to use the Google Testing Framework in your Xcode projects on Mac OS X. This tutorial begins by quickly explaining what to do for experienced users. After the quick start, the guide goes provides additional explanation about each step.
# Quick Start #
Here is the quick guide for using Google Test in your Xcode project.
1. Download the source from the [website](http://code.google.com/p/googletest) using this command: `svn checkout http://googletest.googlecode.com/svn/trunk/ googletest-read-only`
1. Open up the `gtest.xcodeproj` in the `googletest-read-only/xcode/` directory and build the gtest.framework.
1. Create a new "Shell Tool" target in your Xcode project called something like "UnitTests"
1. Add the gtest.framework to your project and add it to the "Link Binary with Libraries" build phase of "UnitTests"
1. Add your unit test source code to the "Compile Sources" build phase of "UnitTests"
1. Edit the "UnitTests" executable and add an environment variable named "DYLD\_FRAMEWORK\_PATH" with a value equal to the path to the framework containing the gtest.framework relative to the compiled executable.
1. Build and Go
The following sections further explain each of the steps listed above in depth, describing in more detail how to complete it including some variations.
# Get the Source #
Currently, the gtest.framework discussed here isn't available in a tagged release of Google Test, it is only available in the trunk. As explained at the Google Test [site](http://code.google.com/p/googletest/source/checkout">svn), you can get the code from anonymous SVN with this command:
```
svn checkout http://googletest.googlecode.com/svn/trunk/ googletest-read-only
```
Alternatively, if you are working with Subversion in your own code base, you can add Google Test as an external dependency to your own Subversion repository. By following this approach, everyone that checks out your svn repository will also receive a copy of Google Test (a specific version, if you wish) without having to check it out explicitly. This makes the set up of your project simpler and reduces the copied code in the repository.
To use `svn:externals`, decide where you would like to have the external source reside. You might choose to put the external source inside the trunk, because you want it to be part of the branch when you make a release. However, keeping it outside the trunk in a version-tagged directory called something like `third-party/googletest/1.0.1`, is another option. Once the location is established, use `svn propedit svn:externals _directory_` to set the svn:externals property on a directory in your repository. This directory won't contain the code, but be its versioned parent directory.
The command `svn propedit` will bring up your Subversion editor, making editing the long, (potentially multi-line) property simpler. This same method can be used to check out a tagged branch, by using the appropriate URL (e.g. `http://googletest.googlecode.com/svn/tags/release-1.0.1`). Additionally, the svn:externals property allows the specification of a particular revision of the trunk with the `-r_##_` option (e.g. `externals/src/googletest -r60 http://googletest.googlecode.com/svn/trunk`).
Here is an example of using the svn:externals properties on a trunk (read via `svn propget`) of a project. This value checks out a copy of Google Test into the `trunk/externals/src/googletest/` directory.
```
[Computer:svn] user$ svn propget svn:externals trunk
externals/src/googletest http://googletest.googlecode.com/svn/trunk
```
# Add the Framework to Your Project #
The next step is to build and add the gtest.framework to your own project. This guide describes two common ways below.
* **Option 1** --- The simplest way to add Google Test to your own project, is to open gtest.xcodeproj (found in the xcode/ directory of the Google Test trunk) and build the framework manually. Then, add the built framework into your project using the "Add->Existing Framework..." from the context menu or "Project->Add..." from the main menu. The gtest.framework is relocatable and contains the headers and object code that you'll need to make tests. This method requires rebuilding every time you upgrade Google Test in your project.
* **Option 2** --- If you are going to be living off the trunk of Google Test, incorporating its latest features into your unit tests (or are a Google Test developer yourself). You'll want to rebuild the framework every time the source updates. to do this, you'll need to add the gtest.xcodeproj file, not the framework itself, to your own Xcode project. Then, from the build products that are revealed by the project's disclosure triangle, you can find the gtest.framework, which can be added to your targets (discussed below).
# Make a Test Target #
To start writing tests, make a new "Shell Tool" target. This target template is available under BSD, Cocoa, or Carbon. Add your unit test source code to the "Compile Sources" build phase of the target.
Next, you'll want to add gtest.framework in two different ways, depending upon which option you chose above.
* **Option 1** --- During compilation, Xcode will need to know that you are linking against the gtest.framework. Add the gtest.framework to the "Link Binary with Libraries" build phase of your test target. This will include the Google Test headers in your header search path, and will tell the linker where to find the library.
* **Option 2** --- If your working out of the trunk, you'll also want to add gtest.framework to your "Link Binary with Libraries" build phase of your test target. In addition, you'll want to add the gtest.framework as a dependency to your unit test target. This way, Xcode will make sure that gtest.framework is up to date, every time your build your target. Finally, if you don't share build directories with Google Test, you'll have to copy the gtest.framework into your own build products directory using a "Run Script" build phase.
# Set Up the Executable Run Environment #
Since the unit test executable is a shell tool, it doesn't have a bundle with a `Contents/Frameworks` directory, in which to place gtest.framework. Instead, the dynamic linker must be told at runtime to search for the framework in another location. This can be accomplished by setting the "DYLD\_FRAMEWORK\_PATH" environment variable in the "Edit Active Executable ..." Arguments tab, under "Variables to be set in the environment:". The path for this value is the path (relative or absolute) of the directory containing the gtest.framework.
If you haven't set up the DYLD\_FRAMEWORK\_PATH, correctly, you might get a message like this:
```
[Session started at 2008-08-15 06:23:57 -0600.]
dyld: Library not loaded: @loader_path/../Frameworks/gtest.framework/Versions/A/gtest
Referenced from: /Users/username/Documents/Sandbox/gtestSample/build/Debug/WidgetFrameworkTest
Reason: image not found
```
To correct this problem, got to the directory containing the executable named in "Referenced from:" value in the error message above. Then, with the terminal in this location, find the relative path to the directory containing the gtest.framework. That is the value you'll need to set as the DYLD\_FRAMEWORK\_PATH.
# Build and Go #
Now, when you click "Build and Go", the test will be executed. Dumping out something like this:
```
[Session started at 2008-08-06 06:36:13 -0600.]
[==========] Running 2 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 2 tests from WidgetInitializerTest
[ RUN ] WidgetInitializerTest.TestConstructor
[ OK ] WidgetInitializerTest.TestConstructor
[ RUN ] WidgetInitializerTest.TestConversion
[ OK ] WidgetInitializerTest.TestConversion
[----------] Global test environment tear-down
[==========] 2 tests from 1 test case ran.
[ PASSED ] 2 tests.
The Debugger has exited with status 0.
```
# Summary #
Unit testing is a valuable way to ensure your data model stays valid even during rapid development or refactoring. The Google Testing Framework is a great unit testing framework for C and C++ which integrates well with an Xcode development environment.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,14 @@
This page lists all documentation wiki pages for Google Test **1.6**
-- **if you use a released version of Google Test, please read the
documentation for that specific version instead.**
* [Primer](V1_6_Primer.md) -- start here if you are new to Google Test.
* [Samples](V1_6_Samples.md) -- learn from examples.
* [AdvancedGuide](V1_6_AdvancedGuide.md) -- learn more about Google Test.
* [XcodeGuide](V1_6_XcodeGuide.md) -- how to use Google Test in Xcode on Mac.
* [Frequently-Asked Questions](V1_6_FAQ.md) -- check here before asking a question on the mailing list.
To contribute code to Google Test, read:
* [DevGuide](DevGuide.md) -- read this _before_ writing your first patch.
* [PumpManual](V1_6_PumpManual.md) -- how we generate some of Google Test's source files.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,501 @@
# Introduction: Why Google C++ Testing Framework? #
_Google C++ Testing Framework_ helps you write better C++ tests.
No matter whether you work on Linux, Windows, or a Mac, if you write C++ code,
Google Test can help you.
So what makes a good test, and how does Google C++ Testing Framework fit in? We believe:
1. Tests should be _independent_ and _repeatable_. It's a pain to debug a test that succeeds or fails as a result of other tests. Google C++ Testing Framework isolates the tests by running each of them on a different object. When a test fails, Google C++ Testing Framework allows you to run it in isolation for quick debugging.
1. Tests should be well _organized_ and reflect the structure of the tested code. Google C++ Testing Framework groups related tests into test cases that can share data and subroutines. This common pattern is easy to recognize and makes tests easy to maintain. Such consistency is especially helpful when people switch projects and start to work on a new code base.
1. Tests should be _portable_ and _reusable_. The open-source community has a lot of code that is platform-neutral, its tests should also be platform-neutral. Google C++ Testing Framework works on different OSes, with different compilers (gcc, MSVC, and others), with or without exceptions, so Google C++ Testing Framework tests can easily work with a variety of configurations. (Note that the current release only contains build scripts for Linux - we are actively working on scripts for other platforms.)
1. When tests fail, they should provide as much _information_ about the problem as possible. Google C++ Testing Framework doesn't stop at the first test failure. Instead, it only stops the current test and continues with the next. You can also set up tests that report non-fatal failures after which the current test continues. Thus, you can detect and fix multiple bugs in a single run-edit-compile cycle.
1. The testing framework should liberate test writers from housekeeping chores and let them focus on the test _content_. Google C++ Testing Framework automatically keeps track of all tests defined, and doesn't require the user to enumerate them in order to run them.
1. Tests should be _fast_. With Google C++ Testing Framework, you can reuse shared resources across tests and pay for the set-up/tear-down only once, without making tests depend on each other.
Since Google C++ Testing Framework is based on the popular xUnit
architecture, you'll feel right at home if you've used JUnit or PyUnit before.
If not, it will take you about 10 minutes to learn the basics and get started.
So let's go!
_Note:_ We sometimes refer to Google C++ Testing Framework informally
as _Google Test_.
# Setting up a New Test Project #
To write a test program using Google Test, you need to compile Google
Test into a library and link your test with it. We provide build
files for some popular build systems: `msvc/` for Visual Studio,
`xcode/` for Mac Xcode, `make/` for GNU make, `codegear/` for Borland
C++ Builder, and the autotools script (deprecated) and
`CMakeLists.txt` for CMake (recommended) in the Google Test root
directory. If your build system is not on this list, you can take a
look at `make/Makefile` to learn how Google Test should be compiled
(basically you want to compile `src/gtest-all.cc` with `GTEST_ROOT`
and `GTEST_ROOT/include` in the header search path, where `GTEST_ROOT`
is the Google Test root directory).
Once you are able to compile the Google Test library, you should
create a project or build target for your test program. Make sure you
have `GTEST_ROOT/include` in the header search path so that the
compiler can find `"gtest/gtest.h"` when compiling your test. Set up
your test project to link with the Google Test library (for example,
in Visual Studio, this is done by adding a dependency on
`gtest.vcproj`).
If you still have questions, take a look at how Google Test's own
tests are built and use them as examples.
# Basic Concepts #
When using Google Test, you start by writing _assertions_, which are statements
that check whether a condition is true. An assertion's result can be _success_,
_nonfatal failure_, or _fatal failure_. If a fatal failure occurs, it aborts
the current function; otherwise the program continues normally.
_Tests_ use assertions to verify the tested code's behavior. If a test crashes
or has a failed assertion, then it _fails_; otherwise it _succeeds_.
A _test case_ contains one or many tests. You should group your tests into test
cases that reflect the structure of the tested code. When multiple tests in a
test case need to share common objects and subroutines, you can put them into a
_test fixture_ class.
A _test program_ can contain multiple test cases.
We'll now explain how to write a test program, starting at the individual
assertion level and building up to tests and test cases.
# Assertions #
Google Test assertions are macros that resemble function calls. You test a
class or function by making assertions about its behavior. When an assertion
fails, Google Test prints the assertion's source file and line number location,
along with a failure message. You may also supply a custom failure message
which will be appended to Google Test's message.
The assertions come in pairs that test the same thing but have different
effects on the current function. `ASSERT_*` versions generate fatal failures
when they fail, and **abort the current function**. `EXPECT_*` versions generate
nonfatal failures, which don't abort the current function. Usually `EXPECT_*`
are preferred, as they allow more than one failures to be reported in a test.
However, you should use `ASSERT_*` if it doesn't make sense to continue when
the assertion in question fails.
Since a failed `ASSERT_*` returns from the current function immediately,
possibly skipping clean-up code that comes after it, it may cause a space leak.
Depending on the nature of the leak, it may or may not be worth fixing - so
keep this in mind if you get a heap checker error in addition to assertion
errors.
To provide a custom failure message, simply stream it into the macro using the
`<<` operator, or a sequence of such operators. An example:
```
ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length";
for (int i = 0; i < x.size(); ++i) {
EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i;
}
```
Anything that can be streamed to an `ostream` can be streamed to an assertion
macro--in particular, C strings and `string` objects. If a wide string
(`wchar_t*`, `TCHAR*` in `UNICODE` mode on Windows, or `std::wstring`) is
streamed to an assertion, it will be translated to UTF-8 when printed.
## Basic Assertions ##
These assertions do basic true/false condition testing.
| **Fatal assertion** | **Nonfatal assertion** | **Verifies** |
|:--------------------|:-----------------------|:-------------|
| `ASSERT_TRUE(`_condition_`)`; | `EXPECT_TRUE(`_condition_`)`; | _condition_ is true |
| `ASSERT_FALSE(`_condition_`)`; | `EXPECT_FALSE(`_condition_`)`; | _condition_ is false |
Remember, when they fail, `ASSERT_*` yields a fatal failure and
returns from the current function, while `EXPECT_*` yields a nonfatal
failure, allowing the function to continue running. In either case, an
assertion failure means its containing test fails.
_Availability_: Linux, Windows, Mac.
## Binary Comparison ##
This section describes assertions that compare two values.
| **Fatal assertion** | **Nonfatal assertion** | **Verifies** |
|:--------------------|:-----------------------|:-------------|
|`ASSERT_EQ(`_expected_`, `_actual_`);`|`EXPECT_EQ(`_expected_`, `_actual_`);`| _expected_ `==` _actual_ |
|`ASSERT_NE(`_val1_`, `_val2_`);` |`EXPECT_NE(`_val1_`, `_val2_`);` | _val1_ `!=` _val2_ |
|`ASSERT_LT(`_val1_`, `_val2_`);` |`EXPECT_LT(`_val1_`, `_val2_`);` | _val1_ `<` _val2_ |
|`ASSERT_LE(`_val1_`, `_val2_`);` |`EXPECT_LE(`_val1_`, `_val2_`);` | _val1_ `<=` _val2_ |
|`ASSERT_GT(`_val1_`, `_val2_`);` |`EXPECT_GT(`_val1_`, `_val2_`);` | _val1_ `>` _val2_ |
|`ASSERT_GE(`_val1_`, `_val2_`);` |`EXPECT_GE(`_val1_`, `_val2_`);` | _val1_ `>=` _val2_ |
In the event of a failure, Google Test prints both _val1_ and _val2_
. In `ASSERT_EQ*` and `EXPECT_EQ*` (and all other equality assertions
we'll introduce later), you should put the expression you want to test
in the position of _actual_, and put its expected value in _expected_,
as Google Test's failure messages are optimized for this convention.
Value arguments must be comparable by the assertion's comparison
operator or you'll get a compiler error. We used to require the
arguments to support the `<<` operator for streaming to an `ostream`,
but it's no longer necessary since v1.6.0 (if `<<` is supported, it
will be called to print the arguments when the assertion fails;
otherwise Google Test will attempt to print them in the best way it
can. For more details and how to customize the printing of the
arguments, see this Google Mock [recipe](../../googlemock/docs/CookBook.md#teaching-google-mock-how-to-print-your-values).).
These assertions can work with a user-defined type, but only if you define the
corresponding comparison operator (e.g. `==`, `<`, etc). If the corresponding
operator is defined, prefer using the `ASSERT_*()` macros because they will
print out not only the result of the comparison, but the two operands as well.
Arguments are always evaluated exactly once. Therefore, it's OK for the
arguments to have side effects. However, as with any ordinary C/C++ function,
the arguments' evaluation order is undefined (i.e. the compiler is free to
choose any order) and your code should not depend on any particular argument
evaluation order.
`ASSERT_EQ()` does pointer equality on pointers. If used on two C strings, it
tests if they are in the same memory location, not if they have the same value.
Therefore, if you want to compare C strings (e.g. `const char*`) by value, use
`ASSERT_STREQ()` , which will be described later on. In particular, to assert
that a C string is `NULL`, use `ASSERT_STREQ(NULL, c_string)` . However, to
compare two `string` objects, you should use `ASSERT_EQ`.
Macros in this section work with both narrow and wide string objects (`string`
and `wstring`).
_Availability_: Linux, Windows, Mac.
## String Comparison ##
The assertions in this group compare two **C strings**. If you want to compare
two `string` objects, use `EXPECT_EQ`, `EXPECT_NE`, and etc instead.
| **Fatal assertion** | **Nonfatal assertion** | **Verifies** |
|:--------------------|:-----------------------|:-------------|
| `ASSERT_STREQ(`_expected\_str_`, `_actual\_str_`);` | `EXPECT_STREQ(`_expected\_str_`, `_actual\_str_`);` | the two C strings have the same content |
| `ASSERT_STRNE(`_str1_`, `_str2_`);` | `EXPECT_STRNE(`_str1_`, `_str2_`);` | the two C strings have different content |
| `ASSERT_STRCASEEQ(`_expected\_str_`, `_actual\_str_`);`| `EXPECT_STRCASEEQ(`_expected\_str_`, `_actual\_str_`);` | the two C strings have the same content, ignoring case |
| `ASSERT_STRCASENE(`_str1_`, `_str2_`);`| `EXPECT_STRCASENE(`_str1_`, `_str2_`);` | the two C strings have different content, ignoring case |
Note that "CASE" in an assertion name means that case is ignored.
`*STREQ*` and `*STRNE*` also accept wide C strings (`wchar_t*`). If a
comparison of two wide strings fails, their values will be printed as UTF-8
narrow strings.
A `NULL` pointer and an empty string are considered _different_.
_Availability_: Linux, Windows, Mac.
See also: For more string comparison tricks (substring, prefix, suffix, and
regular expression matching, for example), see the [Advanced Google Test Guide](V1_6_AdvancedGuide.md).
# Simple Tests #
To create a test:
1. Use the `TEST()` macro to define and name a test function, These are ordinary C++ functions that don't return a value.
1. In this function, along with any valid C++ statements you want to include, use the various Google Test assertions to check values.
1. The test's result is determined by the assertions; if any assertion in the test fails (either fatally or non-fatally), or if the test crashes, the entire test fails. Otherwise, it succeeds.
```
TEST(test_case_name, test_name) {
... test body ...
}
```
`TEST()` arguments go from general to specific. The _first_ argument is the
name of the test case, and the _second_ argument is the test's name within the
test case. Both names must be valid C++ identifiers, and they should not contain underscore (`_`). A test's _full name_ consists of its containing test case and its
individual name. Tests from different test cases can have the same individual
name.
For example, let's take a simple integer function:
```
int Factorial(int n); // Returns the factorial of n
```
A test case for this function might look like:
```
// Tests factorial of 0.
TEST(FactorialTest, HandlesZeroInput) {
EXPECT_EQ(1, Factorial(0));
}
// Tests factorial of positive numbers.
TEST(FactorialTest, HandlesPositiveInput) {
EXPECT_EQ(1, Factorial(1));
EXPECT_EQ(2, Factorial(2));
EXPECT_EQ(6, Factorial(3));
EXPECT_EQ(40320, Factorial(8));
}
```
Google Test groups the test results by test cases, so logically-related tests
should be in the same test case; in other words, the first argument to their
`TEST()` should be the same. In the above example, we have two tests,
`HandlesZeroInput` and `HandlesPositiveInput`, that belong to the same test
case `FactorialTest`.
_Availability_: Linux, Windows, Mac.
# Test Fixtures: Using the Same Data Configuration for Multiple Tests #
If you find yourself writing two or more tests that operate on similar data,
you can use a _test fixture_. It allows you to reuse the same configuration of
objects for several different tests.
To create a fixture, just:
1. Derive a class from `::testing::Test` . Start its body with `protected:` or `public:` as we'll want to access fixture members from sub-classes.
1. Inside the class, declare any objects you plan to use.
1. If necessary, write a default constructor or `SetUp()` function to prepare the objects for each test. A common mistake is to spell `SetUp()` as `Setup()` with a small `u` - don't let that happen to you.
1. If necessary, write a destructor or `TearDown()` function to release any resources you allocated in `SetUp()` . To learn when you should use the constructor/destructor and when you should use `SetUp()/TearDown()`, read this [FAQ entry](V1_6_FAQ.md#should-i-use-the-constructordestructor-of-the-test-fixture-or-the-set-uptear-down-function).
1. If needed, define subroutines for your tests to share.
When using a fixture, use `TEST_F()` instead of `TEST()` as it allows you to
access objects and subroutines in the test fixture:
```
TEST_F(test_case_name, test_name) {
... test body ...
}
```
Like `TEST()`, the first argument is the test case name, but for `TEST_F()`
this must be the name of the test fixture class. You've probably guessed: `_F`
is for fixture.
Unfortunately, the C++ macro system does not allow us to create a single macro
that can handle both types of tests. Using the wrong macro causes a compiler
error.
Also, you must first define a test fixture class before using it in a
`TEST_F()`, or you'll get the compiler error "`virtual outside class
declaration`".
For each test defined with `TEST_F()`, Google Test will:
1. Create a _fresh_ test fixture at runtime
1. Immediately initialize it via `SetUp()` ,
1. Run the test
1. Clean up by calling `TearDown()`
1. Delete the test fixture. Note that different tests in the same test case have different test fixture objects, and Google Test always deletes a test fixture before it creates the next one. Google Test does not reuse the same test fixture for multiple tests. Any changes one test makes to the fixture do not affect other tests.
As an example, let's write tests for a FIFO queue class named `Queue`, which
has the following interface:
```
template <typename E> // E is the element type.
class Queue {
public:
Queue();
void Enqueue(const E& element);
E* Dequeue(); // Returns NULL if the queue is empty.
size_t size() const;
...
};
```
First, define a fixture class. By convention, you should give it the name
`FooTest` where `Foo` is the class being tested.
```
class QueueTest : public ::testing::Test {
protected:
virtual void SetUp() {
q1_.Enqueue(1);
q2_.Enqueue(2);
q2_.Enqueue(3);
}
// virtual void TearDown() {}
Queue<int> q0_;
Queue<int> q1_;
Queue<int> q2_;
};
```
In this case, `TearDown()` is not needed since we don't have to clean up after
each test, other than what's already done by the destructor.
Now we'll write tests using `TEST_F()` and this fixture.
```
TEST_F(QueueTest, IsEmptyInitially) {
EXPECT_EQ(0, q0_.size());
}
TEST_F(QueueTest, DequeueWorks) {
int* n = q0_.Dequeue();
EXPECT_EQ(NULL, n);
n = q1_.Dequeue();
ASSERT_TRUE(n != NULL);
EXPECT_EQ(1, *n);
EXPECT_EQ(0, q1_.size());
delete n;
n = q2_.Dequeue();
ASSERT_TRUE(n != NULL);
EXPECT_EQ(2, *n);
EXPECT_EQ(1, q2_.size());
delete n;
}
```
The above uses both `ASSERT_*` and `EXPECT_*` assertions. The rule of thumb is
to use `EXPECT_*` when you want the test to continue to reveal more errors
after the assertion failure, and use `ASSERT_*` when continuing after failure
doesn't make sense. For example, the second assertion in the `Dequeue` test is
`ASSERT_TRUE(n != NULL)`, as we need to dereference the pointer `n` later,
which would lead to a segfault when `n` is `NULL`.
When these tests run, the following happens:
1. Google Test constructs a `QueueTest` object (let's call it `t1` ).
1. `t1.SetUp()` initializes `t1` .
1. The first test ( `IsEmptyInitially` ) runs on `t1` .
1. `t1.TearDown()` cleans up after the test finishes.
1. `t1` is destructed.
1. The above steps are repeated on another `QueueTest` object, this time running the `DequeueWorks` test.
_Availability_: Linux, Windows, Mac.
_Note_: Google Test automatically saves all _Google Test_ flags when a test
object is constructed, and restores them when it is destructed.
# Invoking the Tests #
`TEST()` and `TEST_F()` implicitly register their tests with Google Test. So, unlike with many other C++ testing frameworks, you don't have to re-list all your defined tests in order to run them.
After defining your tests, you can run them with `RUN_ALL_TESTS()` , which returns `0` if all the tests are successful, or `1` otherwise. Note that `RUN_ALL_TESTS()` runs _all tests_ in your link unit -- they can be from different test cases, or even different source files.
When invoked, the `RUN_ALL_TESTS()` macro:
1. Saves the state of all Google Test flags.
1. Creates a test fixture object for the first test.
1. Initializes it via `SetUp()`.
1. Runs the test on the fixture object.
1. Cleans up the fixture via `TearDown()`.
1. Deletes the fixture.
1. Restores the state of all Google Test flags.
1. Repeats the above steps for the next test, until all tests have run.
In addition, if the text fixture's constructor generates a fatal failure in
step 2, there is no point for step 3 - 5 and they are thus skipped. Similarly,
if step 3 generates a fatal failure, step 4 will be skipped.
_Important_: You must not ignore the return value of `RUN_ALL_TESTS()`, or `gcc`
will give you a compiler error. The rationale for this design is that the
automated testing service determines whether a test has passed based on its
exit code, not on its stdout/stderr output; thus your `main()` function must
return the value of `RUN_ALL_TESTS()`.
Also, you should call `RUN_ALL_TESTS()` only **once**. Calling it more than once
conflicts with some advanced Google Test features (e.g. thread-safe death
tests) and thus is not supported.
_Availability_: Linux, Windows, Mac.
# Writing the main() Function #
You can start from this boilerplate:
```
#include "this/package/foo.h"
#include "gtest/gtest.h"
namespace {
// The fixture for testing class Foo.
class FooTest : public ::testing::Test {
protected:
// You can remove any or all of the following functions if its body
// is empty.
FooTest() {
// You can do set-up work for each test here.
}
virtual ~FooTest() {
// You can do clean-up work that doesn't throw exceptions here.
}
// If the constructor and destructor are not enough for setting up
// and cleaning up each test, you can define the following methods:
virtual void SetUp() {
// Code here will be called immediately after the constructor (right
// before each test).
}
virtual void TearDown() {
// Code here will be called immediately after each test (right
// before the destructor).
}
// Objects declared here can be used by all tests in the test case for Foo.
};
// Tests that the Foo::Bar() method does Abc.
TEST_F(FooTest, MethodBarDoesAbc) {
const string input_filepath = "this/package/testdata/myinputfile.dat";
const string output_filepath = "this/package/testdata/myoutputfile.dat";
Foo f;
EXPECT_EQ(0, f.Bar(input_filepath, output_filepath));
}
// Tests that Foo does Xyz.
TEST_F(FooTest, DoesXyz) {
// Exercises the Xyz feature of Foo.
}
} // namespace
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
```
The `::testing::InitGoogleTest()` function parses the command line for Google
Test flags, and removes all recognized flags. This allows the user to control a
test program's behavior via various flags, which we'll cover in [AdvancedGuide](V1_6_AdvancedGuide.md).
You must call this function before calling `RUN_ALL_TESTS()`, or the flags
won't be properly initialized.
On Windows, `InitGoogleTest()` also works with wide strings, so it can be used
in programs compiled in `UNICODE` mode as well.
But maybe you think that writing all those main() functions is too much work? We agree with you completely and that's why Google Test provides a basic implementation of main(). If it fits your needs, then just link your test with gtest\_main library and you are good to go.
## Important note for Visual C++ users ##
If you put your tests into a library and your `main()` function is in a different library or in your .exe file, those tests will not run. The reason is a [bug](https://connect.microsoft.com/feedback/viewfeedback.aspx?FeedbackID=244410&siteid=210) in Visual C++. When you define your tests, Google Test creates certain static objects to register them. These objects are not referenced from elsewhere but their constructors are still supposed to run. When Visual C++ linker sees that nothing in the library is referenced from other places it throws the library out. You have to reference your library with tests from your main program to keep the linker from discarding it. Here is how to do it. Somewhere in your library code declare a function:
```
__declspec(dllexport) int PullInMyLibrary() { return 0; }
```
If you put your tests in a static library (not DLL) then `__declspec(dllexport)` is not required. Now, in your main program, write a code that invokes that function:
```
int PullInMyLibrary();
static int dummy = PullInMyLibrary();
```
This will keep your tests referenced and will make them register themselves at startup.
In addition, if you define your tests in a static library, add `/OPT:NOREF` to your main program linker options. If you use MSVC++ IDE, go to your .exe project properties/Configuration Properties/Linker/Optimization and set References setting to `Keep Unreferenced Data (/OPT:NOREF)`. This will keep Visual C++ linker from discarding individual symbols generated by your tests from the final executable.
There is one more pitfall, though. If you use Google Test as a static library (that's how it is defined in gtest.vcproj) your tests must also reside in a static library. If you have to have them in a DLL, you _must_ change Google Test to build into a DLL as well. Otherwise your tests will not run correctly or will not run at all. The general conclusion here is: make your life easier - do not write your tests in libraries!
# Where to Go from Here #
Congratulations! You've learned the Google Test basics. You can start writing
and running Google Test tests, read some [samples](V1_6_Samples.md), or continue with
[AdvancedGuide](V1_6_AdvancedGuide.md), which describes many more useful Google Test features.
# Known Limitations #
Google Test is designed to be thread-safe. The implementation is
thread-safe on systems where the `pthreads` library is available. It
is currently _unsafe_ to use Google Test assertions from two threads
concurrently on other systems (e.g. Windows). In most tests this is
not an issue as usually the assertions are done in the main thread. If
you want to help, you can volunteer to implement the necessary
synchronization primitives in `gtest-port.h` for your platform.

View File

@@ -0,0 +1,177 @@
<b>P</b>ump is <b>U</b>seful for <b>M</b>eta <b>P</b>rogramming.
# The Problem #
Template and macro libraries often need to define many classes,
functions, or macros that vary only (or almost only) in the number of
arguments they take. It's a lot of repetitive, mechanical, and
error-prone work.
Variadic templates and variadic macros can alleviate the problem.
However, while both are being considered by the C++ committee, neither
is in the standard yet or widely supported by compilers. Thus they
are often not a good choice, especially when your code needs to be
portable. And their capabilities are still limited.
As a result, authors of such libraries often have to write scripts to
generate their implementation. However, our experience is that it's
tedious to write such scripts, which tend to reflect the structure of
the generated code poorly and are often hard to read and edit. For
example, a small change needed in the generated code may require some
non-intuitive, non-trivial changes in the script. This is especially
painful when experimenting with the code.
# Our Solution #
Pump (for Pump is Useful for Meta Programming, Pretty Useful for Meta
Programming, or Practical Utility for Meta Programming, whichever you
prefer) is a simple meta-programming tool for C++. The idea is that a
programmer writes a `foo.pump` file which contains C++ code plus meta
code that manipulates the C++ code. The meta code can handle
iterations over a range, nested iterations, local meta variable
definitions, simple arithmetic, and conditional expressions. You can
view it as a small Domain-Specific Language. The meta language is
designed to be non-intrusive (s.t. it won't confuse Emacs' C++ mode,
for example) and concise, making Pump code intuitive and easy to
maintain.
## Highlights ##
* The implementation is in a single Python script and thus ultra portable: no build or installation is needed and it works cross platforms.
* Pump tries to be smart with respect to [Google's style guide](http://code.google.com/p/google-styleguide/): it breaks long lines (easy to have when they are generated) at acceptable places to fit within 80 columns and indent the continuation lines correctly.
* The format is human-readable and more concise than XML.
* The format works relatively well with Emacs' C++ mode.
## Examples ##
The following Pump code (where meta keywords start with `$`, `[[` and `]]` are meta brackets, and `$$` starts a meta comment that ends with the line):
```
$var n = 3 $$ Defines a meta variable n.
$range i 0..n $$ Declares the range of meta iterator i (inclusive).
$for i [[
$$ Meta loop.
// Foo$i does blah for $i-ary predicates.
$range j 1..i
template <size_t N $for j [[, typename A$j]]>
class Foo$i {
$if i == 0 [[
blah a;
]] $elif i <= 2 [[
blah b;
]] $else [[
blah c;
]]
};
]]
```
will be translated by the Pump compiler to:
```
// Foo0 does blah for 0-ary predicates.
template <size_t N>
class Foo0 {
blah a;
};
// Foo1 does blah for 1-ary predicates.
template <size_t N, typename A1>
class Foo1 {
blah b;
};
// Foo2 does blah for 2-ary predicates.
template <size_t N, typename A1, typename A2>
class Foo2 {
blah b;
};
// Foo3 does blah for 3-ary predicates.
template <size_t N, typename A1, typename A2, typename A3>
class Foo3 {
blah c;
};
```
In another example,
```
$range i 1..n
Func($for i + [[a$i]]);
$$ The text between i and [[ is the separator between iterations.
```
will generate one of the following lines (without the comments), depending on the value of `n`:
```
Func(); // If n is 0.
Func(a1); // If n is 1.
Func(a1 + a2); // If n is 2.
Func(a1 + a2 + a3); // If n is 3.
// And so on...
```
## Constructs ##
We support the following meta programming constructs:
| `$var id = exp` | Defines a named constant value. `$id` is valid util the end of the current meta lexical block. |
|:----------------|:-----------------------------------------------------------------------------------------------|
| `$range id exp..exp` | Sets the range of an iteration variable, which can be reused in multiple loops later. |
| `$for id sep [[ code ]]` | Iteration. The range of `id` must have been defined earlier. `$id` is valid in `code`. |
| `$($)` | Generates a single `$` character. |
| `$id` | Value of the named constant or iteration variable. |
| `$(exp)` | Value of the expression. |
| `$if exp [[ code ]] else_branch` | Conditional. |
| `[[ code ]]` | Meta lexical block. |
| `cpp_code` | Raw C++ code. |
| `$$ comment` | Meta comment. |
**Note:** To give the user some freedom in formatting the Pump source
code, Pump ignores a new-line character if it's right after `$for foo`
or next to `[[` or `]]`. Without this rule you'll often be forced to write
very long lines to get the desired output. Therefore sometimes you may
need to insert an extra new-line in such places for a new-line to show
up in your output.
## Grammar ##
```
code ::= atomic_code*
atomic_code ::= $var id = exp
| $var id = [[ code ]]
| $range id exp..exp
| $for id sep [[ code ]]
| $($)
| $id
| $(exp)
| $if exp [[ code ]] else_branch
| [[ code ]]
| cpp_code
sep ::= cpp_code | empty_string
else_branch ::= $else [[ code ]]
| $elif exp [[ code ]] else_branch
| empty_string
exp ::= simple_expression_in_Python_syntax
```
## Code ##
You can find the source code of Pump in [scripts/pump.py](../scripts/pump.py). It is still
very unpolished and lacks automated tests, although it has been
successfully used many times. If you find a chance to use it in your
project, please let us know what you think! We also welcome help on
improving Pump.
## Real Examples ##
You can find real-world applications of Pump in [Google Test](http://www.google.com/codesearch?q=file%3A\.pump%24+package%3Ahttp%3A%2F%2Fgoogletest\.googlecode\.com) and [Google Mock](http://www.google.com/codesearch?q=file%3A\.pump%24+package%3Ahttp%3A%2F%2Fgooglemock\.googlecode\.com). The source file `foo.h.pump` generates `foo.h`.
## Tips ##
* If a meta variable is followed by a letter or digit, you can separate them using `[[]]`, which inserts an empty string. For example `Foo$j[[]]Helper` generate `Foo1Helper` when `j` is 1.
* To avoid extra-long Pump source lines, you can break a line anywhere you want by inserting `[[]]` followed by a new line. Since any new-line character next to `[[` or `]]` is ignored, the generated code won't contain this new line.

View File

@@ -0,0 +1,14 @@
If you're like us, you'd like to look at some Google Test sample code. The
[samples folder](../samples) has a number of well-commented samples showing how to use a
variety of Google Test features.
* [Sample #1](../samples/sample1_unittest.cc) shows the basic steps of using Google Test to test C++ functions.
* [Sample #2](../samples/sample2_unittest.cc) shows a more complex unit test for a class with multiple member functions.
* [Sample #3](../samples/sample3_unittest.cc) uses a test fixture.
* [Sample #4](../samples/sample4_unittest.cc) is another basic example of using Google Test.
* [Sample #5](../samples/sample5_unittest.cc) teaches how to reuse a test fixture in multiple test cases by deriving sub-fixtures from it.
* [Sample #6](../samples/sample6_unittest.cc) demonstrates type-parameterized tests.
* [Sample #7](../samples/sample7_unittest.cc) teaches the basics of value-parameterized tests.
* [Sample #8](../samples/sample8_unittest.cc) shows using `Combine()` in value-parameterized tests.
* [Sample #9](../samples/sample9_unittest.cc) shows use of the listener API to modify Google Test's console output and the use of its reflection API to inspect test results.
* [Sample #10](../samples/sample10_unittest.cc) shows use of the listener API to implement a primitive memory leak checker.

View File

@@ -0,0 +1,93 @@
This guide will explain how to use the Google Testing Framework in your Xcode projects on Mac OS X. This tutorial begins by quickly explaining what to do for experienced users. After the quick start, the guide goes provides additional explanation about each step.
# Quick Start #
Here is the quick guide for using Google Test in your Xcode project.
1. Download the source from the [website](http://code.google.com/p/googletest) using this command: `svn checkout http://googletest.googlecode.com/svn/trunk/ googletest-read-only`
1. Open up the `gtest.xcodeproj` in the `googletest-read-only/xcode/` directory and build the gtest.framework.
1. Create a new "Shell Tool" target in your Xcode project called something like "UnitTests"
1. Add the gtest.framework to your project and add it to the "Link Binary with Libraries" build phase of "UnitTests"
1. Add your unit test source code to the "Compile Sources" build phase of "UnitTests"
1. Edit the "UnitTests" executable and add an environment variable named "DYLD\_FRAMEWORK\_PATH" with a value equal to the path to the framework containing the gtest.framework relative to the compiled executable.
1. Build and Go
The following sections further explain each of the steps listed above in depth, describing in more detail how to complete it including some variations.
# Get the Source #
Currently, the gtest.framework discussed here isn't available in a tagged release of Google Test, it is only available in the trunk. As explained at the Google Test [site](http://code.google.com/p/googletest/source/checkout">svn), you can get the code from anonymous SVN with this command:
```
svn checkout http://googletest.googlecode.com/svn/trunk/ googletest-read-only
```
Alternatively, if you are working with Subversion in your own code base, you can add Google Test as an external dependency to your own Subversion repository. By following this approach, everyone that checks out your svn repository will also receive a copy of Google Test (a specific version, if you wish) without having to check it out explicitly. This makes the set up of your project simpler and reduces the copied code in the repository.
To use `svn:externals`, decide where you would like to have the external source reside. You might choose to put the external source inside the trunk, because you want it to be part of the branch when you make a release. However, keeping it outside the trunk in a version-tagged directory called something like `third-party/googletest/1.0.1`, is another option. Once the location is established, use `svn propedit svn:externals _directory_` to set the svn:externals property on a directory in your repository. This directory won't contain the code, but be its versioned parent directory.
The command `svn propedit` will bring up your Subversion editor, making editing the long, (potentially multi-line) property simpler. This same method can be used to check out a tagged branch, by using the appropriate URL (e.g. `http://googletest.googlecode.com/svn/tags/release-1.0.1`). Additionally, the svn:externals property allows the specification of a particular revision of the trunk with the `-r_##_` option (e.g. `externals/src/googletest -r60 http://googletest.googlecode.com/svn/trunk`).
Here is an example of using the svn:externals properties on a trunk (read via `svn propget`) of a project. This value checks out a copy of Google Test into the `trunk/externals/src/googletest/` directory.
```
[Computer:svn] user$ svn propget svn:externals trunk
externals/src/googletest http://googletest.googlecode.com/svn/trunk
```
# Add the Framework to Your Project #
The next step is to build and add the gtest.framework to your own project. This guide describes two common ways below.
* **Option 1** --- The simplest way to add Google Test to your own project, is to open gtest.xcodeproj (found in the xcode/ directory of the Google Test trunk) and build the framework manually. Then, add the built framework into your project using the "Add->Existing Framework..." from the context menu or "Project->Add..." from the main menu. The gtest.framework is relocatable and contains the headers and object code that you'll need to make tests. This method requires rebuilding every time you upgrade Google Test in your project.
* **Option 2** --- If you are going to be living off the trunk of Google Test, incorporating its latest features into your unit tests (or are a Google Test developer yourself). You'll want to rebuild the framework every time the source updates. to do this, you'll need to add the gtest.xcodeproj file, not the framework itself, to your own Xcode project. Then, from the build products that are revealed by the project's disclosure triangle, you can find the gtest.framework, which can be added to your targets (discussed below).
# Make a Test Target #
To start writing tests, make a new "Shell Tool" target. This target template is available under BSD, Cocoa, or Carbon. Add your unit test source code to the "Compile Sources" build phase of the target.
Next, you'll want to add gtest.framework in two different ways, depending upon which option you chose above.
* **Option 1** --- During compilation, Xcode will need to know that you are linking against the gtest.framework. Add the gtest.framework to the "Link Binary with Libraries" build phase of your test target. This will include the Google Test headers in your header search path, and will tell the linker where to find the library.
* **Option 2** --- If your working out of the trunk, you'll also want to add gtest.framework to your "Link Binary with Libraries" build phase of your test target. In addition, you'll want to add the gtest.framework as a dependency to your unit test target. This way, Xcode will make sure that gtest.framework is up to date, every time your build your target. Finally, if you don't share build directories with Google Test, you'll have to copy the gtest.framework into your own build products directory using a "Run Script" build phase.
# Set Up the Executable Run Environment #
Since the unit test executable is a shell tool, it doesn't have a bundle with a `Contents/Frameworks` directory, in which to place gtest.framework. Instead, the dynamic linker must be told at runtime to search for the framework in another location. This can be accomplished by setting the "DYLD\_FRAMEWORK\_PATH" environment variable in the "Edit Active Executable ..." Arguments tab, under "Variables to be set in the environment:". The path for this value is the path (relative or absolute) of the directory containing the gtest.framework.
If you haven't set up the DYLD\_FRAMEWORK\_PATH, correctly, you might get a message like this:
```
[Session started at 2008-08-15 06:23:57 -0600.]
dyld: Library not loaded: @loader_path/../Frameworks/gtest.framework/Versions/A/gtest
Referenced from: /Users/username/Documents/Sandbox/gtestSample/build/Debug/WidgetFrameworkTest
Reason: image not found
```
To correct this problem, got to the directory containing the executable named in "Referenced from:" value in the error message above. Then, with the terminal in this location, find the relative path to the directory containing the gtest.framework. That is the value you'll need to set as the DYLD\_FRAMEWORK\_PATH.
# Build and Go #
Now, when you click "Build and Go", the test will be executed. Dumping out something like this:
```
[Session started at 2008-08-06 06:36:13 -0600.]
[==========] Running 2 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 2 tests from WidgetInitializerTest
[ RUN ] WidgetInitializerTest.TestConstructor
[ OK ] WidgetInitializerTest.TestConstructor
[ RUN ] WidgetInitializerTest.TestConversion
[ OK ] WidgetInitializerTest.TestConversion
[----------] Global test environment tear-down
[==========] 2 tests from 1 test case ran.
[ PASSED ] 2 tests.
The Debugger has exited with status 0.
```
# Summary #
Unit testing is a valuable way to ensure your data model stays valid even during rapid development or refactoring. The Google Testing Framework is a great unit testing framework for C and C++ which integrates well with an Xcode development environment.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,14 @@
This page lists all documentation wiki pages for Google Test **(the SVN trunk version)**
-- **if you use a released version of Google Test, please read the
documentation for that specific version instead.**
* [Primer](V1_7_Primer.md) -- start here if you are new to Google Test.
* [Samples](V1_7_Samples.md) -- learn from examples.
* [AdvancedGuide](V1_7_AdvancedGuide.md) -- learn more about Google Test.
* [XcodeGuide](V1_7_XcodeGuide.md) -- how to use Google Test in Xcode on Mac.
* [Frequently-Asked Questions](V1_7_FAQ.md) -- check here before asking a question on the mailing list.
To contribute code to Google Test, read:
* [DevGuide](DevGuide.md) -- read this _before_ writing your first patch.
* [PumpManual](V1_7_PumpManual.md) -- how we generate some of Google Test's source files.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,501 @@
# Introduction: Why Google C++ Testing Framework? #
_Google C++ Testing Framework_ helps you write better C++ tests.
No matter whether you work on Linux, Windows, or a Mac, if you write C++ code,
Google Test can help you.
So what makes a good test, and how does Google C++ Testing Framework fit in? We believe:
1. Tests should be _independent_ and _repeatable_. It's a pain to debug a test that succeeds or fails as a result of other tests. Google C++ Testing Framework isolates the tests by running each of them on a different object. When a test fails, Google C++ Testing Framework allows you to run it in isolation for quick debugging.
1. Tests should be well _organized_ and reflect the structure of the tested code. Google C++ Testing Framework groups related tests into test cases that can share data and subroutines. This common pattern is easy to recognize and makes tests easy to maintain. Such consistency is especially helpful when people switch projects and start to work on a new code base.
1. Tests should be _portable_ and _reusable_. The open-source community has a lot of code that is platform-neutral, its tests should also be platform-neutral. Google C++ Testing Framework works on different OSes, with different compilers (gcc, MSVC, and others), with or without exceptions, so Google C++ Testing Framework tests can easily work with a variety of configurations. (Note that the current release only contains build scripts for Linux - we are actively working on scripts for other platforms.)
1. When tests fail, they should provide as much _information_ about the problem as possible. Google C++ Testing Framework doesn't stop at the first test failure. Instead, it only stops the current test and continues with the next. You can also set up tests that report non-fatal failures after which the current test continues. Thus, you can detect and fix multiple bugs in a single run-edit-compile cycle.
1. The testing framework should liberate test writers from housekeeping chores and let them focus on the test _content_. Google C++ Testing Framework automatically keeps track of all tests defined, and doesn't require the user to enumerate them in order to run them.
1. Tests should be _fast_. With Google C++ Testing Framework, you can reuse shared resources across tests and pay for the set-up/tear-down only once, without making tests depend on each other.
Since Google C++ Testing Framework is based on the popular xUnit
architecture, you'll feel right at home if you've used JUnit or PyUnit before.
If not, it will take you about 10 minutes to learn the basics and get started.
So let's go!
_Note:_ We sometimes refer to Google C++ Testing Framework informally
as _Google Test_.
# Setting up a New Test Project #
To write a test program using Google Test, you need to compile Google
Test into a library and link your test with it. We provide build
files for some popular build systems: `msvc/` for Visual Studio,
`xcode/` for Mac Xcode, `make/` for GNU make, `codegear/` for Borland
C++ Builder, and the autotools script (deprecated) and
`CMakeLists.txt` for CMake (recommended) in the Google Test root
directory. If your build system is not on this list, you can take a
look at `make/Makefile` to learn how Google Test should be compiled
(basically you want to compile `src/gtest-all.cc` with `GTEST_ROOT`
and `GTEST_ROOT/include` in the header search path, where `GTEST_ROOT`
is the Google Test root directory).
Once you are able to compile the Google Test library, you should
create a project or build target for your test program. Make sure you
have `GTEST_ROOT/include` in the header search path so that the
compiler can find `"gtest/gtest.h"` when compiling your test. Set up
your test project to link with the Google Test library (for example,
in Visual Studio, this is done by adding a dependency on
`gtest.vcproj`).
If you still have questions, take a look at how Google Test's own
tests are built and use them as examples.
# Basic Concepts #
When using Google Test, you start by writing _assertions_, which are statements
that check whether a condition is true. An assertion's result can be _success_,
_nonfatal failure_, or _fatal failure_. If a fatal failure occurs, it aborts
the current function; otherwise the program continues normally.
_Tests_ use assertions to verify the tested code's behavior. If a test crashes
or has a failed assertion, then it _fails_; otherwise it _succeeds_.
A _test case_ contains one or many tests. You should group your tests into test
cases that reflect the structure of the tested code. When multiple tests in a
test case need to share common objects and subroutines, you can put them into a
_test fixture_ class.
A _test program_ can contain multiple test cases.
We'll now explain how to write a test program, starting at the individual
assertion level and building up to tests and test cases.
# Assertions #
Google Test assertions are macros that resemble function calls. You test a
class or function by making assertions about its behavior. When an assertion
fails, Google Test prints the assertion's source file and line number location,
along with a failure message. You may also supply a custom failure message
which will be appended to Google Test's message.
The assertions come in pairs that test the same thing but have different
effects on the current function. `ASSERT_*` versions generate fatal failures
when they fail, and **abort the current function**. `EXPECT_*` versions generate
nonfatal failures, which don't abort the current function. Usually `EXPECT_*`
are preferred, as they allow more than one failures to be reported in a test.
However, you should use `ASSERT_*` if it doesn't make sense to continue when
the assertion in question fails.
Since a failed `ASSERT_*` returns from the current function immediately,
possibly skipping clean-up code that comes after it, it may cause a space leak.
Depending on the nature of the leak, it may or may not be worth fixing - so
keep this in mind if you get a heap checker error in addition to assertion
errors.
To provide a custom failure message, simply stream it into the macro using the
`<<` operator, or a sequence of such operators. An example:
```
ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length";
for (int i = 0; i < x.size(); ++i) {
EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i;
}
```
Anything that can be streamed to an `ostream` can be streamed to an assertion
macro--in particular, C strings and `string` objects. If a wide string
(`wchar_t*`, `TCHAR*` in `UNICODE` mode on Windows, or `std::wstring`) is
streamed to an assertion, it will be translated to UTF-8 when printed.
## Basic Assertions ##
These assertions do basic true/false condition testing.
| **Fatal assertion** | **Nonfatal assertion** | **Verifies** |
|:--------------------|:-----------------------|:-------------|
| `ASSERT_TRUE(`_condition_`)`; | `EXPECT_TRUE(`_condition_`)`; | _condition_ is true |
| `ASSERT_FALSE(`_condition_`)`; | `EXPECT_FALSE(`_condition_`)`; | _condition_ is false |
Remember, when they fail, `ASSERT_*` yields a fatal failure and
returns from the current function, while `EXPECT_*` yields a nonfatal
failure, allowing the function to continue running. In either case, an
assertion failure means its containing test fails.
_Availability_: Linux, Windows, Mac.
## Binary Comparison ##
This section describes assertions that compare two values.
| **Fatal assertion** | **Nonfatal assertion** | **Verifies** |
|:--------------------|:-----------------------|:-------------|
|`ASSERT_EQ(`_expected_`, `_actual_`);`|`EXPECT_EQ(`_expected_`, `_actual_`);`| _expected_ `==` _actual_ |
|`ASSERT_NE(`_val1_`, `_val2_`);` |`EXPECT_NE(`_val1_`, `_val2_`);` | _val1_ `!=` _val2_ |
|`ASSERT_LT(`_val1_`, `_val2_`);` |`EXPECT_LT(`_val1_`, `_val2_`);` | _val1_ `<` _val2_ |
|`ASSERT_LE(`_val1_`, `_val2_`);` |`EXPECT_LE(`_val1_`, `_val2_`);` | _val1_ `<=` _val2_ |
|`ASSERT_GT(`_val1_`, `_val2_`);` |`EXPECT_GT(`_val1_`, `_val2_`);` | _val1_ `>` _val2_ |
|`ASSERT_GE(`_val1_`, `_val2_`);` |`EXPECT_GE(`_val1_`, `_val2_`);` | _val1_ `>=` _val2_ |
In the event of a failure, Google Test prints both _val1_ and _val2_
. In `ASSERT_EQ*` and `EXPECT_EQ*` (and all other equality assertions
we'll introduce later), you should put the expression you want to test
in the position of _actual_, and put its expected value in _expected_,
as Google Test's failure messages are optimized for this convention.
Value arguments must be comparable by the assertion's comparison
operator or you'll get a compiler error. We used to require the
arguments to support the `<<` operator for streaming to an `ostream`,
but it's no longer necessary since v1.6.0 (if `<<` is supported, it
will be called to print the arguments when the assertion fails;
otherwise Google Test will attempt to print them in the best way it
can. For more details and how to customize the printing of the
arguments, see this Google Mock [recipe](../../googlemock/docs/CookBook.md#teaching-google-mock-how-to-print-your-values).).
These assertions can work with a user-defined type, but only if you define the
corresponding comparison operator (e.g. `==`, `<`, etc). If the corresponding
operator is defined, prefer using the `ASSERT_*()` macros because they will
print out not only the result of the comparison, but the two operands as well.
Arguments are always evaluated exactly once. Therefore, it's OK for the
arguments to have side effects. However, as with any ordinary C/C++ function,
the arguments' evaluation order is undefined (i.e. the compiler is free to
choose any order) and your code should not depend on any particular argument
evaluation order.
`ASSERT_EQ()` does pointer equality on pointers. If used on two C strings, it
tests if they are in the same memory location, not if they have the same value.
Therefore, if you want to compare C strings (e.g. `const char*`) by value, use
`ASSERT_STREQ()` , which will be described later on. In particular, to assert
that a C string is `NULL`, use `ASSERT_STREQ(NULL, c_string)` . However, to
compare two `string` objects, you should use `ASSERT_EQ`.
Macros in this section work with both narrow and wide string objects (`string`
and `wstring`).
_Availability_: Linux, Windows, Mac.
## String Comparison ##
The assertions in this group compare two **C strings**. If you want to compare
two `string` objects, use `EXPECT_EQ`, `EXPECT_NE`, and etc instead.
| **Fatal assertion** | **Nonfatal assertion** | **Verifies** |
|:--------------------|:-----------------------|:-------------|
| `ASSERT_STREQ(`_expected\_str_`, `_actual\_str_`);` | `EXPECT_STREQ(`_expected\_str_`, `_actual\_str_`);` | the two C strings have the same content |
| `ASSERT_STRNE(`_str1_`, `_str2_`);` | `EXPECT_STRNE(`_str1_`, `_str2_`);` | the two C strings have different content |
| `ASSERT_STRCASEEQ(`_expected\_str_`, `_actual\_str_`);`| `EXPECT_STRCASEEQ(`_expected\_str_`, `_actual\_str_`);` | the two C strings have the same content, ignoring case |
| `ASSERT_STRCASENE(`_str1_`, `_str2_`);`| `EXPECT_STRCASENE(`_str1_`, `_str2_`);` | the two C strings have different content, ignoring case |
Note that "CASE" in an assertion name means that case is ignored.
`*STREQ*` and `*STRNE*` also accept wide C strings (`wchar_t*`). If a
comparison of two wide strings fails, their values will be printed as UTF-8
narrow strings.
A `NULL` pointer and an empty string are considered _different_.
_Availability_: Linux, Windows, Mac.
See also: For more string comparison tricks (substring, prefix, suffix, and
regular expression matching, for example), see the [Advanced Google Test Guide](V1_7_AdvancedGuide.md).
# Simple Tests #
To create a test:
1. Use the `TEST()` macro to define and name a test function, These are ordinary C++ functions that don't return a value.
1. In this function, along with any valid C++ statements you want to include, use the various Google Test assertions to check values.
1. The test's result is determined by the assertions; if any assertion in the test fails (either fatally or non-fatally), or if the test crashes, the entire test fails. Otherwise, it succeeds.
```
TEST(test_case_name, test_name) {
... test body ...
}
```
`TEST()` arguments go from general to specific. The _first_ argument is the
name of the test case, and the _second_ argument is the test's name within the
test case. Both names must be valid C++ identifiers, and they should not contain underscore (`_`). A test's _full name_ consists of its containing test case and its
individual name. Tests from different test cases can have the same individual
name.
For example, let's take a simple integer function:
```
int Factorial(int n); // Returns the factorial of n
```
A test case for this function might look like:
```
// Tests factorial of 0.
TEST(FactorialTest, HandlesZeroInput) {
EXPECT_EQ(1, Factorial(0));
}
// Tests factorial of positive numbers.
TEST(FactorialTest, HandlesPositiveInput) {
EXPECT_EQ(1, Factorial(1));
EXPECT_EQ(2, Factorial(2));
EXPECT_EQ(6, Factorial(3));
EXPECT_EQ(40320, Factorial(8));
}
```
Google Test groups the test results by test cases, so logically-related tests
should be in the same test case; in other words, the first argument to their
`TEST()` should be the same. In the above example, we have two tests,
`HandlesZeroInput` and `HandlesPositiveInput`, that belong to the same test
case `FactorialTest`.
_Availability_: Linux, Windows, Mac.
# Test Fixtures: Using the Same Data Configuration for Multiple Tests #
If you find yourself writing two or more tests that operate on similar data,
you can use a _test fixture_. It allows you to reuse the same configuration of
objects for several different tests.
To create a fixture, just:
1. Derive a class from `::testing::Test` . Start its body with `protected:` or `public:` as we'll want to access fixture members from sub-classes.
1. Inside the class, declare any objects you plan to use.
1. If necessary, write a default constructor or `SetUp()` function to prepare the objects for each test. A common mistake is to spell `SetUp()` as `Setup()` with a small `u` - don't let that happen to you.
1. If necessary, write a destructor or `TearDown()` function to release any resources you allocated in `SetUp()` . To learn when you should use the constructor/destructor and when you should use `SetUp()/TearDown()`, read this [FAQ entry](V1_7_FAQ.md#should-i-use-the-constructordestructor-of-the-test-fixture-or-the-set-uptear-down-function).
1. If needed, define subroutines for your tests to share.
When using a fixture, use `TEST_F()` instead of `TEST()` as it allows you to
access objects and subroutines in the test fixture:
```
TEST_F(test_case_name, test_name) {
... test body ...
}
```
Like `TEST()`, the first argument is the test case name, but for `TEST_F()`
this must be the name of the test fixture class. You've probably guessed: `_F`
is for fixture.
Unfortunately, the C++ macro system does not allow us to create a single macro
that can handle both types of tests. Using the wrong macro causes a compiler
error.
Also, you must first define a test fixture class before using it in a
`TEST_F()`, or you'll get the compiler error "`virtual outside class
declaration`".
For each test defined with `TEST_F()`, Google Test will:
1. Create a _fresh_ test fixture at runtime
1. Immediately initialize it via `SetUp()` ,
1. Run the test
1. Clean up by calling `TearDown()`
1. Delete the test fixture. Note that different tests in the same test case have different test fixture objects, and Google Test always deletes a test fixture before it creates the next one. Google Test does not reuse the same test fixture for multiple tests. Any changes one test makes to the fixture do not affect other tests.
As an example, let's write tests for a FIFO queue class named `Queue`, which
has the following interface:
```
template <typename E> // E is the element type.
class Queue {
public:
Queue();
void Enqueue(const E& element);
E* Dequeue(); // Returns NULL if the queue is empty.
size_t size() const;
...
};
```
First, define a fixture class. By convention, you should give it the name
`FooTest` where `Foo` is the class being tested.
```
class QueueTest : public ::testing::Test {
protected:
virtual void SetUp() {
q1_.Enqueue(1);
q2_.Enqueue(2);
q2_.Enqueue(3);
}
// virtual void TearDown() {}
Queue<int> q0_;
Queue<int> q1_;
Queue<int> q2_;
};
```
In this case, `TearDown()` is not needed since we don't have to clean up after
each test, other than what's already done by the destructor.
Now we'll write tests using `TEST_F()` and this fixture.
```
TEST_F(QueueTest, IsEmptyInitially) {
EXPECT_EQ(0, q0_.size());
}
TEST_F(QueueTest, DequeueWorks) {
int* n = q0_.Dequeue();
EXPECT_EQ(NULL, n);
n = q1_.Dequeue();
ASSERT_TRUE(n != NULL);
EXPECT_EQ(1, *n);
EXPECT_EQ(0, q1_.size());
delete n;
n = q2_.Dequeue();
ASSERT_TRUE(n != NULL);
EXPECT_EQ(2, *n);
EXPECT_EQ(1, q2_.size());
delete n;
}
```
The above uses both `ASSERT_*` and `EXPECT_*` assertions. The rule of thumb is
to use `EXPECT_*` when you want the test to continue to reveal more errors
after the assertion failure, and use `ASSERT_*` when continuing after failure
doesn't make sense. For example, the second assertion in the `Dequeue` test is
`ASSERT_TRUE(n != NULL)`, as we need to dereference the pointer `n` later,
which would lead to a segfault when `n` is `NULL`.
When these tests run, the following happens:
1. Google Test constructs a `QueueTest` object (let's call it `t1` ).
1. `t1.SetUp()` initializes `t1` .
1. The first test ( `IsEmptyInitially` ) runs on `t1` .
1. `t1.TearDown()` cleans up after the test finishes.
1. `t1` is destructed.
1. The above steps are repeated on another `QueueTest` object, this time running the `DequeueWorks` test.
_Availability_: Linux, Windows, Mac.
_Note_: Google Test automatically saves all _Google Test_ flags when a test
object is constructed, and restores them when it is destructed.
# Invoking the Tests #
`TEST()` and `TEST_F()` implicitly register their tests with Google Test. So, unlike with many other C++ testing frameworks, you don't have to re-list all your defined tests in order to run them.
After defining your tests, you can run them with `RUN_ALL_TESTS()` , which returns `0` if all the tests are successful, or `1` otherwise. Note that `RUN_ALL_TESTS()` runs _all tests_ in your link unit -- they can be from different test cases, or even different source files.
When invoked, the `RUN_ALL_TESTS()` macro:
1. Saves the state of all Google Test flags.
1. Creates a test fixture object for the first test.
1. Initializes it via `SetUp()`.
1. Runs the test on the fixture object.
1. Cleans up the fixture via `TearDown()`.
1. Deletes the fixture.
1. Restores the state of all Google Test flags.
1. Repeats the above steps for the next test, until all tests have run.
In addition, if the text fixture's constructor generates a fatal failure in
step 2, there is no point for step 3 - 5 and they are thus skipped. Similarly,
if step 3 generates a fatal failure, step 4 will be skipped.
_Important_: You must not ignore the return value of `RUN_ALL_TESTS()`, or `gcc`
will give you a compiler error. The rationale for this design is that the
automated testing service determines whether a test has passed based on its
exit code, not on its stdout/stderr output; thus your `main()` function must
return the value of `RUN_ALL_TESTS()`.
Also, you should call `RUN_ALL_TESTS()` only **once**. Calling it more than once
conflicts with some advanced Google Test features (e.g. thread-safe death
tests) and thus is not supported.
_Availability_: Linux, Windows, Mac.
# Writing the main() Function #
You can start from this boilerplate:
```
#include "this/package/foo.h"
#include "gtest/gtest.h"
namespace {
// The fixture for testing class Foo.
class FooTest : public ::testing::Test {
protected:
// You can remove any or all of the following functions if its body
// is empty.
FooTest() {
// You can do set-up work for each test here.
}
virtual ~FooTest() {
// You can do clean-up work that doesn't throw exceptions here.
}
// If the constructor and destructor are not enough for setting up
// and cleaning up each test, you can define the following methods:
virtual void SetUp() {
// Code here will be called immediately after the constructor (right
// before each test).
}
virtual void TearDown() {
// Code here will be called immediately after each test (right
// before the destructor).
}
// Objects declared here can be used by all tests in the test case for Foo.
};
// Tests that the Foo::Bar() method does Abc.
TEST_F(FooTest, MethodBarDoesAbc) {
const string input_filepath = "this/package/testdata/myinputfile.dat";
const string output_filepath = "this/package/testdata/myoutputfile.dat";
Foo f;
EXPECT_EQ(0, f.Bar(input_filepath, output_filepath));
}
// Tests that Foo does Xyz.
TEST_F(FooTest, DoesXyz) {
// Exercises the Xyz feature of Foo.
}
} // namespace
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
```
The `::testing::InitGoogleTest()` function parses the command line for Google
Test flags, and removes all recognized flags. This allows the user to control a
test program's behavior via various flags, which we'll cover in [AdvancedGuide](V1_7_AdvancedGuide.md).
You must call this function before calling `RUN_ALL_TESTS()`, or the flags
won't be properly initialized.
On Windows, `InitGoogleTest()` also works with wide strings, so it can be used
in programs compiled in `UNICODE` mode as well.
But maybe you think that writing all those main() functions is too much work? We agree with you completely and that's why Google Test provides a basic implementation of main(). If it fits your needs, then just link your test with gtest\_main library and you are good to go.
## Important note for Visual C++ users ##
If you put your tests into a library and your `main()` function is in a different library or in your .exe file, those tests will not run. The reason is a [bug](https://connect.microsoft.com/feedback/viewfeedback.aspx?FeedbackID=244410&siteid=210) in Visual C++. When you define your tests, Google Test creates certain static objects to register them. These objects are not referenced from elsewhere but their constructors are still supposed to run. When Visual C++ linker sees that nothing in the library is referenced from other places it throws the library out. You have to reference your library with tests from your main program to keep the linker from discarding it. Here is how to do it. Somewhere in your library code declare a function:
```
__declspec(dllexport) int PullInMyLibrary() { return 0; }
```
If you put your tests in a static library (not DLL) then `__declspec(dllexport)` is not required. Now, in your main program, write a code that invokes that function:
```
int PullInMyLibrary();
static int dummy = PullInMyLibrary();
```
This will keep your tests referenced and will make them register themselves at startup.
In addition, if you define your tests in a static library, add `/OPT:NOREF` to your main program linker options. If you use MSVC++ IDE, go to your .exe project properties/Configuration Properties/Linker/Optimization and set References setting to `Keep Unreferenced Data (/OPT:NOREF)`. This will keep Visual C++ linker from discarding individual symbols generated by your tests from the final executable.
There is one more pitfall, though. If you use Google Test as a static library (that's how it is defined in gtest.vcproj) your tests must also reside in a static library. If you have to have them in a DLL, you _must_ change Google Test to build into a DLL as well. Otherwise your tests will not run correctly or will not run at all. The general conclusion here is: make your life easier - do not write your tests in libraries!
# Where to Go from Here #
Congratulations! You've learned the Google Test basics. You can start writing
and running Google Test tests, read some [samples](V1_7_Samples.md), or continue with
[AdvancedGuide](V1_7_AdvancedGuide.md), which describes many more useful Google Test features.
# Known Limitations #
Google Test is designed to be thread-safe. The implementation is
thread-safe on systems where the `pthreads` library is available. It
is currently _unsafe_ to use Google Test assertions from two threads
concurrently on other systems (e.g. Windows). In most tests this is
not an issue as usually the assertions are done in the main thread. If
you want to help, you can volunteer to implement the necessary
synchronization primitives in `gtest-port.h` for your platform.

View File

@@ -0,0 +1,177 @@
<b>P</b>ump is <b>U</b>seful for <b>M</b>eta <b>P</b>rogramming.
# The Problem #
Template and macro libraries often need to define many classes,
functions, or macros that vary only (or almost only) in the number of
arguments they take. It's a lot of repetitive, mechanical, and
error-prone work.
Variadic templates and variadic macros can alleviate the problem.
However, while both are being considered by the C++ committee, neither
is in the standard yet or widely supported by compilers. Thus they
are often not a good choice, especially when your code needs to be
portable. And their capabilities are still limited.
As a result, authors of such libraries often have to write scripts to
generate their implementation. However, our experience is that it's
tedious to write such scripts, which tend to reflect the structure of
the generated code poorly and are often hard to read and edit. For
example, a small change needed in the generated code may require some
non-intuitive, non-trivial changes in the script. This is especially
painful when experimenting with the code.
# Our Solution #
Pump (for Pump is Useful for Meta Programming, Pretty Useful for Meta
Programming, or Practical Utility for Meta Programming, whichever you
prefer) is a simple meta-programming tool for C++. The idea is that a
programmer writes a `foo.pump` file which contains C++ code plus meta
code that manipulates the C++ code. The meta code can handle
iterations over a range, nested iterations, local meta variable
definitions, simple arithmetic, and conditional expressions. You can
view it as a small Domain-Specific Language. The meta language is
designed to be non-intrusive (s.t. it won't confuse Emacs' C++ mode,
for example) and concise, making Pump code intuitive and easy to
maintain.
## Highlights ##
* The implementation is in a single Python script and thus ultra portable: no build or installation is needed and it works cross platforms.
* Pump tries to be smart with respect to [Google's style guide](http://code.google.com/p/google-styleguide/): it breaks long lines (easy to have when they are generated) at acceptable places to fit within 80 columns and indent the continuation lines correctly.
* The format is human-readable and more concise than XML.
* The format works relatively well with Emacs' C++ mode.
## Examples ##
The following Pump code (where meta keywords start with `$`, `[[` and `]]` are meta brackets, and `$$` starts a meta comment that ends with the line):
```
$var n = 3 $$ Defines a meta variable n.
$range i 0..n $$ Declares the range of meta iterator i (inclusive).
$for i [[
$$ Meta loop.
// Foo$i does blah for $i-ary predicates.
$range j 1..i
template <size_t N $for j [[, typename A$j]]>
class Foo$i {
$if i == 0 [[
blah a;
]] $elif i <= 2 [[
blah b;
]] $else [[
blah c;
]]
};
]]
```
will be translated by the Pump compiler to:
```
// Foo0 does blah for 0-ary predicates.
template <size_t N>
class Foo0 {
blah a;
};
// Foo1 does blah for 1-ary predicates.
template <size_t N, typename A1>
class Foo1 {
blah b;
};
// Foo2 does blah for 2-ary predicates.
template <size_t N, typename A1, typename A2>
class Foo2 {
blah b;
};
// Foo3 does blah for 3-ary predicates.
template <size_t N, typename A1, typename A2, typename A3>
class Foo3 {
blah c;
};
```
In another example,
```
$range i 1..n
Func($for i + [[a$i]]);
$$ The text between i and [[ is the separator between iterations.
```
will generate one of the following lines (without the comments), depending on the value of `n`:
```
Func(); // If n is 0.
Func(a1); // If n is 1.
Func(a1 + a2); // If n is 2.
Func(a1 + a2 + a3); // If n is 3.
// And so on...
```
## Constructs ##
We support the following meta programming constructs:
| `$var id = exp` | Defines a named constant value. `$id` is valid util the end of the current meta lexical block. |
|:----------------|:-----------------------------------------------------------------------------------------------|
| `$range id exp..exp` | Sets the range of an iteration variable, which can be reused in multiple loops later. |
| `$for id sep [[ code ]]` | Iteration. The range of `id` must have been defined earlier. `$id` is valid in `code`. |
| `$($)` | Generates a single `$` character. |
| `$id` | Value of the named constant or iteration variable. |
| `$(exp)` | Value of the expression. |
| `$if exp [[ code ]] else_branch` | Conditional. |
| `[[ code ]]` | Meta lexical block. |
| `cpp_code` | Raw C++ code. |
| `$$ comment` | Meta comment. |
**Note:** To give the user some freedom in formatting the Pump source
code, Pump ignores a new-line character if it's right after `$for foo`
or next to `[[` or `]]`. Without this rule you'll often be forced to write
very long lines to get the desired output. Therefore sometimes you may
need to insert an extra new-line in such places for a new-line to show
up in your output.
## Grammar ##
```
code ::= atomic_code*
atomic_code ::= $var id = exp
| $var id = [[ code ]]
| $range id exp..exp
| $for id sep [[ code ]]
| $($)
| $id
| $(exp)
| $if exp [[ code ]] else_branch
| [[ code ]]
| cpp_code
sep ::= cpp_code | empty_string
else_branch ::= $else [[ code ]]
| $elif exp [[ code ]] else_branch
| empty_string
exp ::= simple_expression_in_Python_syntax
```
## Code ##
You can find the source code of Pump in [scripts/pump.py](../scripts/pump.py). It is still
very unpolished and lacks automated tests, although it has been
successfully used many times. If you find a chance to use it in your
project, please let us know what you think! We also welcome help on
improving Pump.
## Real Examples ##
You can find real-world applications of Pump in [Google Test](http://www.google.com/codesearch?q=file%3A\.pump%24+package%3Ahttp%3A%2F%2Fgoogletest\.googlecode\.com) and [Google Mock](http://www.google.com/codesearch?q=file%3A\.pump%24+package%3Ahttp%3A%2F%2Fgooglemock\.googlecode\.com). The source file `foo.h.pump` generates `foo.h`.
## Tips ##
* If a meta variable is followed by a letter or digit, you can separate them using `[[]]`, which inserts an empty string. For example `Foo$j[[]]Helper` generate `Foo1Helper` when `j` is 1.
* To avoid extra-long Pump source lines, you can break a line anywhere you want by inserting `[[]]` followed by a new line. Since any new-line character next to `[[` or `]]` is ignored, the generated code won't contain this new line.

View File

@@ -0,0 +1,14 @@
If you're like us, you'd like to look at some Google Test sample code. The
[samples folder](../samples) has a number of well-commented samples showing how to use a
variety of Google Test features.
* [Sample #1](../samples/sample1_unittest.cc) shows the basic steps of using Google Test to test C++ functions.
* [Sample #2](../samples/sample2_unittest.cc) shows a more complex unit test for a class with multiple member functions.
* [Sample #3](../samples/sample3_unittest.cc) uses a test fixture.
* [Sample #4](../samples/sample4_unittest.cc) is another basic example of using Google Test.
* [Sample #5](../samples/sample5_unittest.cc) teaches how to reuse a test fixture in multiple test cases by deriving sub-fixtures from it.
* [Sample #6](../samples/sample6_unittest.cc) demonstrates type-parameterized tests.
* [Sample #7](../samples/sample7_unittest.cc) teaches the basics of value-parameterized tests.
* [Sample #8](../samples/sample8_unittest.cc) shows using `Combine()` in value-parameterized tests.
* [Sample #9](../samples/sample9_unittest.cc) shows use of the listener API to modify Google Test's console output and the use of its reflection API to inspect test results.
* [Sample #10](../samples/sample10_unittest.cc) shows use of the listener API to implement a primitive memory leak checker.

View File

@@ -0,0 +1,93 @@
This guide will explain how to use the Google Testing Framework in your Xcode projects on Mac OS X. This tutorial begins by quickly explaining what to do for experienced users. After the quick start, the guide goes provides additional explanation about each step.
# Quick Start #
Here is the quick guide for using Google Test in your Xcode project.
1. Download the source from the [website](http://code.google.com/p/googletest) using this command: `svn checkout http://googletest.googlecode.com/svn/trunk/ googletest-read-only`
1. Open up the `gtest.xcodeproj` in the `googletest-read-only/xcode/` directory and build the gtest.framework.
1. Create a new "Shell Tool" target in your Xcode project called something like "UnitTests"
1. Add the gtest.framework to your project and add it to the "Link Binary with Libraries" build phase of "UnitTests"
1. Add your unit test source code to the "Compile Sources" build phase of "UnitTests"
1. Edit the "UnitTests" executable and add an environment variable named "DYLD\_FRAMEWORK\_PATH" with a value equal to the path to the framework containing the gtest.framework relative to the compiled executable.
1. Build and Go
The following sections further explain each of the steps listed above in depth, describing in more detail how to complete it including some variations.
# Get the Source #
Currently, the gtest.framework discussed here isn't available in a tagged release of Google Test, it is only available in the trunk. As explained at the Google Test [site](http://code.google.com/p/googletest/source/checkout">svn), you can get the code from anonymous SVN with this command:
```
svn checkout http://googletest.googlecode.com/svn/trunk/ googletest-read-only
```
Alternatively, if you are working with Subversion in your own code base, you can add Google Test as an external dependency to your own Subversion repository. By following this approach, everyone that checks out your svn repository will also receive a copy of Google Test (a specific version, if you wish) without having to check it out explicitly. This makes the set up of your project simpler and reduces the copied code in the repository.
To use `svn:externals`, decide where you would like to have the external source reside. You might choose to put the external source inside the trunk, because you want it to be part of the branch when you make a release. However, keeping it outside the trunk in a version-tagged directory called something like `third-party/googletest/1.0.1`, is another option. Once the location is established, use `svn propedit svn:externals _directory_` to set the svn:externals property on a directory in your repository. This directory won't contain the code, but be its versioned parent directory.
The command `svn propedit` will bring up your Subversion editor, making editing the long, (potentially multi-line) property simpler. This same method can be used to check out a tagged branch, by using the appropriate URL (e.g. `http://googletest.googlecode.com/svn/tags/release-1.0.1`). Additionally, the svn:externals property allows the specification of a particular revision of the trunk with the `-r_##_` option (e.g. `externals/src/googletest -r60 http://googletest.googlecode.com/svn/trunk`).
Here is an example of using the svn:externals properties on a trunk (read via `svn propget`) of a project. This value checks out a copy of Google Test into the `trunk/externals/src/googletest/` directory.
```
[Computer:svn] user$ svn propget svn:externals trunk
externals/src/googletest http://googletest.googlecode.com/svn/trunk
```
# Add the Framework to Your Project #
The next step is to build and add the gtest.framework to your own project. This guide describes two common ways below.
* **Option 1** --- The simplest way to add Google Test to your own project, is to open gtest.xcodeproj (found in the xcode/ directory of the Google Test trunk) and build the framework manually. Then, add the built framework into your project using the "Add->Existing Framework..." from the context menu or "Project->Add..." from the main menu. The gtest.framework is relocatable and contains the headers and object code that you'll need to make tests. This method requires rebuilding every time you upgrade Google Test in your project.
* **Option 2** --- If you are going to be living off the trunk of Google Test, incorporating its latest features into your unit tests (or are a Google Test developer yourself). You'll want to rebuild the framework every time the source updates. to do this, you'll need to add the gtest.xcodeproj file, not the framework itself, to your own Xcode project. Then, from the build products that are revealed by the project's disclosure triangle, you can find the gtest.framework, which can be added to your targets (discussed below).
# Make a Test Target #
To start writing tests, make a new "Shell Tool" target. This target template is available under BSD, Cocoa, or Carbon. Add your unit test source code to the "Compile Sources" build phase of the target.
Next, you'll want to add gtest.framework in two different ways, depending upon which option you chose above.
* **Option 1** --- During compilation, Xcode will need to know that you are linking against the gtest.framework. Add the gtest.framework to the "Link Binary with Libraries" build phase of your test target. This will include the Google Test headers in your header search path, and will tell the linker where to find the library.
* **Option 2** --- If your working out of the trunk, you'll also want to add gtest.framework to your "Link Binary with Libraries" build phase of your test target. In addition, you'll want to add the gtest.framework as a dependency to your unit test target. This way, Xcode will make sure that gtest.framework is up to date, every time your build your target. Finally, if you don't share build directories with Google Test, you'll have to copy the gtest.framework into your own build products directory using a "Run Script" build phase.
# Set Up the Executable Run Environment #
Since the unit test executable is a shell tool, it doesn't have a bundle with a `Contents/Frameworks` directory, in which to place gtest.framework. Instead, the dynamic linker must be told at runtime to search for the framework in another location. This can be accomplished by setting the "DYLD\_FRAMEWORK\_PATH" environment variable in the "Edit Active Executable ..." Arguments tab, under "Variables to be set in the environment:". The path for this value is the path (relative or absolute) of the directory containing the gtest.framework.
If you haven't set up the DYLD\_FRAMEWORK\_PATH, correctly, you might get a message like this:
```
[Session started at 2008-08-15 06:23:57 -0600.]
dyld: Library not loaded: @loader_path/../Frameworks/gtest.framework/Versions/A/gtest
Referenced from: /Users/username/Documents/Sandbox/gtestSample/build/Debug/WidgetFrameworkTest
Reason: image not found
```
To correct this problem, got to the directory containing the executable named in "Referenced from:" value in the error message above. Then, with the terminal in this location, find the relative path to the directory containing the gtest.framework. That is the value you'll need to set as the DYLD\_FRAMEWORK\_PATH.
# Build and Go #
Now, when you click "Build and Go", the test will be executed. Dumping out something like this:
```
[Session started at 2008-08-06 06:36:13 -0600.]
[==========] Running 2 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 2 tests from WidgetInitializerTest
[ RUN ] WidgetInitializerTest.TestConstructor
[ OK ] WidgetInitializerTest.TestConstructor
[ RUN ] WidgetInitializerTest.TestConversion
[ OK ] WidgetInitializerTest.TestConversion
[----------] Global test environment tear-down
[==========] 2 tests from 1 test case ran.
[ PASSED ] 2 tests.
The Debugger has exited with status 0.
```
# Summary #
Unit testing is a valuable way to ensure your data model stays valid even during rapid development or refactoring. The Google Testing Framework is a great unit testing framework for C and C++ which integrates well with an Xcode development environment.

View File

@@ -0,0 +1,93 @@
This guide will explain how to use the Google Testing Framework in your Xcode projects on Mac OS X. This tutorial begins by quickly explaining what to do for experienced users. After the quick start, the guide goes provides additional explanation about each step.
# Quick Start #
Here is the quick guide for using Google Test in your Xcode project.
1. Download the source from the [website](http://code.google.com/p/googletest) using this command: `svn checkout http://googletest.googlecode.com/svn/trunk/ googletest-read-only`
1. Open up the `gtest.xcodeproj` in the `googletest-read-only/xcode/` directory and build the gtest.framework.
1. Create a new "Shell Tool" target in your Xcode project called something like "UnitTests"
1. Add the gtest.framework to your project and add it to the "Link Binary with Libraries" build phase of "UnitTests"
1. Add your unit test source code to the "Compile Sources" build phase of "UnitTests"
1. Edit the "UnitTests" executable and add an environment variable named "DYLD\_FRAMEWORK\_PATH" with a value equal to the path to the framework containing the gtest.framework relative to the compiled executable.
1. Build and Go
The following sections further explain each of the steps listed above in depth, describing in more detail how to complete it including some variations.
# Get the Source #
Currently, the gtest.framework discussed here isn't available in a tagged release of Google Test, it is only available in the trunk. As explained at the Google Test [site](http://code.google.com/p/googletest/source/checkout">svn), you can get the code from anonymous SVN with this command:
```
svn checkout http://googletest.googlecode.com/svn/trunk/ googletest-read-only
```
Alternatively, if you are working with Subversion in your own code base, you can add Google Test as an external dependency to your own Subversion repository. By following this approach, everyone that checks out your svn repository will also receive a copy of Google Test (a specific version, if you wish) without having to check it out explicitly. This makes the set up of your project simpler and reduces the copied code in the repository.
To use `svn:externals`, decide where you would like to have the external source reside. You might choose to put the external source inside the trunk, because you want it to be part of the branch when you make a release. However, keeping it outside the trunk in a version-tagged directory called something like `third-party/googletest/1.0.1`, is another option. Once the location is established, use `svn propedit svn:externals _directory_` to set the svn:externals property on a directory in your repository. This directory won't contain the code, but be its versioned parent directory.
The command `svn propedit` will bring up your Subversion editor, making editing the long, (potentially multi-line) property simpler. This same method can be used to check out a tagged branch, by using the appropriate URL (e.g. `http://googletest.googlecode.com/svn/tags/release-1.0.1`). Additionally, the svn:externals property allows the specification of a particular revision of the trunk with the `-r_##_` option (e.g. `externals/src/googletest -r60 http://googletest.googlecode.com/svn/trunk`).
Here is an example of using the svn:externals properties on a trunk (read via `svn propget`) of a project. This value checks out a copy of Google Test into the `trunk/externals/src/googletest/` directory.
```
[Computer:svn] user$ svn propget svn:externals trunk
externals/src/googletest http://googletest.googlecode.com/svn/trunk
```
# Add the Framework to Your Project #
The next step is to build and add the gtest.framework to your own project. This guide describes two common ways below.
* **Option 1** --- The simplest way to add Google Test to your own project, is to open gtest.xcodeproj (found in the xcode/ directory of the Google Test trunk) and build the framework manually. Then, add the built framework into your project using the "Add->Existing Framework..." from the context menu or "Project->Add..." from the main menu. The gtest.framework is relocatable and contains the headers and object code that you'll need to make tests. This method requires rebuilding every time you upgrade Google Test in your project.
* **Option 2** --- If you are going to be living off the trunk of Google Test, incorporating its latest features into your unit tests (or are a Google Test developer yourself). You'll want to rebuild the framework every time the source updates. to do this, you'll need to add the gtest.xcodeproj file, not the framework itself, to your own Xcode project. Then, from the build products that are revealed by the project's disclosure triangle, you can find the gtest.framework, which can be added to your targets (discussed below).
# Make a Test Target #
To start writing tests, make a new "Shell Tool" target. This target template is available under BSD, Cocoa, or Carbon. Add your unit test source code to the "Compile Sources" build phase of the target.
Next, you'll want to add gtest.framework in two different ways, depending upon which option you chose above.
* **Option 1** --- During compilation, Xcode will need to know that you are linking against the gtest.framework. Add the gtest.framework to the "Link Binary with Libraries" build phase of your test target. This will include the Google Test headers in your header search path, and will tell the linker where to find the library.
* **Option 2** --- If your working out of the trunk, you'll also want to add gtest.framework to your "Link Binary with Libraries" build phase of your test target. In addition, you'll want to add the gtest.framework as a dependency to your unit test target. This way, Xcode will make sure that gtest.framework is up to date, every time your build your target. Finally, if you don't share build directories with Google Test, you'll have to copy the gtest.framework into your own build products directory using a "Run Script" build phase.
# Set Up the Executable Run Environment #
Since the unit test executable is a shell tool, it doesn't have a bundle with a `Contents/Frameworks` directory, in which to place gtest.framework. Instead, the dynamic linker must be told at runtime to search for the framework in another location. This can be accomplished by setting the "DYLD\_FRAMEWORK\_PATH" environment variable in the "Edit Active Executable ..." Arguments tab, under "Variables to be set in the environment:". The path for this value is the path (relative or absolute) of the directory containing the gtest.framework.
If you haven't set up the DYLD\_FRAMEWORK\_PATH, correctly, you might get a message like this:
```
[Session started at 2008-08-15 06:23:57 -0600.]
dyld: Library not loaded: @loader_path/../Frameworks/gtest.framework/Versions/A/gtest
Referenced from: /Users/username/Documents/Sandbox/gtestSample/build/Debug/WidgetFrameworkTest
Reason: image not found
```
To correct this problem, got to the directory containing the executable named in "Referenced from:" value in the error message above. Then, with the terminal in this location, find the relative path to the directory containing the gtest.framework. That is the value you'll need to set as the DYLD\_FRAMEWORK\_PATH.
# Build and Go #
Now, when you click "Build and Go", the test will be executed. Dumping out something like this:
```
[Session started at 2008-08-06 06:36:13 -0600.]
[==========] Running 2 tests from 1 test case.
[----------] Global test environment set-up.
[----------] 2 tests from WidgetInitializerTest
[ RUN ] WidgetInitializerTest.TestConstructor
[ OK ] WidgetInitializerTest.TestConstructor
[ RUN ] WidgetInitializerTest.TestConversion
[ OK ] WidgetInitializerTest.TestConversion
[----------] Global test environment tear-down
[==========] 2 tests from 1 test case ran.
[ PASSED ] 2 tests.
The Debugger has exited with status 0.
```
# Summary #
Unit testing is a valuable way to ensure your data model stays valid even during rapid development or refactoring. The Google Testing Framework is a great unit testing framework for C and C++ which integrates well with an Xcode development environment.

View File

@@ -0,0 +1,294 @@
// 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_

View File

@@ -0,0 +1,250 @@
// 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

View File

@@ -0,0 +1,510 @@
$$ -*- 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, \
::testing::internal::CodeLocation(\
__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_ATTRIBUTE_UNUSED_; \
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()
// The optional last argument to INSTANTIATE_TEST_CASE_P allows the user
// to specify a function or functor that generates custom test name suffixes
// based on the test parameters. The function should accept one argument of
// type testing::TestParamInfo<class ParamType>, and return std::string.
//
// testing::PrintToStringParamName is a builtin test suffix generator that
// returns the value of testing::PrintToString(GetParam()).
//
// Note: test names must be non-empty, unique, and may only contain ASCII
// alphanumeric characters or underscore. Because PrintToString adds quotes
// to std::string and C strings, it won't work for these types.
# 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; } \
::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \
const ::testing::TestParamInfo<test_case_name::ParamType>& info) { \
return ::testing::internal::GetParamNameGen<test_case_name::ParamType> \
(__VA_ARGS__)(info); \
} \
int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \
::testing::UnitTest::GetInstance()->parameterized_test_registry(). \
GetTestCasePatternHolder<test_case_name>(\
#test_case_name, \
::testing::internal::CodeLocation(\
__FILE__, __LINE__))->AddTestCaseInstantiation(\
#prefix, \
&gtest_##prefix##test_case_name##_EvalGenerator_, \
&gtest_##prefix##test_case_name##_EvalGenerateName_, \
__FILE__, __LINE__)
} // namespace testing
#endif // GTEST_HAS_PARAM_TEST
#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_

View File

@@ -0,0 +1,993 @@
// 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"
#if GTEST_HAS_STD_TUPLE_
# include <tuple>
#endif
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 {
// FormatForComparison<ToPrint, OtherOperand>::Format(value) formats a
// value of type ToPrint that is an operand of a comparison assertion
// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in
// the comparison, and is used to help determine the best way to
// format the value. In particular, when the value is a C string
// (char pointer) and the other operand is an STL string object, we
// want to format the C string as a string, since we know it is
// compared by value with the string object. If the value is a char
// pointer but the other operand is not an STL string object, we don't
// know whether the pointer is supposed to point to a NUL-terminated
// string, and thus want to print it as a pointer to be safe.
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
// The default case.
template <typename ToPrint, typename OtherOperand>
class FormatForComparison {
public:
static ::std::string Format(const ToPrint& value) {
return ::testing::PrintToString(value);
}
};
// Array.
template <typename ToPrint, size_t N, typename OtherOperand>
class FormatForComparison<ToPrint[N], OtherOperand> {
public:
static ::std::string Format(const ToPrint* value) {
return FormatForComparison<const ToPrint*, OtherOperand>::Format(value);
}
};
// By default, print C string as pointers to be safe, as we don't know
// whether they actually point to a NUL-terminated string.
#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \
template <typename OtherOperand> \
class FormatForComparison<CharType*, OtherOperand> { \
public: \
static ::std::string Format(CharType* value) { \
return ::testing::PrintToString(static_cast<const void*>(value)); \
} \
}
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char);
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char);
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t);
GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t);
#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_
// If a C string is compared with an STL string object, we know it's meant
// to point to a NUL-terminated string, and thus can print it as a string.
#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \
template <> \
class FormatForComparison<CharType*, OtherStringType> { \
public: \
static ::std::string Format(CharType* value) { \
return ::testing::PrintToString(value); \
} \
}
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string);
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string);
#if GTEST_HAS_GLOBAL_STRING
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string);
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string);
#endif
#if GTEST_HAS_GLOBAL_WSTRING
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring);
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring);
#endif
#if GTEST_HAS_STD_WSTRING
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring);
GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring);
#endif
#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_
// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc)
// operand to be used in a failure message. The type (but not value)
// of the other operand may affect the format. This allows us to
// print a char* as a raw pointer when it is compared against another
// char* or void*, and print it as a C string when it is compared
// against an std::string object, for example.
//
// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.
template <typename T1, typename T2>
std::string FormatForComparisonFailureMessage(
const T1& value, const T2& /* other_operand */) {
return FormatForComparison<T1, T2>::Format(value);
}
// 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 || GTEST_HAS_STD_TUPLE_
// 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);
#endif // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_
#if GTEST_HAS_TR1_TUPLE
// Overload for ::std::tr1::tuple. Needed for printing function arguments,
// which are packed as tuples.
// 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
#if GTEST_HAS_STD_TUPLE_
template <typename... Types>
void PrintTo(const ::std::tuple<Types...>& t, ::std::ostream* os) {
PrintTupleTo(t, os);
}
#endif // GTEST_HAS_STD_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.
GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180)
// 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);
}
GTEST_DISABLE_MSC_WARNINGS_POP_()
};
// 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.
GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180)
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);
}
GTEST_DISABLE_MSC_WARNINGS_POP_()
};
// 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);
}
typedef ::std::vector<string> Strings;
// TuplePolicy<TupleT> must provide:
// - tuple_size
// size of tuple TupleT.
// - get<size_t I>(const TupleT& t)
// static function extracting element I of tuple TupleT.
// - tuple_element<size_t I>::type
// type of element I of tuple TupleT.
template <typename TupleT>
struct TuplePolicy;
#if GTEST_HAS_TR1_TUPLE
template <typename TupleT>
struct TuplePolicy {
typedef TupleT Tuple;
static const size_t tuple_size = ::std::tr1::tuple_size<Tuple>::value;
template <size_t I>
struct tuple_element : ::std::tr1::tuple_element<I, Tuple> {};
template <size_t I>
static typename AddReference<
const typename ::std::tr1::tuple_element<I, Tuple>::type>::type get(
const Tuple& tuple) {
return ::std::tr1::get<I>(tuple);
}
};
template <typename TupleT>
const size_t TuplePolicy<TupleT>::tuple_size;
#endif // GTEST_HAS_TR1_TUPLE
#if GTEST_HAS_STD_TUPLE_
template <typename... Types>
struct TuplePolicy< ::std::tuple<Types...> > {
typedef ::std::tuple<Types...> Tuple;
static const size_t tuple_size = ::std::tuple_size<Tuple>::value;
template <size_t I>
struct tuple_element : ::std::tuple_element<I, Tuple> {};
template <size_t I>
static const typename ::std::tuple_element<I, Tuple>::type& get(
const Tuple& tuple) {
return ::std::get<I>(tuple);
}
};
template <typename... Types>
const size_t TuplePolicy< ::std::tuple<Types...> >::tuple_size;
#endif // GTEST_HAS_STD_TUPLE_
#if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_
// 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);
GTEST_INTENTIONAL_CONST_COND_PUSH_()
if (N > 1) {
GTEST_INTENTIONAL_CONST_COND_POP_()
*os << ", ";
}
UniversalPrinter<
typename TuplePolicy<Tuple>::template tuple_element<N - 1>::type>
::Print(TuplePolicy<Tuple>::template 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(TuplePolicy<Tuple>::template get<N - 1>(t), &ss);
strings->push_back(ss.str());
}
};
// Base case.
template <>
struct TuplePrefixPrinter<0> {
template <typename Tuple>
static void PrintPrefixTo(const Tuple&, ::std::ostream*) {}
template <typename Tuple>
static void TersePrintPrefixToStrings(const Tuple&, Strings*) {}
};
// Helper function for printing a tuple.
// Tuple must be either std::tr1::tuple or std::tuple type.
template <typename Tuple>
void PrintTupleTo(const Tuple& t, ::std::ostream* os) {
*os << "(";
TuplePrefixPrinter<TuplePolicy<Tuple>::tuple_size>::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<TuplePolicy<Tuple>::tuple_size>::
TersePrintPrefixToStrings(value, &result);
return result;
}
#endif // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_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
// Include any custom printer added by the local installation.
// We must include this header at the end to make sure it can use the
// declarations from this file.
#include "gtest/internal/custom/gtest-printers.h"
#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_

View File

@@ -0,0 +1,232 @@
// 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(\
&gtest_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
{\
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
::testing::ScopedFakeTestPartResultReporter:: \
INTERCEPT_ONLY_CURRENT_THREAD, &gtest_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(\
&gtest_failures, ::testing::TestPartResult::kFatalFailure, (substr));\
{\
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
::testing::ScopedFakeTestPartResultReporter:: \
INTERCEPT_ALL_THREADS, &gtest_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(\
&gtest_failures, ::testing::TestPartResult::kNonFatalFailure, \
(substr));\
{\
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
::testing::ScopedFakeTestPartResultReporter:: \
INTERCEPT_ONLY_CURRENT_THREAD, &gtest_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(\
&gtest_failures, ::testing::TestPartResult::kNonFatalFailure, \
(substr));\
{\
::testing::ScopedFakeTestPartResultReporter gtest_reporter(\
::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \
&gtest_failures);\
if (::testing::internal::AlwaysTrue()) { statement; }\
}\
} while (::testing::internal::AlwaysFalse())
#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_

View File

@@ -0,0 +1,179 @@
// 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_

View File

@@ -0,0 +1,263 @@
// 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(\
"", ::testing::internal::CodeLocation(__FILE__, __LINE__), \
#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, \
::testing::internal::CodeLocation(__FILE__, __LINE__), \
&GTEST_TYPED_TEST_CASE_P_STATE_(CaseName), \
#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

View File

@@ -0,0 +1,358 @@
// 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_

View File

@@ -0,0 +1,58 @@
// 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_

View File

@@ -0,0 +1,69 @@
// Copyright 2015, 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.
//
// Injection point for custom user configurations.
// The following macros can be defined:
//
// Flag related macros:
// GTEST_FLAG(flag_name)
// GTEST_USE_OWN_FLAGFILE_FLAG_ - Define to 0 when the system provides its
// own flagfile flag parsing.
// GTEST_DECLARE_bool_(name)
// GTEST_DECLARE_int32_(name)
// GTEST_DECLARE_string_(name)
// GTEST_DEFINE_bool_(name, default_val, doc)
// GTEST_DEFINE_int32_(name, default_val, doc)
// GTEST_DEFINE_string_(name, default_val, doc)
//
// Test filtering:
// GTEST_TEST_FILTER_ENV_VAR_ - The name of an environment variable that
// will be used if --GTEST_FLAG(test_filter)
// is not provided.
//
// Logging:
// GTEST_LOG_(severity)
// GTEST_CHECK_(condition)
// Functions LogToStderr() and FlushInfoLog() have to be provided too.
//
// Threading:
// GTEST_HAS_NOTIFICATION_ - Enabled if Notification is already provided.
// GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ - Enabled if Mutex and ThreadLocal are
// already provided.
// Must also provide GTEST_DECLARE_STATIC_MUTEX_(mutex) and
// GTEST_DEFINE_STATIC_MUTEX_(mutex)
//
// GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks)
// GTEST_LOCK_EXCLUDED_(locks)
//
// ** Custom implementation starts here **
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_
#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_

View File

@@ -0,0 +1,42 @@
// Copyright 2015, 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 provides an injection point for custom printers in a local
// installation of gTest.
// It will be included from gtest-printers.h and the overrides in this file
// will be visible to everyone.
// See documentation at gtest/gtest-printers.h for details on how to define a
// custom printer.
//
// ** Custom implementation starts here **
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_
#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_

View File

@@ -0,0 +1,41 @@
// Copyright 2015, 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.
//
// Injection point for custom user configurations.
// The following macros can be defined:
//
// GTEST_OS_STACK_TRACE_GETTER_ - The name of an implementation of
// OsStackTraceGetterInterface.
//
// ** Custom implementation starts here **
#ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_
#define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_
#endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_

View File

@@ -0,0 +1,319 @@
// 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, &gtest_regex, \
__FILE__, __LINE__, &gtest_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_

View File

@@ -0,0 +1,206 @@
// 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

View File

@@ -0,0 +1,243 @@
// 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) {
assert(p->next_ != this &&
"Trying to join() a linked ring we are already in. "
"Is GMock thread safety enabled?");
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) {
assert(p->next_ != next_ &&
"Trying to depart() a linked ring we are not in. "
"Is GMock thread safety enabled?");
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

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