/*****************************************************************************
 * $LastChangedDate: 2011-04-23 21:07:07 -0400 (Sat, 23 Apr 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Support for checking type signatures.
 * @remarks Documented at typesig_doc.hh.
 *//*
 * LEGAL:   COPYRIGHT (C) 2004 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 *****************************************************************************/

#ifndef DOXYGEN  // doxygen can't parse this correctly
#ifndef BASE_TYPESIG_HH
#define BASE_TYPESIG_HH 1

namespace base {

/// COMPILE_TYPESIGS controls compiling type signatures.
#ifndef COMPILE_TYPESIGS
#   if DEBUG
#       define COMPILE_TYPESIGS 1
#   else
#       define COMPILE_TYPESIGS 0
#   endif
#endif

/// Macro to declare a type signature as a member in a class/struct.
/// GetTypesig() is for compatibility with objects encapsulated inside shptr/SafePtrs
/// without having to use their PTR().
/// GetTypesig##TYPESIG() expands unambiguous name
/// in case a derivative has its own different typesig value.
#if COMPILE_TYPESIGS
#define DECLARE_TYPESIG( TYPESIG ) typesig_t typesig##TYPESIG; typesig_t GetTypesig##TYPESIG( void ) const { return typesig##TYPESIG; }
#else
#define DECLARE_TYPESIG( TYPESIG )
#endif

/// Macro to declare a type signature member and expand
/// a constructor/destructor to automatically set it.
/// Recommended for structs but isn't appropriate in most classes.
#define DECLARE_TYPESIG_AUTO( CLASS, TYPESIG )        \
    CLASS()  {        SET_TYPESIG( this, TYPESIG ); } \
    ~CLASS() { INVALIDATE_TYPESIG( this, TYPESIG ); } \
    DECLARE_TYPESIG( TYPESIG )

/// Macro to assign a type signature member.
/// Ensure typesig value isn't greater than what typesig member can hold.
#if COMPILE_TYPESIGS
#define SET_TYPESIG( OBJ, TYPESIG ) (OBJ)->typesig##TYPESIG = TYPESIG;
#else
#define SET_TYPESIG( OBJ, TYPESIG )
#endif

/// Macro to check a type signature -- WILL FAIL IF PASSED A NULL POINTER!!
#if COMPILE_TYPESIGS
#define CHECK_TYPESIG( OBJ, TYPESIG ) ASSERT( (OBJ)->GetTypesig##TYPESIG() == TYPESIG )
#else
#define CHECK_TYPESIG( OBJ, TYPESIG )
#endif

/// Macro to check a type signature -- will accept NULL pointer (ok)
#if COMPILE_TYPESIGS
#define CHECK_TYPESIG_NULL_OK( OBJ, TYPESIG ) ASSERT( ((OBJ) == NULL) or ((OBJ)->GetTypesig##TYPESIG() == TYPESIG) )
#else
#define CHECK_TYPESIG_NULL_OK( OBJ, TYPESIG )
#endif

/// Macro to invalidate a type signature member.
/// First check if it was valid in the first place
#if COMPILE_TYPESIGS
#define INVALIDATE_TYPESIG( OBJ, TYPESIG ) ( CHECK_TYPESIG((OBJ),TYPESIG), ((OBJ)->typesig##TYPESIG = TYPESIG_INVALID) )
#else
#define INVALIDATE_TYPESIG( OBJ, TYPESIG )
#endif

/// Macro to return true if a type signature is correct (doesn't assert).
#if COMPILE_TYPESIGS
#define TYPESIG_OK( OBJ, TYPESIG ) ( ((OBJ) != NULL) and ((OBJ)->GetTypesig##TYPESIG() == TYPESIG) )
#else
#define TYPESIG_OK( OBJ, TYPESIG ) (true)
#endif

} // namespace base

#endif // BASE_TYPESIG_HH
#endif // DOXYGEN
