// Copyright (c) 2012, Evgeny Panasyuk

// 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.

// e-mail: E?????[dot]P???????[at]gmail.???

namespace stack_unwinding
{

#if defined(_MSC_VER)
namespace details {extern "C" char * _getptd(); }
inline unsigned uncaught_exception_count()
{
    // MSVC specific. Tested on {MSVC2005SP1,MSVC2008SP1,MSVC2010SP1,MSVC2012}x{x32,x64}.
    return *(static_cast<unsigned*>(static_cast<void*>( details::_getptd() + (sizeof(void*)==8 ? 0x100 : 0x90) ))); // x32 offset - 0x90 , x64 - 0x100
}
#elif defined(__GNUG__) || defined(__CLANG__)
namespace details { extern "C" char * __cxa_get_globals(); }
inline unsigned uncaught_exception_count()
{
    // Tested on {clang 3.2,GCC 3.5.6,,GCC 4.1.2,GCC 4.4.6,GCC 4.4.7}x{x32,x64}
    return *(static_cast<unsigned*>(static_cast<void*>( details::__cxa_get_globals() + (sizeof(void*)==8 ? 0x8 : 0x4) ))); // x32 offset - 0x4 , x64 - 0x8
}
#endif
}

#include <iostream>
#include <ostream>
#include <string>
#include <vector>
#include <numeric>
#include <algorithm>
#include <functional>

using namespace std;

vector<unsigned> exception_counts;
const unsigned test_count=500;

struct ExpCountSaver
{
    ~ExpCountSaver()
    {
        exception_counts.push_back(stack_unwinding::uncaught_exception_count());
    }
};


template<int n>
struct ExptSwallower
{
    ~ExptSwallower()
    {
        try
        {
            ExpCountSaver p;
            ExptSwallower<n-1> a;
            throw 1;
            (void)p;(void)a;
        }catch(int){}
    }
};
template<>
struct ExptSwallower<0>
{
    ~ExptSwallower() {}
};
int main(int,char *[])
{
    exception_counts.reserve(test_count);
    try
    {
        ExptSwallower<test_count>();
    } catch(int) {}
    if(exception_counts.size()!=test_count)
        return 1;
    adjacent_difference(exception_counts.rbegin(),exception_counts.rend(),exception_counts.rbegin());
    if
    (
        find_if(exception_counts.begin(),exception_counts.end(), bind2nd(not_equal_to<unsigned>(),1) )
            !=
        exception_counts.end()
    )
        return 2;
    return 0;
}
