Home
aliakseis' Journal
 
[Most Recent Entries] [Calendar View] [Friends]

Below are the 20 most recent journal entries recorded in aliakseis' LiveJournal:

    Saturday, August 22nd, 2009
    1:28 pm
    Opus #11
    #define WIN32_LEAN_AND_MEAN     // Exclude rarely-used stuff from Windows headers
    
    #ifndef _WIN32_WINNT
    #define _WIN32_WINNT 0x0400
    #endif
    
    #include <windows.h>
    #include <Dbghelp.h>
    #include <tchar.h>
    #include <string> 
    #include <vector>
    
    #pragma comment(lib, "Dbghelp.lib")
    
    #include <shlwapi.h>
    #pragma comment(lib, "shlwapi.lib")
    
    #include <Tlhelp32.h>
    
    using std::string;
    using std::vector;
    
    
    ///////////////////////////////////////////////////////////////////////////////
    //
    // bool GetPdbFileName(LPCTSTR FileName, LPTSTR DebugDir)
    // Adaptation of DebugDir example source code by Oleg Starodumov (www.debuginfo.com)
    //
    //
    
    
    ///////////////////////////////////////////////////////////////////////////////
    // Include files 
    //
    
    #include <crtdbg.h>
    
    ///////////////////////////////////////////////////////////////////////////////
    // Helper macros 
    //
    
        // Thanks to Matt Pietrek 
    #define MakePtr( cast, ptr, addValue ) (cast)( (DWORD_PTR)(ptr) + (DWORD_PTR)(addValue))
    
    
    ///////////////////////////////////////////////////////////////////////////////
    // CodeView debug information structures 
    //
    
    #define CV_SIGNATURE_NB10   '01BN'
    #define CV_SIGNATURE_RSDS   'SDSR'
    
    // CodeView header 
    struct CV_HEADER 
    {
        DWORD CvSignature; // NBxx
        LONG  Offset;      // Always 0 for NB10
    };
    
    // CodeView NB10 debug information 
    // (used when debug information is stored in a PDB 2.00 file) 
    struct CV_INFO_PDB20 
    {
        CV_HEADER  Header; 
        DWORD      Signature;       // seconds since 01.01.1970
        DWORD      Age;             // an always-incrementing value 
        BYTE       PdbFileName[1];  // zero terminated string with the name of the PDB file 
    };
    
    // CodeView RSDS debug information 
    // (used when debug information is stored in a PDB 7.00 file) 
    struct CV_INFO_PDB70 
    {
        DWORD      CvSignature; 
        GUID       Signature;       // unique identifier 
        DWORD      Age;             // an always-incrementing value 
        BYTE       PdbFileName[1];  // zero terminated string with the name of the PDB file 
    };
    
    
    ///////////////////////////////////////////////////////////////////////////////
    // Functions 
    //
    
    
    // 
    // Check whether the specified IMAGE_OPTIONAL_HEADER belongs to 
    // a PE32 or PE32+ file format 
    // 
    // Return value: "true" if succeeded (bPE32Plus contains "true" if the file 
    //  format is PE32+, and "false" if the file format is PE32), 
    //  "false" if failed 
    // 
    bool IsPE32Plus( PIMAGE_OPTIONAL_HEADER pOptionalHeader, bool& bPE32Plus ) 
    {
        // Note: The function does not check the header for validity. 
        // It assumes that the caller has performed all the necessary checks. 
    
        // IMAGE_OPTIONAL_HEADER.Magic field contains the value that allows 
        // to distinguish between PE32 and PE32+ formats 
    
        if( pOptionalHeader->Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC ) 
        {
            // PE32 
            bPE32Plus = false; 
        }
        else if( pOptionalHeader->Magic == IMAGE_NT_OPTIONAL_HDR64_MAGIC ) 
        {
            // PE32+
            bPE32Plus = true; 
        }
        else 
        {
            // Unknown value -> Report an error 
            bPE32Plus = false; 
            return false; 
        }
    
        return true; 
    }
    
    // 
    // Returns (in [out] parameters) the RVA and size of the debug directory, 
    // using the information in IMAGE_OPTIONAL_HEADER.DebugDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]
    // 
    // Return value: "true" if succeeded, "false" if failed
    // 
    bool GetDebugDirectoryRVA( PIMAGE_OPTIONAL_HEADER pOptionalHeader, DWORD& DebugDirRva, DWORD& DebugDirSize ) 
    {
        // Check parameters 
    
        if( pOptionalHeader == 0 ) 
        {
            _ASSERT( 0 ); 
            return false; 
        }
    
    
        // Determine the format of the PE executable 
    
        bool bPE32Plus = false; 
    
        if( !IsPE32Plus( pOptionalHeader, bPE32Plus ) ) 
        {
            // Probably invalid IMAGE_OPTIONAL_HEADER.Magic
            return false; 
        }
    
        // Obtain the debug directory RVA and size 
    
        if( bPE32Plus ) 
        {
            PIMAGE_OPTIONAL_HEADER64 pOptionalHeader64 = (PIMAGE_OPTIONAL_HEADER64)pOptionalHeader; 
            DebugDirRva = pOptionalHeader64->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; 
            DebugDirSize = pOptionalHeader64->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size; 
        }
        else 
        {
            PIMAGE_OPTIONAL_HEADER32 pOptionalHeader32 = (PIMAGE_OPTIONAL_HEADER32)pOptionalHeader; 
            DebugDirRva = pOptionalHeader32->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; 
            DebugDirSize = pOptionalHeader32->DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].Size; 
        }
    
        if( ( DebugDirRva == 0 ) && ( DebugDirSize == 0 ) ) 
        {
            // No debug directory in the executable -> no debug information 
            return true; 
        }
        else if( ( DebugDirRva == 0 ) || ( DebugDirSize == 0 ) )
        {
            // Inconsistent data in the data directory 
            return false; 
        }
    
        return true; 
    }
    
    // 
    // The function walks through the section headers, finds out the section 
    // the given RVA belongs to, and uses the section header to determine 
    // the file offset that corresponds to the given RVA 
    // 
    // Return value: "true" if succeeded, "false" if failed 
    // 
    bool GetFileOffsetFromRVA( PIMAGE_NT_HEADERS pNtHeaders, DWORD Rva, DWORD& FileOffset ) 
    {
        // Check parameters 
    
        if( pNtHeaders == 0 ) 
        {
            _ASSERT( 0 ); 
            return false; 
        }
    
    
        // Look up the section the RVA belongs to 
    
        bool bFound = false; 
    
        PIMAGE_SECTION_HEADER pSectionHeader = IMAGE_FIRST_SECTION( pNtHeaders ); 
    
        for( int i = 0; i < pNtHeaders->FileHeader.NumberOfSections; i++, pSectionHeader++ ) 
        {
            DWORD SectionSize = pSectionHeader->Misc.VirtualSize; 
    
            if( SectionSize == 0 ) // compensate for Watcom linker strangeness, according to Matt Pietrek 
                pSectionHeader->SizeOfRawData; 
    
            if( ( Rva >= pSectionHeader->VirtualAddress ) && 
                ( Rva < pSectionHeader->VirtualAddress + SectionSize ) ) 
            {
                // Yes, the RVA belongs to this section 
                bFound = true; 
                break; 
            }
        }
    
        if( !bFound ) 
        {
            // Section not found 
            return false; 
        }
    
    
        // Look up the file offset using the section header 
    
        INT Diff = (INT)( pSectionHeader->VirtualAddress - pSectionHeader->PointerToRawData ); 
    
        FileOffset = Rva - Diff; 
    
        return true; 
    }
    
    // 
    // Display information about CodeView debug information block 
    // 
    bool DumpCodeViewDebugInfo( LPBYTE pDebugInfo, DWORD DebugInfoSize, LPTSTR DebugDir ) 
    {
        // Check parameters 
    
        if( ( pDebugInfo == 0 ) || ( DebugInfoSize == 0 ) ) 
            return false;
    
        if( IsBadReadPtr( pDebugInfo, DebugInfoSize ) ) 
            return false;
    
        if( DebugInfoSize < sizeof(DWORD) ) // size of the signature 
            return false;
    
    
        // Determine the format of the information and display it accordingly 
    
        DWORD CvSignature = *(DWORD*)pDebugInfo; 
    
        if( CvSignature == CV_SIGNATURE_NB10 ) 
        {
            // NB10 -> PDB 2.00 
    
            CV_INFO_PDB20* pCvInfo = (CV_INFO_PDB20*)pDebugInfo; 
    
            if( IsBadReadPtr( pDebugInfo, sizeof(CV_INFO_PDB20) ) ) 
                return false;
            
            if( IsBadStringPtrA( (CHAR*)pCvInfo->PdbFileName, UINT_MAX ) ) 
                return false;
    
            strcpy(DebugDir, (const char*)pCvInfo->PdbFileName);
            return true;
        }
        else if( CvSignature == CV_SIGNATURE_RSDS ) 
        {
            // RSDS -> PDB 7.00 
    
            CV_INFO_PDB70* pCvInfo = (CV_INFO_PDB70*)pDebugInfo; 
    
            if( IsBadReadPtr( pDebugInfo, sizeof(CV_INFO_PDB70) ) ) 
                return false;
            
            if( IsBadStringPtrA( (CHAR*)pCvInfo->PdbFileName, UINT_MAX ) ) 
                return false; 
    
            strcpy(DebugDir, (const char*)pCvInfo->PdbFileName);
            return true;
        }
    
        return false;
    }
    
    // 
    // Display information about debug directory entry 
    // 
    bool DumpDebugDirectoryEntry( LPBYTE pImageBase, PIMAGE_DEBUG_DIRECTORY pDebugDir, LPTSTR DebugDir  ) 
    {
        // Check parameters 
    
        if( pDebugDir == 0 ) 
        {
            _ASSERT( 0 ); 
            return false; 
        }
    
        if( pImageBase == 0 ) 
        {
            _ASSERT( 0 ); 
            return false; 
        }
    
    
        // Display additional information for some interesting debug information types 
    
        LPBYTE pDebugInfo = pImageBase + pDebugDir->PointerToRawData; 
    
        if( pDebugDir->Type == IMAGE_DEBUG_TYPE_CODEVIEW ) 
        {
            return DumpCodeViewDebugInfo( pDebugInfo, pDebugDir->SizeOfData, DebugDir ); 
        }
        return false;
    }
    
    // 
    // Walk through each entry in the debug directory and display information about it 
    // 
    bool DumpDebugDirectoryEntries( LPBYTE pImageBase, PIMAGE_DEBUG_DIRECTORY pDebugDir, DWORD DebugDirSize, LPTSTR DebugDir ) 
    {
        // Check parameters 
    
        if( pImageBase == 0 ) 
        {
            _ASSERT( 0 ); 
            return false; 
        }
    
    
        // Determine the number of entries in the debug directory 
    
        int NumEntries = DebugDirSize / sizeof(IMAGE_DEBUG_DIRECTORY); 
    
        if( NumEntries == 0 ) 
        {
            _ASSERT( 0 ); 
            return false; 
        }
    
        // Display information about every entry 
    
        for( int i = 1; i <= NumEntries; i++, pDebugDir++ ) 
        {
            if (DumpDebugDirectoryEntry( pImageBase, pDebugDir, DebugDir ))
                return true;
        }
    
        return false;
    }
    
    
    ///////////////////////////////////////////////////////////////////////////////
    // main 
    //
    
    bool GetPdbFileName(LPCTSTR FileName, LPTSTR DebugDir)
    {
        // Process the command line and obtain the file name 
    
        if( FileName == 0 ) 
            return 0; 
    
        // Process the file 
    
        HANDLE hFile      = NULL; 
        HANDLE hFileMap   = NULL; 
        LPVOID lpFileMem  = 0; 
    
        bool bOK = false;
    
        do 
        {
            // Open the file and map it into memory 
    
            hFile = CreateFile( FileName, GENERIC_READ, FILE_SHARE_READ, NULL, 
                                OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); 
    
            if( ( hFile == INVALID_HANDLE_VALUE ) || ( hFile == NULL ) ) 
            {
                break; 
            }
    
            hFileMap = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0, 0, NULL ); 
    
            if( hFileMap == NULL ) 
            {
                break; 
            }
        
            lpFileMem = MapViewOfFile( hFileMap, FILE_MAP_READ, 0, 0, 0 ); 
    
            if( lpFileMem == 0 ) 
            {
                break; 
            }
    
    
            PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)lpFileMem; 
            PIMAGE_NT_HEADERS pNtHeaders = MakePtr( PIMAGE_NT_HEADERS, pDosHeader, pDosHeader->e_lfanew );
    
            // Look up the debug directory 
    
            DWORD DebugDirRva   = 0; 
            DWORD DebugDirSize  = 0; 
    
            if( !GetDebugDirectoryRVA( &pNtHeaders->OptionalHeader, DebugDirRva, DebugDirSize ) ) 
            {
                break; 
            }
    
            if( ( DebugDirRva == 0 ) || ( DebugDirSize == 0 ) ) 
            {
                break; 
            }
    
            DWORD DebugDirOffset = 0; 
    
            if( !GetFileOffsetFromRVA( pNtHeaders, DebugDirRva, DebugDirOffset ) ) 
            {
                break; 
            }
    
            PIMAGE_DEBUG_DIRECTORY pDebugDir = MakePtr( PIMAGE_DEBUG_DIRECTORY, lpFileMem, DebugDirOffset ); 
    
            // Display information about every entry in the debug directory 
    
            if (!DumpDebugDirectoryEntries( (LPBYTE)lpFileMem, pDebugDir, DebugDirSize, DebugDir ))
                break; 
    
            bOK = true;
        }
        while (false); 
    
    
        // Cleanup 
    
        if( lpFileMem != 0 ) 
        {
            if( !UnmapViewOfFile( lpFileMem ) ) 
            {
                _ASSERT( 0 ); 
            }
        }
    
        if( hFileMap != NULL ) 
        {
            if( !CloseHandle( hFileMap ) ) 
            {
                _ASSERT( 0 ); 
            }
        }
    
        if( ( hFile != NULL ) && ( hFile != INVALID_HANDLE_VALUE ) ) 
        {
            if( !CloseHandle( hFile ) ) 
            {
                _ASSERT( 0 ); 
            }
        }
    
        // Complete 
    
        return bOK; 
    }
    
    
    ///////////////////////////////////////////////////////////////////////////////
    
    
    enum { MAXNAMELENGTH = 1024 }; // max name length for found symbols
    
    
    struct ModuleEntry
    {
        string imageName;
        string moduleName;
        DWORD baseAddress;
        DWORD size;
    };
    typedef vector<ModuleEntry> ModuleList;
    
    
    bool GetModuleList(ModuleList& modules, DWORD pid)
    {
        HANDLE hSnap = CreateToolhelp32Snapshot( TH32CS_SNAPMODULE, pid );
        if (hSnap == (HANDLE) -1)
            return false;
        
        MODULEENTRY32 me;
        me.dwSize = sizeof(me);
    
        for (BOOL ok = Module32First(hSnap, &me)
            ; ok
            ; ok = Module32Next(hSnap, &me))
        {
            ModuleEntry e;
            e.imageName = me.szExePath;
            e.moduleName = me.szModule;
            e.baseAddress = (DWORD) me.modBaseAddr;
            e.size = me.modBaseSize;
            modules.push_back(e);
        }
        
        CloseHandle(hSnap);
        
        return !modules.empty();
    }
    
    
    std::string GetModuleDebugSearchPath(HMODULE hModule)
    {
        const int BUF_SIZE = 10000;
        CHAR tt[BUF_SIZE] = "";
        string semicolon(";");
    
        // build symbol search path from:
        string symSearchPath = "";
        // current directory
        if ( GetCurrentDirectoryA( BUF_SIZE, tt ) )
          symSearchPath += tt + semicolon;
        // dir with executable
        if ( GetModuleFileNameA( 0, tt, BUF_SIZE ) )
        {
            PathRemoveFileSpec(tt);
            symSearchPath += tt + semicolon;
        }
    
        if ( GetEnvironmentVariableA( "_NT_SYMBOL_PATH", tt, BUF_SIZE ) )
          symSearchPath += tt + semicolon;
        if ( GetEnvironmentVariableA( "_NT_ALTERNATE_SYMBOL_PATH", tt, BUF_SIZE ) )
          symSearchPath += tt + semicolon;
        if ( GetEnvironmentVariableA( "SYSTEMROOT", tt, BUF_SIZE ) )
          symSearchPath += tt + semicolon;
    
        if (hModule != NULL 
            && GetModuleFileNameA(hModule, tt, BUF_SIZE)
            && GetPdbFileName(tt, tt))
        {
            PathRemoveFileSpec(tt);
            symSearchPath += tt + semicolon;
        }
    
        if ( symSearchPath.size() > 0 ) // if we added anything, we have a trailing semicolon
          symSearchPath = symSearchPath.substr( 0, symSearchPath.size() - 1 );
    
        return symSearchPath;
    }
    
    
    void EnumAndLoadModuleSymbols(HANDLE hProcess, DWORD pid)
    {
      ModuleList modules;
    
      // fill in module list
      GetModuleList(modules, pid);
    
      for (ModuleList::iterator it(modules.begin()); it != modules.end(); ++it)
      {
        string sPath = GetModuleDebugSearchPath((HMODULE)it->baseAddress);
        SymSetSearchPath(hProcess, const_cast<char*>(sPath.c_str()));
    
        SymLoadModule64( hProcess, 0, 
            const_cast<char*>(it->imageName.c_str()), const_cast<char*>(it->moduleName.c_str()), 
            it->baseAddress, it->size );
      }
    }
    
    
    HMODULE ModuleFromAddress(LPCVOID pv)
    {
        MEMORY_BASIC_INFORMATION mbi;
        return (VirtualQuery(pv, &mbi, sizeof(mbi)) != 0) ? (HMODULE) mbi.AllocationBase : NULL;
    }
    
    
    template <typename T>
    void DoStackTrace( HANDLE hThread, 
                     CONTEXT& c, 
                     const T fLogFile, 
                     HANDLE hSWProcess) 
    {
      HANDLE hProcess = GetCurrentProcess();
      
      struct 
      {
        IMAGEHLP_SYMBOL64 sym;
        char name[MAXNAMELENGTH];
      }
      symBuffer = {0};
    
      IMAGEHLP_SYMBOL64* const pSym = &symBuffer.sym;
      IMAGEHLP_MODULE64 Module;
      IMAGEHLP_LINE64 Line;
    
      static bool bInitialized = false;
    
      if (!bInitialized) 
      {
        HMODULE hModule = ModuleFromAddress(&ModuleFromAddress);
        string symSearchPath = GetModuleDebugSearchPath(hModule);
    
        if (!SymInitialize(hProcess, const_cast<char*>(symSearchPath.c_str()), false))
        {
          _ftprintf(fLogFile, _T("SymInitialize(): GetLastError = %lu\n"), GetLastError());
          return;
        }
    
        DWORD symOptions = SymGetOptions();
        symOptions |= SYMOPT_LOAD_LINES;
        symOptions &= ~(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS);
        SymSetOptions( symOptions ); 
    
        bInitialized = true;
      }
    
      EnumAndLoadModuleSymbols(hProcess, GetCurrentProcessId());
    
      STACKFRAME64 s = {0}; 
      // init STACKFRAME for first call
      s.AddrPC.Offset = c.Eip;
      s.AddrPC.Mode = AddrModeFlat;
      s.AddrFrame.Offset = c.Ebp;
      s.AddrFrame.Mode = AddrModeFlat;
      s.AddrStack.Offset = c.Ebp;
      s.AddrStack.Mode = AddrModeFlat;
    
      pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
      pSym->MaxNameLength = MAXNAMELENGTH;
    
      memset( &Line, '\0', sizeof Line );
      Line.SizeOfStruct = sizeof Line;
    
      memset( &Module, '\0', sizeof Module );
      Module.SizeOfStruct = sizeof Module;
    
      do
      {
        // CONTEXT not needed if imageType is IMAGE_FILE_MACHINE_I386
        if (!StackWalk64(IMAGE_FILE_MACHINE_I386, hSWProcess, hThread, &s, NULL, NULL, &SymFunctionTableAccess64, &SymGetModuleBase64, NULL))
        {
            break;
        }
    
        HMODULE hModule = ModuleFromAddress((LPCVOID)s.AddrPC.Offset);
        char szModuleName[MAX_PATH] = "";
        GetModuleFileName(hModule, szModuleName, MAX_PATH);
    
        if (s.AddrPC.Offset != 0)
        {
            char undecoratedName[MAXNAMELENGTH] = "";
            DWORD64 offsetFromSymbol = 0;
            BOOL hasSymbols = SymGetSymFromAddr64(hProcess, s.AddrPC.Offset, &offsetFromSymbol, pSym);
            if (hasSymbols)
                UnDecorateSymbolName(pSym->Name, undecoratedName, MAXNAMELENGTH, UNDNAME_NAME_ONLY);
    
            DWORD offsetFromLine = 0;
            if ( ! SymGetLineFromAddr64( hProcess, s.AddrPC.Offset, &offsetFromLine, &Line ) )
            {
                if (hasSymbols)
                    _ftprintf(fLogFile, "%s: %s (+%d bytes)\n", szModuleName, undecoratedName, (long) offsetFromSymbol);
                else
                    _ftprintf(fLogFile, "%s: (0x%08X + 0x%X bytes)\n", szModuleName, (DWORD)hModule, ((DWORD)s.AddrPC.Offset) - (DWORD)hModule);
            }
            else
            {
                _ftprintf(fLogFile, "%s(%lu): %+ld bytes (%s)\n",
                        Line.FileName, Line.LineNumber, offsetFromLine, undecoratedName);
            }
        }
      } 
      while (s.AddrReturn.Offset != 0);
    }
    
    
    struct CriticalSection : public CRITICAL_SECTION
    {
        CriticalSection() 
        {
            InitializeCriticalSection(this);
        };
        ~CriticalSection() 
        {
            DeleteCriticalSection(this);
        };
    };
    
    
    static CriticalSection g_csStackTrace;
    
    template <typename T>
    void StackTrace( HANDLE hThread, 
                     CONTEXT& c, 
                     const T fLogFile, 
                     HANDLE hSWProcess) 
    
    {
        EnterCriticalSection(&g_csStackTrace);
        DoStackTrace(hThread, 
                     c, 
                     fLogFile, 
                     hSWProcess) ;
    
        LeaveCriticalSection(&g_csStackTrace);
    }
    
    // OutputDebugExceptionStackTrace() implementation
    
    void _ftprintf(void (__stdcall * const OutputDebugStringFunc)(LPCTSTR), const TCHAR *format, ...)
    {
        enum { BUFFER_SIZE = 4000 };
        TCHAR buffer[BUFFER_SIZE];
    
        va_list vl;
        va_start(vl, format);
    
        _vsntprintf(buffer, BUFFER_SIZE - 1, format, vl);
        buffer[BUFFER_SIZE - 1] = 0;
    
        va_end(vl);
        OutputDebugStringFunc(buffer);
    }
    
    
    // See http://www.ddj.com/windows/184416600
    
    #ifdef _MT
    
    extern "C"
    {
        // merged from VC 6, .NET and 2005 internal headers in CRT source code
        struct _tiddata 
        {
            unsigned long   _tid;       /* thread ID */
    
    #if _MSC_VER >= 1400
            uintptr_t _thandle;         /* thread handle */
    #else
            unsigned long   _thandle;   /* thread handle */
    #endif
            int     _terrno;            /* errno value */
            unsigned long   _tdoserrno; /* _doserrno value */
            unsigned int    _fpds;      /* Floating Point data segment */
            unsigned long   _holdrand;  /* rand() seed value */
            char *      _token;         /* ptr to strtok() token */
            wchar_t *   _wtoken;        /* ptr to wcstok() token */
            unsigned char * _mtoken;    /* ptr to _mbstok() token */
    
            /* following pointers get malloc'd at runtime */
            char *      _errmsg;        /* ptr to strerror()/_strerror()
                                           buff */
    #if _MSC_VER >= 1300
            wchar_t *   _werrmsg;       /* ptr to _wcserror()/__wcserror() buff */
    #endif
            char *      _namebuf0;      /* ptr to tmpnam() buffer */
            wchar_t *   _wnamebuf0;     /* ptr to _wtmpnam() buffer */
            char *      _namebuf1;      /* ptr to tmpfile() buffer */
            wchar_t *   _wnamebuf1;     /* ptr to _wtmpfile() buffer */
            char *      _asctimebuf;    /* ptr to asctime() buffer */
            wchar_t *   _wasctimebuf;   /* ptr to _wasctime() buffer */
            void *      _gmtimebuf;     /* ptr to gmtime() structure */
            char *      _cvtbuf;        /* ptr to ecvt()/fcvt buffer */
    #if _MSC_VER >= 1400
            unsigned char _con_ch_buf[MB_LEN_MAX]; /* ptr to putch() buffer */
            unsigned short _ch_buf_used;   /* if the _con_ch_buf is used */
    #endif
            /* following fields are needed by _beginthread code */
            void *      _initaddr;      /* initial user thread address */
            void *      _initarg;       /* initial user thread argument */
    
            /* following three fields are needed to support 
             * signal handling and
             * runtime errors */
            void *      _pxcptacttab;   /* ptr to exception-action table */
            void *      _tpxcptinfoptrs; /* ptr to exception info pointers*/
            int         _tfpecode;      /* float point exception code */
    #if _MSC_VER >= 1300
            /* pointer to the copy of the multibyte character 
             * information used by the thread */
            /*pthreadmbcinfo*/ void *  ptmbcinfo;
    
            /* pointer to the copy of the locale informaton 
             * used by the thead */
            /*pthreadlocinfo*/ void *  ptlocinfo;
    #endif
    #if _MSC_VER >= 1400
            int         _ownlocale;     /* if 1, this thread owns its own locale */
    #endif
            /* following field is needed by NLG routines */
            unsigned long   _NLG_dwCode;
    
    #if _MSC_VER == 1200 && !defined(_DEBUG) && defined(_DLL)
            void *dummy1, *dummy2; // Weird misalignment in msvcrt.dll fixed
    #endif
    
            /*
             * Per-Thread data needed by C++ Exception Handling
             */
            void *      _terminate;     /* terminate() routine */
            void *      _unexpected;    /* unexpected() routine */
            void *      _translator;    /* S.E. translator */
    #if _MSC_VER >= 1400
            void *      _purecall;      /* called when pure virtual happens */
    #endif
            void *      _curexception;  /* current exception */
            void *      _curcontext;    /* current exception context */
    #if _MSC_VER >= 1300
            int         _ProcessingThrow; /* for uncaught_exception */
    #endif
        };
    
        typedef struct _tiddata * _ptiddata;
    
        _ptiddata __cdecl _getptd();
    }
    
    
    #ifdef _DLL
    
    
    CONTEXT* GetCurrentExceptionContext()
    {
        _tiddata* pTiddata = (_tiddata*)(((BYTE*) __pxcptinfoptrs()) - offsetof(_tiddata, _tpxcptinfoptrs));
        return (CONTEXT*) pTiddata->_curcontext;
    }
    
    #else
    
    CONTEXT* GetCurrentExceptionContext()
    {
        _tiddata* p = _getptd();
        return (CONTEXT*) p->_curcontext;
    }
    
    #endif
    
    #else
    
    extern CONTEXT* _pCurrentExContext;
    
    CONTEXT* GetCurrentExceptionContext()
    {
        return _pCurrentExContext;
    }
    
    #endif
    
    
    void OutputDebugExceptionStackTrace()
    {
        CONTEXT* pEC = GetCurrentExceptionContext();
        if (pEC != NULL)
        {
            HANDLE hThread = NULL;
            DuplicateHandle( GetCurrentProcess(), GetCurrentThread(),
                GetCurrentProcess(), &hThread, 0, false, DUPLICATE_SAME_ACCESS );
    
            StackTrace( hThread, *pEC, OutputDebugString, GetCurrentProcess());
    
            CloseHandle( hThread );
        }
    }
    
    void GetTheAnswer()
    {
        throw 42;
    }
    
    int main(int argc, char* argv[])
    {
        try
        {
            GetTheAnswer();
        }
        catch (...)
        {
            OutputDebugExceptionStackTrace();
        }
    
        return 0;
    }
    
    Friday, May 1st, 2009
    2:04 pm
    Friday, April 10th, 2009
    4:18 pm
    Opus #10 from Outer Space
    #include <atldbcli.h>
    #include <OLEDBERR.H>
    #include <algorithm>
    #include <vector>
    
    
    //  Generic numeric transformer from one radix to another.
    //  Divides array elements one by one,
    //  reverses output sequence to preserve order. 
    //  Modifies input data as well.
    template <typename TRAITS, typename INTYPE, typename OUTTYPE>
    inline void TransformRadix(OUTTYPE* out, int outSize,  INTYPE* in, int inSize)
    {
        for (int j = outSize; j--; )
        {
            unsigned long ulBuf = ((in[0] % TRAITS::EOutRadix) * TRAITS::EInRadix) + in[1];
            in[0] /= TRAITS::EOutRadix;
    
            for (int i = 1; i < inSize - 1; ++i)
            {
                in[i] = static_cast<INTYPE>(ulBuf / TRAITS::EOutRadix);
                ulBuf = ((ulBuf % TRAITS::EOutRadix) * TRAITS::EInRadix) + in[i + 1];
            }
    
            in[inSize - 1] = static_cast<INTYPE>(ulBuf / TRAITS::EOutRadix);
            out[j] = static_cast<OUTTYPE>(ulBuf % TRAITS::EOutRadix);
        }
    }
    
    
    struct TraitsB2A
    {
        enum {
            EInRadix = 0x00000100, 
            EOutRadix = 10, 
        };
    };
    
    inline void ThrowIfFailed(HRESULT hr, LPCSTR szExpr)
    {
        if (FAILED(hr))
        { 
            CString s;
            s.Format("Failure in %s: %d", szExpr, hr); 
            throw s; 
        }
    }
    
    #define CHECK_HR(expr) \
        if (false); \
        else for (HRESULT hr, b = true; b; ThrowIfFailed(hr, #expr), b = false) \
        hr = expr
    
    #define CHECK_NOT_NULL(expr) \
        if ((expr) != NULL); \
        else throw CString(#expr " is null");
    
    
    CString GetVarNumeric(IUnknown* res1, long columnOrdinal) // OLE DB column index starts with 1
    {
        ADODB::ADORecordsetConstructionPtr adoRecordsetConstruction(res1);
        CHECK_NOT_NULL(adoRecordsetConstruction);
        CComQIPtr<IRowset> spIRowset(adoRecordsetConstruction->GetRowset());
        CHECK_NOT_NULL(spIRowset);
        CComQIPtr<IColumnsInfo> spIColumnsInfo(spIRowset);
        CHECK_NOT_NULL(spIColumnsInfo);
    
        DBBINDING dbBinding;
    
        bool bOK = false;
    
        {
            ULONG cColumns;
            DBCOLUMNINFO * prgInfo;
            OLECHAR * pStringsBuffer;
    
            CHECK_HR(spIColumnsInfo->GetColumnInfo)(& cColumns, & prgInfo, & pStringsBuffer);
    
            // prgInfo[idx].wType will be DBTYPE_VARNUMERIC == 139
    
            int idx;
            for (idx = cColumns; --idx >= 0; )
            {
                if (columnOrdinal == prgInfo[idx].iOrdinal)
                    break;
            }
    
            bOK = idx != -1 && DBTYPE_VARNUMERIC == prgInfo[idx].wType;
            if (bOK)
            {
                dbBinding.iOrdinal = prgInfo[idx].iOrdinal;
                dbBinding.obValue = 0;
                dbBinding.obLength = 0;
                dbBinding.obStatus = 0;
                dbBinding.pTypeInfo = NULL;
                dbBinding.pObject = NULL;
                dbBinding.pBindExt = NULL;
                dbBinding.dwPart = DBPART_VALUE;
                dbBinding.dwMemOwner = DBMEMOWNER_CLIENTOWNED;
                dbBinding.eParamIO = DBPARAMIO_NOTPARAM;
                dbBinding.cbMaxLen = prgInfo[idx].ulColumnSize;
                dbBinding.dwFlags = prgInfo[idx].dwFlags;
                dbBinding.wType = prgInfo[idx].wType;
                dbBinding.bPrecision = prgInfo[idx].bPrecision;
                dbBinding.bScale = prgInfo[idx].bScale;
            }
    
            CComPtr<IMalloc> spMalloc;
            if (SUCCEEDED(CoGetMalloc(1, &spMalloc)) && spMalloc != NULL)
            {
                spMalloc->Free( pStringsBuffer );
                spMalloc->Free( prgInfo );
            }
        }
    
        if (!bOK)
            throw CString("No DBTYPE_VARNUMERIC type column found");
    
        CComQIPtr<IAccessor> spIAccessor(spIRowset);
        CHECK_NOT_NULL(spIAccessor);
    
        HACCESSOR hAccessor;
        DBBINDSTATUS DBBindStatus[2];
    
        CHECK_HR(spIAccessor->CreateAccessor)(DBACCESSOR_ROWDATA, 
            1, 
            &dbBinding, 
            dbBinding.cbMaxLen, 
            & hAccessor, 
            DBBindStatus);
    
        CString value;
    
        try
        {
            HROW rghRows;
    
            CComQIPtr<IRowPosition> spRowPosition(adoRecordsetConstruction->GetRowPosition());
            CHECK_NOT_NULL(spRowPosition);
            CHECK_HR(spRowPosition->GetRowPosition)(NULL, &rghRows, NULL);
    
            // add 3 bytes for precision, scale, and sign
            std::vector<BYTE> buffer(dbBinding.cbMaxLen + 3);
    
            CHECK_HR(spIRowset->GetData)(rghRows, hAccessor, &buffer[0]);
    
            DB_VARNUMERIC* pVar = (DB_VARNUMERIC*) &buffer[0];
    
            int prec = ( int ) pVar->precision;
            int scale = ( int ) pVar->scale;
    
            std::reverse(pVar->val, pVar->val + dbBinding.cbMaxLen);
    
            LPTSTR buf = value.GetBuffer(prec);
            TransformRadix<TraitsB2A>(buf, 
                prec,
                pVar->val,
                dbBinding.cbMaxLen);
    
            for (int i = 0; i < prec; ++i)
                buf[i] += '0';
            buf[prec] = 0; // Ending zero
    
            value.ReleaseBuffer();
    
            if (scale > 0 && scale <= prec)
            {
                value.Insert(prec - scale, '.');
            }
            else if (scale != 0)
            {
                CString tmp(value);
                value.Format(".%se%d", tmp, prec - scale);
            }
    
            if (pVar->sign <= 0)
                value = '-' + value;
        }
        catch (...)
        {
            spIAccessor->ReleaseAccessor(hAccessor, NULL);
            throw;
        }
    
        spIAccessor->ReleaseAccessor(hAccessor, NULL);
    
        return value;
    }
    
    Monday, April 6th, 2009
    4:22 pm
    Opus #9 from Outer Space
    #include <stdlib.h>
    #include <assert.h>
    
    #include <vector>
    #include <algorithm>
    #include <iostream>
    
    typedef std::vector<unsigned int> LongNumber;
    
    LongNumber& operator *= (LongNumber& n1, int n2)
    {
        if (0 == n2)
            n1.clear();
        else
        {
            __int64 buf = 0;
    
            for (LongNumber::iterator it(n1.begin()); it != n1.end(); ++it)
            {
                buf += (*it) * (__int64) n2;
                *it = (unsigned int) buf;
                buf >>= (sizeof(int) * 8);
            }
            if (buf != 0)
                n1.push_back((unsigned int) buf);
        }
        return n1;
    }
    
    LongNumber& operator /= (LongNumber& n1, int n2)
    {
        __int64 buf = 0;
    
        for (LongNumber::reverse_iterator it(n1.rbegin()); it != n1.rend(); ++it)
        {
            buf += (*it);
            (*it) = (unsigned int) (buf / n2);
            buf = (buf % n2) << (sizeof(int) * 8);
        }
        assert (0 == buf);
    
        size_t size = n1.size();
        if (size != 0 && 0 == n1[size - 1])
            n1.resize(size - 1);
    
        return n1;
    }
    
    LongNumber& operator += (LongNumber& n1, const LongNumber& n2)
    {
        if (n1.size() < n2.size())
            n1.resize(n2.size());
    
        __int64 buf = 0;
    
        LongNumber::iterator it1(n1.begin());
        for (LongNumber::const_iterator it2(n2.begin())
            ; it2 != n2.end(); ++it1, ++it2)
        {
            buf += (*it1); buf += (*it2);
            *it1 = (unsigned int) buf;
            buf >>= (sizeof(int) * 8);
        }
        for (; it1 != n1.end() && buf != 0; ++it1)
        {
            buf += (*it1);
            *it1 = (unsigned int) buf;
            buf >>= (sizeof(int) * 8);
        }
        if (buf != 0)
            n1.push_back((unsigned int) buf);
    
        return n1;
    }
    
    LongNumber& operator -= (LongNumber& n1, const LongNumber& n2)
    {
        assert(n1.size() >= n2.size());
    
        __int64 buf = 0;
    
        LongNumber::iterator it1(n1.begin());
        for (LongNumber::const_iterator it2(n2.begin())
            ; it2 != n2.end(); ++it1, ++it2)
        {
            buf += (*it1); buf -= (*it2);
            *it1 = (unsigned int) buf;
            buf >>= (sizeof(int) * 8);
        }
        for (; it1 != n1.end() && buf != 0; ++it1)
        {
            buf += (*it1);
            *it1 = (unsigned int) buf;
            buf >>= (sizeof(int) * 8);
        }
    
        assert(0 == buf);
    
        LongNumber::reverse_iterator it(n1.rbegin());
        for (; it != n1.rend(); ++it)
            if (0 != (*it))
            {
                size_t delta = it - n1.rbegin();
                if (delta != 0)
                    n1.resize(n1.size() - delta);
                break;
            }
    
        if (n1.rend() == it)
            n1.clear();
    
        return n1;
    }
    
    
    bool operator < (const LongNumber& n1, const LongNumber& n2)
    {
        if (n1.size() < n2.size())
            return true;
        if (n1.size() > n2.size())
            return false;
    
        return std::lexicographical_compare(
            n1.rbegin(), n1.rend(), n2.rbegin(), n2.rend());
    }
    
    
    enum { MEMBER_SIZE = 0x10000 };
    
    template <typename T>
    class CombTemplate
    {
    public:
        void Process()
        {
            int m = static_cast<T*>(this)->GetSize();
            LongNumber l;
            l.push_back(MEMBER_SIZE - 1);
            for (int i = 2; i <= m; ++i)
            {
                l *= (MEMBER_SIZE - i); 
                l /= i;
            }
    
            int n = MEMBER_SIZE - 1;
    
            for (; m > 0; --m)
            {
                bool elementProcessed;
                do
                {
                    elementProcessed 
                        = static_cast<T*>(this)->ElementProcessed(l, m - 1, n);
                    l *= elementProcessed? m : (n - m);
                    l /= n;
                    --n;
                }
                while(!elementProcessed);
            }
        }
    };
    
    class CombEncoder : public CombTemplate<CombEncoder>
    {
        int m_size;
        const unsigned short* m_pdata;
        LongNumber& m_encodedData;
    
    public:
        int GetSize() const { return m_size; }
        bool ElementProcessed(LongNumber& l, int m, int n)
        {
            if (m_pdata[m] == n)
            {
                m_encodedData += l;
                return true;
            }
            return false;
        }
    
    public:
        template <typename T>
        CombEncoder(const T& data, LongNumber& encodedData)
        : m_pdata(data), m_size(sizeof(data) / sizeof(data[0]))
        , m_encodedData(encodedData) {}
    };
    
    class CombDecoder : public CombTemplate<CombDecoder>
    {
        int m_size;
        unsigned short* m_pdata;
        LongNumber& m_encodedData;
    
    public:
        int GetSize() const { return m_size; }
        bool ElementProcessed(LongNumber& l, int m, int n)
        {
            if (!(m_encodedData < l))
            {
                m_encodedData -= l;
                m_pdata[m] = n;
                return true;
            }
            return false;
        }
    
    public:
        template <typename T>
        CombDecoder(T& data, LongNumber& encodedData)
        : m_pdata(data), m_size(sizeof(data) / sizeof(data[0]))
        , m_encodedData(encodedData) {}
    };
    
    
    template<typename T> void Stuff(T& data)
    {
        unsigned int val = rand();
        for (int i = 0; i < sizeof(data) / sizeof(data[0]); ++i)
        {
            unsigned short* p;
            do 
            {
                val = (val << 15) + rand();
            }
            while ((p = std::lower_bound(data, data+i, (unsigned short) val)) != data+i
                && *p == (unsigned short) val);
            memmove(p + 1, p, (data + i - p) * sizeof(unsigned short));
            *p = (unsigned short) val;
        }
    }
    
    int main(int argc, char* argv[])
    {
        typedef unsigned short BUFFER[30];
    
        BUFFER data;
    
        Stuff(data);
    
        LongNumber encodedData;
    
        CombEncoder encoder(data, encodedData);
        encoder.Process();
    
        std::cout << "Compressed set size is " 
            << encodedData.size() * sizeof(int) << " bytes.\nDecoding ";
    
        BUFFER restoredData;
    
        CombDecoder decoder(restoredData, encodedData);
        decoder.Process();
    
        std::cout << ((0 == memcmp(data, restoredData, sizeof(data)))
            ? "succeeded" : "failed") << ".\n";
    
        return 0;
    }
    11:44 am
    "Minsk - Out Of A Center Which Is Neither Dead Nor Alive"


    Paul McCartney wrote this. It's about a man who is considered a fool by others, but whose foolish demeanor is actually an indication of wisdom. An event which prompted this song happened when Paul was walking his dog Martha, on Primrose Hill one morning. As he watched the sun rise, he noticed that Martha was missing. Paul turned around to look for his dog, and there a man stood, who appeared on the hill without making a sound. The gentleman was dressed respectably, in a belted raincoat. Paul knew this man had not been there seconds earlier as he had looked in that direction for Martha. Paul and the stranger exchanged a greeting, and this man then spoke of what a beautiful view it was from the top of this hill that overlooked London. Within a few seconds, Paul looked around again, and the man was gone. He had vanished as he had appeared. A friend of McCartney's, Alistair Taylor, was present with Paul during this strange incident, and wrote of this event in his book, Yesterday.


    http://www.songfacts.com/detail.php?id=134
    Sunday, April 5th, 2009
    1:33 pm
    And the Piper will lead us to reason, the Piper at the Gates of Dawn
    Who's the Piper?



    Башни с зубцами,
    Нам покоритесь!
    Гордые девы,
    Нам улыбнитесь!
    Все вы сдадитесь!
    Славная плата
    Смелым трудам!
    Подвиг солдата
    Сладостен нам.
    Сватаны все мы
    Звонкой трубою
    К радости шумной,
    К смертному бою.
    В битвах и штурмах
    Дни наши мчатся;
    Стены и девы
    Нам покорятся.
    Славная плата
    Смелым трудам!
    Миг - и солдата
    Нет уже там.

    Voices, talking perfectly loud.
    12:14 pm
    Opus #8
    // Life.cpp : Defines the entry point for the console application.
    //
    //	This is an adaptation of HashLife Java implementation by Tomas G. Rokicki:
    //	http://www.ddj.com/184406478
    //  Modified to allow producing arbitrary number of steps, converted to C++
    //
    //	Name: Aliaksei Sanko
    //	Blog: aliakseis.livejournal.com
    //	Country: Belarus
    
    #include "stdafx.h"
    
    #include <iostream>
    #include <fstream>
    
    #include <shlwapi.h>
    #pragma comment(lib, "shlwapi")
    
    #include <assert.h>
    
    
    using std::cerr;
    using std::ofstream;
    using std::endl;
    
    
    enum { HASH_SIZE = 128 * 1024 };
    
    
    class Node;
    
    class NextGeneration_MT
    {
    public:
        NextGeneration_MT(Node* pBase, unsigned long supplement = 0);
        ~NextGeneration_MT();
        operator Node*();
    
    private:
        NextGeneration_MT(const NextGeneration_MT&);
        NextGeneration_MT& operator = (const NextGeneration_MT&);
    
        static DWORD CALLBACK ProcessData( void* pv );
    
        unsigned long m_supplement;
        Node* m_pBase;
        Node* m_pNext;
        HANDLE m_hEvent;
    };
    
    /**
    *   This class contains the tree maintenance functions for quadtrees.
    */
    class Node 
    {
    public:
        /**
        *   Construct a node given four children.
        */
    
        Node()
        {
            level = 0;
        }
    
        Node(Node* nw_, Node* ne_, Node* sw_, Node* se_, bool living) 
        {
            render[0] = render[1] = false;
            nw = nw_ ;
            ne = ne_ ;
            sw = sw_ ;
            se = se_ ;
            alive = living;
        }
    
        void setup()
        {
            result[0] = 0;
            result[1] = 0;
            // Nasty hack
            level = (nw < (void*)0x800)? 2 : nw->level + 1 ;
        }
    
        /**
        *   Set a bit in this node in its relative coordinate system;
        *   returns a whole new node since our nodes are immutable.
        *
        *   In the recursive call, we simply adjust the coordinate system
        *   and call down a level.
        */
        Node* setBit(int x, int y) 
        {
            // Nasty hack
            if (this < (void*)0x800)
            {
                size_t idx = (size_t) this;
                idx |= 1 << (-y * 4 - x);
                return (Node*) idx;
            }
    
            // distance from center of this node to center of subnode is
            // one fourth the size of this node.
            int offset = 1 << (level - 2) ;
            if (x < 0)
                if (y < 0)
                    return create(nw->setBit(x+offset, y+offset), ne, sw, se) ;
                else
                    return create(nw, ne, sw->setBit(x+offset, y-offset), se) ;
            else
                if (y < 0)
                    return create(nw, ne->setBit(x-offset, y+offset), sw, se) ;
                else
                    return create(nw, ne, sw, se->setBit(x-offset, y-offset)) ;
        }
        /**
        *   If we ever really need to get a bit one at a time, we can
        *   use this subroutine.  For convenience it returns 0/1 rather
        *   than false/true.
        */
        int getBit(int x, int y) 
        {
            // Nasty hack
            if (this < (void*)0x800)
            {
                size_t idx = (size_t) this;
                return (idx & (1 << (-y * 4 - x))) ? 1 : 0;
            }
    
            if (!alive)
                return 0;
    
            int offset = 1 << (level - 2) ;
            if (x < 0)
                if (y < 0)
                    return nw->getBit(x+offset, y+offset) ;
                else
                    return sw->getBit(x+offset, y-offset) ;
            else
                if (y < 0)
                    return ne->getBit(x-offset, y+offset) ;
                else
                    return se->getBit(x-offset, y-offset) ;
        }
        /**
        *   Build an empty tree at the given level.
        */
        static Node* emptyTree(int lev) 
        {
            // Nasty hack
            if (lev == 1)
                return 0;
    
            Node* n = emptyTree(lev-1) ;
            return create(n, n, n, n, false) ;
        }
        /**
        *   Expand the universe; return a new node up one level with the
        *   current node in the center.  Requires us to disassemble the
        *   current node.
        */
        Node* expandUniverse() {
            Node* border = emptyTree(level-1) ;
            return create(create(border, border, border, nw, nw->alive),
                create(border, border, ne, border, ne->alive),
                create(border, sw, border, border, sw->alive),
                create(se, border, border, border, se->alive), alive) ;
        }
    
        /**
        *   HorizontalForward() takes two horizontally adjacent nodes,
        *   builds a new node from the east half of the west node and
        *   the west half of the east node, and computes the next
        *   step for that new node.
        */
        Node* horizontalForward(Node* w, Node* e) {
            return create(w->ne, e->nw, w->se, e->sw)->nextGeneration() ;
        }
        /**
        *   VerticalForward() takes two vertically adjacent nodes,
        *   builds a new node from the south half of the north node
        *   and the north half of the south node, and computes the
        *   next step for that node.
        */
        Node* verticalForward(Node* n, Node* s) {
            return create(n->sw, n->se, s->nw, s->ne)->nextGeneration() ;
        }
        /**
        *   CenterForward() builds a new subnode that is half the
        *   size of the this node out of the center portions.  It
        *   then does a generation step and returns that result.
        */
        Node* centerForward() {
            return create(nw->se, ne->sw, sw->ne, se->nw)->nextGeneration() ;
        }
    
        /**
        *   Return a new node one level down containing only the
        *   center elements.
        */
        Node* centeredSubnode() {
            return create(nw->se, ne->sw, sw->ne, se->nw) ;
        }
        /**
        *   Return a new node one level down from two given nodes
        *   that contains the east centered two sub sub nodes from
        *   the west node and the west centered two sub sub nodes
        *   from the east node.
        */
        Node* centeredHorizontal(Node* w, Node* e) {
            return create(w->ne->se, e->nw->sw, w->se->ne, e->sw->nw) ;
        }
        /**
        *   Similar, but this does it north/south instead of east/west.
        */
        Node* centeredVertical(Node* n, Node* s) {
            return create(n->sw->se, n->se->sw, s->nw->ne, s->ne->nw) ;
        }
        /**
        *   Return a new node two levels down containing only the
        *   centered elements.
        */
        Node* centeredSubSubnode() {
            return create(nw->se->se, ne->sw->sw, sw->ne->ne, se->nw->nw) ;
        }
    
        /**
        *   NextGeneration() is the core HashLife recursive algorithm.
        *   It builds 9 subnodes that are one quarter the size of the
        *   current node and advanced in time one eighth the size of
        *   the current node.  It then takes these 9 subnodes in groups
        *   of four and builds 4 subnodes, each one quarter the size
        *   of the current node and advanced in time one fourth the size
        *   of the current node.  It combines these four subnodes into
        *   a new node and returns that as its result.
        */
        Node* nextGeneration(unsigned long supplement = 0)
        {
            bool direct = level > 2 && (supplement & (1ul << (level - 3)));
            
            while (render[direct])
                Sleep(0);
    
            if (result[direct] != 0)
                return result[direct];
            if (!alive)
                return result[direct] = nw ;
            if (level == 2)
                return result[direct] = slowSimulation() ;
    
            render[direct] = true;
    
            Node *n00, *n01 ,*n02 ,*n10 ,*n11 ,*n12 ,*n20 ,*n21 ,*n22; 
    
            if (direct)
            {
                n00 = nw->centeredSubnode();
                n01 = centeredHorizontal(nw, ne);
                n02 = ne->centeredSubnode();
                n10 = centeredVertical(nw, sw);
                n11 = centeredSubSubnode();
                n12 = centeredVertical(ne, se);
                n20 = sw->centeredSubnode();
                n21 = centeredHorizontal(sw, se);
                n22 = se->centeredSubnode();
            }
            else
            {
                n00 = nw->nextGeneration();
                n01 = horizontalForward(nw, ne);
                n02 = ne->nextGeneration();
                n10 = verticalForward(nw, sw);
                n11 = centerForward();
                n12 = verticalForward(ne, se);
                n20 = sw->nextGeneration();
                n21 = horizontalForward(sw, se);
                n22 = se->nextGeneration();
            }
    
            //return 
            result[direct] = create(
                create(n00, n01, n10, n11)->nextGeneration(supplement),
                create(n01, n02, n11, n12)->nextGeneration(supplement),
                create(n10, n11, n20, n21)->nextGeneration(supplement),
                create(n11, n12, n21, n22)->nextGeneration(supplement)) ;
    
            render[direct] = false;
    
            return result[direct];
        }
    
    
        Node* nextGeneration_MT(unsigned long supplement)
        {
            assert(!(level > 2 && (supplement & (1ul << (level - 3)))));
    
            NextGeneration_MT n00(nw);
            NextGeneration_MT n01(create(nw->ne, ne->nw, nw->se, ne->sw));
            NextGeneration_MT n02(ne);
            NextGeneration_MT n10(create(nw->sw, nw->se, sw->nw, sw->ne));
            NextGeneration_MT n11(create(nw->se, ne->sw, sw->ne, se->nw));
            NextGeneration_MT n12(create(ne->sw, ne->se, se->nw, se->ne));
            NextGeneration_MT n20(sw);
            NextGeneration_MT n21(create(sw->ne, se->nw, sw->se, se->sw));
            NextGeneration_MT n22(se);
    
            NextGeneration_MT nw_(create(n00, n01, n10, n11), supplement);
            NextGeneration_MT ne_(create(n01, n02, n11, n12), supplement);
            NextGeneration_MT sw_(create(n10, n11, n20, n21), supplement);
            NextGeneration_MT se_(create(n11, n12, n21, n22), supplement) ;
    
            return create(nw_, ne_, sw_, se_);
        }
    
        /**
        *   create functions.
        */
        static Node* create(Node* nw, Node* ne, Node* sw, Node* se, bool living = true) {
            return Node(nw, ne, sw, se, living).intern() ;
        }
        static Node* create() {
            return emptyTree(3) ;
        }
    
        /**
        *   We need to provide a hashCode() and an equals() method to be
        *   able to hash these objects.
        */
    
        size_t hashCode() 
        {
            size_t result = (size_t(nw) +
                11 * size_t(ne) +
                101 * size_t(sw) +
                1007 * size_t(se));
    
            // Nasty hack
            if (nw > (void*)0x800)
                result >>= 5;
    
            return result;
        }
        
        bool operator ==(const Node& t) const
        {
            return nw == t.nw && ne == t.ne && sw == t.sw && se == t.se;
        }
    
        /**
        *   Given a node, return the canonical one if it exists, or make it
        *   the canonical one.
        */
        Node* intern();
    
        /**
        *   Given an integer with a bitmask indicating which bits are
        *   set in the neighborhood, calculate whether this cell is
        *   alive or dead in the next generation.  The bottom three
        *   bits are the south neighbors; bits 4..6 are the current
        *   row with bit 5 being the cell itself, and bits 8..10
        *   are the north neighbors.
        */
        static bool oneGen(int bitmask) 
        {
            int self = bitmask & (1 << 5);
            bitmask &= 0x757 ; // mask out bits we don't care about
    
            if (bitmask == 0)
                return 0;
            bitmask &= bitmask - 1 ; // clear least significant bit
            if (bitmask == 0)
                return 0;
            bitmask &= bitmask - 1 ; // clear least significant bit
            if (bitmask == 0)
                return self? 1 : 0;
            bitmask &= bitmask - 1 ; // clear least significant bit
            return (bitmask == 0)? 1 : 0;
        }
    
    
        /**
        *   At level 2, we can use slow simulation to compute the next
        *   generation.  We use bitmask tricks.
        */
        Node* slowSimulation() 
        {
            // Nasty hack
            size_t allbits = (size_t(nw) << 10) + (size_t(ne) << 8) + (size_t(sw) << 2) + size_t(se);
            return (Node*) (size_t) ((cachedOneGen[allbits>>5] << 5) 
                + (cachedOneGen[(allbits>>4) & 0x7FF] << 4) 
                + (cachedOneGen[(allbits>>1) & 0x7FF] << 1) 
                + cachedOneGen[allbits & 0x7FF]);
        }
    
    
        Node *nw, *ne, *sw, *se ; // our children
        volatile long level ;           // distance to root
        volatile bool render[2];
        bool alive;       // if leaf node, are we alive or dead?
        Node* volatile result[2];
        //Node* next;
    
        static bool cachedOneGen[0x800];
    };
    
    
    static Node hashTable[HASH_SIZE];
    
    
    bool Node::cachedOneGen[0x800];
    
    
    Node* Node::intern() 
    {
        int i =  hashCode() % HASH_SIZE;
        int disp = 0;
    
        Node* canon;
        for (;;) 
        {
            long level_;
            while ((level_ = (canon = hashTable + i)->level) > 1)
            {
                if (*this == *canon)
                {
                    return canon;
                }
    
                disp++;
                if ((i -= disp) < 0) 
                    i += HASH_SIZE;
            }
            if (level_ != 1 && 0 == InterlockedCompareExchange(&hashTable[i].level, 1, 0))
                break;
            //Sleep(0);
        } 
    
        level = 1;
        *canon = *this;
        canon->setup();
        return canon;
    }
    
    
    class Universe
    {
    public:
        Universe()
        {
            // Initialize static nodes stuff
            static bool first = true;
    
            if (first)
            {
                first = false;
                for (int i = 0; i < sizeof(Node::cachedOneGen) / sizeof(Node::cachedOneGen[0]); ++i)
                    Node::cachedOneGen[i] = Node::oneGen(i);
            }
            else
            {
                for (int i = 0; i < HASH_SIZE; ++i)
                    hashTable[i].level = 0;
            }
    
            generationCount = 0;
            root = Node::create();
        }
    
        void runSteps(unsigned long numSteps) 
        {
            //while (root->level < 3 ||
            //		root->nw->population != root->nw->se->se->population ||
            //		root->ne->population != root->ne->sw->sw->population ||
            //		root->sw->population != root->sw->ne->ne->population ||
            //		root->se->population != root->se->nw->nw->population)
            //	root = root->expandUniverse();
    
            unsigned long stepSize;
            while ((stepSize = 1ul << (root->level - 2)) < numSteps)
                root = root->expandUniverse();
    
            root = root->nextGeneration_MT(stepSize - numSteps);
            //root = root->nextGeneration(stepSize - numSteps);
            generationCount += numSteps;
        }
    
        /**
        *   Set a single bit; can only do this before running, and once
        *   we've started running cannot change.
        */
        void setBit(int x, int y) 
        {
            /*
            *   We need to make sure the current universe is large enough
            *   to handle these parameters.  A root node at level n supports
            *   coordinates from -2^(n-1) .. 2^(n-1)-1.
            */
            for (;;) {
                int maxCoordinate = 1 << (root->level - 1) ;
                if (-maxCoordinate <= x && x <= maxCoordinate-1 &&
                    -maxCoordinate <= y && y <= maxCoordinate-1)
                    break ;
                root = root->expandUniverse() ;
            }
            /*
            *   Call our recursive routine to set the bit.
            */
            root = root->setBit(x, y) ;
        }
    
        Node* root;
        unsigned long generationCount;
    };
    
    /////////////////////////////////////////////////////////////////////
    
    NextGeneration_MT::NextGeneration_MT(Node* pBase, unsigned long supplement /*= 0*/)
    : m_pBase(pBase), m_pNext(0), m_supplement(supplement), m_hEvent(CreateEvent(NULL, TRUE, FALSE, NULL))
    {
        QueueUserWorkItem(            
            ProcessData,            
            this,            
            //WT_EXECUTEDEFAULT ); //<< don't use, despite docs.            
            WT_EXECUTELONGFUNCTION );
    }
    
    NextGeneration_MT::~NextGeneration_MT()
    {
        CloseHandle(m_hEvent);
    }
    
    NextGeneration_MT::operator Node*()
    {
        if (0 == m_pNext)
            WaitForSingleObject(m_hEvent, INFINITE);
        return m_pNext;
    }
    
    DWORD CALLBACK NextGeneration_MT::ProcessData( void* pv )
    {
        NextGeneration_MT* pThis = (NextGeneration_MT*) pv;
        pThis->m_pNext = pThis->m_pBase->nextGeneration(pThis->m_supplement);
        SetEvent(pThis->m_hEvent);
        return 0;
    }
    
    /////////////////////////////////////////////////////////////////////
    
    void SetBit(Universe& universe, int x, int y)
    {
        for (int i = -1000; i <= 1000; i += 1000)
            for (int j = -1000; j <= 1000; j += 1000)
                universe.setBit(x + i, y + j);
    }
    
    
    int main(int /*argc*/, char* argv[])
    {
        LARGE_INTEGER frequency;
        QueryPerformanceFrequency(&frequency);
        LARGE_INTEGER start, stop;
    
        QueryPerformanceCounter(&start);
        
        int runsCount = 0;
    
        for (;;) 
        {
            Universe universe;
    
            SetBit(universe, 1, 0);
            SetBit(universe, 2, 0);
            SetBit(universe, 0, 1);
            SetBit(universe, 1, 1);
            SetBit(universe, 1, 2);
    
            universe.runSteps(1000);
    
            runsCount++;
    
            QueryPerformanceCounter(&stop);
            if ((stop.QuadPart - start.QuadPart) / frequency.QuadPart < 5)
                continue;
    
            char path[_MAX_PATH];
            strcpy(path, argv[0]);
            char* pFileName = PathFindFileNameA(path);
    
            strcpy(pFileName, "life.txt");
    
            ofstream outputFile(path);
            if (!outputFile) 
            {
                cerr << "Unable to open output file.\n";
                return EXIT_FAILURE;
            }
    
            for (int y = -500; y < 500; ++y)
            {
                for (int x = -500; x < 500; ++x)
                {
                    outputFile << ((int) universe.root->getBit(x, y));
                }
                outputFile << '\n';
            }
    
            outputFile << "\nSolution time: " <<
                double(stop.QuadPart - start.QuadPart) / frequency.QuadPart / runsCount <<
                " seconds" << endl;
    
            break;
        } 
    
        return 0;
    }
    
    Sunday, February 15th, 2009
    1:23 pm
    Opus #7
    #define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff from Windows headers
    #define _WIN32_WINNT 0x0400
    
    #pragma warning(disable:4786)
    
    #include <windows.h>
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <Tlhelp32.h>
    #include <iostream>
    #include <map>
    #include <vector>
    #include <algorithm>
    
    using std::cerr;
    using std::cout;
    using std::hex;
    
    DWORD WINAPI TestThreadProc(LPVOID pParameter)
    {
        CRITICAL_SECTION* pCS = (CRITICAL_SECTION*) pParameter;
        EnterCriticalSection(pCS);
        LeaveCriticalSection(pCS);
        
        return 0;
    }
    
    
    DWORD GetReferenceAddress()
    {
        CRITICAL_SECTION crTest;	
        InitializeCriticalSection(&crTest);
        EnterCriticalSection(&crTest);
        CRITICAL_SECTION crTestSnapshot(crTest);
        
        HANDLE hTestThread = CreateThread(NULL, 0, TestThreadProc, &crTest, 0, NULL);
        
        while (0 == memcmp(&crTest, &crTestSnapshot, sizeof(CRITICAL_SECTION)))
            SwitchToThread();
        
        SuspendThread(hTestThread);
        CONTEXT context = { CONTEXT_CONTROL };	
        GetThreadContext(hTestThread, &context);
        DWORD result = *(DWORD*)(context.Ebp + 4);
        ResumeThread(hTestThread);
        
        LeaveCriticalSection(&crTest);
        
        WaitForSingleObject(hTestThread, INFINITE);
        CloseHandle(hTestThread);	
        DeleteCriticalSection(&crTest);
    
        return result;
    }
    
    bool WalkThreads(DWORD pid, DWORD address)
    {
        HANDLE hProcess = OpenProcess(PROCESS_VM_READ, false, pid);
        if (!hProcess)
            return false;
    
        HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, pid);
        if (INVALID_HANDLE_VALUE == hSnapshot)
        {
            CloseHandle(hProcess);
            return false;
        }
    
        std::map<DWORD, DWORD> waitingTreads;
    
        THREADENTRY32 te = { sizeof(te) };	
        for (BOOL fok = Thread32First(hSnapshot, &te); fok; fok = Thread32Next(hSnapshot, &te)) 
        {
            if (te.th32OwnerProcessID == pid) 
            {
                HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID);
                if (hThread == NULL)
                    continue;
                
                if (SuspendThread(hThread) != -1)
                {
                    CONTEXT ct = { CONTEXT_CONTROL | CONTEXT_INTEGER };
                    DWORD remAddr = 0;
                    _RTL_CRITICAL_SECTION csLock;
                    if (GetThreadContext(hThread, &ct)
                        && ReadProcessMemory(hProcess, (void*)(ct.Ebp + 4), &remAddr, sizeof(remAddr), 0)
                        && remAddr == address
                        && ReadProcessMemory(hProcess, (void*)ct.Esi, &csLock, sizeof(csLock), 0))
                    {
                        waitingTreads[te.th32ThreadID] = (DWORD) csLock.OwningThread;
                    }
    
                    ResumeThread(hThread);
                }
                CloseHandle(hThread);
            }
        }
    
        CloseHandle(hSnapshot);
        CloseHandle(hProcess);
    
        while (!waitingTreads.empty())	
        {
            std::map<DWORD, DWORD>::iterator it = waitingTreads.begin();
    
            std::vector<DWORD> path;
            path.push_back(it->first);
    
            DWORD next = it->second;
    
            waitingTreads.erase(it);
    
            while ((it = waitingTreads.find(next)) != waitingTreads.end()) 
            {
                path.push_back(next);
                next = it->second;
                waitingTreads.erase(it);
                if (std::find(path.begin(), path.end(), next) != path.end())
                {
                    cout << "Cycle found: ";
                    for (std::vector<DWORD>::const_iterator it = path.begin(); it != path.end(); ++it)
                        cout << hex << *it << " > ";
                    cout << hex << next << "\n";
                }
            }
        }
    
        return true;
    }
    
    int main(int argc, char* argv[])
    {
        DWORD pid = 0;
        if(argc >= 2)
        {
            pid = atol(argv[1]);
        }
        if (pid == 0)
        {
            cerr << "Usage: cswalker.exe pid\n";
            return 1;
        }
    
        WalkThreads(pid, GetReferenceAddress());
        
        return 0;
    }
    
    Sunday, November 9th, 2008
    1:10 pm
    Opus #6
    #undef	_WIN32_WINNT
    #define _WIN32_WINNT 0x0403
    
    #include <windows.h>
    
    #include <assert.h>
    #include <process.h>
    
    #include <boost/thread/condition_variable.hpp>
    
    #include <vector>
    
    using std::vector;
    
    //////////////////////////////////////////////////////////////
    
    class CNotifiedMutex;
    
    class CNotificationItemBase
    {
    public:
        CNotificationItemBase() 
            : m_bNow(false)
        {
        }
    
        CNotificationItemBase* m_pNext;
        volatile bool m_bNow;
        CNotifiedMutex* m_pNotifiedMutex;
    
        virtual bool IsCondition() = 0;
    };
    
    template <typename T>
    class CNotificationItem : public CNotificationItemBase
    {
    public:
        CNotificationItem(CNotifiedMutex* pNotifiedMutex, T& cond) : m_cond(cond) 
        {
            m_pNotifiedMutex = pNotifiedMutex;
        }
        virtual bool IsCondition() 
        {
            return m_cond();
        }
    private:
        T& m_cond;
    };
    
    class CNotifiedMutex
    {
        friend class CNotifiedCondVar;
    public:
        CNotifiedMutex()
            : m_pNotificationFinished(NULL)
            , m_bOnCondition(false)
        {
            InitializeCriticalSectionAndSpinCount(&m_csLock, 200);
        }
        ~CNotifiedMutex()
        {
            // check state validity and absence of deadlocks
            assert(-1 == m_csLock.LockCount);
    
            // release resources
            DeleteCriticalSection(&m_csLock);
        }
    
        void lock()
        {
            EnterCriticalSection(&m_csLock);
        }
        void unlock()
        {
            assert(m_csLock.LockCount != -1);
            if (m_bOnCondition)
            {
                m_bOnCondition = false;
                *m_pNotificationFinished = true;
            }
            else
            {
                LeaveCriticalSection(&m_csLock);
            }
        }
    
    private:
        CRITICAL_SECTION m_csLock;
        volatile bool* m_pNotificationFinished;
        volatile bool m_bOnCondition;
    };
    
    class CNotifiedCondVar
    {
    public:
        CNotifiedCondVar()
            : m_pNotificationItems(NULL)
            , m_ppLastNotificationItem(&m_pNotificationItems)
        {
        }
    
        void notify_all()
        {
            CNotificationItemBase* pNotificationItem;
            m_ppLastNotificationItem = &m_pNotificationItems;
            while ((pNotificationItem = *m_ppLastNotificationItem) != NULL)
            {
                if (pNotificationItem->IsCondition())
                {
                    pNotificationItem->m_pNotifiedMutex->m_bOnCondition = true;
    
                    *m_ppLastNotificationItem = pNotificationItem->m_pNext;
    
                    volatile bool bNow = false;
                    pNotificationItem->m_pNotifiedMutex->m_pNotificationFinished = &bNow;
                    pNotificationItem->m_bNow = true;
                    while (!bNow)
                        SwitchToThread();
                }
                else
                    m_ppLastNotificationItem = &pNotificationItem->m_pNext;
            }
        }
    
        template<typename T>
        void wait(boost::unique_lock<CNotifiedMutex>& m, T pred)
        {
            if (pred())
            {
                return;
            }
    
            // "subscribe" for notification session
            CNotifiedMutex* pNotifiedMutex = m.mutex();
            assert(pNotifiedMutex->m_csLock.LockCount != -1);
            CNotificationItem<T> notificationItem(pNotifiedMutex, pred);
    
            notificationItem.m_pNext = NULL;
            assert(NULL == *m_ppLastNotificationItem);
            *m_ppLastNotificationItem = &notificationItem;
            m_ppLastNotificationItem = &notificationItem.m_pNext;
    
            pNotifiedMutex->unlock();
            while (!notificationItem.m_bNow)
                SwitchToThread();
        }
    
    private:
        CNotificationItemBase* m_pNotificationItems;
        CNotificationItemBase** m_ppLastNotificationItem;
    };
    
    //////////////////////////////////////////////////////////////
    
    template<typename M, typename CV>
    class CReadWriteLock
    {
        enum { QUEUE_SIZE = 1000 };
    
    public:
        CReadWriteLock()
            : m_lockOwnerThread(0)
            , m_lockCount(0)
            , m_tokenCounter(0)
            , m_lockOwnerToken(0)
            , m_readCount(0)
        {
        }
    
        bool Lock(bool write)
        {
            boost::unique_lock<M> lock(m_mutex);
    
            if (GetCurrentThreadId() == m_lockOwnerThread)
            {
                assert(0 == m_readCount);
                m_lockCount++;
                return true;
            }
    
            int token = m_tokenCounter;
            if (write)
            {
                m_tokenCounter++;
                m_condVar.notify_all();
            }
    
            m_condVar.wait(lock, boost::bind(
                &CReadWriteLock::Condition, this, write, token, GetCurrentThreadId()));
    
            if ((m_tokenCounter - token) <= QUEUE_SIZE)
                return true;
    
            return false;
        }
    
    private:
        bool Condition(bool write, int token, DWORD threadID)
        {
            if (m_lockOwnerThread != 0)
                return false;
    
            if ((m_tokenCounter - token) > QUEUE_SIZE)
                return true;
    
            if (write)
            {
                if (0 == m_readCount
                    && (m_lockOwnerToken == token || (token + QUEUE_SIZE) == m_tokenCounter))
                {
                    assert(0 == m_lockOwnerThread);
                    m_lockOwnerThread = threadID;//GetCurrentThreadId();
                    assert(0 == m_lockCount);
                    m_lockCount = 1;
                    m_lockOwnerToken = token;
                    assert(m_tokenCounter != m_lockOwnerToken);
                    return true;
                }
            }
            else
            {
                if (m_tokenCounter == m_lockOwnerToken)
                {
                    m_readCount++;
                    return true;
                }
            }
    
            return false;
        }
    
    public:
        void Unlock()
        {
            boost::unique_lock<M> lock(m_mutex);
            if (GetCurrentThreadId() != m_lockOwnerThread)
            {
                if (0 == m_lockOwnerThread && m_readCount > 0)
                {
                    if (0 == --m_readCount)
                    {
                        m_condVar.notify_all();
                    }
                }
                else
                {
                    assert(0);
                }
                return;
            }
    
            if (0 == --m_lockCount)
            {
                assert(0 == m_readCount);
                assert(0 != m_lockOwnerThread);
    
                m_lockOwnerThread = 0;
                m_lockOwnerToken++;
                m_condVar.notify_all();
            }
        }
    
    private:
        M m_mutex;
        CV m_condVar;
    
        volatile DWORD m_lockOwnerThread;
        volatile int m_lockCount;
        volatile int m_tokenCounter;
        volatile int m_lockOwnerToken;
        volatile int m_readCount;
    };
    
    //////////////////////////////////////////////////////////////
    
    template<typename M, typename CV>
    class CSimpleReadWriteLockTestObject
    {
        CReadWriteLock<M, CV> m_lock;
    
        volatile long m_bWriting;
        volatile long m_lReadCount;
    
        long m_rejectCount;
    
    public:
        CSimpleReadWriteLockTestObject() 
            : m_bWriting(0)
            , m_lReadCount(0)
            , m_rejectCount(0)
        {
        }
    
        void ReadingMethod()
        {
            if (m_lock.Lock(false))
            {
                InterlockedIncrement(&m_lReadCount);
                assert(0 == m_bWriting);
    
                Sleep(0);
    
                InterlockedDecrement(&m_lReadCount);
    
                m_lock.Unlock();
            }
            else
                InterlockedIncrement(&m_rejectCount);
        }
    
        void WritingMethod()
        {
            if (m_lock.Lock(true))
            {
                long bWriting = InterlockedIncrement(&m_bWriting);
                assert(1 == bWriting);
                assert(0 == m_lReadCount);
    
                Sleep(0);
    
                InterlockedDecrement(&m_bWriting);
    
                m_lock.Unlock();
            }
            else
                InterlockedIncrement(&m_rejectCount);
        }
    
        enum { NUM_ITERATIONS = 50000 };
    
        static unsigned int __stdcall ReadingThread(void *param)
        {
            CSimpleReadWriteLockTestObject* pObject = 
                (CSimpleReadWriteLockTestObject*) param;
    
            for (int i = NUM_ITERATIONS; --i >= 0;)	
            {
                pObject->ReadingMethod();
            }
    
            return 0;
        }
    
        static unsigned int __stdcall WritingThread(void *param)
        {
            CSimpleReadWriteLockTestObject* pObject = 
                (CSimpleReadWriteLockTestObject*) param;
    
            for (int i = NUM_ITERATIONS; --i >= 0;)	
            {
                pObject->WritingMethod();
            }
    
            return 0;
    }
    
        static long DoTest()
        {
            enum { NUM_THERADS = 10 };
    
            CSimpleReadWriteLockTestObject testObject;
    
            vector<HANDLE> threads;
            threads.reserve(NUM_THERADS);
    
            for (int i = 0; i < NUM_THERADS / 2; ++i)
            {
                threads.push_back((HANDLE)_beginthreadex( NULL, 0, &ReadingThread, &testObject, 0, NULL ));
                threads.push_back((HANDLE)_beginthreadex( NULL, 0, &WritingThread, &testObject, 0, NULL ));
            }
    
            for (vector<HANDLE>::iterator it(threads.begin()); it != threads.end(); ++it)
            {
                WaitForSingleObject(*it, INFINITE);
                CloseHandle(*it);
            }
    
            return testObject.m_rejectCount;
        }
    };
    
    
    //////////////////////////////////////////////////////////////
    
    int main(int argc, char* argv[])
    {
        clock_t start = clock();
        long rejectCount = CSimpleReadWriteLockTestObject<CNotifiedMutex, CNotifiedCondVar>::DoTest();
        std::cout << "CNotifiedCondVar RWL test executed at " 
            << (double)(clock() - start) / CLOCKS_PER_SEC
            << " seconds; rejected " << rejectCount << " times.\n";
    
        start = clock();
        rejectCount = CSimpleReadWriteLockTestObject<boost::mutex, boost::condition_variable>::DoTest();
        std::cout << "boost::condition_variable RWL test executed at " 
            << (double)(clock() - start) / CLOCKS_PER_SEC
            << " seconds; rejected " << rejectCount << " times.\n";
    
        return 0;
    }
    
    Sunday, April 20th, 2008
    1:42 pm
    Opus #5
    class CThreadFifoQueue
    {
        HANDLE m_guard;
        HANDLE m_notify[2];
        HANDLE m_notificationFinished;
        
        volatile long m_waitCount;
        volatile long m_lockCount;
        volatile bool m_fEvenGeneration;
        
        volatile long m_ticket;
        
    public:
        enum { QUEUE_SIZE = 10 };
        
        CThreadFifoQueue()
            : m_guard(CreateMutex(NULL, FALSE, NULL))
            , m_notificationFinished(CreateEvent(NULL, FALSE, FALSE, NULL))	
            , m_waitCount(0)
            , m_lockCount(0)
            , m_fEvenGeneration(0)
            , m_ticket(0)
        {
            m_notify[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
            m_notify[1] = CreateEvent(NULL, TRUE, FALSE, NULL);
        }
        
        ~CThreadFifoQueue()
        {
            CloseHandle(m_guard);
            CloseHandle(m_notify[0]);
            CloseHandle(m_notify[1]);
            CloseHandle(m_notificationFinished);
        }
        
        void Wait(HANDLE hStopEvent);
    };
    
    void CThreadFifoQueue::Wait(HANDLE hStopEvent)
    {
        // Notifying begins
        VERIFY(WAIT_OBJECT_0 == WaitForSingleObject (m_guard, INFINITE)); // acquire
        
        long ticket = m_ticket++;
        
        ASSERT(0 == m_lockCount);
        if (m_waitCount != 0)
        {
            m_lockCount = m_waitCount;
            m_fEvenGeneration = !m_fEvenGeneration;
            
            // Fire notification and let other threads handle it
            // Note that mutex guards notification session
            VERIFY(SetEvent(m_notify[m_fEvenGeneration]));
            
            // wait till notification handled and acquire
            VERIFY(WAIT_OBJECT_0 == WaitForSingleObject(m_notificationFinished, INFINITE)); 
        }
        
        m_waitCount++; // "subscribe" for notification session
        bool fEvenGeneration = m_fEvenGeneration;
        
        VERIFY(ReleaseMutex(m_guard));
        
        bool bStop = false;
        
        // Waiting begins
        do
        {		
            fEvenGeneration = !fEvenGeneration;
            
            HANDLE events[2] = { m_notify[fEvenGeneration], hStopEvent };
            DWORD dwRes;
            while (WAIT_OBJECT_0 + 2 == (dwRes = MsgWaitForMultipleObjects(2, events, FALSE, INFINITE, QS_ALLINPUT)))
            {	// Handle messages if any
                MSG msg;
                while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
                {
                    CWinThread* pThread = AfxGetThread();
                    if (pThread == NULL || !pThread->PreTranslateMessage(&msg))
                    {
                        TranslateMessage(&msg);
                        DispatchMessage(&msg);
                    }
                }
            }
            
            if (WAIT_OBJECT_0 + 1 == dwRes)
            {	// Handle owner shutdown
                bStop = true;
                HANDLE objects[2] = { m_notify[fEvenGeneration], m_guard };
                
                if (WAIT_OBJECT_0 + 1 == WaitForMultipleObjects(2, objects, FALSE, INFINITE))
                {	// m_guard
                    ASSERT(0 == m_lockCount);
                    m_waitCount--;	// "un-subscribe" from notification session, already synchronized by mutex
                    VERIFY(ReleaseMutex(m_guard));
                    continue; // exit out of outer loop
                }
            }
            
            ASSERT(WAIT_TIMEOUT == WaitForSingleObject(m_guard, 0)); 
            
            if (m_ticket - ticket > QUEUE_SIZE)
            {
                ASSERT(m_ticket - ticket == QUEUE_SIZE + 1);
                bStop = true;
            }
            
            if (bStop)
                InterlockedDecrement((long*)&m_waitCount); // "un-subscribe" from notification session
            
            if (0 == InterlockedDecrement((long*)&m_lockCount))
            {
                VERIFY(ResetEvent(m_notify[fEvenGeneration]));
                VERIFY(SetEvent(m_notificationFinished));
            }
        }
        while (!bStop);
    }
    
    Saturday, January 26th, 2008
    11:34 am
    Opus #4
    #include <iostream>
    #include <algorithm>
    
    using std::swap;
    using std::cout;
    
    struct Box
    {
        int weight, strength;
    };
    
    inline long long fac(int n)
    {
        long long res = 1;
        for (int i = 2; i <= n; ++i)
            res *= i;
        return res;
    }
    
    long long GetNumVariants(Box* pBoxes, 
                             int nCount, 
                             long long nExtraWeight,
                             long long nTotalWeight)
    {
        if (1 == nCount)
            return (pBoxes->strength < nExtraWeight)? 0 : 1;
    
        int i;
        if (nExtraWeight > 0)
            for (i = 0; i < nCount; ++i)
                if (pBoxes[i].strength < nExtraWeight)
                    return 0;
    
        for (i = nCount; --i >= 0; )
            if (pBoxes[i].strength < nTotalWeight)
                break;
        if (-1 == i)
            return fac(nCount);
    
        int nBorder = nCount / 2;
        int* positions = new int[nBorder];  
    
        for (i = 0; i < nBorder; ++i)
            positions[i] = i;
    
        long long nResult = 0;
    
        for (;;)
        {
            for (i = 0; i < nBorder; ++i)
                if (i != positions[i])
                    swap(pBoxes[i], pBoxes[positions[i]]);
    
            int nNewExtraWeight = 0;
            for (i = nBorder; i < nCount; ++i)
                nNewExtraWeight += pBoxes[i].weight;
    
            long long nLower = GetNumVariants(pBoxes, 
                                            nBorder, 
                                            nExtraWeight + nNewExtraWeight,
                                            nTotalWeight);
            if (nLower != 0)
                nResult += nLower * GetNumVariants(pBoxes + nBorder, 
                                            nCount - nBorder, 
                                            nExtraWeight,
                                            nExtraWeight + nNewExtraWeight);
    
            for (i = nBorder; --i >= 0; )
                if (i != positions[i])
                    swap(pBoxes[i], pBoxes[positions[i]]);
    
            if (positions[nBorder - 1] < nCount - 1)
                ++positions[nBorder - 1];
            else
            {
                for (i = nBorder - 1; --i >= 0; )
                    if (positions[i] < positions[i + 1] - 1)
                        break;
                if (i < 0)
                    break;
                int newValue = positions[i];
                do
                    positions[i] = ++newValue;
                while (++i < nBorder);
            }
        }
        delete[] positions;
        return nResult;
    }
    
    int main(int argc, char* argv[])
    {
        Box boxes[] = 
        {
    /*
            { 15, 200,  },
            { 10, 200,  },
            { 13, 170,  },
            { 14, 156,  },
            { 15, 415,  },
            { 18, 514,  },
            { 91, 813, },
            { 16, 192,  },
            { 9,    116,  },
            { 33,   910,  },
            { 21, 89,   },
            { 54, 18,   },
            { 76, 357,  },
            { 76, 876,  },
            { 9,    9, },
            { 1,  99,  },
            { 4,    76,  },
            { 3,  300,  },
            { 12, 654,  },
            { 8,    12,  },
    //*/
    //*
            { 15, 220, },
            { 10, 200, },
            { 13, 170, },
            { 14, 186, },
            { 15, 415, },
            { 8,    584, },
            { 91, 813, },
            { 16, 192, },
            { 9,    116, },
            { 33, 610, },
            { 31, 99,  },
            { 44, 78,  },
            { 71, 357, },
            { 76, 876, },
            { 9,    79, },
            { 1,  99,  },
            { 4,    76,  },
            { 3,  300, },
            { 12, 654, },
            { 8,    120,  },
    //*/
    /*
            { 1, 100 },
            { 1, 100 },
            { 1, 100 },
            { 1, 100 },
            { 1, 100 },
            { 1, 100 },
            { 1, 100 },
            { 1, 100 },
            { 1, 100 },
            { 1, 100 },
            { 1, 100 },
            { 1, 100 },
            { 1, 100 },
            { 1, 100 },
            { 1, 100 },
            { 1, 100 },
            { 1, 100 },
            { 1, 100 },
            { 1, 100 },
            { 1, 100 },
    */
        };
    
        long long nTotalWeight = 0;
        for (int i = 0; i < sizeof(boxes) / sizeof(boxes[0]); ++i)
            nTotalWeight += boxes[i].weight;
    
        long long count = GetNumVariants(boxes, 
                                sizeof(boxes) / sizeof(boxes[0]), 
                                0,
                                nTotalWeight);
        cout << count << '\n';
        return 0;
    }
    
    Friday, January 25th, 2008
    7:02 pm
    Opus #3
    
    // Usage: PUT_AS_SAFE_ARR_TO_VT(vsa, foo1 & foo2);
    // Throws _com_error
    
    namespace SafeArrayToVariantHelpers
    {
    
    template <typename P, typename T>
    class CVarReferrer
    {
        const P& m_prev;
        const T& m_ref;
    
    public:
        enum { OFFSET = P::OFFSET + 1 };
    
        CVarReferrer(const P& prev, const T& ref)
            : m_prev(prev), m_ref(ref) {}
    
        void PutToSafeArray(VARIANT* pData) const
        {
            m_prev.PutToSafeArray(pData);
            static_cast<_variant_t&>(pData[OFFSET]) = m_ref;
        }
    };
    
    class CStubReferrer
    {
    public:
        enum { OFFSET = -1 };
    
        void PutToSafeArray(VARIANT*) const
        {
        }
    };
    
    template<typename T>
    inline void DoPutAsSafeArrayToVariant(VARIANT& vsa, const T& params)
    {
        _com_util::CheckError(VariantClear(&vsa));
        V_ARRAY(&vsa) = SafeArrayCreateVector(VT_VARIANT, 0, T::OFFSET + 1);
        vsa.vt = VT_VARIANT | VT_ARRAY;
    
        VARIANT* pData = NULL;
    
        _com_util::CheckError(SafeArrayAccessData(V_ARRAY(&vsa), (void **)&pData));
        try
        {
            params.PutToSafeArray(pData);
        }
        catch (...)
        {
            SafeArrayUnaccessData(V_ARRAY(&vsa));
            throw;  
        }
        _com_util::CheckError(SafeArrayUnaccessData(V_ARRAY(&vsa)));
    }
    
    template <typename P, typename T>
    inline CVarReferrer<P, T> operator & (const P& prev, const T& input)
    {
        return CVarReferrer<P, T>(prev, input);
    }
    
    }
    
    
    #define PUT_AS_SAFE_ARR_TO_VT(vsa, params) \
        SafeArrayToVariantHelpers::DoPutAsSafeArrayToVariant( \
            vsa, SafeArrayToVariantHelpers::CStubReferrer() & params)
    
    
    Thursday, January 24th, 2008
    3:09 pm
    Opus #2
    
    #include <iostream>
    
    using std::cout; 
    
    long g_buf[1024]; 
    int g_arrValues[25]; 
    int g_arrBest[25]; 
    int g_nLevels; 
    int g_nBest; 
    
    void Step(int nLevel) 
    {
        int nVal = g_arrValues[nLevel++]; 
    
        if(nLevel == g_nLevels) 
        {
            while(g_buf[nVal++] != 0); 
    
            if(nVal > g_nBest) 
            {
                for(int i = 0; i < nLevel; i++) 
                    g_arrBest[i] = g_arrValues[i];
                g_nBest = nVal;
            }
        }
        else 
        {
            do 
            {
                ++g_buf[nVal++];
    
                long* pFrom = g_buf; 
                long* pTo = g_buf + nVal;
                int nCount = (nVal + 7) / 8; 
    
                switch (nVal & 7) 
                {
                case 0: 
                    do 
                    {
                        *pTo++ += short(*pFrom++) << 8; *pTo++ += short(*pFrom++) << 8; 
                case 7: *pTo++ += short(*pFrom++) << 8; *pTo++ += short(*pFrom++) << 8; 
                case 6: *pTo++ += short(*pFrom++) << 8; *pTo++ += short(*pFrom++) << 8; 
                case 5: *pTo++ += short(*pFrom++) << 8; *pTo++ += short(*pFrom++) << 8; 
                case 4: *pTo++ += short(*pFrom++) << 8; *pTo++ += short(*pFrom++) << 8; 
                case 3: *pTo++ += short(*pFrom++) << 8; *pTo++ += short(*pFrom++) << 8; 
                case 2: *pTo++ += short(*pFrom++) << 8; *pTo++ += short(*pFrom++) << 8; 
                case 1: *pTo++ += short(*pFrom++) << 8; *pTo++ += short(*pFrom++) << 8; 
                    }
                    while(--nCount > 0); 
                }
    
                g_arrValues[nLevel] = nVal;
    
                Step(nLevel);
    
                pFrom = g_buf + nVal * 2 - 1;
                pTo = g_buf + nVal * 3 - 1;
                nCount = (nVal + 7) / 8;
    
                switch (nVal & 7) 
                {
                case 0: 
                    do 
                    {
                        *pTo-- -= short(*pFrom--) << 8; *pTo-- -= short(*pFrom--) << 8; 
                case 7: *pTo-- -= short(*pFrom--) << 8; *pTo-- -= short(*pFrom--) << 8; 
                case 6: *pTo-- -= short(*pFrom--) << 8; *pTo-- -= short(*pFrom--) << 8; 
                case 5: *pTo-- -= short(*pFrom--) << 8; *pTo-- -= short(*pFrom--) << 8; 
                case 4: *pTo-- -= short(*pFrom--) << 8; *pTo-- -= short(*pFrom--) << 8; 
                case 3: *pTo-- -= short(*pFrom--) << 8; *pTo-- -= short(*pFrom--) << 8; 
                case 2: *pTo-- -= short(*pFrom--) << 8; *pTo-- -= short(*pFrom--) << 8; 
                case 1: *pTo-- -= short(*pFrom--) << 8; *pTo-- -= short(*pFrom--) << 8; 
                    }
                    while(--nCount > 0); 
                }
            }
            while(--g_buf[nVal-1] != 0); 
        }
    }
    
    int main(int argc, char* argv[]) 
    {
        g_nBest = 0;
        g_arrValues[0] = 1;
        g_buf[0] = 0x00000001;
        g_buf[1] = 0x00000100;
        g_buf[2] = 0x00010000;
        g_nLevels = 9;
    
        Step(0);
    
        cout << "Max sum: " << g_nBest - 1 <<'\n';
    
        for (int i = 0; i < g_nLevels; ++i) 
            cout << g_arrBest[i] << ' ';
    
        cout << '\n';
    
        return 0; 
    }
    
    
    Tuesday, January 22nd, 2008
    6:29 pm
    Opus #1
    #include <google/dense_hash_map>
    
    
    namespace __gnu_cxx
    {
        template<> struct hash<const void*>
        {
            size_t operator()(const void* p) const
            { 
                return size_t(p) >> 4;
            }
        };
    }
    
    
    namespace ThreadCollision
    {
    
    struct Entry
    {
        unsigned __int64 m_sumThreadIDs;
        unsigned __int64 m_sumSqrThreadIDs;
        int m_nCount;
        int m_nMutatingCount;
    
        LPCSTR m_lpszMutatingFileName;
        int m_nMutatingLine;
    
        Entry() 
            : m_sumThreadIDs(0)
            , m_sumSqrThreadIDs(0)
            , m_nCount(0)
            , m_nMutatingCount(0)
            , m_lpszMutatingFileName(0)
            , m_nMutatingLine(0)
        {}
    
        Entry(DWORD threadID, bool bMutating) 
            : m_sumThreadIDs(threadID)
            , m_sumSqrThreadIDs((unsigned __int64)threadID * threadID)
            , m_nCount(1)
            , m_nMutatingCount(bMutating? 1 : 0)
            , m_lpszMutatingFileName(0)
            , m_nMutatingLine(0)
        {}
    
        bool IsInOneThread()
        {
            return m_sumThreadIDs * m_sumThreadIDs == m_sumSqrThreadIDs * m_nCount;
        }
        DWORD GetThreadId()
        {
            ASSERT(m_nCount > 0);
            return DWORD(m_sumThreadIDs / m_nCount);
        }
    };
    
    class CEntryMap 
    : public GOOGLE_NAMESPACE::dense_hash_map<const void*, Entry>
    {
        static bool& GetDestructing()
        {
            static bool g_bDestructing;
            return g_bDestructing;
        }
    
    public:
        CEntryMap()
        {
            set_empty_key(NULL);
            set_deleted_key((const char*)NULL + 1);
        }
    
        ~CEntryMap()
        {
            GetDestructing() = true;
        }
    
        static bool IsDestructing()
        {
            return GetDestructing();
        }
    };
    
    
    template <typename T, int N>
    class CThreadCollisionDetectorBase
    {
    public:
        enum { NUM_ENTRIES = N };
        
    
    protected:
        const void* m_p;
        bool m_bMutating; // to be set in subclass constructors
    
        static CEntryMap s_entryMaps[NUM_ENTRIES];
        static CComAutoCriticalSection s_entryCritSecs[NUM_ENTRIES];
    
        void CommonConstructBase(LPCSTR lpszFileName, int nLine)
        {
            if (CEntryMap::IsDestructing())
                return;
    
            const DWORD threadID(GetCurrentThreadId());
            const int idx = DWORD_PTR(m_p) % NUM_ENTRIES;
    
            s_entryCritSecs[idx].Lock();
            std::pair<CEntryMap::iterator, bool> ins 
                (s_entryMaps[idx].insert(
                    CEntryMap::value_type(m_p, Entry(threadID, m_bMutating))));
    
            Entry& entry = ins.first->second;
            
            if (!ins.second)
            {
                const bool isInOneThread(entry.IsInOneThread());
                const DWORD otherThreadId(entry.GetThreadId());
    
                if (!(!m_bMutating && 0 == entry.m_nMutatingCount 
                    || isInOneThread && otherThreadId == threadID))
                {
                    CString strTrace;
                    if (0 != entry.m_nMutatingCount)
                        strTrace.Format(
                            _T("Thread collision: current %s thread at %s:%d, other mutating thread at %s:%d.\n"),
                            m_bMutating? _T("mutating") : _T("reading"), 
                            lpszFileName, 
                            nLine, 
                            entry.m_lpszMutatingFileName,
                            entry.m_nMutatingLine);
                    else
                        strTrace.Format(
                            "Thread collision: current %s thread at %s:%d, other threads are reading.\n",
                            m_bMutating? _T("mutating") : _T("reading"), 
                            lpszFileName, 
                            nLine);
                    static_cast<T*>(this)->Trace(strTrace);
                }
    
    
                entry.m_sumThreadIDs += threadID;
                entry.m_sumSqrThreadIDs += (unsigned __int64)threadID * threadID;
                ++entry.m_nCount;
                if (m_bMutating)
                    ++entry.m_nMutatingCount;
            }
    
            if (m_bMutating && 1 == entry.m_nMutatingCount) // first time but already set/incremented to 1
            {
                entry.m_lpszMutatingFileName = lpszFileName;
                entry.m_nMutatingLine = nLine;
            }
    
            s_entryCritSecs[idx].Unlock();
        }
    
    protected:
        CThreadCollisionDetectorBase() 
            : m_p(NULL), m_bMutating(false)
        {
        }
    
    public:
        ~CThreadCollisionDetectorBase()
        {
            if (CEntryMap::IsDestructing())
                return;
    
            const DWORD threadID(GetCurrentThreadId());
            const int idx = DWORD_PTR(m_p) % NUM_ENTRIES;
            s_entryCritSecs[idx].Lock();
            CEntryMap::iterator it(s_entryMaps[idx].find(m_p));
            if (it != s_entryMaps[idx].end())
            {
                Entry& entry = it->second;
                if (0 == --entry.m_nCount)
                {
                    s_entryMaps[idx].erase(it);
                }
                else
                {
                    entry.m_sumThreadIDs -= threadID;
                    entry.m_sumSqrThreadIDs -= (unsigned __int64)threadID * threadID;
                    if (m_bMutating)
                        --entry.m_nMutatingCount;
                }
            }
            else
                ASSERT(0);
            s_entryCritSecs[idx].Unlock();
        }
    };
    
    }; // namespace ThreadCollision
    
    Saturday, November 17th, 2007
    4:09 am
    Shiny Summer Souvenir
    Here it is.

    0115
    Originally uploaded by aliakseis
    Saturday, October 27th, 2007
    12:37 pm
    Sunshine Reggae - MSVC specific
    That's the Sunshine Reggae (MSVC specific):
    // MockObject.h
    #pragma once
    
    #include <memory.h>
    #include <assert.h>
    
    class CMockObject
    {
        template <bool x> struct STATIC_ASSERTION_FAILURE;
    
        template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
    
        template<int x> struct static_assert_test{};
    
        #define DECL_TEN(hundreds, tens)	\
            FINAL_V_DECL(hundreds, tens, 0) \
            FINAL_V_DECL(hundreds, tens, 1) \
            FINAL_V_DECL(hundreds, tens, 2) \
            FINAL_V_DECL(hundreds, tens, 3) \
            FINAL_V_DECL(hundreds, tens, 4) \
            FINAL_V_DECL(hundreds, tens, 5) \
            FINAL_V_DECL(hundreds, tens, 6) \
            FINAL_V_DECL(hundreds, tens, 7) \
            FINAL_V_DECL(hundreds, tens, 8) \
            FINAL_V_DECL(hundreds, tens, 9) 
    
        #define DECL_HUNDRED(hundreds)\
            DECL_TEN(hundreds, 0) \
            DECL_TEN(hundreds, 1) \
            DECL_TEN(hundreds, 2) \
            DECL_TEN(hundreds, 3) \
            DECL_TEN(hundreds, 4) \
            DECL_TEN(hundreds, 5) \
            DECL_TEN(hundreds, 6) \
            DECL_TEN(hundreds, 7) \
            DECL_TEN(hundreds, 8) \
            DECL_TEN(hundreds, 9) 
    
        #define DECL_RETRIEVER \
            DECL_HUNDRED(0) \
            DECL_HUNDRED(1) \
            DECL_HUNDRED(2) \
            DECL_HUNDRED(3) \
            DECL_HUNDRED(4) \
            DECL_HUNDRED(5) \
            DECL_HUNDRED(6) \
            DECL_HUNDRED(7) \
            DECL_HUNDRED(8) \
            DECL_HUNDRED(9) 
    
        #define FINAL_V_DECL(hundreds, tens, units) \
            virtual int V##hundreds##tens##units() { return hundreds * 100 + tens * 10 + units; };
    
        class CThisCallVtIdxRetriever
        {
            DECL_RETRIEVER
        };
    
        #undef FINAL_V_DECL	
        #define FINAL_V_DECL(hundreds, tens, units) \
            virtual int __cdecl V##hundreds##tens##units() { return hundreds * 100 + tens * 10 + units; };
    
        class CCdeclVtIdxRetriever
        {
            DECL_RETRIEVER
        };
    
        #undef FINAL_V_DECL	
        #define FINAL_V_DECL(hundreds, tens, units) \
            virtual int __stdcall V##hundreds##tens##units() { return hundreds * 100 + tens * 10 + units; };
    
        class CStdCallVtIdxRetriever
        {
            DECL_RETRIEVER
        };
    
        #undef FINAL_V_DECL	
        #define FINAL_V_DECL(hundreds, tens, units) \
            virtual int __fastcall V##hundreds##tens##units() { return hundreds * 100 + tens * 10 + units; };
    
        class CFastCallVtIdxRetriever
        {
            DECL_RETRIEVER
        };
    
        #undef DECL_RETRIEVER
        #undef DECL_HUNDRED
        #undef DECL_TEN
        #undef FINAL_V_DECL
            
    protected:
        void** const m_ppVT;
    
        CMockObject()
            : m_ppVT(new void*[1000])
        {
            memset(m_ppVT, 0, sizeof(void*) * 1000);
        }
        ~CMockObject()
        {
            delete[] m_ppVT;
        }
    
    private:
        template <typename SRC_FUN, typename MOCK_FUN>
        void DoInstantiateThisCall(SRC_FUN pFun, MOCK_FUN pSubst)
        {
            int (CThisCallVtIdxRetriever::*pV)() = (int (CThisCallVtIdxRetriever::*)()) pFun;
            const int idx = (CThisCallVtIdxRetriever().*pV)();
            ((MOCK_FUN*) m_ppVT)[idx] = pSubst;
        }
        template <typename SRC_FUN, typename MOCK_FUN>
        void DoInstantiateCdecl(SRC_FUN pFun, MOCK_FUN pSubst)
        {
            int (__cdecl CCdeclVtIdxRetriever::*pV)() = (int (__cdecl CCdeclVtIdxRetriever::*)()) pFun;
            const int idx = (CCdeclVtIdxRetriever().*pV)();
            ((MOCK_FUN*) m_ppVT)[idx] = pSubst;
        }
        template <typename SRC_FUN, typename MOCK_FUN>
        void DoInstantiateStdCall(SRC_FUN pFun, MOCK_FUN pSubst)
        {
            int (__stdcall CStdCallVtIdxRetriever::*pV)() = (int (__stdcall CStdCallVtIdxRetriever::*)()) pFun;
            const int idx = (CStdCallVtIdxRetriever().*pV)();
            ((MOCK_FUN*) m_ppVT)[idx] = pSubst;
        }
        template <typename SRC_FUN, typename MOCK_FUN>
        void DoInstantiateFastCall(SRC_FUN pFun, MOCK_FUN pSubst)
        {
            int (__fastcall CFastCallVtIdxRetriever::*pV)() = (int (__fastcall CFastCallVtIdxRetriever::*)()) pFun;
            const int idx = (CFastCallVtIdxRetriever().*pV)();
            ((MOCK_FUN*) m_ppVT)[idx] = pSubst;
        }
    
    protected:
    
    #define DECL_EMPTY
    #define DECL_VARARGS_0 ...
    #define DECL_VARARGS_X , ...
    #define DECL_INSTANTIATE(convention, modifier, varargs0, varargsX, DoInstantiate, Instantiate) \
        /* no parameters */ \
        template<typename R, typename SRC, typename MOCK> \
        void Instantiate(R (convention SRC::*pFun)(varargs0) modifier \
            , R (convention MOCK::*pSubst)(varargs0) modifier) \
        { \
            DoInstantiate(pFun, pSubst); \
        } \
        /* one parameter */ \
        template<typename P, typename R, typename SRC, typename MOCK> \
        void Instantiate(R (convention SRC::*pFun)(P varargsX) modifier \
            , R (convention MOCK::*pSubst)(P varargsX) modifier) \
        { \
            DoInstantiate(pFun, pSubst); \
        } \
        /* two parameters */ \
        template<typename P1, typename P2, \
                    typename R, typename SRC, typename MOCK> \
        void Instantiate(R (convention SRC::*pFun)(P1, P2 varargsX) modifier \
            , R (convention MOCK::*pSubst)(P1, P2 varargsX) modifier) \
        { \
            DoInstantiate(pFun, pSubst); \
        } \
        /* three parameters */ \
        template<typename P1, typename P2, typename P3, \
                    typename R, typename SRC, typename MOCK> \
        void Instantiate(R (convention SRC::*pFun)(P1, P2, P3 varargsX) modifier \
            , R (convention MOCK::*pSubst)(P1, P2, P3 varargsX) modifier) \
        { \
            DoInstantiate(pFun, pSubst); \
        } \
        /* four parameters */ \
        template<typename P1, typename P2, typename P3, typename P4, \
                    typename R, typename SRC, typename MOCK> \
        void Instantiate(R (convention SRC::*pFun)(P1, P2, P3, P4 varargsX) modifier \
            , R (convention MOCK::*pSubst)(P1, P2, P3, P4 varargsX) modifier) \
        { \
            DoInstantiate(pFun, pSubst); \
        } \
        /* five parameters */ \
        template<typename P1, typename P2, typename P3, typename P4, typename P5, \
                    typename R, typename SRC, typename MOCK> \
        void Instantiate(R (convention SRC::*pFun)(P1, P2, P3, P4, P5 varargsX) modifier \
            , R (convention MOCK::*pSubst)(P1, P2, P3, P4, P5 varargsX) modifier) \
        { \
            DoInstantiate(pFun, pSubst); \
        }  \
        /* six parameters */ \
        template<typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, \
                    typename R, typename SRC, typename MOCK> \
        void Instantiate(R (convention SRC::*pFun)(P1, P2, P3, P4, P5, P6 varargsX) modifier \
            , R (convention MOCK::*pSubst)(P1, P2, P3, P4, P5, P6 varargsX) modifier) \
        { \
            DoInstantiate(pFun, pSubst); \
        }
    
    #define DECL_INSTANTIATE_CONVENTION(convention, CustomInstantiate) \
        DECL_INSTANTIATE(DECL_EMPTY convention, DECL_EMPTY,	DECL_EMPTY,	DECL_EMPTY,	CustomInstantiate, Instantiate) \
        DECL_INSTANTIATE(DECL_EMPTY convention, const,		DECL_EMPTY,	DECL_EMPTY,	CustomInstantiate, Instantiate)
    
        DECL_INSTANTIATE_CONVENTION(DECL_EMPTY, DoInstantiateThisCall)
        DECL_INSTANTIATE_CONVENTION(__cdecl, DoInstantiateCdecl)
        DECL_INSTANTIATE_CONVENTION(__stdcall, DoInstantiateStdCall)
        DECL_INSTANTIATE_CONVENTION(__fastcall, DoInstantiateFastCall)
    
        DECL_INSTANTIATE(__cdecl, DECL_EMPTY,	DECL_VARARGS_0, DECL_VARARGS_X, DoInstantiateCdecl, InstantiateVA)
        DECL_INSTANTIATE(__cdecl, const,		DECL_VARARGS_0, DECL_VARARGS_X, DoInstantiateCdecl, InstantiateVA)
    
    #undef DECL_INSTANTIATE
    #undef DECL_EMPTY
    #undef DECL_VARARGS_0
    #undef DECL_VARARGS_X
    
        template<typename T> size_t GetTypeMemberOffset(T& r)
        {
            size_t nOffset = (size_t)&reinterpret_cast<const volatile char&>(r);
            return nOffset;
        }
    
        template<typename T> void ExecuteStructor(T& r, bool construct)
        {
            int nOffset = GetTypeMemberOffset(r);
            void* pBuf = (char*) this + nOffset;
            if (construct)
            {
                ::new(pBuf) T();
            }
            else
            {
                ((T*) pBuf)->~T();
            }
        }
    };
    
    #define DECLARE_MOCK_MEMBERS(src, mock)					\
    public:									\
        typedef src TMockOrigin;						\
        char m_membersAllocBuffer[sizeof(src)];				\
        void CheckReservedBytesOK()						\
        {									\
            /* test whether members buffer is adjacent to 'vptr' */		\
            /* fails if there are virtual functions in mock as well */	\
                typedef static_assert_test<					\
                  sizeof(STATIC_ASSERTION_FAILURE				\
                  <offsetof(mock, m_membersAllocBuffer) == sizeof(void**)>)> \
                static_assert_typedef_;					\
        }									\
        class CStructorsExecutor						\
        {	/* no members */						\
            void ExecuteStructors(bool construct)				\
            {								\
                mock* pParent = (mock*)					\
                    ((char*)this - offsetof(mock, m_ctorsExecutor));	\
                pParent->ExecuteStructors(construct);			\
            }								\
        public:								\
            CStructorsExecutor()						\
            {								\
                 ExecuteStructors(true);					\
            }								\
            ~CStructorsExecutor()						\
            {								\
                 ExecuteStructors(false);					\
            }								\
        } m_ctorsExecutor;							\
    public:									\
        void ExecuteStructors(bool construct)				\
        {									\
            int iMemberCountN = -1;						\
            EnumerateStructors(iMemberCountN, construct);			\
            iMemberCountN = ~iMemberCountN;					\
            if (construct)							\
            {								\
                int i = 0;							\
                try								\
                {								\
                    for (; i < iMemberCountN; ++i)				\
                    {							\
                        ExecuteNthStructor(i, construct);			\
                    }							\
                }								\
                catch (...)							\
                {								\
                    for (; i >= 0; --i)					\
                    {							\
                        ExecuteNthStructor(i, false);			\
                    }							\
                    throw;							\
                }								\
            }								\
            else								\
                for (int i = iMemberCountN; --i >= 0; )			\
                {								\
                    ExecuteNthStructor(i, construct);			\
                }								\
        }									\
        void ExecuteNthStructor(int iMemberToCall, bool construct)		\
        {									\
            EnumerateStructors(iMemberToCall, construct);			\
            assert(0 == iMemberToCall);					\
        }									\
        void EnumerateStructors(int& iMemberToCall, bool construct)
    
    
    // It is not necessary to declare POD types
    #define DECLARE_MOCK_MEMBER(member)					\
            if (0 == iMemberToCall)						\
            {								\
                ExecuteStructor(((TMockOrigin*)0)->member, construct);	\
                return;							\
            }								\
            --iMemberToCall;
    

    That's an example of its usage:
    #include "MockObject.h"
    
    #include <iostream>
    #include <sstream>
    
    using std::string;
    using std::ostringstream;
    using std::cerr;
    
    class A
    {
    public:
        virtual string Dummy0(int*);
    
        virtual string Dummy0(int) const;
    
        virtual void Dummy2(char*);
        virtual void __stdcall StdCall(char*);
    
        virtual int Dummy3();
        virtual int Dummy3Const() const;
    
        virtual string SomeOtherTest(int i, int& j);
    
        virtual int TakeThree(int i, int j, int k);
    
        virtual int TakeFour(int i, int j, int k, int l);
    
        virtual int TakeThreeConst(int i, int j, int k) const;
    
        virtual int TakeFourConst(int i, int j, int k, int l) const;
    
        virtual int TakeFive(int i, int j, int k, int l, int m);
        virtual int TakeFiveConst(int i, int j, int k, int l, int m) const;
    
        virtual double TakeFive2(int i, int j, int k, int l, int m);
    
        virtual double Test2ThisCall(int i, int& j);
        virtual double __cdecl Test2Cdecl(int i, int& j);
        virtual double __stdcall Test2StdCall(int i, int& j);
        virtual double __fastcall Test2FastCall(int i, int& j);
    
        virtual double TestVarArgsThisCall(int i, ...);
    
        virtual double TestVarArgs0ThisCall(...);
    
        int dummy;
    
        string buffer2;
    
        int dummy2;
    
        string buffer;
    };
    
    class CXTest : public CMockObject
    {
    public:
        
        CXTest()
        {
            Instantiate(static_cast<string (A::*)(int) const>(&A::Dummy0), &CXTest::DoTest);
            Instantiate(static_cast<string (A::*)(int*)>(&A::Dummy0), &CXTest::DoAnotherTest);
            Instantiate(&A::Dummy2, &CXTest::YetAnotherTest);
            Instantiate(&A::StdCall, &CXTest::StdCall);
    
            Instantiate(&A::Dummy3, &CXTest::NoParamsTest);
            Instantiate(&A::Dummy3Const, &CXTest::NoParamsTestConst);
            Instantiate(&A::TakeThree, &CXTest::TakeThree);
            Instantiate(&A::TakeFour, &CXTest::TakeFour);
            Instantiate(&A::TakeThreeConst, &CXTest::TakeThreeConst);
            Instantiate(&A::TakeFourConst, &CXTest::TakeFourConst);
            Instantiate(&A::TakeFive, &CXTest::TakeFive);
            Instantiate(&A::TakeFive2, &CXTest::TakeFive2);
            Instantiate(&A::TakeFiveConst, &CXTest::TakeFiveConst);
    
            Instantiate(&A::SomeOtherTest, &CXTest::SomeOtherTest);
    
            Instantiate(&A::Test2ThisCall, &CXTest::Test2ThisCall);
            Instantiate(&A::Test2Cdecl, &CXTest::Test2Cdecl);
            Instantiate(&A::Test2StdCall, &CXTest::Test2StdCall);
            Instantiate(&A::Test2FastCall, &CXTest::Test2FastCall);
    
            InstantiateVA(&A::TestVarArgsThisCall, &CXTest::TestVarArgsThisCall);
            InstantiateVA(&A::TestVarArgs0ThisCall, &CXTest::TestVarArgs0ThisCall);
        }
    
        DECLARE_MOCK_MEMBERS(A, CXTest)
        {
            DECLARE_MOCK_MEMBER(buffer)
            DECLARE_MOCK_MEMBER(buffer2)
        }
    
        string DoTest(int i) const
        {
            ostringstream s;
            s << i;
            return s.str();
        }
    
        string DoAnotherTest(int* i) 
        {
            ostringstream s;
            s << -*i;
            return s.str();
        }
    
        void YetAnotherTest(char* p)
        {
            ((A*)this)->buffer = p;
        }
    
        void __stdcall StdCall(char* p)
        {
            ((A*)this)->buffer = p;
        }
    
        int NoParamsTest() 
        {
            return ((A*)this)->dummy;
        }
        int NoParamsTestConst() const
        {
            return ((A*)this)->dummy;
        }
    
        string SomeOtherTest(int i, int& j)
        {
            j = i;
            return ((A*)this)->buffer2;
        }
    
        int TakeThree(int i, int j, int k)
        {
            return i + j + k;
        }
    
        int TakeFour(int i, int j, int k, int l)
        {
            return i + j + k + l;
        }
    
        int TakeThreeConst(int i, int j, int k) const
        {
            return i + j + k;
        }
    
        int TakeFourConst(int i, int j, int k, int l) const
        {
            return i + j + k + l;
        }
    
        int TakeFive(int i, int j, int k, int l, int m)
        {
            return i + j + k + l + m;
        }
    
        double TakeFive2(int i, int j, int k, int l, int m)
        {
            return i + j + k + l + m;
        }
    
        int TakeFiveConst(int i, int j, int k, int l, int m) const
        {
            return i + j + k + l + m;
        }
    
        double Test2ThisCall(int i, int& j)
        {
            return 0.1;
        }
        double __cdecl Test2Cdecl(int i, int& j)
        {
            return 0.2;
        }
        double __stdcall Test2StdCall(int i, int& j)
        {
            return 0.3;
        }
        double __fastcall Test2FastCall(int i, int& j)
        {
            return 0.4;
        }
    
        double TestVarArgsThisCall(int i, ...)
        {
            return 11.;
        }
    
        double TestVarArgs0ThisCall(...)
        {
            return 21.;
        }
    };
    
    #define CHECK_EQUAL(a, b) \
        if ((a) == (b)); else cerr << "CHECK_EQUAL failed at " __FILE__ "(" << __LINE__ << ")\n";
    
    int main()
    {
        CXTest test;
    
        A* pA = (A*) &test;
    
        CHECK_EQUAL("777", pA->Dummy0(777));
    
        int i = 999;
        CHECK_EQUAL("-999", pA->Dummy0(&i));
    
        pA->Dummy2("YetAnotherTest");
        CHECK_EQUAL("YetAnotherTest", pA->buffer);
    
        pA->StdCall("StdCallTest");
        CHECK_EQUAL("StdCallTest", pA->buffer);
    
        pA->dummy = 3456;
        CHECK_EQUAL(3456, pA->Dummy3());
        CHECK_EQUAL(3456, pA->Dummy3Const());
    
        int j = 0;
        pA->buffer2 = "This would be to miss an opportunity.";
        CHECK_EQUAL("This would be to miss an opportunity.", pA->SomeOtherTest(i, j));
        CHECK_EQUAL(i, j);
    
        CHECK_EQUAL(6, pA->TakeThree(1, 2, 3));
        CHECK_EQUAL(10, pA->TakeFour(1, 2, 3, 4));
    
        CHECK_EQUAL(6, pA->TakeThreeConst(1, 2, 3));
        CHECK_EQUAL(10, pA->TakeFourConst(1, 2, 3, 4));
    
        CHECK_EQUAL(15, pA->TakeFive(1, 2, 3, 4, 5));
        CHECK_EQUAL(15, pA->TakeFiveConst(1, 2, 3, 4, 5));
    
        CHECK_EQUAL(0.1, pA->Test2ThisCall(1, j));
        CHECK_EQUAL(0.2, pA->Test2Cdecl(1, j));
        CHECK_EQUAL(0.3, pA->Test2StdCall(1, j));
        CHECK_EQUAL(0.4, pA->Test2FastCall(1, j));
    
        CHECK_EQUAL(11., pA->TestVarArgsThisCall(1, j));
        CHECK_EQUAL(21., pA->TestVarArgs0ThisCall(1, j));
    }
    
    Thursday, November 30th, 2006
    12:01 am
    Database Connection Pools and Oracle LOBs
    Various pools are used to cache JDBC connections. It can cause problems with Oracle LOBs since these pools hide Oracle specific objects from the client and prevent from obtaining oracle.sql.BLOB or oracle.sql.CLOB instances.

    The next code snippet can help:
        private Object createTemporary(Connection conn,
                                       boolean cache,
                                       int duration,
                                       int lobType)
                                throws SQLException {
            CallableStatement cstmt = null;
            try {
                String query =
                    "{call dbms_lob.createtemporary(?, " + cache + ", " + duration + ")}";
                cstmt = conn.prepareCall(query);
                cstmt.registerOutParameter(1, lobType);
                cstmt.execute();
                return cstmt.getObject(1);
            } finally {
                if (cstmt != null) {
                    cstmt.close();
                }
            }
        }
    


    It is used as follows:
        BLOB blob = (BLOB) createTemporary(connection, false,
                        BLOB.DURATION_CALL, java.sql.Types.BLOB);
    
        CLOB clob = (CLOB) createTemporary(connection, true,
                        CLOB.DURATION_SESSION, java.sql.Types.CLOB);
    
    Sunday, November 26th, 2006
    12:31 pm
    Trigonometric etude
    A smooth plane trajectory without sharp transitions consists of five segments, sequentially: linear, circular, linear, circular and linear ones. Hence we have eight parameters:
    • l1 - the first segment length

    • phi1 - the first segment deviation angle

    • r1 - the second segment radius

    • l2 - the third segment length

    • phi2 - the third segment deviation angle

    • r2 - the fourth segment radius

    • l3 - the fifth segment length

    • phi3 - the fifth segment deviation angle.

    Provided any six of these parameters and the trajectory extension in two directions are known, the missing two ones are to be calculated if possible.

    The console application source code and test Windows batch file are here:

    #define _USE_MATH_DEFINES
    #include <math.h>
    #include <assert.h>
    
    #include <iostream>
    
    using std::cout;
    using std::cerr;
    
    
    struct PLANE_TRAJ_CELL
    {
        double L, Phi, R;
    };
    
    typedef PLANE_TRAJ_CELL PLANE_TRAJ_ARR[3];
    
    class CPlaneTrajectory
    {
    public:
    
        enum {
            M_TURN     = 1,
            M_ROT_DOWN = 2,
            M_ROT_UP   = 4,
    
            F_L1    = 0x0080,
            F_PHI1  = 0x0040,
            F_R1    = 0x0020,
            F_L2    = 0x0010,
            F_PHI2  = 0x0008,
            F_R2    = 0x0004,
            F_L3    = 0x0002,
            F_PHI3  = 0x0001,
        };
    
        CPlaneTrajectory()
        {
            memset(m_c, 0, sizeof(m_c));
            m_fX = 0;
            m_fY = 0;
        };
    
        bool Calculate(double* pParameters, double fX, double fY, int nMode);
    
    protected:
        void SetData(double* pParameters);
        void GetData(double* pParameters);
        void ToCanonical(int nFlags);
        void FromCanonical(int nFlags);
        double GetXError();
        double GetYError();
    
        bool FindSolution2x2();
        void FindAngle();
        bool SimpleTrigonometric();
        bool AdvancedTrigonometric();
    
        bool CalcLwhereR();
        bool CalcLltR();
        bool CalcLL();
        bool CalcRR();
        bool CalcLwherePhi();
        bool CalcLltPhi();
        bool CalcRwherePhi();
        bool CalcRgtPhi();
        bool CalcPhiPhi();
    
        bool Calc(bool (CPlaneTrajectory::*doCalc)(), int nFlags)
        {
            ToCanonical(nFlags);
            bool result = (this->*doCalc)();
            FromCanonical(nFlags);
            return result;
        }
    
    private:
        PLANE_TRAJ_ARR m_c;
        double sin0, sin1, sin2,
                cos0, cos1, cos2,
                fA, fB, fC, fD, fE, fF, fG, fH,
                m_fX, m_fY;
    };
    
    
    ////////////////////////////////////////////////
    //  Math methods
    
    const double EPSILON = 1e-8;
    
    void Turn(PLANE_TRAJ_ARR m_c)
    {
        double fBuf = m_c[0].L;
        m_c[0].L = m_c[2].L;
        m_c[2].L = fBuf;
        fBuf = m_c[0].Phi;
        m_c[0].Phi = m_c[2].Phi;
        m_c[2].Phi = fBuf;
        fBuf = m_c[0].R;
        m_c[0].R = -m_c[1].R;
        m_c[1].R = -fBuf;
    }
    
    void RotateDown(PLANE_TRAJ_ARR m_c)
    {
        PLANE_TRAJ_CELL Buf = m_c[2];
        m_c[2] = m_c[1];
        m_c[1] = m_c[0];
        m_c[0] = Buf;
    }
    
    void RotateUp(PLANE_TRAJ_ARR m_c)
    {
        PLANE_TRAJ_CELL Buf = m_c[0];
        m_c[0] = m_c[1];
        m_c[1] = m_c[2];
        m_c[2] = Buf;
    }
    
    inline void Normalize(double& fPhi)
    {
        while (fPhi > M_PI) fPhi -= 2 * M_PI;
        while (fPhi <-M_PI) fPhi += 2 * M_PI;
    }
    
    void CPlaneTrajectory::SetData(double* pParameters)
    {
        for (int i = 0;; ++i)
        {
            m_c[i].L = *pParameters++;
            m_c[i].Phi = *pParameters++;
            if (2 == i)
                break;
            m_c[i].R = *pParameters++;
        }
    }
    
    void CPlaneTrajectory::GetData(double* pParameters)
    {
        for (int i = 0;; ++i)
        {
            *pParameters++ = m_c[i].L;
            *pParameters++ = m_c[i].Phi;
            if (2 == i)
                break;
            *pParameters++ = m_c[i].R;
        }
    }
    
    void CPlaneTrajectory::ToCanonical(int nFlags)
    {
        assert(m_c[2].R == 0);
        if (nFlags & M_TURN) Turn(m_c);
        if (nFlags & M_ROT_DOWN) RotateDown(m_c);
        else if (nFlags & M_ROT_UP) RotateUp(m_c);
    
        sin0 = sin(m_c[0].Phi);
        sin1 = sin(m_c[1].Phi);
        sin2 = sin(m_c[2].Phi);
    
        cos0 = cos(m_c[0].Phi);
        cos1 = cos(m_c[1].Phi);
        cos2 = cos(m_c[2].Phi);
    }
    
    void CPlaneTrajectory::FromCanonical(int nFlags)
    {
        if (nFlags & M_ROT_DOWN) RotateUp(m_c);
        else if (nFlags & M_ROT_UP) RotateDown(m_c);
        if (nFlags & M_TURN) Turn(m_c);
        assert(m_c[2].R == 0);
    }
    
    double CPlaneTrajectory::GetXError()
    {
        return fabs(m_c[0].L * cos0 + m_c[0].R * (sin1 - sin0) +
                        m_c[1].L * cos1 + m_c[1].R * (sin2 - sin1) +
                        m_c[2].L * cos2 + m_c[2].R * (sin0 - sin2) - m_fX);
    }
    
    double CPlaneTrajectory::GetYError()
    {
        return fabs(m_c[0].L * sin0 + m_c[0].R * (cos0 - cos1) +
                        m_c[1].L * sin1 + m_c[1].R * (cos1 - cos2) +
                        m_c[2].L * sin2 + m_c[2].R * (cos2 - cos0) - m_fY);
    }
    
    //  A * x + B * y = C
    //  D * x + E * y = F
    //  x => A     y => B
    
    bool CPlaneTrajectory::FindSolution2x2()
    {
        double fMod = fB * fD - fE * fA;
        if (fabs(fMod) < EPSILON)
            return false;
        double fBuf = (fB * fF - fC * fE) / fMod;
        fB = (fC * fD - fF * fA) / fMod;
        fA = fBuf;
        return true;
    }
    
    // B = C * sin(Phi) + D * cos(Phi)
    // A <= Phi = arcsin(B / sqrt(C * C + D * D)) - arctg(D / C)
    
    void CPlaneTrajectory::FindAngle()
    {
        double fArg = fB / sqrt( fC * fC + fD * fD );
        double fBuf = atan2( fD, fC );
        if (fBuf > -M_PI/2)
            if (fBuf < M_PI/2) fA = asin(fArg) - fBuf;
            else fA = M_PI - asin(fArg) - fBuf;
        else fA = -M_PI - asin(fArg) - fBuf;
    }
    
    //  A * x + B * sin(Phi) + C * cos(Phi) = D
    //  E * x + F * sin(Phi) + G * cos(Phi) = H
    // Phi => A     x => B
    
    bool CPlaneTrajectory::SimpleTrigonometric()
    {
        double fLeft = fB * fE - fF * fA;
        if (fabs(fLeft) < EPSILON) return false;
        double fRight = fC * fE - fG * fA;
        double fArg = (fD * fE - fH * fA) / sqrt( fLeft * fLeft + fRight * fRight);
        if (fArg < -1 || fArg > 1) return false;
        double fBuf = atan2(fRight, fLeft);
        if (fBuf > -M_PI/2)
            if (fBuf < M_PI/2) fA = asin(fArg) - fBuf;
            else fA = M_PI - asin(fArg) - fBuf;
        else fA = -M_PI - asin(fArg) - fBuf;
        fB = ((fC * fF - fG * fB) * cos(fA) + fH * fB - fD * fF) / fLeft;
        return true;
    }
    
    // A * cos(Phi) - (x - B) * sin(Phi) + C * x = D
    // A * sin(Phi) + (x - B) * cos(Phi) - E * x = F
    // Phi => A     x => B
    
    bool CPlaneTrajectory::AdvancedTrigonometric()
    {
        double fLeft = fA * fC + fB * fE + fF;
        if (fabs(fLeft) < EPSILON) return false;
        double fRight = fD - fB * fC + fA * fE;
        double fArg = (fA + fD * fE + fF * fC) / sqrt( fLeft * fLeft + fRight * fRight);
        if (fArg < -1 || fArg > 1) return false;
        double fBuf = atan2(fRight, fLeft);
        double fAngle = asin(fArg) - fBuf;
        double fSin = sin(fAngle);
        double fCos = cos(fAngle);
        if (fabs(fE - fCos) < EPSILON && fabs(fC - fSin) < EPSILON) {
            fAngle = M_PI - asin(fArg) - fBuf;
            if (fAngle > M_PI) fAngle -= 2 * M_PI;
            fSin = sin(fAngle);
            fCos = cos(fAngle);
        }
        if (fabs(fE - fCos) > fabs(fC - fSin))
            fB = (fA * fSin - fB * fCos -fF) / (fE - fCos);
        else fB = (fD - fA * fCos - fB * fSin) / (fC - fSin);
        fA = fAngle;
        return true;
    }
    
    // Main Equations :
    // X = L0 * cos0 + R0 * (sin1 - sin0) +
    //         L1 * cos1 + R1 * (sin2 - sin1) +
    //          L2 * cos2 + R2 * (sin0 - sin2)
    
    // Y = L0 * sin0 + R0 * (cos0 - cos1) +
    //         L1 * sin1 + R1 * (cos1 - cos2) +
    //          L2 * sin2 + R2 * (cos2 - cos0)
    
    //  Find: L0, R0
    bool CPlaneTrajectory::CalcLwhereR()
    {
        fA = cos0;
        fB = sin1 - sin0;
        fC = m_fX - m_c[1].L * cos1 - m_c[1].R * (sin2 - sin1) -
                        m_c[2].L * cos2 - m_c[2].R * (sin0 - sin2);
        fD = sin0;
        fE = cos0 - cos1;
        fF = m_fY - m_c[1].L * sin1 - m_c[1].R * (cos1 - cos2) -
                         m_c[2].L * sin2 - m_c[2].R * (cos2 - cos0);
        bool bResult = FindSolution2x2();
        if (bResult) {
            m_c[0].L = fA;
            m_c[0].R = fB;
        }
        return bResult;
    }
    
    // Find: L0, R1
    bool CPlaneTrajectory::CalcLltR()
    {
        fA = cos0;
        fB = sin2 - sin1;
        fC = m_fX - m_c[1].L * cos1 - m_c[0].R * (sin1 - sin0) -
                        m_c[2].L * cos2 - m_c[2].R * (sin0 - sin2);
        fD = sin0;
        fE = cos1 - cos2;
        fF = m_fY - m_c[1].L * sin1 - m_c[0].R * (cos0 - cos1) -
                         m_c[2].L * sin2 - m_c[2].R * (cos2 - cos0);
        bool bResult = FindSolution2x2();
        if (bResult) {
            m_c[0].L = fA;
            m_c[1].R = fB;
        }
        return bResult;
    }
    
    bool CPlaneTrajectory::CalcLL()
    {
        fA = cos0;
        fB = cos1;
        fC = m_fX - m_c[0].R * (sin1 - sin0) -
                        m_c[1].R * (sin2 - sin1) -
                        m_c[2].R * (sin0 - sin2) - m_c[2].L * cos2;
        fD = sin0;
        fE = sin1;
        fF = m_fY - m_c[0].R * (cos0 - cos1) -
                        m_c[1].R * (cos1 - cos2) -
                        m_c[2].R * (cos2 - cos0) - m_c[2].L * sin2;
        bool bResult = FindSolution2x2();
        if (bResult) {
            m_c[0].L = fA;
            m_c[1].L = fB;
        }
        return bResult;
    }
    
    bool CPlaneTrajectory::CalcRR()
    {
        fA = sin1 - sin0;
        fB = sin2 - sin1;
        fC = m_fX - m_c[0].L * cos0 - m_c[1].L * cos1 - m_c[2].L * cos2;
        fD = cos0 - cos1;
        fE = cos1 - cos2;
        fF = m_fY - m_c[0].L * sin0 - m_c[1].L * sin1 - m_c[2].L * sin2;
    
        bool bResult = FindSolution2x2();
        if (bResult) {
            m_c[0].R = fA;
            m_c[1].R = fB;
        }
        return bResult;
    }
    
    //  Find: L0, Phi0
    bool CPlaneTrajectory::CalcLwherePhi()
    {
        fB = m_c[2].R - m_c[0].R;
        fC = m_fX - m_c[0].R * sin1 -
                            m_c[1].L * cos1 - m_c[1].R * (sin2 - sin1) -
                            m_c[2].L * cos2 + m_c[2].R * sin2;
        fD = -(m_fY + m_c[0].R * cos1 -
                            m_c[1].L * sin1 - m_c[1].R * (cos1 - cos2) -
                            m_c[2].L * sin2 - m_c[2].R * cos2);
    
        double fArg = fB / sqrt( fC * fC + fD * fD );
        if (fabs(fArg) > 1.) return false;
        double fBuf = atan2( fD, fC );
    
        double fPhi[2], fL[2], fErr[2];
        fPhi[0] = asin(fArg) - fBuf;
        fPhi[1] = (M_PI - asin(fArg) -fBuf);
        for (int i =0; i<2; i++) {
            Normalize(fPhi[i]);
            if (fPhi[i] > -M_PI/4 && fPhi[i] < M_PI/4)
                    fL[i] = ((fC - fB * sin(fPhi[i])) / cos(fPhi[i]));
            else  fL[i] = ((-fD + fB * cos(fPhi[i])) / sin(fPhi[i]));
    
            m_c[0].Phi = fPhi[i];
            sin0 = sin(fPhi[i]);
            cos0 = cos(fPhi[i]);
            m_c[0].L = fL[i];
            fErr[i] = GetXError() + GetYError();
        }
        if (fL[1] < 0 ||
                fErr[1] > fErr[0] && fL[0] >= 0) {
            if (fErr[0] > EPSILON) return false;
            m_c[0].Phi = fPhi[0];
            m_c[0].L = fL[0];
        }
        else if (fErr[1] > EPSILON) return false;
    
        return true;
    }
    
    //  Find: L0, Phi1
    bool CPlaneTrajectory::CalcLltPhi()
    {
        fA = cos0;
        fB = m_c[0].R - m_c[1].R;
        fC = m_c[1].L;
        fD = m_fX + m_c[0].R * sin0 - m_c[1].R * sin2 -
                        m_c[2].L * cos2 - m_c[2].R * (sin0 - sin2);
        fE = sin0;
        fF = m_c[1].L;
        fG = -m_c[0].R + m_c[1].R;
        fH = m_fY - m_c[0].R * cos0 + m_c[1].R * cos2 -
                         m_c[2].L * sin2 - m_c[2].R * (cos2 - cos0);
        bool bResult = SimpleTrigonometric();
        if (bResult) {
            m_c[1].Phi = fA;
            m_c[0].L = fB;
        }
        return bResult;
    }
    
    // Main Equations :
    // X = L0 * cos0 + R0 * (sin1 - sin0) +
    //         L1 * cos1 + R1 * (sin2 - sin1) +
    //          L2 * cos2 + R2 * (sin0 - sin2)
    
    // Y = L0 * sin0 + R0 * (cos0 - cos1) +
    //         L1 * sin1 + R1 * (cos1 - cos2) +
    //          L2 * sin2 + R2 * (cos2 - cos0)
    
    
    //  Find: R0, Phi0
    bool CPlaneTrajectory::CalcRwherePhi()
    {
        fA = m_c[0].L;
        fB = m_c[2].R;
        fC = sin1;
        fD = m_fX -  m_c[1].L * cos1 - m_c[1].R * (sin2 - sin1) -
                            m_c[2].L * cos2 + m_c[2].R * sin2;
        fE = cos1;
        fF = m_fY - m_c[1].L * sin1 - m_c[1].R * (cos1 - cos2) -
                            m_c[2].L * sin2 - m_c[2].R * cos2;
    
        bool bResult = AdvancedTrigonometric();
        if (bResult) {
            m_c[0].Phi = fA;
            m_c[0].R = fB;
        }
        return bResult;
    }
    
    //  Find: R1, Phi0
    bool CPlaneTrajectory::CalcRgtPhi()
    {
        fA = sin2 - sin1;
        fB = m_c[2].R - m_c[0].R;
        fC = m_c[0].L;
        fD = m_fX -  m_c[1].L * cos1 - m_c[0].R * sin1 -
                            m_c[2].L * cos2 + m_c[2].R * sin2;
        fE = cos1 - cos2;
        fF = m_c[0].L;
        fG = m_c[0].R - m_c[2].R;
        fH = m_fY - m_c[1].L * sin1 + m_c[0].R * cos1 -
                            m_c[2].L * sin2 - m_c[2].R * cos2;
    
        bool bResult = SimpleTrigonometric();
        if (bResult) {
            m_c[0].Phi = fA;
            m_c[1].R = fB;
        }
        return bResult;
    }
    
    double GetRoot(double fAsin, double fAtan, int i)
    {
        return ((0 != i) ^ (fabs(M_PI - fAsin - fAtan) > fabs(fAsin - fAtan)))?
            fAsin - fAtan : M_PI - fAsin - fAtan;
    }
    
    // Main Equations :
    // X = L0 * cos0 + R0 * (sin1 - sin0) +
    //         L1 * cos1 + R1 * (sin2 - sin1) +
    //          L2 * cos2 + R2 * (sin0 - sin2)
    
    // Y = L0 * sin0 + R0 * (cos0 - cos1) +
    //         L1 * sin1 + R1 * (cos1 - cos2) +
    //          L2 * sin2 + R2 * (cos2 - cos0)
    
    //  A * cos(Phi0) - B * sin(Phi0) + C * cos(Phi1) - D * sin(Phi1) = E
    //  A * cos(Phi0) + B * sin(Phi0) + C * cos(Phi1) + D * sin(Phi1) = F
    
    //  Find: Phi0, Phi1
    bool CPlaneTrajectory::CalcPhiPhi()
    {
        int i;
    
        fA = m_c[0].L;
        fB = m_c[0].R - m_c[2].R;
        fC = m_c[1].L;
        fD = m_c[1].R - m_c[0].R;
        fE = m_fX - m_c[1].R * sin2 - m_c[2].L * cos2 + m_c[2].R * sin2;
        fF = m_fY+ m_c[1].R * cos2 - m_c[2].L * sin2 - m_c[2].R * cos2;
        double fLeft = fA * fD - fB * fC;
        double fRight= fB * fD + fA * fC;
        double fArg = (fE * fE + fF * fF - fA * fA - fB * fB - fC * fC - fD * fD) / 2. /
                            sqrt(fLeft * fLeft + fRight * fRight);
        if (fabs(fArg) > 1) return false;
        fArg = asin(fArg);
        double fAtan = atan2(fRight, fLeft);
        for (i = 0; i < 2; i++) {
            double fDelta = - GetRoot(fArg, fAtan, i);
            Normalize(fDelta);
            if (fDelta * m_c[0].R < 0) continue;
            double fSin = sin(fDelta);
            double fCos = cos(fDelta);
            double fLeft1 = -fB - fC * fSin - fD * fCos;
            double fRight1= fA + fC * fCos - fD * fSin;
            double fArg1 = fE / sqrt(fLeft1 * fLeft1 + fRight1 * fRight1);
            if (fabs(fArg1) > 1) continue;
            fArg1 = asin(fArg1);
            double fAtan1 = atan2(fRight1, fLeft1);
            for (int j = 0; j < 2; j++) {
                m_c[0].Phi = GetRoot(fArg1, fAtan1, j);
                Normalize(m_c[0].Phi);
                sin0 = sin(m_c[0].Phi);
                cos0 = cos(m_c[0].Phi);
                m_c[1].Phi = m_c[0].Phi + fDelta;
                Normalize(m_c[1].Phi);
                sin1 = sin(m_c[1].Phi);
                cos1 = cos(m_c[1].Phi);
                if (GetXError() < EPSILON && GetYError() < EPSILON) {
                    return true;
                }
            }
        }
        return false;
    }
    
    
    bool CPlaneTrajectory::Calculate(double* pParameters, double fX, double fY, int nMode)
    {
        SetData(pParameters);
        m_c[2].R = 0;
        m_fX = fX;
        m_fY = fY;
    
        bool bCorrect = false;
        switch (nMode)
        {
        case F_L1 | F_R1:
            bCorrect = Calc(&CPlaneTrajectory::CalcLwhereR, 0); break;
        case F_L2 | F_R2:
            bCorrect = Calc(&CPlaneTrajectory::CalcLwhereR, M_ROT_UP); break;
        case F_L2 | F_R1:
            bCorrect = Calc(&CPlaneTrajectory::CalcLwhereR, M_TURN | M_ROT_UP); break;
        case F_L3 | F_R2:
            bCorrect = Calc(&CPlaneTrajectory::CalcLwhereR, M_TURN); break;
    
        case F_L1 | F_R2:
            bCorrect = Calc(&CPlaneTrajectory::CalcLltR, 0); break;
        case F_L3 | F_R1:
            bCorrect = Calc(&CPlaneTrajectory::CalcLltR, M_TURN); break;
    
        case F_L1 | F_L2:
            bCorrect = Calc(&CPlaneTrajectory::CalcLL, 0); break;
        case F_L1 | F_L3:
            bCorrect = Calc(&CPlaneTrajectory::CalcLL, M_ROT_DOWN); break;
        case F_L2 | F_L3:
            bCorrect = Calc(&CPlaneTrajectory::CalcLL, M_ROT_UP); break;
    
        case F_R1 | F_R2:
            bCorrect = Calc(&CPlaneTrajectory::CalcRR, 0); break;
    
        case F_L1 | F_PHI1:
            bCorrect = Calc(&CPlaneTrajectory::CalcLwherePhi, 0); break;
        case F_L2 | F_PHI2:
            bCorrect = Calc(&CPlaneTrajectory::CalcLwherePhi, M_ROT_UP); break;
        case F_L3 | F_PHI3:
            bCorrect = Calc(&CPlaneTrajectory::CalcLwherePhi, M_ROT_DOWN); break;
    
        case F_L1 | F_PHI2:
            bCorrect = Calc(&CPlaneTrajectory::CalcLltPhi, 0); break;
        case F_L1 | F_PHI3:
            bCorrect = Calc(&CPlaneTrajectory::CalcLltPhi, M_TURN | M_ROT_DOWN); break;
        case F_L2 | F_PHI1:
            bCorrect = Calc(&CPlaneTrajectory::CalcLltPhi, M_TURN | M_ROT_UP); break;
        case F_L2 | F_PHI3:
            bCorrect = Calc(&CPlaneTrajectory::CalcLltPhi, M_ROT_UP); break;
        case F_L3 | F_PHI1:
            bCorrect = Calc(&CPlaneTrajectory::CalcLltPhi, M_ROT_DOWN); break;
        case F_L3 | F_PHI2:
            bCorrect = Calc(&CPlaneTrajectory::CalcLltPhi, M_TURN); break;
    
        case F_R1 | F_PHI1:
            bCorrect = Calc(&CPlaneTrajectory::CalcRwherePhi, 0); break;
        case F_R1 | F_PHI2:
            bCorrect = Calc(&CPlaneTrajectory::CalcRwherePhi, M_TURN | M_ROT_UP); break;
        case F_R2 | F_PHI2:
            bCorrect = Calc(&CPlaneTrajectory::CalcRwherePhi, M_ROT_UP); break;
        case F_R2 | F_PHI3:
            bCorrect = Calc(&CPlaneTrajectory::CalcRwherePhi, M_TURN); break;
    
        case F_R2 | F_PHI1:
            bCorrect = Calc(&CPlaneTrajectory::CalcRgtPhi, 0); break;
        case F_R1 | F_PHI3:
            bCorrect = Calc(&CPlaneTrajectory::CalcRgtPhi, M_TURN); break;
    
        case F_PHI1 | F_PHI2:
            bCorrect = Calc(&CPlaneTrajectory::CalcPhiPhi, 0); break;
        case F_PHI1 | F_PHI3:
            bCorrect = Calc(&CPlaneTrajectory::CalcPhiPhi, M_ROT_DOWN); break;
        case F_PHI2 | F_PHI3:
            bCorrect = Calc(&CPlaneTrajectory::CalcPhiPhi, M_ROT_UP); break;
        }
    
        if (bCorrect)
            GetData(pParameters);
    
        return bCorrect;
    }
    
    
    int main(int argc, char* argv[])
    {
        if (argc != 11)
        {
            cerr << "Wrong number of arguments: 10 expected.\n";
            return EXIT_FAILURE;
        }
    
        double params[10];
        memset(params, 0, sizeof(params));
    
        int indices[2];
    
        int j = 0;
        for (int i = 0; i < 10; ++i)
        {
            char* szParam = argv[i + 1];
            if (1 != sscanf(szParam, "%le", params + i))
            {
                if (2 == j || i >= 8)
                {
                    cerr << "Wrong number arguments: only two variables expected.\n";
                    return EXIT_FAILURE;
                }
                indices[j++] = i;
            }
        }
        if (2 != j)
        {
            cerr << "Wrong number arguments: two variables expected.\n";
            return EXIT_FAILURE;
        }
    
        CPlaneTrajectory planeTrajectory;
        if (!planeTrajectory.Calculate(params, params[8], params[9],
                (0x0080 >> indices[0]) | (0x0080 >> indices[1])))
            cout << "Could not calculate variables.\n";
        else
            cout << params[indices[0]] << ' ' << params[indices[1]] << '\n';
    
        return 0;
    }
    


    @echo off
    echo 1250 0.5236 573 2071.4 0.94228 -573 1250 0.2618 4000 3000

    PlaneTrajectory ? ? 573 2071.4 0.94228 -573 1250 0.2618 4000 3000
    PlaneTrajectory ? 0.5236 ? 2071.4 0.94228 -573 1250 0.2618 4000 3000
    PlaneTrajectory ? 0.5236 573 ? 0.94228 -573 1250 0.2618 4000 3000
    PlaneTrajectory ? 0.5236 573 2071.4 ? -573 1250 0.2618 4000 3000
    PlaneTrajectory ? 0.5236 573 2071.4 0.94228 ? 1250 0.2618 4000 3000
    PlaneTrajectory ? 0.5236 573 2071.4 0.94228 -573 ? 0.2618 4000 3000
    PlaneTrajectory ? 0.5236 573 2071.4 0.94228 -573 1250 ? 4000 3000

    PlaneTrajectory 1250 ? ? 2071.4 0.94228 -573 1250 0.2618 4000 3000
    PlaneTrajectory 1250 ? 573 ? 0.94228 -573 1250 0.2618 4000 3000
    PlaneTrajectory 1250 ? 573 2071.4 ? -573 1250 0.2618 4000 3000
    PlaneTrajectory 1250 ? 573 2071.4 0.94228 ? 1250 0.2618 4000 3000
    PlaneTrajectory 1250 ? 573 2071.4 0.94228 -573 ? 0.2618 4000 3000
    PlaneTrajectory 1250 ? 573 2071.4 0.94228 -573 1250 ? 4000 3000

    PlaneTrajectory 1250 0.5236 ? ? 0.94228 -573 1250 0.2618 4000 3000
    PlaneTrajectory 1250 0.5236 ? 2071.4 ? -573 1250 0.2618 4000 3000
    PlaneTrajectory 1250 0.5236 ? 2071.4 0.94228 ? 1250 0.2618 4000 3000
    PlaneTrajectory 1250 0.5236 ? 2071.4 0.94228 -573 ? 0.2618 4000 3000
    PlaneTrajectory 1250 0.5236 ? 2071.4 0.94228 -573 1250 ? 4000 3000

    PlaneTrajectory 1250 0.5236 573 ? ? -573 1250 0.2618 4000 3000
    PlaneTrajectory 1250 0.5236 573 ? 0.94228 ? 1250 0.2618 4000 3000
    PlaneTrajectory 1250 0.5236 573 ? 0.94228 -573 ? 0.2618 4000 3000
    PlaneTrajectory 1250 0.5236 573 ? 0.94228 -573 1250 ? 4000 3000

    PlaneTrajectory 1250 0.5236 573 2071.4 ? ? 1250 0.2618 4000 3000
    PlaneTrajectory 1250 0.5236 573 2071.4 ? -573 ? 0.2618 4000 3000
    PlaneTrajectory 1250 0.5236 573 2071.4 ? -573 1250 ? 4000 3000

    PlaneTrajectory 1250 0.5236 573 2071.4 0.94228 ? ? 0.2618 4000 3000
    PlaneTrajectory 1250 0.5236 573 2071.4 0.94228 ? 1250 ? 4000 3000

    PlaneTrajectory 1250 0.5236 573 2071.4 0.94228 -573 ? ? 4000 3000
    Sunday, November 12th, 2006
    3:32 am
    Template Metaprogramming and Puzzle 15 Optimal Solution
    Here is an attempt to accelerate finding an optimal Puzzle 15 solution using C++ Template Metaprogramming.
    Sunday, January 9th, 2005
    11:39 am
    An old idea on noise reducing in FM stereo receivers
    This idea concerns noise reducing in FM stereo receivers and is relative to the device described in US Pat. 5,027,402. A part of the abstract is put below for consistency.

    An FM stereo decoding and separating circuit has an (AM) demodulator multiplier to which is connected the FM stereo composite signal and a signal of dominant frequency equal to and in phase (0 deg. ) with respect to the pilot signal for retrieving the L-R signal from the composite signal. This demodulator also has a blend control circuit for diminishing the magnitude of the L-R signal as a function of a blend control voltage that may be applied to the input of the blend control circuit. The decoding circuit also includes a special multiplier to which is connected the FM stereo composite signal and a signal of dominant frequency equal to that of the 38 KHz subcarrier but shifted 90 deg. with respect to the phase of the pilot, for AM demodulating the composite signal with respect to the subcarrier …

    The device described does not contain a blend circuit.
    Instead, device addition consists of:
    · a low pass filter with voltage controlled cutoff frequency which processes L-R signal;
    · a differential amplifier which yields difference between filter input and output signal (rejected part);
    · two equal separate channels both consisting of an amplifier with optimal frequency characteristic and a rectifier. Differential (rejected part of L-R signal) and noise (demodulated with shifted 90 deg. subcarrier) signals both pass through these channels;
    · a second differential amplifier. Its output voltage is proportional to difference between rejected and noise signal amplitudes. This voltage controls low frequency pass filter mentioned above.
    At the end, the passed L-R signal is used for reconstruction of the left and right stereo components.
About LiveJournal.com

Advertisement