diff options
author | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:01:29 +0200 |
---|---|---|
committer | Daniel Wilhelm <daniel@wili.li> | 2014-04-18 17:01:29 +0200 |
commit | 9a2a524f1e311853d08050be2dcdddc09ac7759a (patch) | |
tree | d8e4a24169fce88c2d89931d58514889a0bcb0ea /shared | |
parent | 2.3 (diff) | |
download | FreeFileSync-9a2a524f1e311853d08050be2dcdddc09ac7759a.tar.gz FreeFileSync-9a2a524f1e311853d08050be2dcdddc09ac7759a.tar.bz2 FreeFileSync-9a2a524f1e311853d08050be2dcdddc09ac7759a.zip |
3.0
Diffstat (limited to 'shared')
72 files changed, 23185 insertions, 640 deletions
diff --git a/shared/appMain.cpp b/shared/appMain.cpp new file mode 100644 index 00000000..fe6d3af5 --- /dev/null +++ b/shared/appMain.cpp @@ -0,0 +1,24 @@ +#include "appMain.h" +#include <wx/window.h> +#include <wx/app.h> + +using namespace FreeFileSync; + + +bool AppMainWindow::mainWndAct = false; + + +void FreeFileSync::AppMainWindow::setMainWindow(wxWindow* window) +{ + wxTheApp->SetTopWindow(window); + wxTheApp->SetExitOnFrameDelete(true); + + assert (!mainWndAct); + mainWndAct = true; +} + + +bool AppMainWindow::mainWindowWasSet() +{ + return mainWndAct; +} diff --git a/shared/appMain.h b/shared/appMain.h new file mode 100644 index 00000000..130a6e2a --- /dev/null +++ b/shared/appMain.h @@ -0,0 +1,21 @@ +#ifndef APPMAIN_H_INCLUDED +#define APPMAIN_H_INCLUDED + +class wxWindow; + +namespace FreeFileSync +{ +//just some wrapper around a global variable representing the (logical) main application window +class AppMainWindow +{ +public: + static void setMainWindow(wxWindow* window); //set main window and enable "exit on frame delete" + static bool mainWindowWasSet(); + +private: + static bool mainWndAct; +}; +} + + +#endif // APPMAIN_H_INCLUDED diff --git a/shared/customButton.cpp b/shared/customButton.cpp index 4027d3ef..40c0397f 100644 --- a/shared/customButton.cpp +++ b/shared/customButton.cpp @@ -10,9 +10,9 @@ wxButtonWithImage::wxButtonWithImage(wxWindow *parent, long style, const wxValidator& validator, const wxString& name) : - wxBitmapButton(parent, id, wxNullBitmap, pos, size, style | wxBU_AUTODRAW, validator, name), - m_spaceAfter(0), - m_spaceBefore(0) + wxBitmapButton(parent, id, wxNullBitmap, pos, size, style | wxBU_AUTODRAW, validator, name), + m_spaceAfter(0), + m_spaceBefore(0) { setTextLabel(label); } diff --git a/shared/dragAndDrop.cpp b/shared/dragAndDrop.cpp index 9261d604..89f4da4d 100644 --- a/shared/dragAndDrop.cpp +++ b/shared/dragAndDrop.cpp @@ -19,9 +19,9 @@ class FFSFileDropEvent : public wxCommandEvent { public: FFSFileDropEvent(const wxString& nameDropped, const wxWindow* dropWindow) : - wxCommandEvent(FFS_DROP_FILE_EVENT), - nameDropped_(nameDropped), - dropWindow_(dropWindow) {} + wxCommandEvent(FFS_DROP_FILE_EVENT), + nameDropped_(nameDropped), + dropWindow_(dropWindow) {} virtual wxEvent* Clone() const { @@ -39,7 +39,7 @@ class WindowDropTarget : public wxFileDropTarget { public: WindowDropTarget(wxWindow* dropWindow) : - dropWindow_(dropWindow) {} + dropWindow_(dropWindow) {} virtual bool OnDropFiles(wxCoord x, wxCoord y, const wxArrayString& filenames) { @@ -68,10 +68,10 @@ DragDropOnMainDlg::DragDropOnMainDlg(wxWindow* dropWindow1, wxWindow* dropWindow2, wxDirPickerCtrl* dirPicker, wxComboBox* dirName) : - dropWindow1_(dropWindow1), - dropWindow2_(dropWindow2), - dirPicker_(dirPicker), - dirName_(dirName) + dropWindow1_(dropWindow1), + dropWindow2_(dropWindow2), + dirPicker_(dirPicker), + dirName_(dirName) { //prepare drag & drop dropWindow1->SetDropTarget(new WindowDropTarget(dropWindow1)); //takes ownership @@ -155,9 +155,9 @@ using FreeFileSync::DragDropOnDlg; DragDropOnDlg::DragDropOnDlg(wxWindow* dropWindow, wxDirPickerCtrl* dirPicker, wxTextCtrl* dirName) : - dropWindow_(dropWindow), - dirPicker_(dirPicker), - dirName_(dirName) + dropWindow_(dropWindow), + dirPicker_(dirPicker), + dirName_(dirName) { //prepare drag & drop dropWindow->SetDropTarget(new WindowDropTarget(dropWindow)); //takes ownership diff --git a/shared/dragAndDrop.h b/shared/dragAndDrop.h index a8c7561a..4e6bbd31 100644 --- a/shared/dragAndDrop.h +++ b/shared/dragAndDrop.h @@ -15,48 +15,48 @@ class wxFileDirPickerEvent; namespace FreeFileSync { - //add drag and drop functionality, coordinating a wxWindow, wxDirPickerCtrl, and wxComboBox/wxTextCtrl +//add drag and drop functionality, coordinating a wxWindow, wxDirPickerCtrl, and wxComboBox/wxTextCtrl - class DragDropOnMainDlg : private wxEvtHandler - { - public: - DragDropOnMainDlg(wxWindow* dropWindow1, - wxWindow* dropWindow2, - wxDirPickerCtrl* dirPicker, - wxComboBox* dirName); - - virtual ~DragDropOnMainDlg() {} - - virtual bool AcceptDrop(const wxString& dropName) = 0; //return true if drop should be processed +class DragDropOnMainDlg : private wxEvtHandler +{ +public: + DragDropOnMainDlg(wxWindow* dropWindow1, + wxWindow* dropWindow2, + wxDirPickerCtrl* dirPicker, + wxComboBox* dirName); - private: - void OnFilesDropped(FFSFileDropEvent& event); - void OnWriteDirManually(wxCommandEvent& event); - void OnDirSelected(wxFileDirPickerEvent& event); + virtual ~DragDropOnMainDlg() {} - const wxWindow* dropWindow1_; - const wxWindow* dropWindow2_; - wxDirPickerCtrl* dirPicker_; - wxComboBox* dirName_; - }; + virtual bool AcceptDrop(const wxString& dropName) = 0; //return true if drop should be processed +private: + void OnFilesDropped(FFSFileDropEvent& event); + void OnWriteDirManually(wxCommandEvent& event); + void OnDirSelected(wxFileDirPickerEvent& event); - class DragDropOnDlg: private wxEvtHandler - { - public: - DragDropOnDlg(wxWindow* dropWindow, - wxDirPickerCtrl* dirPicker, - wxTextCtrl* dirName); + const wxWindow* dropWindow1_; + const wxWindow* dropWindow2_; + wxDirPickerCtrl* dirPicker_; + wxComboBox* dirName_; +}; - private: - void OnFilesDropped(FFSFileDropEvent& event); - void OnWriteDirManually(wxCommandEvent& event); - void OnDirSelected(wxFileDirPickerEvent& event); - const wxWindow* dropWindow_; - wxDirPickerCtrl* dirPicker_; - wxTextCtrl* dirName_; - }; +class DragDropOnDlg: private wxEvtHandler +{ +public: + DragDropOnDlg(wxWindow* dropWindow, + wxDirPickerCtrl* dirPicker, + wxTextCtrl* dirName); + +private: + void OnFilesDropped(FFSFileDropEvent& event); + void OnWriteDirManually(wxCommandEvent& event); + void OnDirSelected(wxFileDirPickerEvent& event); + + const wxWindow* dropWindow_; + wxDirPickerCtrl* dirPicker_; + wxTextCtrl* dirName_; +}; } diff --git a/shared/fileError.h b/shared/fileError.h index f5c6bdbd..daf97910 100644 --- a/shared/fileError.h +++ b/shared/fileError.h @@ -6,20 +6,20 @@ namespace FreeFileSync { - class FileError //Exception class used to notify file/directory copy/delete errors - { - public: - FileError(const wxString& message) : - errorMessage(message) {} +class FileError //Exception class used to notify file/directory copy/delete errors +{ +public: + FileError(const wxString& message) : + errorMessage(message) {} - const wxString& show() const - { - return errorMessage; - } + const wxString& show() const + { + return errorMessage; + } - private: - wxString errorMessage; - }; +private: + wxString errorMessage; +}; } #endif // FILEERROR_H_INCLUDED diff --git a/shared/fileHandling.cpp b/shared/fileHandling.cpp index 55fd7ff5..cea701cc 100644 --- a/shared/fileHandling.cpp +++ b/shared/fileHandling.cpp @@ -1,6 +1,7 @@ #include "fileHandling.h" #include <wx/intl.h> #include "systemFunctions.h" +#include "globalFunctions.h" #include "systemConstants.h" #include "fileTraverser.h" #include <wx/file.h> @@ -8,6 +9,8 @@ #include <boost/bind.hpp> #include <algorithm> #include <wx/log.h> +#include <wx/datetime.h> +#include "stringConv.h" #ifdef FFS_WIN #include <wx/msw/wrapwin.h> //includes "windows.h" @@ -28,21 +31,30 @@ using FreeFileSync::FileError; Zstring FreeFileSync::getFormattedDirectoryName(const Zstring& dirname) -{ //Formatting is needed since functions expect the directory to end with '\' to be able to split the relative names. +{ + //Formatting is needed since functions expect the directory to end with '\' to be able to split the relative names. //Also improves usability. - Zstring dirnameTmp = dirname; + wxString dirnameTmp = zToWx(dirname); dirnameTmp.Trim(true); //remove whitespace characters from right dirnameTmp.Trim(false); //remove whitespace characters from left if (dirnameTmp.empty()) //an empty string is interpreted as "\"; this is not desired return Zstring(); - if (!dirnameTmp.EndsWith(globalFunctions::FILE_NAME_SEPARATOR)) - dirnameTmp += globalFunctions::FILE_NAME_SEPARATOR; + if (!dirnameTmp.EndsWith(zToWx(globalFunctions::FILE_NAME_SEPARATOR))) + dirnameTmp += zToWx(globalFunctions::FILE_NAME_SEPARATOR); + + //replace macros + wxString timeNow = wxDateTime::Now().FormatISOTime(); + timeNow.Replace(wxT(":"), wxT("-")); + dirnameTmp.Replace(wxT("%time%"), timeNow.c_str()); + + const wxString dateToday = wxDateTime::Now().FormatISODate(); + dirnameTmp.Replace(wxT("%date%"), dateToday.c_str()); //don't do directory formatting with wxFileName, as it doesn't respect //?/ - prefix - return dirnameTmp; + return wxToZ(dirnameTmp); } @@ -64,7 +76,7 @@ public: private: RecycleBin() : - recycleBinAvailable(false) + recycleBinAvailable(false) { #ifdef FFS_WIN recycleBinAvailable = true; @@ -117,7 +129,8 @@ bool moveToRecycleBin(const Zstring& filename) //throw (std::logic_error) bool FreeFileSync::fileExists(const DefaultChar* filename) -{ //symbolic links (broken or not) are also treated as existing files! +{ + //symbolic links (broken or not) are also treated as existing files! #ifdef FFS_WIN // we must use GetFileAttributes() instead of the ANSI C functions because // it can cope with network (UNC) paths unlike them @@ -134,7 +147,8 @@ bool FreeFileSync::fileExists(const DefaultChar* filename) bool FreeFileSync::dirExists(const DefaultChar* dirname) -{ //symbolic links (broken or not) are also treated as existing directories! +{ + //symbolic links (broken or not) are also treated as existing directories! #ifdef FFS_WIN // we must use GetFileAttributes() instead of the ANSI C functions because // it can cope with network (UNC) paths unlike them @@ -166,15 +180,15 @@ bool FreeFileSync::symlinkExists(const DefaultChar* objname) bool FreeFileSync::isMovable(const Zstring& pathFrom, const Zstring& pathTo) { - wxLogNull noWxLogs; //prevent wxWidgets logging if dummy file creation failed + wxLogNull noWxLogs; //prevent wxWidgets logging if dummy file creation failed const Zstring dummyFileSource = pathFrom.EndsWith(globalFunctions::FILE_NAME_SEPARATOR) ? - pathFrom + wxT("DeleteMe.tmp") : - pathFrom + globalFunctions::FILE_NAME_SEPARATOR + wxT("DeleteMe.tmp"); + pathFrom + DefaultStr("DeleteMe.tmp") : + pathFrom + globalFunctions::FILE_NAME_SEPARATOR + DefaultStr("DeleteMe.tmp"); const Zstring dummyFileTarget = pathTo.EndsWith(globalFunctions::FILE_NAME_SEPARATOR) ? - pathTo + wxT("DeleteMe.tmp") : - pathTo + globalFunctions::FILE_NAME_SEPARATOR + wxT("DeleteMe.tmp"); + pathTo + DefaultStr("DeleteMe.tmp") : + pathTo + globalFunctions::FILE_NAME_SEPARATOR + DefaultStr("DeleteMe.tmp"); try { removeFile(dummyFileSource, false); @@ -184,7 +198,7 @@ bool FreeFileSync::isMovable(const Zstring& pathFrom, const Zstring& pathTo) //create dummy file { - wxFile dummy(dummyFileSource.c_str(), wxFile::write); + wxFile dummy(zToWx(dummyFileSource), wxFile::write); if (!dummy.IsOpened()) return false; //if there's no write access, files can't be moved neither dummy.Write(wxT("FreeFileSync dummy file. May be deleted safely.\n")); @@ -195,7 +209,7 @@ bool FreeFileSync::isMovable(const Zstring& pathFrom, const Zstring& pathTo) #ifdef FFS_WIN ::MoveFileEx(dummyFileSource.c_str(), //__in LPCTSTR lpExistingFileName, dummyFileTarget.c_str(), //__in_opt LPCTSTR lpNewFileName, - 0) != 0; //__in DWORD dwFlags + 0) != 0; //__in DWORD dwFlags #elif defined FFS_LINUX ::rename(dummyFileSource.c_str(), dummyFileTarget.c_str()) == 0; #endif @@ -227,7 +241,7 @@ void FreeFileSync::removeFile(const Zstring& filename, const bool useRecycleBin) if (useRecycleBin) { if (!moveToRecycleBin(filename)) - throw FileError(wxString(_("Error moving to Recycle Bin:")) + wxT("\n\"") + filename.c_str() + wxT("\"")); + throw FileError(wxString(_("Error moving to Recycle Bin:")) + wxT("\n\"") + zToWx(filename) + wxT("\"")); return; } @@ -237,20 +251,20 @@ void FreeFileSync::removeFile(const Zstring& filename, const bool useRecycleBin) filename.c_str(), //address of filename FILE_ATTRIBUTE_NORMAL)) //attributes to set { - wxString errorMessage = wxString(_("Error deleting file:")) + wxT("\n\"") + filename.c_str() + wxT("\""); + wxString errorMessage = wxString(_("Error deleting file:")) + wxT("\n\"") + zToWx(filename) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); } //remove file, support for \\?\-prefix if (!::DeleteFile(filename.c_str())) { - wxString errorMessage = wxString(_("Error deleting file:")) + wxT("\n\"") + filename.c_str() + wxT("\""); + wxString errorMessage = wxString(_("Error deleting file:")) + wxT("\n\"") + zToWx(filename) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); } #elif defined FFS_LINUX if (::unlink(filename.c_str()) != 0) { - wxString errorMessage = wxString(_("Error deleting file:")) + wxT("\n\"") + filename.c_str() + wxT("\""); + wxString errorMessage = wxString(_("Error deleting file:")) + wxT("\n\"") + zToWx(filename) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); } #endif @@ -286,7 +300,8 @@ void FreeFileSync::moveFile(const Zstring& sourceFile, const Zstring& targetFile { if (fileExists(targetFile.c_str())) //test file existence: e.g. Linux might silently overwrite existing symlinks { - const wxString errorMessage = wxString(_("Error moving file:")) + wxT("\n\"") + sourceFile + wxT("\" ->\n\"") + targetFile + wxT("\""); + const wxString errorMessage = wxString(_("Error moving file:")) + wxT("\n\"") + zToWx(sourceFile) + wxT("\" ->\n\"") + + zToWx(targetFile) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + _("Target file already existing!")); } @@ -303,7 +318,8 @@ void FreeFileSync::moveFile(const Zstring& sourceFile, const Zstring& targetFile const DWORD lastError = ::GetLastError(); if (lastError != ERROR_NOT_SAME_DEVICE) { - const wxString errorMessage = wxString(_("Error moving file:")) + wxT("\n\"") + sourceFile.c_str() + wxT("\" ->\n\"") + targetFile.c_str() + wxT("\""); + const wxString errorMessage = wxString(_("Error moving file:")) + wxT("\n\"") + zToWx(sourceFile) + wxT("\" ->\n\"") + + zToWx(targetFile) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted(lastError)); } @@ -318,14 +334,15 @@ void FreeFileSync::moveFile(const Zstring& sourceFile, const Zstring& targetFile #elif defined FFS_LINUX //first try to move the file directly without copying - if (rename(sourceFile.c_str(), targetFile.c_str()) == 0) + if (::rename(sourceFile.c_str(), targetFile.c_str()) == 0) return; //if moving failed treat as error (except when it tried to move to a different volume: in this case we will copy the file) if (errno != EXDEV) { - const wxString errorMessage = wxString(_("Error moving file:")) + wxT("\n\"") + sourceFile.c_str() + wxT("\" ->\n\"") + targetFile.c_str() + wxT("\""); - throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted(errno)); + const wxString errorMessage = wxString(_("Error moving file:")) + wxT("\n\"") + zToWx(sourceFile) + wxT("\" ->\n\"") + + zToWx(targetFile) + wxT("\""); + throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); } //file is on a different volume: let's copy it @@ -349,8 +366,8 @@ public: typedef std::vector<std::pair<Zstring, Zstring> > NamePair; TraverseOneLevel(NamePair& filesShort, NamePair& dirsShort) : - m_files(filesShort), - m_dirs(dirsShort) {} + m_files(filesShort), + m_dirs(dirsShort) {} virtual ReturnValue onFile(const DefaultChar* shortName, const Zstring& fullName, const FileInfo& details) { @@ -375,19 +392,22 @@ private: void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool ignoreExistingDirs, MoveFileCallback* callback) //throw (FileError); { + using namespace FreeFileSync; + //handle symbolic links - if (FreeFileSync::symlinkExists(sourceDir)) + if (symlinkExists(sourceDir)) { - FreeFileSync::createDirectory(targetDir, sourceDir, true); //copy symbolic link - FreeFileSync::removeDirectory(sourceDir, false); //if target is already another symlink or directory, sourceDir-symlink is silently deleted + createDirectory(targetDir, sourceDir, true); //copy symbolic link + removeDirectory(sourceDir, false); //if target is already another symlink or directory, sourceDir-symlink is silently deleted return; } - if (FreeFileSync::dirExists(targetDir)) + if (dirExists(targetDir)) { if (!ignoreExistingDirs) //directory or symlink exists { - const wxString errorMessage = wxString(_("Error moving directory:")) + wxT("\n\"") + sourceDir + wxT("\" ->\n\"") + targetDir + wxT("\""); + const wxString errorMessage = wxString(_("Error moving directory:")) + wxT("\n\"") + + zToWx(sourceDir) + wxT("\" ->\n\"") + zToWx(targetDir) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + _("Target directory already existing!")); } } @@ -404,7 +424,8 @@ void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool const DWORD lastError = ::GetLastError(); if (lastError != ERROR_NOT_SAME_DEVICE) { - const wxString errorMessage = wxString(_("Error moving directory:")) + wxT("\n\"") + sourceDir.c_str() + wxT("\" ->\n\"") + targetDir.c_str() + wxT("\""); + const wxString errorMessage = wxString(_("Error moving directory:")) + wxT("\n\"") + zToWx(sourceDir) + wxT("\" ->\n\"") + + zToWx(targetDir) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted(lastError)); } #elif defined FFS_LINUX @@ -414,13 +435,14 @@ void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool //if moving failed treat as error (except when it tried to move to a different volume: in this case we will copy the directory) if (errno != EXDEV) { - const wxString errorMessage = wxString(_("Error moving directory:")) + wxT("\n\"") + sourceDir.c_str() + wxT("\" ->\n\"") + targetDir.c_str() + wxT("\""); - throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted(errno)); + const wxString errorMessage = wxString(_("Error moving directory:")) + wxT("\n\"") + + zToWx(sourceDir) + wxT("\" ->\n\"") + zToWx(targetDir) + wxT("\""); + throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); } #endif //create target - FreeFileSync::createDirectory(targetDir, sourceDir, false); //throw (FileError); + createDirectory(targetDir, sourceDir, false); //throw (FileError); } //call back once per folder @@ -431,8 +453,8 @@ void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool break; case MoveFileCallback::CANCEL: //an user aborted operation IS an error condition! - throw FileError(wxString(_("Error moving directory:")) + wxT("\n\"") + sourceDir.c_str() + wxT("\" ->\n\"") + - targetDir.c_str() + wxT("\"") + wxT("\n\n") + _("Operation aborted!")); + throw FileError(wxString(_("Error moving directory:")) + wxT("\n\"") + zToWx(sourceDir) + wxT("\" ->\n\"") + + zToWx(targetDir) + wxT("\"") + wxT("\n\n") + _("Operation aborted!")); } //move files/folders recursively @@ -441,7 +463,7 @@ void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool //traverse source directory one level TraverseOneLevel traverseCallback(fileList, dirList); - FreeFileSync::traverseFolder(sourceDir, false, &traverseCallback); //traverse one level + traverseFolder(sourceDir, false, &traverseCallback); //traverse one level const Zstring targetDirFormatted = targetDir.EndsWith(globalFunctions::FILE_NAME_SEPARATOR) ? //ends with path separator targetDir : @@ -458,9 +480,7 @@ void moveDirectoryImpl(const Zstring& sourceDir, const Zstring& targetDir, bool //attention: if move-operation was cancelled an exception is thrown => sourceDir is not deleted, as we wish! //delete source - FreeFileSync::removeDirectory(sourceDir, false); //throw (FileError); - - return; + removeDirectory(sourceDir, false); //throw (FileError); } @@ -488,8 +508,8 @@ class FilesDirsOnlyTraverser : public FreeFileSync::TraverseCallback { public: FilesDirsOnlyTraverser(std::vector<Zstring>& files, std::vector<Zstring>& dirs) : - m_files(files), - m_dirs(dirs) {} + m_files(files), + m_dirs(dirs) {} virtual ReturnValue onFile(const DefaultChar* shortName, const Zstring& fullName, const FileInfo& details) { @@ -529,7 +549,7 @@ void FreeFileSync::removeDirectory(const Zstring& directory, const bool useRecyc if (useRecycleBin) { if (!moveToRecycleBin(directory)) - throw FileError(wxString(_("Error moving to Recycle Bin:")) + wxT("\n\"") + directory.c_str() + wxT("\"")); + throw FileError(wxString(_("Error moving to Recycle Bin:")) + wxT("\n\"") + zToWx(directory) + wxT("\"")); return; } @@ -561,7 +581,7 @@ void FreeFileSync::removeDirectory(const Zstring& directory, const bool useRecyc { if (::unlink(directory.c_str()) != 0) { - wxString errorMessage = wxString(_("Error deleting directory:")) + wxT("\n\"") + directory.c_str() + wxT("\""); + wxString errorMessage = wxString(_("Error deleting directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); } return; @@ -585,17 +605,13 @@ void FreeFileSync::removeDirectory(const Zstring& directory, const bool useRecyc #ifdef FFS_WIN //remove directory, support for \\?\-prefix if (!::RemoveDirectory(directory.c_str())) - { - wxString errorMessage = wxString(_("Error deleting directory:")) + wxT("\n\"") + directory.c_str() + wxT("\""); - throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); - } #else if (::rmdir(directory.c_str()) != 0) +#endif { - wxString errorMessage = wxString(_("Error deleting directory:")) + wxT("\n\"") + directory.c_str() + wxT("\""); + wxString errorMessage = wxString(_("Error deleting directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); } -#endif } @@ -697,8 +713,8 @@ public: private: KernelDllHandler() : - getFinalPathNameByHandle(NULL), - hKernel(NULL) + getFinalPathNameByHandle(NULL), + hKernel(NULL) { //get a handle to the DLL module containing required functionality hKernel = ::LoadLibrary(wxT("kernel32.dll")); @@ -748,50 +764,49 @@ Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target pa return targetPath; } - +//#warning teste //#include <aclapi.h> -//optionally: copy additional metadata, DO NOTHING if something fails +////optionally: copy additional metadata, DO NOTHING if something fails //void copyAdditionalMetadata(const Zstring& sourceDir, const Zstring& targetDir) //{ +// //copy NTFS permissions +// // PSECURITY_DESCRIPTOR pSD; // -// PSID pSidOwner; -// PSID pSidGroup; // PACL pDacl; -// PACL pSacl; // if (::GetNamedSecurityInfo( // const_cast<DefaultChar*>(sourceDir.c_str()), // SE_FILE_OBJECT, //file or directory -// OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, -// &pSidOwner, -// &pSidGroup, +// DACL_SECURITY_INFORMATION, +// NULL, +// NULL, // &pDacl, -// &pSacl, +// NULL, // &pSD // ) == ERROR_SUCCESS) // { // //(try to) set new security information // if (::SetNamedSecurityInfo( -// const_cast<DefaultChar*>(targetDir.c_str()), -// SE_FILE_OBJECT, //file or directory -// OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, -// pSidOwner, -// pSidGroup, -// pDacl, -// pSacl) != ERROR_SUCCESS) //return value not evalutated! -// { +// const_cast<DefaultChar*>(targetDir.c_str()), +// SE_FILE_OBJECT, //file or directory +// DACL_SECURITY_INFORMATION, +// NULL, +// NULL, +// pDacl, +// NULL) != ERROR_SUCCESS) //return value not evalutated! +// { // const wxString errorMessage = wxString(wxT("Error 2:")) + wxT("\n\"") + targetDir.c_str() + wxT("\""); // throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); // } -//warning BUG! // -// LocalFree(pSD); //pSidOwner, pSidGroup, pDacl, pSacl must not be freed! +//#warning BUG! +// LocalFree(pSD); // } // else -// { -// const wxString errorMessage = wxString(wxT("Error 1:")) + wxT("\n\"") + sourceDir.c_str() + wxT("\""); -// throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); -// } +// { +// const wxString errorMessage = wxString(wxT("Error 1:")) + wxT("\n\"") + sourceDir.c_str() + wxT("\""); +// throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); +// } // //} #endif @@ -799,6 +814,8 @@ Zstring resolveDirectorySymlink(const Zstring& dirLinkName) //get full target pa void createDirectoryRecursively(const Zstring& directory, const Zstring& templateDir, const bool copyDirectorySymLinks, const int level) { + using namespace FreeFileSync; + if (FreeFileSync::dirExists(directory)) return; @@ -882,7 +899,7 @@ void createDirectoryRecursively(const Zstring& directory, const Zstring& templat const int bytesWritten = readlink(templateDir.c_str(), buffer, BUFFER_SIZE); if (bytesWritten < 0 || bytesWritten == BUFFER_SIZE) { - wxString errorMessage = wxString(_("Error resolving symbolic link:")) + wxT("\n\"") + templateDir.c_str() + wxT("\""); + wxString errorMessage = wxString(_("Error resolving symbolic link:")) + wxT("\n\"") + zToWx(templateDir) + wxT("\""); if (bytesWritten < 0) errorMessage += wxString(wxT("\n\n")) + FreeFileSync::getLastErrorFormatted(); throw FileError(errorMessage); } @@ -891,7 +908,7 @@ void createDirectoryRecursively(const Zstring& directory, const Zstring& templat if (symlink(buffer, directory.c_str()) != 0) { - wxString errorMessage = wxString(_("Error creating directory:")) + wxT("\n\"") + directory.c_str() + wxT("\""); + wxString errorMessage = wxString(_("Error creating directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); } return; //symlink created successfully @@ -899,9 +916,9 @@ void createDirectoryRecursively(const Zstring& directory, const Zstring& templat } //default directory creation - if (mkdir(directory.c_str(), 0755) != 0 && level == 0) + if (::mkdir(directory.c_str(), 0755) != 0 && level == 0) { - wxString errorMessage = wxString(_("Error creating directory:")) + wxT("\n\"") + directory.c_str() + wxT("\""); + wxString errorMessage = wxString(_("Error creating directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); } @@ -944,6 +961,24 @@ void FreeFileSync::createDirectory(const Zstring& directory, const Zstring& temp } +Zstring createTempName(const Zstring& filename) +{ + Zstring output = filename + DefaultStr(".tmp"); + + //ensure uniqueness + if (FreeFileSync::fileExists(output)) + { + //if it's not unique, add a postfix number + int postfix = 1; + while (FreeFileSync::fileExists(output + DefaultChar('_') + numberToZstring(postfix))) + ++postfix; + + output += DefaultChar('_') + numberToZstring(postfix); + } + return output; +} + + #ifdef FFS_WIN #ifndef COPY_FILE_COPY_SYMLINK @@ -1011,8 +1046,8 @@ bool supportForSymbolicLinks() void FreeFileSync::copyFile(const Zstring& sourceFile, const Zstring& targetFile, const bool copyFileSymLinks, - ShadowCopy* shadowCopyHandler, - CopyFileCallback* callback) + FreeFileSync::ShadowCopy* shadowCopyHandler, + FreeFileSync::CopyFileCallback* callback) { DWORD copyFlags = COPY_FILE_FAIL_IF_EXISTS; @@ -1021,9 +1056,10 @@ void FreeFileSync::copyFile(const Zstring& sourceFile, if (copyFileSymLinks && symlinksSupported) copyFlags |= COPY_FILE_COPY_SYMLINK; + const Zstring temporary = createTempName(targetFile); //use temporary file until a correct date has been set if (!::CopyFileEx( //same performance as CopyFile() sourceFile.c_str(), - targetFile.c_str(), + temporary.c_str(), copyCallbackInternal, callback, NULL, @@ -1039,17 +1075,26 @@ void FreeFileSync::copyFile(const Zstring& sourceFile, lastError == ERROR_LOCK_VIOLATION)) { const Zstring shadowFilename(shadowCopyHandler->makeShadowCopy(sourceFile)); - FreeFileSync::copyFile(shadowFilename, //transferred bytes is automatically reset when new file is copied - targetFile, - copyFileSymLinks, - NULL, - callback); + copyFile(shadowFilename, //transferred bytes is automatically reset when new file is copied + targetFile, + copyFileSymLinks, + NULL, + callback); return; } const wxString errorMessage = wxString(_("Error copying file:")) + wxT("\n\"") + sourceFile.c_str() + wxT("\" ->\n\"") + targetFile.c_str() + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted(lastError)); } + + //rename temporary file + if (!::MoveFileEx(temporary.c_str(), //__in LPCTSTR lpExistingFileName, + targetFile.c_str(), //__in_opt LPCTSTR lpNewFileName, + 0)) //__in DWORD dwFlags + { + const wxString errorMessage = wxString(_("Error moving file:")) + wxT("\n\"") + temporary + wxT("\" ->\n\"") + targetFile + wxT("\""); + throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); + } } @@ -1079,7 +1124,7 @@ void FreeFileSync::copyFile(const Zstring& sourceFile, using FreeFileSync::CopyFileCallback; if (FreeFileSync::fileExists(targetFile.c_str())) - throw FileError(wxString(_("Error copying file:")) + wxT("\n\"") + sourceFile.c_str() + wxT("\" ->\n\"") + targetFile.c_str() + wxT("\"\n\n") + throw FileError(wxString(_("Error copying file:")) + wxT("\n\"") + zToWx(sourceFile) + wxT("\" ->\n\"") + zToWx(targetFile) + wxT("\"\n\n") + _("Target file already existing!")); //symbolic link handling @@ -1089,7 +1134,7 @@ void FreeFileSync::copyFile(const Zstring& sourceFile, struct stat linkInfo; if (lstat(sourceFile.c_str(), &linkInfo) != 0) { - const wxString errorMessage = wxString(_("Error reading file attributes:")) + wxT("\n\"") + sourceFile.c_str() + wxT("\""); + const wxString errorMessage = wxString(_("Error reading file attributes:")) + wxT("\n\"") + zToWx(sourceFile) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); } @@ -1101,7 +1146,7 @@ void FreeFileSync::copyFile(const Zstring& sourceFile, const int bytesWritten = readlink(sourceFile.c_str(), buffer, BUFFER_SIZE); if (bytesWritten < 0 || bytesWritten == BUFFER_SIZE) { - wxString errorMessage = wxString(_("Error resolving symbolic link:")) + wxT("\n\"") + sourceFile.c_str() + wxT("\""); + wxString errorMessage = wxString(_("Error resolving symbolic link:")) + wxT("\n\"") + zToWx(sourceFile) + wxT("\""); if (bytesWritten < 0) errorMessage += wxString(wxT("\n\n")) + FreeFileSync::getLastErrorFormatted(); throw FileError(errorMessage); } @@ -1110,7 +1155,7 @@ void FreeFileSync::copyFile(const Zstring& sourceFile, if (symlink(buffer, targetFile.c_str()) != 0) { - const wxString errorMessage = wxString(_("Error writing file:")) + wxT("\n\"") + targetFile.c_str() + wxT("\""); + const wxString errorMessage = wxString(_("Error writing file:")) + wxT("\n\"") + zToWx(targetFile) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); } @@ -1122,19 +1167,21 @@ void FreeFileSync::copyFile(const Zstring& sourceFile, struct stat fileInfo; if (stat(sourceFile.c_str(), &fileInfo) != 0) //read file attributes from source file (resolving symlinks; but cannot be one in this context) { - const wxString errorMessage = wxString(_("Error reading file attributes:")) + wxT("\n\"") + sourceFile.c_str() + wxT("\""); + const wxString errorMessage = wxString(_("Error reading file attributes:")) + wxT("\n\"") + zToWx(sourceFile) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); } //open sourceFile for reading std::ifstream fileIn(sourceFile.c_str(), std::ios_base::binary); if (fileIn.fail()) - throw FileError(wxString(_("Error opening file:")) + wxT("\n\"") + sourceFile.c_str() + wxT("\"")); + throw FileError(wxString(_("Error opening file:")) + wxT("\n\"") + zToWx(sourceFile) + wxT("\"")); //create targetFile and open it for writing - std::ofstream fileOut(targetFile.c_str(), std::ios_base::binary); + const Zstring temporary = createTempName(targetFile); //use temporary file until a correct date has been set + + std::ofstream fileOut(temporary.c_str(), std::ios_base::binary); if (fileOut.fail()) - throw FileError(wxString(_("Error opening file:")) + wxT("\n\"") + targetFile.c_str() + wxT("\"")); + throw FileError(wxString(_("Error opening file:")) + wxT("\n\"") + zToWx(targetFile) + wxT("\"")); try { @@ -1148,16 +1195,16 @@ void FreeFileSync::copyFile(const Zstring& sourceFile, { fileOut.write(memory.buffer, fileIn.gcount()); if (fileOut.bad()) - throw FileError(wxString(_("Error writing file:")) + wxT("\n\"") + targetFile.c_str() + wxT("\"")); + throw FileError(wxString(_("Error writing file:")) + wxT("\n\"") + zToWx(targetFile) + wxT("\"")); break; } else if (fileIn.fail()) - throw FileError(wxString(_("Error reading file:")) + wxT("\n\"") + sourceFile.c_str() + wxT("\"")); + throw FileError(wxString(_("Error reading file:")) + wxT("\n\"") + zToWx(sourceFile) + wxT("\"")); fileOut.write(memory.buffer, memory.bufferSize); if (fileOut.bad()) - throw FileError(wxString(_("Error writing file:")) + wxT("\n\"") + targetFile.c_str() + wxT("\"")); + throw FileError(wxString(_("Error writing file:")) + wxT("\n\"") + zToWx(targetFile) + wxT("\"")); totalBytesTransferred += memory.bufferSize; @@ -1171,8 +1218,8 @@ void FreeFileSync::copyFile(const Zstring& sourceFile, case CopyFileCallback::CANCEL: //an user aborted operation IS an error condition! - throw FileError(wxString(_("Error copying file:")) + wxT("\n\"") + sourceFile.c_str() + wxT("\" ->\n\"") + - targetFile.c_str() + wxT("\"\n\n") + _("Operation aborted!")); + throw FileError(wxString(_("Error copying file:")) + wxT("\n\"") + zToWx(sourceFile) + wxT("\" ->\n\"") + + zToWx(targetFile) + wxT("\"\n\n") + _("Operation aborted!")); } } } @@ -1183,25 +1230,35 @@ void FreeFileSync::copyFile(const Zstring& sourceFile, //adapt file modification time: struct utimbuf newTimes; - time(&newTimes.actime); //set file access time to current time + ::time(&newTimes.actime); //set file access time to current time newTimes.modtime = fileInfo.st_mtime; - if (utime(targetFile.c_str(), &newTimes) != 0) + if (utime(temporary.c_str(), &newTimes) != 0) { - wxString errorMessage = wxString(_("Error changing modification time:")) + wxT("\n\"") + targetFile.c_str() + wxT("\""); + wxString errorMessage = wxString(_("Error changing modification time:")) + wxT("\n\"") + zToWx(targetFile) + wxT("\""); + throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); + } + + //rename temporary file + if (::rename(temporary.c_str(), targetFile.c_str()) != 0) + { + const wxString errorMessage = wxString(_("Error moving file:")) + wxT("\n\"") + zToWx(temporary) + wxT("\" ->\n\"") + zToWx(targetFile) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); } //set file access rights - if (chmod(targetFile.c_str(), fileInfo.st_mode) != 0) + if (::chmod(targetFile.c_str(), fileInfo.st_mode) != 0) { - wxString errorMessage = wxString(_("Error writing file attributes:")) + wxT("\n\"") + targetFile.c_str() + wxT("\""); + const wxString errorMessage = wxString(_("Error writing file attributes:")) + wxT("\n\"") + zToWx(targetFile) + wxT("\""); throw FileError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted()); } } catch (...) - { //try to delete target file if error occured, or exception was thrown in callback function + { + //try to delete target file if error occured, or exception was thrown in callback function if (FreeFileSync::fileExists(targetFile)) ::unlink(targetFile); //don't handle error situations! + if (FreeFileSync::fileExists(temporary)) + ::unlink(temporary); //don't handle error situations! throw; } diff --git a/shared/fileHandling.h b/shared/fileHandling.h index 5ccd595f..d856603f 100644 --- a/shared/fileHandling.h +++ b/shared/fileHandling.h @@ -8,76 +8,74 @@ namespace FreeFileSync { - Zstring getFormattedDirectoryName(const Zstring& dirname); +Zstring getFormattedDirectoryName(const Zstring& dirname); - bool fileExists(const DefaultChar* filename); //throw() replaces wxFileExists()! - bool dirExists(const DefaultChar* dirname); //throw() replaces wxDirExists(): optional 'cause wxDirExists treats symlinks correctly - bool symlinkExists(const DefaultChar* objname); //throw() check if a symbolic link exists +bool fileExists(const DefaultChar* filename); //throw() replaces wxFileExists()! +bool dirExists(const DefaultChar* dirname); //throw() replaces wxDirExists(): optional 'cause wxDirExists treats symlinks correctly +bool symlinkExists(const DefaultChar* objname); //throw() check if a symbolic link exists - //check if files can be moved between two EXISTING paths (without copying) - bool isMovable(const Zstring& pathFrom, const Zstring& pathTo); //throw() +//check if files can be moved between two EXISTING paths (without copying) +bool isMovable(const Zstring& pathFrom, const Zstring& pathTo); //throw() - //optionally: copy directory last change date, DOES NOTHING if something fails - void copyDirLastChangeDate(const Zstring& sourceDir, const Zstring& targetDir); +//optionally: copy directory last change date, DOES NOTHING if something fails +void copyDirLastChangeDate(const Zstring& sourceDir, const Zstring& targetDir); - //recycler - bool recycleBinExists(); //test existence of Recycle Bin API on current system +//recycler +bool recycleBinExists(); //test existence of Recycle Bin API on current system - //file handling - void removeFile(const Zstring& filename, const bool useRecycleBin); //throw (FileError, std::logic_error) - void removeDirectory(const Zstring& directory, const bool useRecycleBin); //throw (FileError) +//file handling +void removeFile(const Zstring& filename, const bool useRecycleBin); //throw (FileError, std::logic_error) +void removeDirectory(const Zstring& directory, const bool useRecycleBin); //throw (FileError) - class MoveFileCallback //callback functionality +struct MoveFileCallback //callback functionality +{ + virtual ~MoveFileCallback() {} + + enum Response { - public: - virtual ~MoveFileCallback() {} - - enum Response - { - CONTINUE, - CANCEL - }; - virtual Response requestUiRefresh() = 0; //DON'T throw exceptions here, at least in Windows build! + CONTINUE, + CANCEL }; + virtual Response requestUiRefresh() = 0; //DON'T throw exceptions here, at least in Windows build! +}; - //move source to target; expectations: target not existing, all super-directories of target exist - void moveFile(const Zstring& sourceFile, const Zstring& targetFile, MoveFileCallback* callback = NULL); //throw (FileError); +//move source to target; expectations: target not existing, all super-directories of target exist +void moveFile(const Zstring& sourceFile, const Zstring& targetFile, MoveFileCallback* callback = NULL); //throw (FileError); - //move source to target including subdirectories - //"ignoreExistingDirs": existing directories will be enhanced as long as this is possible without overwriting files - void moveDirectory(const Zstring& sourceDir, const Zstring& targetDir, bool ignoreExistingDirs, MoveFileCallback* callback = NULL); //throw (FileError); +//move source to target including subdirectories +//"ignoreExistingDirs": existing directories will be enhanced as long as this is possible without overwriting files +void moveDirectory(const Zstring& sourceDir, const Zstring& targetDir, bool ignoreExistingDirs, MoveFileCallback* callback = NULL); //throw (FileError); - //creates superdirectories automatically: - void createDirectory(const Zstring& directory, const Zstring& templateDir = Zstring(), const bool copyDirectorySymLinks = false); //throw (FileError); +//creates superdirectories automatically: +void createDirectory(const Zstring& directory, const Zstring& templateDir = Zstring(), const bool copyDirectorySymLinks = false); //throw (FileError); + +struct CopyFileCallback //callback functionality +{ + virtual ~CopyFileCallback() {} - class CopyFileCallback //callback functionality + enum Response { - public: - virtual ~CopyFileCallback() {} - - enum Response - { - CONTINUE, - CANCEL - }; - virtual Response updateCopyStatus(const wxULongLong& totalBytesTransferred) = 0; //DON'T throw exceptions here, at least in Windows build! + CONTINUE, + CANCEL }; + virtual Response updateCopyStatus(const wxULongLong& totalBytesTransferred) = 0; //DON'T throw exceptions here, at least in Windows build! +}; #ifdef FFS_WIN - class ShadowCopy; +class ShadowCopy; - void copyFile(const Zstring& sourceFile, - const Zstring& targetFile, - const bool copyFileSymLinks, - ShadowCopy* shadowCopyHandler = NULL, //supply handler for making shadow copies - CopyFileCallback* callback = NULL); //throw (FileError); +void copyFile(const Zstring& sourceFile, + const Zstring& targetFile, + const bool copyFileSymLinks, + ShadowCopy* shadowCopyHandler = NULL, //supply handler for making shadow copies + CopyFileCallback* callback = NULL); //throw (FileError); #elif defined FFS_LINUX - void copyFile(const Zstring& sourceFile, - const Zstring& targetFile, - const bool copyFileSymLinks, - CopyFileCallback* callback = NULL); //throw (FileError); +void copyFile(const Zstring& sourceFile, + const Zstring& targetFile, + const bool copyFileSymLinks, + CopyFileCallback* callback = NULL); //throw (FileError); #endif } diff --git a/shared/fileTraverser.cpp b/shared/fileTraverser.cpp index ab223791..c323f1a3 100644 --- a/shared/fileTraverser.cpp +++ b/shared/fileTraverser.cpp @@ -2,6 +2,7 @@ #include "systemConstants.h" #include "systemFunctions.h" #include <wx/intl.h> +#include "stringConv.h" #ifdef FFS_WIN #include <wx/msw/wrapwin.h> //includes "windows.h" @@ -108,11 +109,11 @@ private: template <bool traverseDirectorySymlinks> bool traverseDirectory(const Zstring& directory, FreeFileSync::TraverseCallback* sink, const int level) { - using FreeFileSync::TraverseCallback; + using namespace FreeFileSync; if (level == 100) //catch endless recursion { - switch (sink->onError(wxString(_("Endless loop when traversing directory:")) + wxT("\n\"") + directory + wxT("\""))) + switch (sink->onError(wxString(_("Endless loop when traversing directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\""))) { case TraverseCallback::TRAVERSING_STOP: return false; @@ -139,7 +140,7 @@ bool traverseDirectory(const Zstring& directory, FreeFileSync::TraverseCallback* return true; //else: we have a problem... report it: - const wxString errorMessage = wxString(_("Error traversing directory:")) + wxT("\n\"") + directory.c_str() + wxT("\"") ; + const wxString errorMessage = wxString(_("Error traversing directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\"") ; switch (sink->onError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted(lastError))) { case TraverseCallback::TRAVERSING_STOP: @@ -151,7 +152,8 @@ bool traverseDirectory(const Zstring& directory, FreeFileSync::TraverseCallback* CloseFindHandleOnExit dummy(searchHandle); do - { //don't return "." and ".." + { + //don't return "." and ".." const wxChar* const shortName = fileMetaData.cFileName; if ( shortName[0] == wxChar('.') && ((shortName[1] == wxChar('.') && shortName[2] == wxChar('\0')) || @@ -211,7 +213,7 @@ bool traverseDirectory(const Zstring& directory, FreeFileSync::TraverseCallback* return true; //everything okay //else: we have a problem... report it: - const wxString errorMessage = wxString(_("Error traversing directory:")) + wxT("\n\"") + directory.c_str() + wxT("\"") ; + const wxString errorMessage = wxString(_("Error traversing directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\"") ; switch (sink->onError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted(lastError))) { case TraverseCallback::TRAVERSING_STOP: @@ -224,7 +226,7 @@ bool traverseDirectory(const Zstring& directory, FreeFileSync::TraverseCallback* DIR* dirObj = ::opendir(directory.c_str()); //directory must NOT end with path separator, except "/" if (dirObj == NULL) { - const wxString errorMessage = wxString(_("Error traversing directory:")) + wxT("\n\"") + directory.c_str() + wxT("\"") ; + const wxString errorMessage = wxString(_("Error traversing directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\"") ; switch (sink->onError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted())) { case TraverseCallback::TRAVERSING_STOP: @@ -245,7 +247,7 @@ bool traverseDirectory(const Zstring& directory, FreeFileSync::TraverseCallback* return true; //everything okay //else: we have a problem... report it: - const wxString errorMessage = wxString(_("Error traversing directory:")) + wxT("\n\"") + directory.c_str() + wxT("\"") ; + const wxString errorMessage = wxString(_("Error traversing directory:")) + wxT("\n\"") + zToWx(directory) + wxT("\"") ; switch (sink->onError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted())) { case TraverseCallback::TRAVERSING_STOP: @@ -256,7 +258,7 @@ bool traverseDirectory(const Zstring& directory, FreeFileSync::TraverseCallback* } //don't return "." and ".." - const wxChar* const shortName = dirEntry->d_name; + const DefaultChar* const shortName = dirEntry->d_name; if ( shortName[0] == wxChar('.') && ((shortName[1] == wxChar('.') && shortName[2] == wxChar('\0')) || shortName[1] == wxChar('\0'))) @@ -269,7 +271,7 @@ bool traverseDirectory(const Zstring& directory, FreeFileSync::TraverseCallback* struct stat fileInfo; if (lstat(fullName.c_str(), &fileInfo) != 0) //lstat() does not resolve symlinks { - const wxString errorMessage = wxString(_("Error reading file attributes:")) + wxT("\n\"") + fullName.c_str() + wxT("\""); + const wxString errorMessage = wxString(_("Error reading file attributes:")) + wxT("\n\"") + zToWx(fullName) + wxT("\""); switch (sink->onError(errorMessage + wxT("\n\n") + FreeFileSync::getLastErrorFormatted())) { case TraverseCallback::TRAVERSING_STOP: diff --git a/shared/fileTraverser.h b/shared/fileTraverser.h index d2aa7f3e..c1277d87 100644 --- a/shared/fileTraverser.h +++ b/shared/fileTraverser.h @@ -10,55 +10,55 @@ namespace FreeFileSync { - class TraverseCallback - { - public: - virtual ~TraverseCallback() {} - - enum ReturnValue - { - TRAVERSING_STOP, - TRAVERSING_CONTINUE - }; +class TraverseCallback +{ +public: + virtual ~TraverseCallback() {} - struct FileInfo - { - wxULongLong fileSize; //unit: bytes! - wxLongLong lastWriteTimeRaw; //number of seconds since Jan. 1st 1970 UTC - }; + enum ReturnValue + { + TRAVERSING_STOP, + TRAVERSING_CONTINUE + }; - class ReturnValDir - { - public: - //some proxy classes - class Stop {}; - class Ignore {}; - class Continue {}; + struct FileInfo + { + wxULongLong fileSize; //unit: bytes! + wxLongLong lastWriteTimeRaw; //number of seconds since Jan. 1st 1970 UTC + }; - ReturnValDir(const Stop&) : returnCode(TRAVERSING_STOP), subDirCb(NULL) {} - ReturnValDir(const Ignore&) : returnCode(TRAVERSING_IGNORE_DIR), subDirCb(NULL) {} - ReturnValDir(const Continue&, TraverseCallback* subDirCallback) : returnCode(TRAVERSING_CONTINUE), subDirCb(subDirCallback) {} + class ReturnValDir + { + public: + //some proxy classes + class Stop {}; + class Ignore {}; + class Continue {}; + ReturnValDir(const Stop&) : returnCode(TRAVERSING_STOP), subDirCb(NULL) {} + ReturnValDir(const Ignore&) : returnCode(TRAVERSING_IGNORE_DIR), subDirCb(NULL) {} + ReturnValDir(const Continue&, TraverseCallback* subDirCallback) : returnCode(TRAVERSING_CONTINUE), subDirCb(subDirCallback) {} - enum ReturnValueEnh - { - TRAVERSING_STOP, - TRAVERSING_IGNORE_DIR, - TRAVERSING_CONTINUE - }; - const ReturnValueEnh returnCode; - TraverseCallback* const subDirCb; + enum ReturnValueEnh + { + TRAVERSING_STOP, + TRAVERSING_IGNORE_DIR, + TRAVERSING_CONTINUE }; - //overwrite these virtual methods - virtual ReturnValue onError(const wxString& errorText) = 0; - virtual ReturnValue onFile(const DefaultChar* shortName, const Zstring& fullName, const FileInfo& details) = 0; - virtual ReturnValDir onDir(const DefaultChar* shortName, const Zstring& fullName) = 0; + const ReturnValueEnh returnCode; + TraverseCallback* const subDirCb; }; - //custom traverser with detail information about files - void traverseFolder(const Zstring& directory, const bool traverseDirectorySymlinks, TraverseCallback* sink); //throw() + //overwrite these virtual methods + virtual ReturnValue onError(const wxString& errorText) = 0; + virtual ReturnValue onFile(const DefaultChar* shortName, const Zstring& fullName, const FileInfo& details) = 0; + virtual ReturnValDir onDir(const DefaultChar* shortName, const Zstring& fullName) = 0; +}; + +//custom traverser with detail information about files +void traverseFolder(const Zstring& directory, const bool traverseDirectorySymlinks, TraverseCallback* sink); //throw() } #endif // FILETRAVERSER_H_INCLUDED diff --git a/shared/globalFunctions.cpp b/shared/globalFunctions.cpp index f50a3097..a5ebba68 100644 --- a/shared/globalFunctions.cpp +++ b/shared/globalFunctions.cpp @@ -1,49 +1,11 @@ #include "globalFunctions.h" #include <wx/msgdlg.h> #include <wx/file.h> -#include <fstream> -#include <wx/stream.h> #include <wx/stopwatch.h> #include <cmath> #include "systemConstants.h" -wxString globalFunctions::numberToWxString(const unsigned int number) -{ - return wxString::Format(wxT("%u"), number); -} - - -wxString globalFunctions::numberToWxString(const int number) -{ - return wxString::Format(wxT("%i"), number); -} - - -wxString globalFunctions::numberToWxString(const float number) -{ - return wxString::Format(wxT("%f"), number); -} - - -int globalFunctions::stringToInt(const std::string& number) -{ - return atoi(number.c_str()); -} - - -long globalFunctions::stringToLong(const std::string& number) -{ - return atol(number.c_str()); -} - - -double globalFunctions::stringToDouble(const std::string& number) -{ - return atof(number.c_str()); -} - - int globalFunctions::wxStringToInt(const wxString& number) { long result = 0; @@ -70,42 +32,10 @@ unsigned int globalFunctions::getDigitCount(const unsigned int number) //count n } -int globalFunctions::readInt(std::ifstream& stream) -{ - int result = 0; - char* buffer = reinterpret_cast<char*>(&result); - stream.read(buffer, sizeof(int)); - return result; -} - - -void globalFunctions::writeInt(std::ofstream& stream, const int number) -{ - const char* buffer = reinterpret_cast<const char*>(&number); - stream.write(buffer, sizeof(int)); -} - - -int globalFunctions::readInt(wxInputStream& stream) -{ - int result = 0; - char* buffer = reinterpret_cast<char*>(&result); - stream.Read(buffer, sizeof(int)); - return result; -} - - -void globalFunctions::writeInt(wxOutputStream& stream, const int number) -{ - const char* buffer = reinterpret_cast<const char*>(&number); - stream.Write(buffer, sizeof(int)); -} - - //############################################################################ Performance::Performance() : - resultWasShown(false), - timer(new wxStopWatch) + resultWasShown(false), + timer(new wxStopWatch) { timer->Start(); } @@ -128,8 +58,8 @@ void Performance::showResult() //############################################################################ DebugLog::DebugLog() : - lineCount(0), - logFile(NULL) + lineCount(0), + logFile(NULL) { logFile = new wxFile; logfileName = assembleFileName(); diff --git a/shared/globalFunctions.h b/shared/globalFunctions.h index b53ba596..74387959 100644 --- a/shared/globalFunctions.h +++ b/shared/globalFunctions.h @@ -9,6 +9,8 @@ #include <wx/longlong.h> #include <memory> #include <sstream> +#include <fstream> +#include <wx/stream.h> class wxInputStream; class wxOutputStream; @@ -20,129 +22,131 @@ namespace globalFunctions //------------------------------------------------ // FUNCTIONS //------------------------------------------------ - inline - int round(double d) //little rounding function - { - return static_cast<int>(d < 0 ? d - .5 : d + .5); - } +inline +int round(double d) //little rounding function +{ + return static_cast<int>(d < 0 ? d - .5 : d + .5); +} - template <class T> - inline - T abs(const T& d) //absolute value - { - return(d < 0 ? -d : d); - } +template <class T> +inline +T abs(const T& d) //absolute value +{ + return(d < 0 ? -d : d); +} - template <class T> - inline std::string numberToString(const T& number) //convert number to string the C++ way - { - std::stringstream ss; - ss << number; - return ss.str(); - } +template <class T> +inline +std::string numberToString(const T& number) //convert number to string the C++ way +{ + std::stringstream ss; + ss << number; + return ss.str(); +} - wxString numberToWxString(const unsigned int number); //convert number to wxString - wxString numberToWxString(const int number); //convert number to wxString - wxString numberToWxString(const float number); //convert number to wxString +wxString numberToWxString(const unsigned int number); //convert number to wxString +wxString numberToWxString(const int number); //convert number to wxString +wxString numberToWxString(const float number); //convert number to wxString - int stringToInt( const std::string& number); //convert String to number - long stringToLong( const std::string& number); //convert String to number - double stringToDouble(const std::string& number); //convert String to number +int stringToInt( const std::string& number); //convert String to number +long stringToLong( const std::string& number); //convert String to number +double stringToDouble(const std::string& number); //convert String to number - int wxStringToInt( const wxString& number); //convert wxString to number - double wxStringToDouble(const wxString& number); //convert wxString to number +int wxStringToInt( const wxString& number); //convert wxString to number +double wxStringToDouble(const wxString& number); //convert wxString to number - unsigned int getDigitCount(const unsigned int number); //count number of digits +unsigned int getDigitCount(const unsigned int number); //count number of digits - int readInt(std::ifstream& stream); //read int from file stream - void writeInt(std::ofstream& stream, const int number); //write int to filestream +//read/write numbers: int, long, unsigned int ... ect +template <class T> T readNumber(std::ifstream& stream); +template <class T> void writeNumber(std::ofstream& stream, T number); - int readInt(wxInputStream& stream); //read int from file stream - void writeInt(wxOutputStream& stream, const int number); //write int to filestream +template <class T> T readNumber(wxInputStream& stream); +template <class T> void writeNumber(wxOutputStream& stream, T number); - inline - wxLongLong convertToSigned(const wxULongLong number) - { - return wxLongLong(number.GetHi(), number.GetLo()); - } +inline +wxLongLong convertToSigned(const wxULongLong number) +{ + return wxLongLong(number.GetHi(), number.GetLo()); +} //Note: the following lines are a performance optimization for deleting elements from a vector: linear runtime at most! - template <class T> - void removeRowsFromVector(const std::set<unsigned int>& rowsToRemove, std::vector<T>& grid) - { - if (rowsToRemove.empty()) - return; +template <class T> +void removeRowsFromVector(const std::set<unsigned int>& rowsToRemove, std::vector<T>& grid) +{ + if (rowsToRemove.empty()) + return; - std::set<unsigned int>::const_iterator rowToSkipIndex = rowsToRemove.begin(); - unsigned int rowToSkip = *rowToSkipIndex; + std::set<unsigned int>::const_iterator rowToSkipIndex = rowsToRemove.begin(); + unsigned int rowToSkip = *rowToSkipIndex; - if (rowToSkip >= grid.size()) - return; + if (rowToSkip >= grid.size()) + return; - typename std::vector<T>::iterator insertPos = grid.begin() + rowToSkip; + typename std::vector<T>::iterator insertPos = grid.begin() + rowToSkip; - for (unsigned int i = rowToSkip; i < grid.size(); ++i) + for (unsigned int i = rowToSkip; i < grid.size(); ++i) + { + if (i != rowToSkip) { - if (i != rowToSkip) - { - *insertPos = grid[i]; - ++insertPos; - } - else - { - ++rowToSkipIndex; - if (rowToSkipIndex != rowsToRemove.end()) - rowToSkip = *rowToSkipIndex; - } + *insertPos = grid[i]; + ++insertPos; } - grid.erase(insertPos, grid.end()); - } - - //bubble sort using swap() instead of assignment: useful if assignment is very expensive - template <class VectorData, typename CompareFct> - void bubbleSwapSort(VectorData& folderCmp, CompareFct compare) - { - for (int i = folderCmp.size() - 2; i >= 0; --i) + else { - bool swapped = false; - for (int j = 0; j <= i; ++j) - if (compare(folderCmp[j + 1], folderCmp[j])) - { - folderCmp[j + 1].swap(folderCmp[j]); - swapped = true; - } - - if (!swapped) - return; + ++rowToSkipIndex; + if (rowToSkipIndex != rowsToRemove.end()) + rowToSkip = *rowToSkipIndex; } } + grid.erase(insertPos, grid.end()); +} - //enhanced binary search template: returns an iterator - template <class ForwardIterator, class T> - inline - ForwardIterator custom_binary_search(ForwardIterator first, ForwardIterator last, const T& value) +//bubble sort using swap() instead of assignment: useful if assignment is very expensive +template <class VectorData, typename CompareFct> +void bubbleSwapSort(VectorData& folderCmp, CompareFct compare) +{ + for (int i = folderCmp.size() - 2; i >= 0; --i) { - first = lower_bound(first, last, value); - if (first != last && !(value < *first)) - return first; - else - return last; - } + bool swapped = false; + for (int j = 0; j <= i; ++j) + if (compare(folderCmp[j + 1], folderCmp[j])) + { + folderCmp[j + 1].swap(folderCmp[j]); + swapped = true; + } - //enhanced binary search template: returns an iterator - template <class ForwardIterator, class T, typename Compare> - inline - ForwardIterator custom_binary_search(ForwardIterator first, ForwardIterator last, const T& value, Compare comp) - { - first = lower_bound(first, last, value, comp); - if (first != last && !comp(value, *first)) - return first; - else - return last; + if (!swapped) + return; } } +//enhanced binary search template: returns an iterator +template <class ForwardIterator, class T> +inline +ForwardIterator custom_binary_search(ForwardIterator first, ForwardIterator last, const T& value) +{ + first = lower_bound(first, last, value); + if (first != last && !(value < *first)) + return first; + else + return last; +} + +//enhanced binary search template: returns an iterator +template <class ForwardIterator, class T, typename Compare> +inline +ForwardIterator custom_binary_search(ForwardIterator first, ForwardIterator last, const T& value, Compare comp) +{ + first = lower_bound(first, last, value, comp); + if (first != last && !comp(value, *first)) + return first; + else + return last; +} +} + //############################################################################ class Performance @@ -185,4 +189,96 @@ wxString getCodeLocation(const wxString file, const int line); //speed alternative: wxLogDebug(wxT("text")) + DebugView + + + + + + + + + + + + + +//---------------Inline Implementation--------------------------------------------------- +template <class T> +inline +T globalFunctions::readNumber(std::ifstream& stream) +{ + T result = 0; + stream.read(reinterpret_cast<char*>(&result), sizeof(T)); + return result; +} + + +template <class T> +inline +void globalFunctions::writeNumber(std::ofstream& stream, T number) +{ + stream.write(reinterpret_cast<const char*>(&number), sizeof(T)); +} + + +template <class T> +inline +T globalFunctions::readNumber(wxInputStream& stream) +{ + T result = 0; + stream.Read(&result, sizeof(T)); + return result; +} + + +template <class T> +inline +void globalFunctions::writeNumber(wxOutputStream& stream, T number) +{ + stream.Write(&number, sizeof(T)); +} + + +inline +wxString globalFunctions::numberToWxString(const unsigned int number) +{ + return wxString::Format(wxT("%u"), number); +} + + +inline +wxString globalFunctions::numberToWxString(const int number) +{ + return wxString::Format(wxT("%i"), number); +} + + +inline +wxString globalFunctions::numberToWxString(const float number) +{ + return wxString::Format(wxT("%f"), number); +} + + +inline +int globalFunctions::stringToInt(const std::string& number) +{ + return atoi(number.c_str()); +} + + +inline +long globalFunctions::stringToLong(const std::string& number) +{ + return atol(number.c_str()); +} + + +inline +double globalFunctions::stringToDouble(const std::string& number) +{ + return atof(number.c_str()); +} + + #endif // GLOBALFUNCTIONS_H_INCLUDED diff --git a/shared/localization.cpp b/shared/localization.cpp index 20bf6d2e..ff14c980 100644 --- a/shared/localization.cpp +++ b/shared/localization.cpp @@ -1,6 +1,7 @@ #include "localization.h" #include <wx/msgdlg.h> #include "../shared/standardPaths.h" +#include "../shared/stringConv.h" #include "systemConstants.h" #include <fstream> #include <map> @@ -112,6 +113,13 @@ LocalizationInfo::LocalizationInfo() newEntry.languageFlag = wxT("brazil.png"); locMapping.push_back(newEntry); + newEntry.languageID = wxLANGUAGE_ROMANIAN; + newEntry.languageName = wxT("Română"); + newEntry.languageFile = wxT("romanian.lng"); + newEntry.translatorName = wxT("Alexandru Bogdan Munteanu"); + newEntry.languageFlag = wxT("romania.png"); + locMapping.push_back(newEntry); + newEntry.languageID = wxLANGUAGE_SLOVENIAN; newEntry.languageName = wxT("SlovenÅ¡Äina"); newEntry.languageFile = wxT("slovenian.lng"); @@ -119,6 +127,13 @@ LocalizationInfo::LocalizationInfo() newEntry.languageFlag = wxT("slovakia.png"); locMapping.push_back(newEntry); + newEntry.languageID = wxLANGUAGE_TURKISH; + newEntry.languageName = wxT("Türkçe"); + newEntry.languageFile = wxT("turkish.lng"); + newEntry.translatorName = wxT("H.Barbaros BIÇAKCI"); + newEntry.languageFlag = wxT("turkey.png"); + locMapping.push_back(newEntry); + newEntry.languageID = wxLANGUAGE_JAPANESE; newEntry.languageName = wxT("日本語"); newEntry.languageFile = wxT("japanese.lng"); @@ -236,9 +251,9 @@ CustomLocale& CustomLocale::getInstance() CustomLocale::CustomLocale() : - wxLocale(wxLANGUAGE_DEFAULT), //setting a different language needn't be supported on all systems! - translationDB(new Translation), - currentLanguage(wxLANGUAGE_ENGLISH) {} + wxLocale(wxLANGUAGE_DEFAULT), //setting a different language needn't be supported on all systems! + translationDB(new Translation), + currentLanguage(wxLANGUAGE_ENGLISH) {} inline @@ -290,7 +305,7 @@ class UnicodeFileReader { public: UnicodeFileReader(const wxString& filename) : - inputFile(NULL) + inputFile(NULL) { //workaround to get a FILE* from a unicode filename wxFFile dummyFile(filename, wxT("rb")); @@ -363,8 +378,8 @@ void CustomLocale::setLanguage(const int language) translationDB->clear(); if (!languageFile.empty()) { - UnicodeFileReader langFile(FreeFileSync::getInstallationDir() + globalFunctions::FILE_NAME_SEPARATOR + - wxT("Languages") + globalFunctions::FILE_NAME_SEPARATOR + languageFile); + UnicodeFileReader langFile(FreeFileSync::getInstallationDir() + zToWx(globalFunctions::FILE_NAME_SEPARATOR) + + wxT("Languages") + zToWx(globalFunctions::FILE_NAME_SEPARATOR) + languageFile); if (langFile.isOkay()) { int rowNumber = 0; diff --git a/shared/localization.h b/shared/localization.h index 2a5ee80d..0a5ca4fb 100644 --- a/shared/localization.h +++ b/shared/localization.h @@ -10,53 +10,55 @@ class Translation; namespace FreeFileSync { - //language dependent global variables: need to be initialized by CustomLocale on program startup and language switch +//language dependent global variables: need to be initialized by CustomLocale on program startup and language switch - extern const wxChar* THOUSANDS_SEPARATOR; - extern const wxChar* DECIMAL_POINT; +extern const wxChar* THOUSANDS_SEPARATOR; +extern const wxChar* DECIMAL_POINT; - struct LocInfoLine - { - int languageID; - wxString languageName; - wxString languageFile; - wxString translatorName; - wxString languageFlag; - }; - - class LocalizationInfo - { - public: - static const std::vector<LocInfoLine>& getMapping(); +struct LocInfoLine +{ + int languageID; + wxString languageName; + wxString languageFile; + wxString translatorName; + wxString languageFlag; +}; + +class LocalizationInfo +{ +public: + static const std::vector<LocInfoLine>& getMapping(); - private: - LocalizationInfo(); +private: + LocalizationInfo(); + LocalizationInfo(const LocalizationInfo&); + LocalizationInfo& operator=(const LocalizationInfo&); - std::vector<LocInfoLine> locMapping; - }; + std::vector<LocInfoLine> locMapping; +}; - class CustomLocale : public wxLocale - { - public: - static CustomLocale& getInstance(); +class CustomLocale : public wxLocale +{ +public: + static CustomLocale& getInstance(); - void setLanguage(const int language); + void setLanguage(const int language); - int getLanguage() const - { - return currentLanguage; - } + int getLanguage() const + { + return currentLanguage; + } - virtual const wxChar* GetString(const wxChar* szOrigString, const wxChar* szDomain = NULL) const; + virtual const wxChar* GetString(const wxChar* szOrigString, const wxChar* szDomain = NULL) const; - private: - CustomLocale(); +private: + CustomLocale(); - std::auto_ptr<Translation> translationDB; - int currentLanguage; - }; + std::auto_ptr<Translation> translationDB; + int currentLanguage; +}; } #endif // MISC_H_INCLUDED diff --git a/shared/loki/AbstractFactory.h b/shared/loki/AbstractFactory.h new file mode 100644 index 00000000..8ff518dc --- /dev/null +++ b/shared/loki/AbstractFactory.h @@ -0,0 +1,185 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_ABSTRACTFACTORY_INC_ +#define LOKI_ABSTRACTFACTORY_INC_ + +// $Id: AbstractFactory.h 771 2006-10-27 18:05:03Z clitte_bbt $ + + +#include "Typelist.h" +#include "Sequence.h" +#include "TypeManip.h" +#include "HierarchyGenerators.h" + +#include <cassert> + +/** + * \defgroup FactoriesGroup Factories + * \defgroup AbstractFactoryGroup Abstract Factory + * \ingroup FactoriesGroup + * \brief Implements an abstract object factory. + */ + +/** + * \class AbstractFactory + * \ingroup AbstractFactoryGroup + * \brief Implements an abstract object factory. + */ + +namespace Loki +{ + +//////////////////////////////////////////////////////////////////////////////// +// class template AbstractFactoryUnit +// The building block of an Abstract Factory +//////////////////////////////////////////////////////////////////////////////// + + template <class T> + class AbstractFactoryUnit + { + public: + virtual T* DoCreate(Type2Type<T>) = 0; + virtual ~AbstractFactoryUnit() {} + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template AbstractFactory +// Defines an Abstract Factory interface starting from a typelist +//////////////////////////////////////////////////////////////////////////////// + + template + < + class TList, + template <class> class Unit = AbstractFactoryUnit + > + class AbstractFactory : public GenScatterHierarchy<TList, Unit> + { + public: + typedef TList ProductList; + + template <class T> T* Create() + { + Unit<T>& unit = *this; + return unit.DoCreate(Type2Type<T>()); + } + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template OpNewFactoryUnit +// Creates an object by invoking the new operator +//////////////////////////////////////////////////////////////////////////////// + + template <class ConcreteProduct, class Base> + class OpNewFactoryUnit : public Base + { + typedef typename Base::ProductList BaseProductList; + + protected: + typedef typename BaseProductList::Tail ProductList; + + public: + typedef typename BaseProductList::Head AbstractProduct; + ConcreteProduct* DoCreate(Type2Type<AbstractProduct>) + { + return new ConcreteProduct; + } + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template PrototypeFactoryUnit +// Creates an object by cloning a prototype +// There is a difference between the implementation herein and the one described +// in the book: GetPrototype and SetPrototype use the helper friend +// functions DoGetPrototype and DoSetPrototype. The friend functions avoid +// name hiding issues. Plus, GetPrototype takes a reference to pointer +// instead of returning the pointer by value. +//////////////////////////////////////////////////////////////////////////////// + + template <class ConcreteProduct, class Base> + class PrototypeFactoryUnit : public Base + { + typedef typename Base::ProductList BaseProductList; + + protected: + typedef typename BaseProductList::Tail ProductList; + + public: + typedef typename BaseProductList::Head AbstractProduct; + + PrototypeFactoryUnit(AbstractProduct* p = 0) + : pPrototype_(p) + {} + + template <class CP, class Base1> + friend void DoGetPrototype(const PrototypeFactoryUnit<CP, Base1>& me, + typename Base1::ProductList::Head*& pPrototype); + + template <class CP, class Base1> + friend void DoSetPrototype(PrototypeFactoryUnit<CP, Base1>& me, + typename Base1::ProductList::Head* pObj); + + template <class U> + void GetPrototype(U*& p) + { return DoGetPrototype(*this, p); } + + template <class U> + void SetPrototype(U* pObj) + { DoSetPrototype(*this, pObj); } + + AbstractProduct* DoCreate(Type2Type<AbstractProduct>) + { + assert(pPrototype_); + return pPrototype_->Clone(); + } + + private: + AbstractProduct* pPrototype_; + }; + + template <class CP, class Base> + inline void DoGetPrototype(const PrototypeFactoryUnit<CP, Base>& me, + typename Base::ProductList::Head*& pPrototype) + { pPrototype = me.pPrototype_; } + + template <class CP, class Base> + inline void DoSetPrototype(PrototypeFactoryUnit<CP, Base>& me, + typename Base::ProductList::Head* pObj) + { me.pPrototype_ = pObj; } + +//////////////////////////////////////////////////////////////////////////////// +// class template ConcreteFactory +// Implements an AbstractFactory interface +//////////////////////////////////////////////////////////////////////////////// + + template + < + class AbstractFact, + template <class, class> class Creator = OpNewFactoryUnit, + class TList = typename AbstractFact::ProductList + > + class ConcreteFactory + : public GenLinearHierarchy< + typename TL::Reverse<TList>::Result, Creator, AbstractFact> + { + public: + typedef typename AbstractFact::ProductList ProductList; + typedef TList ConcreteProductList; + }; + +} // namespace Loki + + +#endif // end file guardian + diff --git a/shared/loki/Allocator.h b/shared/loki/Allocator.h new file mode 100644 index 00000000..a79ee061 --- /dev/null +++ b/shared/loki/Allocator.h @@ -0,0 +1,153 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2008 by Rich Sposato +// +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// + +#ifndef LOKI_ALLOCATOR_HPP_INCLUDED +#define LOKI_ALLOCATOR_HPP_INCLUDED + +// $Id: Allocator.h 896 2008-08-08 22:20:05Z syntheticpp $ + +// Requires project to be compiled with loki/src/SmallObj.cpp and loki/src/Singleton.cpp + +#include <loki/SmallObj.h> + + +namespace Loki +{ + + +//----------------------------------------------------------------------------- + +/** @class LokiAllocator + Adapts Loki's Small-Object Allocator for STL container classes. + This class provides all the functionality required for STL allocators, but + uses Loki's Small-Object Allocator to perform actual memory operations. + Implementation comes from a post in Loki forums (by Rasmus Ekman?). + */ +template +< + typename Type, + typename AllocT = Loki::AllocatorSingleton<> +> +class LokiAllocator +{ +public: + + typedef ::std::size_t size_type; + typedef ::std::ptrdiff_t difference_type; + typedef Type * pointer; + typedef const Type * const_pointer; + typedef Type & reference; + typedef const Type & const_reference; + typedef Type value_type; + + /// Default constructor does nothing. + inline LokiAllocator( void ) throw() { } + + /// Copy constructor does nothing. + inline LokiAllocator( const LokiAllocator & ) throw() { } + + /// Type converting allocator constructor does nothing. + template < typename Type1 > + inline LokiAllocator( const LokiAllocator< Type1 > & ) throw() { } + + /// Destructor does nothing. + inline ~LokiAllocator() throw() { } + + /// Convert an allocator<Type> to an allocator <Type1>. + template < typename Type1 > + struct rebind + { + typedef LokiAllocator< Type1 > other; + }; + + /// Return address of reference to mutable element. + pointer address( reference elem ) const { return &elem; } + + /// Return address of reference to const element. + const_pointer address( const_reference elem ) const { return &elem; } + + /** Allocate an array of count elements. Warning! The true parameter in + the call to Allocate means this function can throw exceptions. This is + better than not throwing, and returning a null pointer in case the caller + assumes the return value is not null. + @param count # of elements in array. + @param hint Place where caller thinks allocation should occur. + @return Pointer to block of memory. + */ + pointer allocate( size_type count, const void * hint = 0 ) + { + (void)hint; // Ignore the hint. + void * p = AllocT::Instance().Allocate( count * sizeof( Type ), true ); + return reinterpret_cast< pointer >( p ); + } + + /// Ask allocator to release memory at pointer with size bytes. + void deallocate( pointer p, size_type size ) + { + AllocT::Instance().Deallocate( p, size * sizeof( Type ) ); + } + + /// Calculate max # of elements allocator can handle. + size_type max_size( void ) const throw() + { + // A good optimizer will see these calculations always produce the same + // value and optimize this function away completely. + const size_type max_bytes = size_type( -1 ); + const size_type bytes = max_bytes / sizeof( Type ); + return bytes; + } + + /// Construct an element at the pointer. + void construct( pointer p, const Type & value ) + { + // A call to global placement new forces a call to copy constructor. + ::new( p ) Type( value ); + } + + /// Destruct the object at pointer. + void destroy( pointer p ) + { + // If the Type has no destructor, then some compilers complain about + // an unreferenced parameter, so use the void cast trick to prevent + // spurious warnings. + (void)p; + p->~Type(); + } + +}; + +//----------------------------------------------------------------------------- + +/** All equality operators return true since LokiAllocator is basically a + monostate design pattern, so all instances of it are identical. + */ +template < typename Type > +inline bool operator == ( const LokiAllocator< Type > &, const LokiAllocator< Type > & ) +{ + return true; +} + +/** All inequality operators return false since LokiAllocator is basically a + monostate design pattern, so all instances of it are identical. + */ +template < typename Type > +inline bool operator != ( const LokiAllocator< Type > & , const LokiAllocator< Type > & ) +{ + return false; +} + +//----------------------------------------------------------------------------- + +} // namespace Loki + +#endif // LOKI_ALLOCATOR_INCLUDED diff --git a/shared/loki/AssocVector.h b/shared/loki/AssocVector.h new file mode 100644 index 00000000..905e0963 --- /dev/null +++ b/shared/loki/AssocVector.h @@ -0,0 +1,358 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_ASSOCVECTOR_INC_ +#define LOKI_ASSOCVECTOR_INC_ + +// $Id: AssocVector.h 765 2006-10-18 13:55:32Z syntheticpp $ + + +#include <algorithm> +#include <functional> +#include <vector> +#include <utility> + +namespace Loki +{ +//////////////////////////////////////////////////////////////////////////////// +// class template AssocVectorCompare +// Used by AssocVector +//////////////////////////////////////////////////////////////////////////////// + + namespace Private + { + template <class Value, class C> + class AssocVectorCompare : public C + { + typedef std::pair<typename C::first_argument_type, Value> + Data; + typedef typename C::first_argument_type first_argument_type; + + public: + AssocVectorCompare() + {} + + AssocVectorCompare(const C& src) : C(src) + {} + + bool operator()(const first_argument_type& lhs, + const first_argument_type& rhs) const + { return C::operator()(lhs, rhs); } + + bool operator()(const Data& lhs, const Data& rhs) const + { return operator()(lhs.first, rhs.first); } + + bool operator()(const Data& lhs, + const first_argument_type& rhs) const + { return operator()(lhs.first, rhs); } + + bool operator()(const first_argument_type& lhs, + const Data& rhs) const + { return operator()(lhs, rhs.first); } + }; + } + +//////////////////////////////////////////////////////////////////////////////// +// class template AssocVector +// An associative vector built as a syntactic drop-in replacement for std::map +// BEWARE: AssocVector doesn't respect all map's guarantees, the most important +// being: +// * iterators are invalidated by insert and erase operations +// * the complexity of insert/erase is O(N) not O(log N) +// * value_type is std::pair<K, V> not std::pair<const K, V> +// * iterators are random +//////////////////////////////////////////////////////////////////////////////// + + + template + < + class K, + class V, + class C = std::less<K>, + class A = std::allocator< std::pair<K, V> > + > + class AssocVector + : private std::vector< std::pair<K, V>, A > + , private Private::AssocVectorCompare<V, C> + { + typedef std::vector<std::pair<K, V>, A> Base; + typedef Private::AssocVectorCompare<V, C> MyCompare; + + public: + typedef K key_type; + typedef V mapped_type; + typedef typename Base::value_type value_type; + + typedef C key_compare; + typedef A allocator_type; + typedef typename A::reference reference; + typedef typename A::const_reference const_reference; + typedef typename Base::iterator iterator; + typedef typename Base::const_iterator const_iterator; + typedef typename Base::size_type size_type; + typedef typename Base::difference_type difference_type; + typedef typename A::pointer pointer; + typedef typename A::const_pointer const_pointer; + typedef typename Base::reverse_iterator reverse_iterator; + typedef typename Base::const_reverse_iterator const_reverse_iterator; + + class value_compare + : public std::binary_function<value_type, value_type, bool> + , private key_compare + { + friend class AssocVector; + + protected: + value_compare(key_compare pred) : key_compare(pred) + {} + + public: + bool operator()(const value_type& lhs, const value_type& rhs) const + { return key_compare::operator()(lhs.first, rhs.first); } + }; + + // 23.3.1.1 construct/copy/destroy + + explicit AssocVector(const key_compare& comp = key_compare(), + const A& alloc = A()) + : Base(alloc), MyCompare(comp) + {} + + template <class InputIterator> + AssocVector(InputIterator first, InputIterator last, + const key_compare& comp = key_compare(), + const A& alloc = A()) + : Base(first, last, alloc), MyCompare(comp) + { + MyCompare& me = *this; + std::sort(begin(), end(), me); + } + + AssocVector& operator=(const AssocVector& rhs) + { + AssocVector(rhs).swap(*this); + return *this; + } + + // iterators: + // The following are here because MWCW gets 'using' wrong + iterator begin() { return Base::begin(); } + const_iterator begin() const { return Base::begin(); } + iterator end() { return Base::end(); } + const_iterator end() const { return Base::end(); } + reverse_iterator rbegin() { return Base::rbegin(); } + const_reverse_iterator rbegin() const { return Base::rbegin(); } + reverse_iterator rend() { return Base::rend(); } + const_reverse_iterator rend() const { return Base::rend(); } + + // capacity: + bool empty() const { return Base::empty(); } + size_type size() const { return Base::size(); } + size_type max_size() { return Base::max_size(); } + + // 23.3.1.2 element access: + mapped_type& operator[](const key_type& key) + { return insert(value_type(key, mapped_type())).first->second; } + + // modifiers: + std::pair<iterator, bool> insert(const value_type& val) + { + bool found(true); + iterator i(lower_bound(val.first)); + + if (i == end() || this->operator()(val.first, i->first)) + { + i = Base::insert(i, val); + found = false; + } + return std::make_pair(i, !found); + } + //Section [23.1.2], Table 69 + //http://developer.apple.com/documentation/DeveloperTools/gcc-3.3/libstdc++/23_containers/howto.html#4 + iterator insert(iterator pos, const value_type& val) + { + if( (pos == begin() || this->operator()(*(pos-1),val)) && + (pos == end() || this->operator()(val, *pos)) ) + { + return Base::insert(pos, val); + } + return insert(val).first; + } + + template <class InputIterator> + void insert(InputIterator first, InputIterator last) + { for (; first != last; ++first) insert(*first); } + + void erase(iterator pos) + { Base::erase(pos); } + + size_type erase(const key_type& k) + { + iterator i(find(k)); + if (i == end()) return 0; + erase(i); + return 1; + } + + void erase(iterator first, iterator last) + { Base::erase(first, last); } + + void swap(AssocVector& other) + { + Base::swap(other); + MyCompare& me = *this; + MyCompare& rhs = other; + std::swap(me, rhs); + } + + void clear() + { Base::clear(); } + + // observers: + key_compare key_comp() const + { return *this; } + + value_compare value_comp() const + { + const key_compare& comp = *this; + return value_compare(comp); + } + + // 23.3.1.3 map operations: + iterator find(const key_type& k) + { + iterator i(lower_bound(k)); + if (i != end() && this->operator()(k, i->first)) + { + i = end(); + } + return i; + } + + const_iterator find(const key_type& k) const + { + const_iterator i(lower_bound(k)); + if (i != end() && this->operator()(k, i->first)) + { + i = end(); + } + return i; + } + + size_type count(const key_type& k) const + { return find(k) != end(); } + + iterator lower_bound(const key_type& k) + { + MyCompare& me = *this; + return std::lower_bound(begin(), end(), k, me); + } + + const_iterator lower_bound(const key_type& k) const + { + const MyCompare& me = *this; + return std::lower_bound(begin(), end(), k, me); + } + + iterator upper_bound(const key_type& k) + { + MyCompare& me = *this; + return std::upper_bound(begin(), end(), k, me); + } + + const_iterator upper_bound(const key_type& k) const + { + const MyCompare& me = *this; + return std::upper_bound(begin(), end(), k, me); + } + + std::pair<iterator, iterator> equal_range(const key_type& k) + { + MyCompare& me = *this; + return std::equal_range(begin(), end(), k, me); + } + + std::pair<const_iterator, const_iterator> equal_range( + const key_type& k) const + { + const MyCompare& me = *this; + return std::equal_range(begin(), end(), k, me); + } + + template <class K1, class V1, class C1, class A1> + friend bool operator==(const AssocVector<K1, V1, C1, A1>& lhs, + const AssocVector<K1, V1, C1, A1>& rhs); + + bool operator<(const AssocVector& rhs) const + { + const Base& me = *this; + const Base& yo = rhs; + return me < yo; + } + + template <class K1, class V1, class C1, class A1> + friend bool operator!=(const AssocVector<K1, V1, C1, A1>& lhs, + const AssocVector<K1, V1, C1, A1>& rhs); + + template <class K1, class V1, class C1, class A1> + friend bool operator>(const AssocVector<K1, V1, C1, A1>& lhs, + const AssocVector<K1, V1, C1, A1>& rhs); + + template <class K1, class V1, class C1, class A1> + friend bool operator>=(const AssocVector<K1, V1, C1, A1>& lhs, + const AssocVector<K1, V1, C1, A1>& rhs); + + template <class K1, class V1, class C1, class A1> + friend bool operator<=(const AssocVector<K1, V1, C1, A1>& lhs, + const AssocVector<K1, V1, C1, A1>& rhs); + }; + + template <class K, class V, class C, class A> + inline bool operator==(const AssocVector<K, V, C, A>& lhs, + const AssocVector<K, V, C, A>& rhs) + { + const std::vector<std::pair<K, V>, A>& me = lhs; + return me == rhs; + } + + template <class K, class V, class C, class A> + inline bool operator!=(const AssocVector<K, V, C, A>& lhs, + const AssocVector<K, V, C, A>& rhs) + { return !(lhs == rhs); } + + template <class K, class V, class C, class A> + inline bool operator>(const AssocVector<K, V, C, A>& lhs, + const AssocVector<K, V, C, A>& rhs) + { return rhs < lhs; } + + template <class K, class V, class C, class A> + inline bool operator>=(const AssocVector<K, V, C, A>& lhs, + const AssocVector<K, V, C, A>& rhs) + { return !(lhs < rhs); } + + template <class K, class V, class C, class A> + inline bool operator<=(const AssocVector<K, V, C, A>& lhs, + const AssocVector<K, V, C, A>& rhs) + { return !(rhs < lhs); } + + + // specialized algorithms: + template <class K, class V, class C, class A> + void swap(AssocVector<K, V, C, A>& lhs, AssocVector<K, V, C, A>& rhs) + { lhs.swap(rhs); } + +} // namespace Loki + +#endif // end file guardian + diff --git a/shared/loki/CachedFactory.h b/shared/loki/CachedFactory.h new file mode 100644 index 00000000..15c9a801 --- /dev/null +++ b/shared/loki/CachedFactory.h @@ -0,0 +1,1167 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2006 by Guillaume Chatelet +// +// Code covered by the MIT License +// +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// +// The authors make no representations about the suitability of this software +// for any purpose. It is provided "as is" without express or implied warranty. +// +// This code DOES NOT accompany the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_CACHEDFACTORY_INC_ +#define LOKI_CACHEDFACTORY_INC_ + +// $Id: CachedFactory.h 950 2009-01-26 19:45:54Z syntheticpp $ + +#include <functional> +#include <algorithm> +#include <iostream> +#include <vector> +#include <iterator> +#include <map> +#include <cassert> +#include <loki/Key.h> + +#ifdef DO_EXTRA_LOKI_TESTS + #define D( x ) x +#else + #define D( x ) ; +#endif + +#if defined(_MSC_VER) || defined(__CYGWIN__) +#include <time.h> +#endif + +/** + * \defgroup FactoriesGroup Factories + * \defgroup CachedFactoryGroup Cached Factory + * \ingroup FactoriesGroup + * \brief CachedFactory provides an extension of a Factory with caching + * support. + * + * Once used objects are returned to the CachedFactory that manages its + * destruction. + * If your code uses lots of "long to construct/destruct objects" using the + * CachedFactory will surely speedup the execution. + */ +namespace Loki +{ +/** + * \defgroup EncapsulationPolicyCachedFactoryGroup Encapsulation policies + * \ingroup CachedFactoryGroup + * \brief Defines how the object is returned to the client + */ + /** + * \class SimplePointer + * \ingroup EncapsulationPolicyCachedFactoryGroup + * \brief No encaspulation : returns the pointer + * + * This implementation does not make any encapsulation. + * It simply returns the object's pointer. + */ + template<class AbstractProduct> + class SimplePointer + { + protected: + typedef AbstractProduct* ProductReturn; + ProductReturn encapsulate(AbstractProduct* pProduct) + { + return pProduct; + } + + AbstractProduct* release(ProductReturn &pProduct) + { + AbstractProduct* pPointer(pProduct); + pProduct=NULL; + return pPointer; + } + const char* name(){return "pointer";} + }; + +/** + * \defgroup CreationPolicyCachedFactoryGroup Creation policies + * \ingroup CachedFactoryGroup + * \brief Defines a way to limit the creation operation. + * + * For instance one may want to be alerted (Exception) when + * - Cache has created a more than X object within the last x seconds + * - Cache creation rate has increased dramatically + * . + * which may result from bad caching strategy, or critical overload + */ + /** + * \class NeverCreate + * \ingroup CreationPolicyCachedFactoryGroup + * \brief Never allows creation. Testing purposes only. + * + * Using this policy will throw an exception. + */ + class NeverCreate + { + protected: + struct Exception : public std::exception + { + const char* what() const throw() { return "NeverFetch Policy : No Fetching allowed"; } + }; + + bool canCreate() + { + throw Exception(); + } + + void onCreate(){} + void onDestroy(){} + const char* name(){return "never";} + }; + + /** + * \class AlwaysCreate + * \ingroup CreationPolicyCachedFactoryGroup + * \brief Always allows creation. + * + * Doesn't limit the creation in any way + */ + class AlwaysCreate + { + protected: + bool canCreate() + { + return true; + } + + void onCreate(){} + void onDestroy(){} + const char* name(){return "always";} + }; + + + /** + * \class RateLimitedCreation + * \ingroup CreationPolicyCachedFactoryGroup + * \brief Limit in rate. + * + * This implementation will prevent from Creating more than maxCreation objects + * within byTime ms by throwing an exception. + * Could be usefull to detect prevent loads (http connection for instance). + * Use the setRate method to set the rate parameters. + * default is 10 objects in a second. + */ + // !! CAUTION !! + // The std::clock() function is not quite precise + // under linux this policy might not work. + // TODO : get a better implementation (platform dependant) + class RateLimitedCreation + { + private: + typedef std::vector< clock_t > Vector; + Vector m_vTimes; + unsigned maxCreation; + clock_t timeValidity; + clock_t lastUpdate; + + void cleanVector() + { + using namespace std; + clock_t currentTime = clock(); + D( cout << "currentTime = " << currentTime<< endl; ) + D( cout << "currentTime - lastUpdate = " << currentTime - lastUpdate<< endl; ) + if(currentTime - lastUpdate > timeValidity) + { + m_vTimes.clear(); + D( cout << " is less than time validity " << timeValidity; ) + D( cout << " so clearing vector" << endl; ) + } + else + { + D( cout << "Cleaning time less than " << currentTime - timeValidity << endl; ) + D( displayVector(); ) + Vector::iterator newEnd = remove_if(m_vTimes.begin(), m_vTimes.end(), bind2nd(less<clock_t>(), currentTime - timeValidity)); + // this rearrangement might be costly, consider optimization + // by calling cleanVector in less used onCreate function + // ... although it may not be correct + m_vTimes.erase(newEnd, m_vTimes.end()); + D( displayVector(); ) + } + lastUpdate = currentTime; + } +#ifdef DO_EXTRA_LOKI_TESTS + void displayVector() + { + std::cout << "Vector : "; + copy(m_vTimes.begin(), m_vTimes.end(), std::ostream_iterator<clock_t>(std::cout, " ")); + std::cout << std::endl; + } +#endif + protected: + RateLimitedCreation() : maxCreation(10), timeValidity(CLOCKS_PER_SEC), lastUpdate(clock()) + {} + + struct Exception : public std::exception + { + const char* what() const throw() { return "RateLimitedCreation Policy : Exceeded the authorized creation rate"; } + }; + + bool canCreate() + { + cleanVector(); + if(m_vTimes.size()>maxCreation) + throw Exception(); + else + return true; + } + + void onCreate() + { + m_vTimes.push_back(clock()); + } + + void onDestroy() + { + } + const char* name(){return "rate limited";} + public: + // set the creation rate + // No more than maxCreation within byTime milliseconds + void setRate(unsigned maxCreation, unsigned byTime) + { + assert(byTime>0); + this->maxCreation = maxCreation; + this->timeValidity = static_cast<clock_t>(byTime * CLOCKS_PER_SEC / 1000); + D( std::cout << "Setting no more than "<< maxCreation <<" creation within " << this->timeValidity <<" ms"<< std::endl; ) + } + }; + + /** + * \class AmountLimitedCreation + * \ingroup CreationPolicyCachedFactoryGroup + * \brief Limit by number of objects + * + * This implementation will prevent from Creating more than maxCreation objects + * within byTime ms by calling eviction policy. + * Use the setRate method to set the rate parameters. + * default is 10 objects. + */ + class AmountLimitedCreation + { + private: + unsigned maxCreation; + unsigned created; + + protected: + AmountLimitedCreation() : maxCreation(10), created(0) + {} + + bool canCreate() + { + return !(created>=maxCreation); + } + + void onCreate() + { + ++created; + } + + void onDestroy() + { + --created; + } + const char* name(){return "amount limited";} + public: + // set the creation max amount + void setMaxCreation(unsigned maxCreation) + { + assert(maxCreation>0); + this->maxCreation = maxCreation; + D( std::cout << "Setting no more than " << maxCreation <<" creation" << std::endl; ) + } + }; + +/** + * \defgroup EvictionPolicyCachedFactoryGroup Eviction policies + * \ingroup CachedFactoryGroup + * \brief Gathers informations about the stored objects and choose a + * candidate for eviction. + */ + + class EvictionException : public std::exception + { + public: + const char* what() const throw() { return "Eviction Policy : trying to make room but no objects are available"; } + }; + + // The following class is intented to provide helpers to sort + // the container that will hold an eviction score + template + < + typename ST, // Score type + typename DT // Data type + > + class EvictionHelper + { + protected: + typedef typename std::map< DT, ST > HitMap; + typedef typename HitMap::iterator HitMapItr; + private: + typedef std::pair< ST, DT > SwappedPair; + typedef std::multimap< ST, DT > SwappedHitMap; + typedef typename SwappedHitMap::iterator SwappedHitMapItr; + protected: + HitMap m_mHitCount; + + // This function sorts the map according to the score + // and returns the lower bound of the sorted container + DT& getLowerBound(){ + assert(!m_mHitCount.empty()); + // inserting the swapped pair into a multimap + SwappedHitMap copyMap; + for(HitMapItr itr = m_mHitCount.begin(); itr != m_mHitCount.end(); ++itr) + copyMap.insert(SwappedPair((*itr).second, (*itr).first)); + if((*copyMap.rbegin()).first == 0) // the higher score is 0 ... + throw EvictionException(); // there is no key evict + return (*copyMap.begin()).second; + } + }; + + /** + * \class EvictLRU + * \ingroup EvictionPolicyCachedFactoryGroup + * \brief Evicts least accessed objects first. + * + * Implementation of the Least recent used algorithm as + * described in http://en.wikipedia.org/wiki/Page_replacement_algorithms . + * + * WARNING : If an object is heavily fetched + * (more than ULONG_MAX = UINT_MAX = 4294967295U) + * it could unfortunately be removed from the cache. + */ + template + < + typename DT, // Data Type (AbstractProduct*) + typename ST = unsigned // default data type to use as Score Type + > + class EvictLRU : public EvictionHelper< ST , DT > + { + private: + typedef EvictionHelper< ST , DT > EH; + protected: + + virtual ~EvictLRU(){} + + // OnStore initialize the counter for the new key + // If the key already exists, the counter is reseted + void onCreate(const DT& key) + { + EH::m_mHitCount[key] = 0; + } + + void onFetch(const DT&) + { + } + + // onRelease increments the hit counter associated with the object + void onRelease(const DT& key) + { + ++(EH::m_mHitCount[key]); + } + + void onDestroy(const DT& key) + { + EH::m_mHitCount.erase(key); + } + + // this function is implemented in Cache and redirected + // to the Storage Policy + virtual void remove(DT const key)=0; + + // LRU Eviction policy + void evict() + { + remove(EH::getLowerBound()); + } + const char* name(){return "LRU";} + }; + + /** + * \class EvictAging + * \ingroup EvictionPolicyCachedFactoryGroup + * \brief LRU aware of the time span of use + * + * Implementation of the Aging algorithm as + * described in http://en.wikipedia.org/wiki/Page_replacement_algorithms . + * + * This method is much more costly than evict LRU so + * if you need extreme performance consider switching to EvictLRU + */ + template + < + typename DT, // Data Type (AbstractProduct*) + typename ST = unsigned // default data type to use as Score Type + > + class EvictAging : public EvictionHelper< ST, DT > + { + private: + EvictAging(const EvictAging&); + EvictAging& operator=(const EvictAging&); + typedef EvictionHelper< ST, DT > EH; + typedef typename EH::HitMap HitMap; + typedef typename EH::HitMapItr HitMapItr; + + // update the counter + template<class T> struct updateCounter : public std::unary_function<T, void> + { + updateCounter(const DT& key): key_(key){} + void operator()(T x) + { + x.second = (x.first == key_ ? (x.second >> 1) | ( 1 << ((sizeof(ST)-1)*8) ) : x.second >> 1); + D( std::cout << x.second << std::endl; ) + } + const DT &key_; + updateCounter(const updateCounter& rhs) : key_(rhs.key_){} + private: + updateCounter& operator=(const updateCounter& rhs); + }; + protected: + EvictAging(){} + virtual ~EvictAging(){} + + // OnStore initialize the counter for the new key + // If the key already exists, the counter is reseted + void onCreate(const DT& key){ + EH::m_mHitCount[key] = 0; + } + + void onFetch(const DT&){} + + // onRelease increments the hit counter associated with the object + // Updating every counters by iterating over the map + // If the key is the key of the fetched object : + // the counter is shifted to the right and it's MSB is set to 1 + // else + // the counter is shifted to the left + void onRelease(const DT& key) + { + std::for_each(EH::m_mHitCount.begin(), EH::m_mHitCount.end(), updateCounter< typename HitMap::value_type >(key)); + } + + void onDestroy(const DT& key) + { + EH::m_mHitCount.erase(key); + } + + // this function is implemented in Cache and redirected + // to the Storage Policy + virtual void remove(DT const key)=0; + + // LRU with Aging Eviction policy + void evict() + { + remove(EH::getLowerBound()); + } + const char* name(){return "LRU with aging";} + }; + + /** + * \class EvictRandom + * \ingroup EvictionPolicyCachedFactoryGroup + * \brief Evicts a random object + * + * Implementation of the Random algorithm as + * described in http://en.wikipedia.org/wiki/Page_replacement_algorithms . + */ + template + < + typename DT, // Data Type (AbstractProduct*) + typename ST = void // Score Type not used by this policy + > + class EvictRandom + { + private: + std::vector< DT > m_vKeys; + typedef typename std::vector< DT >::size_type size_type; + typedef typename std::vector< DT >::iterator iterator; + + protected: + + virtual ~EvictRandom(){} + + void onCreate(const DT&){ + } + + void onFetch(const DT& ){ + } + + void onRelease(const DT& key){ + m_vKeys.push_back(key); + } + + void onDestroy(const DT& key){ + using namespace std; + m_vKeys.erase(remove_if(m_vKeys.begin(), m_vKeys.end(), bind2nd(equal_to< DT >(), key)), m_vKeys.end()); + } + + // Implemented in Cache and redirected to the Storage Policy + virtual void remove(DT const key)=0; + + // Random Eviction policy + void evict() + { + if(m_vKeys.empty()) + throw EvictionException(); + size_type random = static_cast<size_type>((m_vKeys.size()*rand())/(static_cast<size_type>(RAND_MAX) + 1)); + remove(*(m_vKeys.begin()+random)); + } + const char* name(){return "random";} + }; + +/** + * \defgroup StatisticPolicyCachedFactoryGroup Statistic policies + * \ingroup CachedFactoryGroup + * \brief Gathers information about the cache. + * + * For debugging purpose this policy proposes to gather informations + * about the cache. This could be useful to determine whether the cache is + * mandatory or if the policies are well suited to the application. + */ + /** + * \class NoStatisticPolicy + * \ingroup StatisticPolicyCachedFactoryGroup + * \brief Do nothing + * + * Should be used in release code for better performances + */ + class NoStatisticPolicy + { + protected: + void onDebug(){} + void onFetch(){} + void onRelease(){} + void onCreate(){} + void onDestroy(){} + const char* name(){return "no";} + }; + + /** + * \class SimpleStatisticPolicy + * \ingroup StatisticPolicyCachedFactoryGroup + * \brief Simple statistics + * + * Provides the following informations about the cache : + * - Created objects + * - Fetched objects + * - Destroyed objects + * - Cache hit + * - Cache miss + * - Currently allocated + * - Currently out + * - Cache overall efficiency + */ + class SimpleStatisticPolicy + { + private: + unsigned allocated, created, hit, out, fetched; + protected: + SimpleStatisticPolicy() : allocated(0), created(0), hit(0), out(0), fetched(0) + { + } + + void onDebug() + { + using namespace std; + cout << "############################" << endl; + cout << "## About this cache " << this << endl; + cout << "## + Created objects : " << created << endl; + cout << "## + Fetched objects : " << fetched << endl; + cout << "## + Destroyed objects : " << created - allocated << endl; + cout << "## + Cache hit : " << hit << endl; + cout << "## + Cache miss : " << fetched - hit << endl; + cout << "## + Currently allocated : " << allocated << endl; + cout << "## + Currently out : " << out << endl; + cout << "############################" << endl; + if(fetched!=0){ + cout << "## Overall efficiency " << 100*double(hit)/fetched <<"%"<< endl; + cout << "############################" << endl; + } + cout << endl; + } + + void onFetch() + { + ++fetched; + ++out; + ++hit; + } + void onRelease() + { + --out; + } + void onCreate() + { + ++created; + ++allocated; + --hit; + } + void onDestroy() + { + --allocated; + } + + const char* name(){return "simple";} + public: + unsigned getCreated(){return created;} + unsigned getFetched(){return fetched;} + unsigned getHit(){return hit;} + unsigned getMissed(){return fetched - hit;} + unsigned getAllocated(){return allocated;} + unsigned getOut(){return out;} + unsigned getDestroyed(){return created-allocated;} + }; + + /////////////////////////////////////////////////////////////////////////// + // Cache Factory definition + /////////////////////////////////////////////////////////////////////////// + class CacheException : public std::exception + { + public: + const char* what() const throw() { return "Internal Cache Error"; } + }; + + /** + * \class CachedFactory + * \ingroup CachedFactoryGroup + * \brief Factory with caching support + * + * This class acts as a Factory (it creates objects) + * but also keeps the already created objects to prevent + * long constructions time. + * + * Note this implementation do not retain ownership. + */ + template + < + class AbstractProduct, + typename IdentifierType, + typename CreatorParmTList = NullType, + template<class> class EncapsulationPolicy = SimplePointer, + class CreationPolicy = AlwaysCreate, + template <typename , typename> class EvictionPolicy = EvictRandom, + class StatisticPolicy = NoStatisticPolicy, + template<typename, class> class FactoryErrorPolicy = DefaultFactoryError, + class ObjVector = std::vector<AbstractProduct*> + > + class CachedFactory : + protected EncapsulationPolicy<AbstractProduct>, + public CreationPolicy, public StatisticPolicy, EvictionPolicy< AbstractProduct * , unsigned > + { + private: + typedef Factory< AbstractProduct, IdentifierType, CreatorParmTList, FactoryErrorPolicy> MyFactory; + typedef FactoryImpl< AbstractProduct, IdentifierType, CreatorParmTList > Impl; + typedef Functor< AbstractProduct* , CreatorParmTList > ProductCreator; + typedef EncapsulationPolicy<AbstractProduct> NP; + typedef CreationPolicy CP; + typedef StatisticPolicy SP; + typedef EvictionPolicy< AbstractProduct* , unsigned > EP; + + typedef typename Impl::Parm1 Parm1; + typedef typename Impl::Parm2 Parm2; + typedef typename Impl::Parm3 Parm3; + typedef typename Impl::Parm4 Parm4; + typedef typename Impl::Parm5 Parm5; + typedef typename Impl::Parm6 Parm6; + typedef typename Impl::Parm7 Parm7; + typedef typename Impl::Parm8 Parm8; + typedef typename Impl::Parm9 Parm9; + typedef typename Impl::Parm10 Parm10; + typedef typename Impl::Parm11 Parm11; + typedef typename Impl::Parm12 Parm12; + typedef typename Impl::Parm13 Parm13; + typedef typename Impl::Parm14 Parm14; + typedef typename Impl::Parm15 Parm15; + + public: + typedef typename NP::ProductReturn ProductReturn; + private: + typedef Key< Impl, IdentifierType > MyKey; + typedef std::map< MyKey, ObjVector > KeyToObjVectorMap; + typedef std::map< AbstractProduct*, MyKey > FetchedObjToKeyMap; + + MyFactory factory; + KeyToObjVectorMap fromKeyToObjVector; + FetchedObjToKeyMap providedObjects; + unsigned outObjects; + + ObjVector& getContainerFromKey(MyKey key){ + return fromKeyToObjVector[key]; + } + + AbstractProduct* const getPointerToObjectInContainer(ObjVector &entry) + { + if(entry.empty()) // No object available + { // the object will be created in the calling function. + // It has to be created in the calling function because of + // the variable number of parameters for CreateObject(...) method + return NULL; + } + else + { // returning the found object + AbstractProduct* pObject(entry.back()); + assert(pObject!=NULL); + entry.pop_back(); + return pObject; + } + } + + bool shouldCreateObject(AbstractProduct * const pProduct){ + if(pProduct!=NULL) // object already exists + return false; + if(CP::canCreate()==false) // Are we allowed to Create ? + EP::evict(); // calling Eviction Policy to clean up + return true; + } + + void ReleaseObjectFromContainer(ObjVector &entry, AbstractProduct * const object) + { + entry.push_back(object); + } + + void onFetch(AbstractProduct * const pProduct) + { + SP::onFetch(); + EP::onFetch(pProduct); + ++outObjects; + } + + void onRelease(AbstractProduct * const pProduct) + { + SP::onRelease(); + EP::onRelease(pProduct); + --outObjects; + } + + void onCreate(AbstractProduct * const pProduct) + { + CP::onCreate(); + SP::onCreate(); + EP::onCreate(pProduct); + } + + void onDestroy(AbstractProduct * const pProduct) + { + CP::onDestroy(); + SP::onDestroy(); + EP::onDestroy(pProduct); + } + + // delete the object + template<class T> struct deleteObject : public std::unary_function<T, void> + { + void operator()(T x){ delete x; } + }; + + // delete the objects in the vector + template<class T> struct deleteVectorObjects : public std::unary_function<T, void> + { + void operator()(T x){ + ObjVector &vec(x.second); + std::for_each(vec.begin(), vec.end(), deleteObject< typename ObjVector::value_type>()); + } + }; + + // delete the keys of the map + template<class T> struct deleteMapKeys : public std::unary_function<T, void> + { + void operator()(T x){ delete x.first; } + }; + + protected: + virtual void remove(AbstractProduct * const pProduct) + { + typename FetchedObjToKeyMap::iterator fetchedItr = providedObjects.find(pProduct); + if(fetchedItr!=providedObjects.end()) // object is unreleased. + throw CacheException(); + bool productRemoved = false; + typename KeyToObjVectorMap::iterator objVectorItr; + typename ObjVector::iterator objItr; + for(objVectorItr=fromKeyToObjVector.begin();objVectorItr!=fromKeyToObjVector.end();++objVectorItr) + { + ObjVector &v((*objVectorItr).second); + objItr = remove_if(v.begin(), v.end(), std::bind2nd(std::equal_to<AbstractProduct*>(), pProduct)); + if(objItr != v.end()) // we found the vector containing pProduct and removed it + { + onDestroy(pProduct); // warning policies we are about to destroy an object + v.erase(objItr, v.end()); // real removing + productRemoved = true; + break; + } + } + if(productRemoved==false) + throw CacheException(); // the product is not in the cache ?! + delete pProduct; // deleting it + } + + public: + CachedFactory() : factory(), fromKeyToObjVector(), providedObjects(), outObjects(0) + { + } + + ~CachedFactory() + { + using namespace std; + // debug information + SP::onDebug(); + // cleaning the Cache + for_each(fromKeyToObjVector.begin(), fromKeyToObjVector.end(), + deleteVectorObjects< typename KeyToObjVectorMap::value_type >() + ); + if(!providedObjects.empty()) + { + // The factory is responsible for the creation and destruction of objects. + // If objects are out during the destruction of the Factory : deleting anyway. + // This might not be a good idea. But throwing an exception in a destructor is + // considered as a bad pratice and asserting might be too much. + // What to do ? Leaking memory or corrupting in use pointers ? hmm... + D( cout << "====>> Cache destructor : deleting "<< providedObjects.size()<<" in use objects <<====" << endl << endl; ) + for_each(providedObjects.begin(), providedObjects.end(), + deleteMapKeys< typename FetchedObjToKeyMap::value_type >() + ); + } + } + + /////////////////////////////////// + // Acts as the proxy pattern and // + // forwards factory methods // + /////////////////////////////////// + + bool Register(const IdentifierType& id, ProductCreator creator) + { + return factory.Register(id, creator); + } + + template <class PtrObj, typename CreaFn> + bool Register(const IdentifierType& id, const PtrObj& p, CreaFn fn) + { + return factory.Register(id, p, fn); + } + + bool Unregister(const IdentifierType& id) + { + return factory.Unregister(id); + } + + /// Return the registered ID in this Factory + std::vector<IdentifierType>& RegisteredIds() + { + return factory.RegisteredIds(); + } + + ProductReturn CreateObject(const IdentifierType& id) + { + MyKey key(id); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1) + { + MyKey key(id,p1); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2) + { + MyKey key(id,p1,p2); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3) + { + MyKey key(id,p1,p2,p3); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4) + { + MyKey key(id,p1,p2,p3,p4); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5) + { + MyKey key(id,p1,p2,p3,p4,p5); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6) + { + MyKey key(id,p1,p2,p3,p4,p5,p6); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7 ) + { + MyKey key(id,p1,p2,p3,p4,p5,p6,p7); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6,key.p7); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8) + { + MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6,key.p7,key.p8); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9) + { + MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9,Parm10 p10) + { + MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9,key.p10); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, + Parm11 p11) + { + MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9,key.p10,key.p11); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, + Parm11 p11, Parm12 p12) + { + MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9,key.p10,key.p11,key.p12); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, + Parm11 p11, Parm12 p12, Parm13 p13) + { + MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9,key.p10,key.p11,key.p12 + ,key.p13); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, + Parm11 p11, Parm12 p12, Parm13 p13, Parm14 p14) + { + MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9,key.p10,key.p11,key.p12 + ,key.p13,key.p14); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + ProductReturn CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, + Parm11 p11, Parm12 p12, Parm13 p13, Parm14 p14, Parm15 p15) + { + MyKey key(id,p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15); + AbstractProduct *pProduct(getPointerToObjectInContainer(getContainerFromKey(key))); + if(shouldCreateObject(pProduct)) + { + pProduct = factory.CreateObject(key.id,key.p1,key.p2,key.p3 + ,key.p4,key.p5,key.p6,key.p7,key.p8,key.p9,key.p10,key.p11,key.p12 + ,key.p13,key.p14,key.p15); + onCreate(pProduct); + } + onFetch(pProduct); + providedObjects[pProduct] = key; + return NP::encapsulate(pProduct); + } + + /// Use this function to release the object + /** + * if execution brakes in this function then you tried + * to release an object that wasn't provided by this Cache + * ... which is bad :-) + */ + void ReleaseObject(ProductReturn &object) + { + AbstractProduct* pProduct(NP::release(object)); + typename FetchedObjToKeyMap::iterator itr = providedObjects.find(pProduct); + if(itr == providedObjects.end()) + throw CacheException(); + onRelease(pProduct); + ReleaseObjectFromContainer(getContainerFromKey((*itr).second), pProduct); + providedObjects.erase(itr); + } + + /// display the cache configuration + void displayCacheType() + { + using namespace std; + cout << "############################" << endl; + cout << "## Cache configuration" << endl; + cout << "## + Encapsulation " << NP::name() << endl; + cout << "## + Creating " << CP::name() << endl; + cout << "## + Eviction " << EP::name() << endl; + cout << "## + Statistics " << SP::name() << endl; + cout << "############################" << endl; + } + }; +} // namespace Loki + +#endif // end file guardian + diff --git a/shared/loki/CheckReturn.h b/shared/loki/CheckReturn.h new file mode 100644 index 00000000..fbe63ed0 --- /dev/null +++ b/shared/loki/CheckReturn.h @@ -0,0 +1,165 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2007 by Rich Sposato +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// + +#ifndef LOKI_CHECK_RETURN_INC_ +#define LOKI_CHECK_RETURN_INC_ + +// $Id$ + + +#include <assert.h> +#include <stdio.h> +#include <stdexcept> + + +namespace Loki +{ + +// ---------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// \class CheckReturn +/// +/// \par Purpose +/// C++ provides no mechanism within the language itself to force code to +/// check the return value from a function call. This simple class provides +/// a mechanism by which programmers can force calling functions to check the +/// return value. Or at least make them consciously choose to disregard the +/// return value. If the calling function fails to use or store the return +/// value, the destructor calls the OnError policy. +/// +/// \par Template Parameters +/// CheckReturn has two template parameters, Value and OnError. +/// - Value is the return type from the function. CheckReturn stores a copy of +/// it rather than a reference or pointer since return value could be local to +/// a function. CheckReturn works best when the return type is a built-in +/// primitive (bool, int, etc...) a pointer, or an enum (such as an error +/// condition enum). It can work with other types that have cheap copy +/// operations. +/// - OnError is a policy class indicating how to handle the situation when a +/// caller does not check or copy the returned value. Loki provides some +/// policy classs and you may also write your own. For example, you can write +/// a policy to create a message box when the function ignores the return value. +/// That would quickly tell you places where code ignores the function call. +/// If your write your own, you only need a templated class or struct with a +/// public function named "run" that accepts a reference to a const value. +/// +/// @par Provided Policy Classes +/// - IgnoreReturnValue Deliberately ignores when the caller ignores the return value. +/// - TriggerAssert Asserts in debug builds if the caller ignores the return value. +/// - FprintfStderr Prints out an error message if the caller ignores the return value. +/// - ThrowTheValue Throws the ignored value as an exception. +/// - ThrowLogicError Throws a logic_error exception to indicate a programming error. +//////////////////////////////////////////////////////////////////////////////// + + +template<class T> +struct IgnoreReturnValue +{ + static void run(const T&) + { + /// Do nothing at all. + } +}; + +template<class T> +struct ThrowTheValue +{ + static void run(const T & value ) + { + throw value; + } +}; + +template<class T> +struct ThrowLogicError +{ + static void run( const T & ) + { + throw ::std::logic_error( "CheckReturn: return value was not checked.\n" ); + } +}; + +template<class T> +struct TriggerAssert +{ + static void run(const T&) + { + assert( 0 ); + } +}; + +template<class T> +struct FprintfStderr +{ + static void run(const T&) + { + fprintf(stderr, "CheckReturn: return value was not checked.\n"); + } +}; + + + +template < class Value , template<class> class OnError = TriggerAssert > +class CheckReturn +{ +public: + + /// Conversion constructor changes Value type to CheckReturn type. + inline CheckReturn( const Value & value ) : + m_value( value ), m_checked( false ) {} + + /// Copy-constructor allows functions to call another function within the + /// return statement. The other CheckReturn's m_checked flag is set since + /// its duty has been passed to the m_checked flag in this one. + inline CheckReturn( const CheckReturn & that ) : + m_value( that.m_value ), m_checked( false ) + { that.m_checked = true; } + + /// Destructor checks if return value was used. + inline ~CheckReturn( void ) + { + // If m_checked is false, then a function failed to check the + // return value from a function call. + if (!m_checked) + OnError<Value>::run(m_value); + } + + /// Conversion operator changes CheckReturn back to Value type. + inline operator Value ( void ) + { + m_checked = true; + return m_value; + } + +private: + /// Default constructor not implemented. + CheckReturn( void ); + + /// Copy-assignment operator not implemented. + CheckReturn & operator = ( const CheckReturn & that ); + + /// Copy of returned value. + Value m_value; + + /// Flag for whether calling function checked return value yet. + mutable bool m_checked; +}; + +// ---------------------------------------------------------------------------- + +} // namespace Loki + +#endif // end file guardian + +// $Log$ + diff --git a/shared/loki/Checker.h b/shared/loki/Checker.h new file mode 100644 index 00000000..19350679 --- /dev/null +++ b/shared/loki/Checker.h @@ -0,0 +1,516 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// The Loki Library +// Copyright (c) 2008 Rich Sposato +// The copyright on this file is protected under the terms of the MIT license. +// +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// +// The author makes no representations about the suitability of this software +// for any purpose. It is provided "as is" without express or implied warranty. +// +//////////////////////////////////////////////////////////////////////////////// + +// $Id$ + +/// @file Checker.h This file provides Loki's Checker facility. + + +// ---------------------------------------------------------------------------- + +#ifndef LOKI_CHECKER_H_INCLUDED +#define LOKI_CHECKER_H_INCLUDED + +#include <exception> // needed for calls to uncaught_exception. +#include <assert.h> + + +namespace Loki +{ + +/** @par ContractChecker and StaticChecker Overview + The ContractChecker and StaticChecker classes have two purposes: + - provide a mechanism by which programmers can determine which functions + violate class/data invariants, + - and determine which exception safety a function provides. + + @par Class & Data Invariants + The ContractChecker and StaticChecker define invariants as "expressions that + are true for particular data". They uses a function which returns true if all + data are valid, and returns false if any datum is invalid. This is called the + validator function, and the host class or function provides a pointer to it. + The validator could also assert for any invariant which fails rather than + return false. If the validator is a static member function, you can use it + with checkers in any function, but especially standalone functions and class + static functions. If the validator is a non-static member function, you can + use it only within non-static member functions. + + @par Exception Safety Levels + Years ago, David Abrahams formalized a framework for assessing the exception + safety level a function provides. His framework describes three levels of + guarantees. Any function which does not provide any of these levels is + considered unsafe. ContractChecker and StaticChecker determine a function's + safety level through the use of policy classes. Checker's policy classes can + show if a function provides any of these three guarantees. Since there is no + universal way to detect leaks, this facility provides no mechanism for finding + leaks, but users may create their own validators which do. StaticChecker's + policy classes only provide direct checking for the no-throw and invariant + guarantees. With some finesse, a programmer can write a validator for + StaticChecker that checks for the Strong guarantee. + + - No-throw guarantee: A function will not throw any exceptions. + - Strong guarantee: A function will not change data if an exception occurs. + (Which I call the no-change guarantee.) + - Basic guarantee: A function will not leak resources and data will remain + in a valid state if an exception occurs. (Which I call either the no-leak + or no-break guarantee depending on context.) + */ + +// ---------------------------------------------------------------------------- + +/** @class CheckForNoThrow + + @par Exception Safety Level: + This exception-checking policy class for ContractChecker asserts if an + exception exists. Host classes can use this to show that a member function + provides the no-throw exception safety guarantees. + + @par Requirements For Host Class: + This policy imposes no requirements on a host class. + */ +template < class Host > +class CheckForNoThrow +{ +public: + + inline explicit CheckForNoThrow( const Host * ) {} + + inline bool Check( const Host * ) const + { + const bool okay = ( !::std::uncaught_exception() ); + assert( okay ); + return okay; + } +}; + +// ---------------------------------------------------------------------------- + +/** @class CheckForNoChange + + @par Exception Safety Level: + This exception-checking policy class for ContractChecker asserts only if a + copy of the host differs from the host object when an exception occurs. Host + classes can use this policy to show which member functions provide the strong + exception guarantee. + + @par Requirements: + This policy requires hosts to provide both the copy-constructor and the + equality operator, and is intended for classes with value semantics. + equality operator. + */ + +template < class Host > +class CheckForNoChange +{ +public: + + inline explicit CheckForNoChange( const Host * host ) : + m_compare( *host ) {} + + inline bool Check( const Host * host ) const + { + const bool okay = ( !::std::uncaught_exception() ) + || ( m_compare == *host ); + assert( okay ); + return okay; + } + +private: + Host m_compare; +}; + +// ---------------------------------------------------------------------------- + +/** @class CheckForNoChangeOrThrow + + @par Exception Safety Level: + This exception-checking policy class for ContractChecker asserts either if a + copy of the host differs from the original host object, or if an exception + occurs. Host classes can use this policy to show which member functions provide + the no-throw exception guarantee, and would never change data anyway. + + @par Requirements For Host Class: + This policy requires hosts to provide both the copy-constructor and the + equality operator, and is intended for classes with value semantics. + */ + +template < class Host > +class CheckForNoChangeOrThrow +{ +public: + + inline explicit CheckForNoChangeOrThrow( const Host * host ) : + m_compare( *host ) {} + + inline bool Check( const Host * host ) const + { + bool okay = ( !::std::uncaught_exception() ); + assert( okay ); + okay = ( m_compare == *host ); + assert( okay ); + return okay; + } + +private: + Host m_compare; +}; + +// ---------------------------------------------------------------------------- + +/** @class CheckForEquality + + @par Exception Safety Level: + This exception-checking policy class for ContractChecker asserts if a copy of the host differs from the host object regardless of whether an exception occurs. + Host classes can use this policy to show which member functions never change + data members, and thereby provide the strong exception safety level by default. + + @par Requirements For Host Class: + This policy requires hosts to provide both the copy-constructor and the + equality operator, and is intended for classes with value semantics. + */ + +template < class Host > +class CheckForEquality +{ +public: + + inline explicit CheckForEquality( const Host * host ) : + m_compare( *host ) {} + + inline bool Check( const Host * host ) const + { + const bool okay = ( m_compare == *host ); + assert( okay ); + return okay; + } + +private: + Host m_compare; +}; + +// ---------------------------------------------------------------------------- + +/** @class CheckForNothing + + @par Exception Safety Level: + This exception-checking policy class for ContractChecker does nothing when + called. Host classes can use this to show which member functions provide + neither the strong nor no-throw exception guarantees. The best guarantee such + functions can provide is that nothing gets leaked. + + @par Requirements For Host Class: + This policy imposes no requirements on a host class. + */ + +template < class Host > +class CheckForNothing +{ +public: + inline explicit CheckForNothing( const Host * ) {} + inline bool Check( const Host * ) const { return true; } +}; + +// ---------------------------------------------------------------------------- + +/** @class ContractChecker + This class determines if a function violated any class invariant, but it also + determines if a function fulfills its contract with client code. In the + "Design by Contract" paradigm, each function has certain pre-conditions and + post-conditions which may differ from the class invariants. This asserts if a + check for an invariant fails as well as if any pre- or post-condition fails. + It also demonstrate which exception safety level a function provides. + + @par Usage + -# Implement a function that checks each class invariant. The function must + have the signature similar to the Validator type. Something like: + "bool Host::IsValid( void ) const;" + - The function should return true if everything is okay, but false if + something is wrong. + - Or it could assert if anything is wrong. + - Ideally, it should be private. + -# Implement similar functions to check for pre-conditions and post-conditions. + Functions which verify pre-conditions and post-conditions do not need to + check all class invariants, just conditions specific to certain public + functions in the host class. + -# Declare some typedef's inside the class declaration like these. Make one + typedef for each exception policy you use. I typedef'ed the CheckForNothing + policy as CheckInvariants because even if a function can't provide either the + no-throw nor the no-change policies, it should still make sure the object + remains in a valid state. + - typedef ::Loki::ContractChecker< Host, ::Loki::CheckForNoThrow > CheckForNoThrow; + - typedef ::Loki::ContractChecker< Host, ::Loki::CheckForNoChange > CheckForNoChange; + - typedef ::Loki::ContractChecker< Host, ::Loki::CheckForEquality > CheckForEquality; + - typedef ::Loki::ContractChecker< Host, ::Loki::CheckForNothing > CheckInvariants; + -# Construct a checker near the top of each member function - except in the + validator member function. Pass the this pointer and the address of your + validator function into the checker's constructor. You may also pass in pointers + to function which check pre- and post-conditions. + - If the function never throws, then use the CheckForNoThrow policy. + - If the function never changes any data members, then use CheckForEquality + policy. + - If the function's normal execution flow changes data, but must make sure + data remains unchanged when any exceptions occur, then use the + CheckForNoChange policy. + - Otherwise use the CheckInvariants policy. + -# Recompile a debug version of your program, run the program and all the unit + tests, and look for which assertions failed. + */ + +template +< + class Host, + template < class > class ExceptionPolicy +> +class ContractChecker : public ExceptionPolicy< Host > +{ + /// Shorthand for the ExceptionPolicy class. + typedef ExceptionPolicy< Host > Ep; + +public: + + /// Signature for the validation function. + typedef bool ( Host:: * Validator )( void ) const; + + /** The constructor makes sure the host is valid at the time the checker + was created, thus insuring the host object was not corrupt from the start. + @par host Pointer to host object. + @par validator Pointer to function that checks class invariants. + @par pre Optional pointer to function that checks pre-conditions. + @par post Optional pointer to function that checks post-conditions. + */ + inline ContractChecker( const Host * host, Validator validator, + Validator pre = 0, Validator post = 0 ) : + Ep( host ), + m_host( host ), + m_validator( validator ), + m_pre( pre ), + m_post( post ) + { + assert( Check() ); + if ( 0 != m_pre ) + assert( ( m_host->*( m_pre ) )() ); + } + + /** The destructor checks if any Host invariants failed, and then calls the + ExceptionPolicy's Check function to determine what to do in case of an + exception. + */ + inline ~ContractChecker( void ) + { + assert( Check() ); + if ( 0 != m_post ) + assert( ( m_host->*( m_post ) )() ); + assert( Ep::Check( m_host ) ); + } + + /** This first checks the invariants for ContractChecker, and then calls the + validator function for the host to make sure no class invariants were + broken by the host within the Host's member function body. The host + member function can call Check directly to verify the object remains valid + at any time. This does not care if the pre- and post-condition validator + pointers are null since a host class may pass in NULL pointers for either + to indicate the pre-conditions or post-conditions are the same as the + overall class invariants. + */ + inline bool Check( void ) const + { + assert( 0 != this ); + assert( 0 != m_host ); + assert( 0 != m_validator ); + // Now that this confirms the pointers to the host and validation + // functions are not null, go ahead and validate the host object. + const bool okay = ( m_host->*( m_validator ) )(); + assert( okay ); + return okay; + } + +private: + + /// Default constructor is not implemented. + ContractChecker( void ); + /// Copy constructor is not implemented. + ContractChecker( const ContractChecker & ); + /// Copy-assignment operator is not implemented. + ContractChecker & operator = ( const ContractChecker & ); + + /// Pointer to the host object. + const Host * m_host; + + /// Pointer to member function that checks Host object's invariants. + Validator m_validator; + + /// Pointer to member function that checks Host object's pre-conditions. + Validator m_pre; + + /// Pointer to member function that checks Host object's post-conditions. + Validator m_post; + +}; + +// ---------------------------------------------------------------------------- + +/** @class CheckStaticForNoThrow + + @par Exception Safety Level: + This exception-checking policy class for StaticChecker asserts if an exception + exists. Functions can use this to show they provide the no-throw exception + safety guarantee. + */ +class CheckStaticForNoThrow +{ +public: + inline bool Check( void ) + { + const bool okay = !::std::uncaught_exception(); + assert( okay ); + return okay; + } +}; + +// ---------------------------------------------------------------------------- + +/** @class CheckStaticForNothing + + @par Exception Safety Level: + This exception-checking policy class for StaticChecker does nothing when called. + Functions can use this to show they might provide the weak exception guarantee. + The best guarantee such functions can provide is that nothing gets leaked. + */ +class CheckStaticForNothing +{ +public: + inline bool Check( void ) { return true; } +}; + +// ---------------------------------------------------------------------------- + +/** @class StaticChecker + This class checks if a function provides the no-throw exception safety level + and if the function violated any invariants. Invariants for stand-alone and + static functions act as pre-conditions and post-conditions. + + @par Usage + -# Implement a function that checks the invariants associated with a function, + or with the static data for a class. The function must + have the signature similar to the Validator type. Something like: + "static bool Host::StaticIsValid( void );" or "bool IsOkay( void );" + - The function should return true if everything is okay, but false if + something is wrong. + - Or it could assert if anything is wrong. + -# If the checker is for static functions within a class, declare typedef's + inside the class declaration like these. Make one typedef for each policy + you use. I typedef'ed the CheckForNothing policy as CheckInvariants because + even if a function can't provide the no-throw guarantee, it should still + make sure that static data remains in a valid state. + - typedef ::Loki::StaticChecker< ::Loki::CheckForNoThrow > CheckStaticForNoThrow; + - typedef ::Loki::StaticChecker< ::Loki::CheckForNothing > CheckStaticInvariants; + -# Construct a checker near the top of each member function - except in the + validator member function. Pass the address of your validator function into + the checker's constructor. + - If the function never throws, then use the CheckForNoThrow policy. + - Otherwise use the CheckInvariants policy. + -# Recompile a debug version of your program, run it, and see if an assertion + fails. + */ + +template +< + class ExceptionPolicy +> +class StaticChecker : public ExceptionPolicy +{ + /// Shorthand for the ExceptionPolicy class. + typedef ExceptionPolicy Ep; + +public: + + /// Signature for the validation function. + typedef bool ( * Validator )( void ); + + /** The constructor makes sure the host is valid at the time the checker + was created, thus insuring the host object was not corrupt from the start. + @par validator Pointer to function that checks class invariants. + @par pre Optional pointer to function that checks pre-conditions. + @par post Optional pointer to function that checks post-conditions. + */ + inline explicit StaticChecker( Validator validator, + Validator pre = 0, Validator post = 0 ) : + Ep(), + m_validator( validator ), + m_pre( pre ), + m_post( post ) + { + assert( Check() ); + if ( 0 != m_pre ) + assert( m_pre() ); + } + + /** The destructor checks if any Host invariants failed, and then calls the + ExceptionPolicy's Check function to determine what to do in case of an + exception. + */ + inline ~StaticChecker( void ) + { + assert( Check() ); + if ( 0 != m_post ) + assert( m_post() ); + assert( Ep::Check() ); + } + + /** This first checks its own invariants, and then calls the validator + function to make sure no invariants were broken by the function which + created this checker. That function can call Check directly to verify the + data remains valid at any time. This does not care if the pre- and post- + condition validator pointers are null since a host class may pass in NULL + pointers for either to indicate the pre-conditions or post-conditions are + the same as the overall class invariants. + */ + inline bool Check( void ) const + { + assert( 0 != this ); + assert( 0 != m_validator ); + // Now that this confirms the pointers to the host and validation + // functions are not null, go ahead and validate the host object. + const bool okay = m_validator(); + assert( okay ); + return okay; + } + +private: + + /// Default constructor is not implemented. + StaticChecker( void ); + /// Copy constructor is not implemented. + StaticChecker( const StaticChecker & ); + /// Copy-assignment operator is not implemented. + StaticChecker & operator = ( const StaticChecker & ); + + /// Pointer to member function that checks Host object's invariants. + Validator m_validator; + + /// Pointer to member function that checks Host object's pre-conditions. + Validator m_pre; + + /// Pointer to member function that checks Host object's post-conditions. + Validator m_post; + +}; + +// ---------------------------------------------------------------------------- + +}; // end namespace Loki + +#endif diff --git a/shared/loki/ConstPolicy.h b/shared/loki/ConstPolicy.h new file mode 100644 index 00000000..74c9e5aa --- /dev/null +++ b/shared/loki/ConstPolicy.h @@ -0,0 +1,61 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2006 Richard Sposato +// Copyright (c) 2006 Peter Kümmel +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The authors make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_CONST_POLICY_INC_ +#define LOKI_CONST_POLICY_INC_ + +// $Id: ConstPolicy.h 769 2006-10-26 10:58:19Z syntheticpp $ + + +namespace Loki +{ + +//////////////////////////////////////////////////////////////////////////////// +/// @note These policy classes are used in LockingPtr and SmartPtr to define +/// how const is propagated from the pointee. +//////////////////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////////////////// +/// \class DontPropagateConst +/// +/// \ingroup ConstGroup +/// Don't propagate constness of pointed or referred object. +//////////////////////////////////////////////////////////////////////////////// + + template< class T > + struct DontPropagateConst + { + typedef T Type; + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \class PropagateConst +/// +/// \ingroup ConstGroup +/// Propagate constness of pointed or referred object. +//////////////////////////////////////////////////////////////////////////////// + + template< class T > + struct PropagateConst + { + typedef const T Type; + }; + +// default will not break existing code +#ifndef LOKI_DEFAULT_CONSTNESS +#define LOKI_DEFAULT_CONSTNESS ::Loki::DontPropagateConst +#endif + +} // end namespace Loki + +#endif // end file guardian diff --git a/shared/loki/DataGenerators.h b/shared/loki/DataGenerators.h new file mode 100644 index 00000000..1c8e2df0 --- /dev/null +++ b/shared/loki/DataGenerators.h @@ -0,0 +1,113 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Data Generator by Shannon Barber +// This code DOES NOT accompany the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// +// Code covered by the MIT License +// The author makes no representations about the suitability of this software +// for any purpose. It is provided "as is" without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_DATAGENERATORS_INC_ +#define LOKI_DATAGENERATORS_INC_ + +// $Id: DataGenerators.h 751 2006-10-17 19:50:37Z syntheticpp $ + + +#include "Typelist.h" + +//Reference version + +/************************************************************************************ +// class template GenData +// Iteratates a Typelist, and invokes the functor GenFunc<T> +// for each type in the list, passing a functor along the way. +// The functor is designed to be an insertion iterator which GenFunc<T> +// can use to output information about the types in the list. +// + +Example Use + +template<typename T> +struct ExtractDataType + { + some_type operator()() + { + return create_value_from_type<T>; + } + }; + +Loki::IterateTypes<parameter_tl, ExtractDataType> gendata; +std::vector<some_type> stuff; +gendata(std::back_inserter(stuff)); +*******************************************************************************/ +namespace Loki +{ + namespace TL + { + template<typename T> + struct nameof_type + { + const char* operator()() + { + return typeid(T).name(); + } + }; + template<typename T> + struct sizeof_type + { + size_t operator()() + { + return sizeof(T); + } + }; + template <class TList, template <class> class GenFunc> + struct IterateTypes; + + template <class T1, class T2, template <class> class GenFunc> + struct IterateTypes<Typelist<T1, T2>, GenFunc> + { + typedef IterateTypes<T1, GenFunc> head_t; + head_t head; + typedef IterateTypes<T2, GenFunc> tail_t; + tail_t tail; + template<class II> + void operator()(II ii) + { + head.operator()(ii); + tail.operator()(ii); + } + }; + + template <class AtomicType, template <class> class GenFunc> + struct IterateTypes + { + template<class II> + void operator()(II ii) + { + GenFunc<AtomicType> genfunc; + *ii = genfunc(); + ++ii; //Is this even needed? + } + }; + + template <template <class> class GenFunc> + struct IterateTypes<NullType, GenFunc> + { + template<class II> + void operator()(II ii) + {} + }; + + template<typename Types, template <class> class UnitFunc, typename II> + void iterate_types(II ii) + { + Loki::TL::IterateTypes<Types, UnitFunc> it; + it(ii); + } + }//ns TL +}//ns Loki + +#endif // end file guardian + diff --git a/shared/loki/EmptyType.h b/shared/loki/EmptyType.h new file mode 100644 index 00000000..b228e2e8 --- /dev/null +++ b/shared/loki/EmptyType.h @@ -0,0 +1,49 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_EMPTYTYPE_INC_ +#define LOKI_EMPTYTYPE_INC_ + +// $Id: EmptyType.h 751 2006-10-17 19:50:37Z syntheticpp $ + + +namespace Loki +{ +//////////////////////////////////////////////////////////////////////////////// +// class EmptyType +// Used as a class type that doesn't hold anything +// Useful as a strawman class +//////////////////////////////////////////////////////////////////////////////// + + class EmptyType {}; + + + inline bool operator==(const EmptyType&, const EmptyType&) + { + return true; + } + + inline bool operator<(const EmptyType&, const EmptyType&) + { + return false; + } + + inline bool operator>(const EmptyType&, const EmptyType&) + { + return false; + } +} + +#endif // end file guardian + diff --git a/shared/loki/Factory.h b/shared/loki/Factory.h new file mode 100644 index 00000000..c4c3b22a --- /dev/null +++ b/shared/loki/Factory.h @@ -0,0 +1,1084 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// Copyright (c) 2005 by Peter Kuemmel +// This code DOES NOT accompany the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// +// Code covered by the MIT License +// The authors make no representations about the suitability of this software +// for any purpose. It is provided "as is" without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_FACTORYPARM_INC_ +#define LOKI_FACTORYPARM_INC_ + +// $Id: Factory.h 788 2006-11-24 22:30:54Z clitte_bbt $ + + +#include "LokiTypeInfo.h" +#include "Functor.h" +#include "AssocVector.h" +#include "SmallObj.h" +#include "Sequence.h" + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable: 4702) +//unreachable code if OnUnknownType throws an exception +#endif + +/** + * \defgroup FactoriesGroup Factories + * \defgroup FactoryGroup Factory + * \ingroup FactoriesGroup + * \brief Implements a generic object factory. + * + * <i>The Factory Method pattern is an object-oriented design pattern. + * Like other creational patterns, it deals with the problem of creating objects + * (products) without specifying the exact class of object that will be created. + * Factory Method, one of the patterns from the Design Patterns book, handles + * this problem by defining a separate method for creating the objects, which + * subclasses can then override to specify the derived type of product that will + * be created. + * <br> + * More generally, the term Factory Method is often used to refer to any method + * whose main purpose is creation of objects.</i> + * <div ALIGN="RIGHT"><a href="http://en.wikipedia.org/wiki/Factory_method_pattern"> + * Wikipedia</a></div> + * + * Loki proposes a generic version of the Factory. Here is a typical use.<br> + * <code><br> + * 1. Factory< AbstractProduct, int > aFactory;<br> + * 2. aFactory.Register( 1, createProductNull );<br> + * 3. aFactory.CreateObject( 1 ); <br> + * </code><br> + * <br> + * - 1. The declaration<br> + * You want a Factory that produces AbstractProduct.<br> + * The client will refer to a creation method through an int.<br> + * - 2.The registration<br> + * The code that will contribute to the Factory will now need to declare its + * ProductCreator by registering them into the Factory.<br> + * A ProductCreator is a just a function that will return the right object. ie <br> + * <code> + * Product* createProductNull()<br> + * {<br> + * return new Product<br> + * }<br> + * </code><br> + * - 3. The use<br> + * Now the client can create object by calling the Factory's CreateObject method + * with the right identifier. If the ProductCreator were to have arguments + * (<i>ie :Product* createProductParm( int a, int b )</i>) + */ + +namespace Loki +{ + +/** + * \defgroup FactoryErrorPoliciesGroup Factory Error Policies + * \ingroup FactoryGroup + * \brief Manages the "Unknown Type" error in an object factory + * + * \class DefaultFactoryError + * \ingroup FactoryErrorPoliciesGroup + * \brief Default policy that throws an exception + * + */ + + template <typename IdentifierType, class AbstractProduct> + struct DefaultFactoryError + { + struct Exception : public std::exception + { + const char* what() const throw() { return "Unknown Type"; } + }; + + static AbstractProduct* OnUnknownType(IdentifierType) + { + throw Exception(); + } + }; + + +#define LOKI_ENABLE_NEW_FACTORY_CODE +#ifdef LOKI_ENABLE_NEW_FACTORY_CODE + + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +//////////////////////////////////////////////////////////////////////////////// + + struct FactoryImplBase + { + typedef EmptyType Parm1; + typedef EmptyType Parm2; + typedef EmptyType Parm3; + typedef EmptyType Parm4; + typedef EmptyType Parm5; + typedef EmptyType Parm6; + typedef EmptyType Parm7; + typedef EmptyType Parm8; + typedef EmptyType Parm9; + typedef EmptyType Parm10; + typedef EmptyType Parm11; + typedef EmptyType Parm12; + typedef EmptyType Parm13; + typedef EmptyType Parm14; + typedef EmptyType Parm15; + }; + + template <typename AP, typename Id, typename TList > + struct FactoryImpl; + + template<typename AP, typename Id> + struct FactoryImpl<AP, Id, NullType> + : public FactoryImplBase + { + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id & id ) = 0; + }; +template <typename AP, typename Id, typename P1 > + struct FactoryImpl<AP,Id, Seq<P1> > + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1 ) = 0; + }; + + template<typename AP, typename Id, typename P1,typename P2 > + struct FactoryImpl<AP, Id, Seq<P1, P2> > + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2 ) = 0; + }; + + template<typename AP, typename Id, typename P1,typename P2,typename P3 > + struct FactoryImpl<AP, Id, Seq<P1, P2, P3> > + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3 ) = 0; + }; + + template<typename AP, typename Id, typename P1,typename P2,typename P3,typename P4 > + struct FactoryImpl<AP, Id, Seq<P1, P2, P3, P4> > + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4 ) = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5 > + struct FactoryImpl<AP, Id, Seq<P1, P2, P3, P4, P5> > + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5 ) = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6> + struct FactoryImpl<AP, Id, Seq<P1, P2, P3, P4, P5, P6> > + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6 ) + = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6,typename P7> + struct FactoryImpl<AP, Id, Seq<P1, P2, P3, P4, P5, P6, P7> > + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7 ) + = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6,typename P7,typename P8> + struct FactoryImpl<AP, Id, Seq<P1, P2, P3, P4, P5, P6, P7, P8> > + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8) + = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6,typename P7,typename P8,typename P9> + struct FactoryImpl<AP, Id, Seq<P1, P2, P3, P4, P5, P6, P7, P8, P9> > + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9) + = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6,typename P7,typename P8,typename P9,typename P10> + struct FactoryImpl<AP, Id, Seq<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10> > + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9,Parm10) + = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6,typename P7,typename P8,typename P9,typename P10, + typename P11> + struct FactoryImpl<AP, Id, Seq<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11> > + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9,Parm10, + Parm11) + = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6,typename P7,typename P8,typename P9,typename P10, + typename P11,typename P12> + struct FactoryImpl<AP, Id, Seq<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12> > + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + typedef typename TypeTraits<P12>::ParameterType Parm12; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9,Parm10, + Parm11,Parm12) + = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6,typename P7,typename P8,typename P9,typename P10, + typename P11,typename P12,typename P13> + struct FactoryImpl<AP, Id, Seq<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13> > + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + typedef typename TypeTraits<P12>::ParameterType Parm12; + typedef typename TypeTraits<P13>::ParameterType Parm13; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9,Parm10, + Parm11,Parm12,Parm13) + = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6,typename P7,typename P8,typename P9,typename P10, + typename P11,typename P12,typename P13,typename P14> + struct FactoryImpl<AP, Id, Seq<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14> > + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + typedef typename TypeTraits<P12>::ParameterType Parm12; + typedef typename TypeTraits<P13>::ParameterType Parm13; + typedef typename TypeTraits<P14>::ParameterType Parm14; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm8,Parm10, + Parm11,Parm12,Parm13,Parm14) + = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6,typename P7,typename P8,typename P9,typename P10, + typename P11,typename P12,typename P13,typename P14,typename P15 > + struct FactoryImpl<AP, Id, Seq<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15> > + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + typedef typename TypeTraits<P12>::ParameterType Parm12; + typedef typename TypeTraits<P13>::ParameterType Parm13; + typedef typename TypeTraits<P14>::ParameterType Parm14; + typedef typename TypeTraits<P15>::ParameterType Parm15; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9,Parm10, + Parm11,Parm12,Parm13,Parm14,Parm15 ) + = 0; + }; + +#ifndef LOKI_DISABLE_TYPELIST_MACROS + + template <typename AP, typename Id, typename P1 > + struct FactoryImpl<AP,Id, LOKI_TYPELIST_1( P1 )> + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1 ) = 0; + }; + + template<typename AP, typename Id, typename P1,typename P2 > + struct FactoryImpl<AP, Id, LOKI_TYPELIST_2( P1, P2 )> + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2 ) = 0; + }; + + template<typename AP, typename Id, typename P1,typename P2,typename P3 > + struct FactoryImpl<AP, Id, LOKI_TYPELIST_3( P1, P2, P3 )> + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3 ) = 0; + }; + + template<typename AP, typename Id, typename P1,typename P2,typename P3,typename P4 > + struct FactoryImpl<AP, Id, LOKI_TYPELIST_4( P1, P2, P3, P4 )> + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4 ) = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5 > + struct FactoryImpl<AP, Id, LOKI_TYPELIST_5( P1, P2, P3, P4, P5 )> + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5 ) = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6> + struct FactoryImpl<AP, Id, LOKI_TYPELIST_6( P1, P2, P3, P4, P5, P6 )> + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6 ) + = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6,typename P7> + struct FactoryImpl<AP, Id, LOKI_TYPELIST_7( P1, P2, P3, P4, P5, P6, P7 )> + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7 ) + = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6,typename P7,typename P8> + struct FactoryImpl<AP, Id, LOKI_TYPELIST_8( P1, P2, P3, P4, P5, P6, P7, P8 )> + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8) + = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6,typename P7,typename P8,typename P9> + struct FactoryImpl<AP, Id, LOKI_TYPELIST_9( P1, P2, P3, P4, P5, P6, P7, P8, P9 )> + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9) + = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6,typename P7,typename P8,typename P9,typename P10> + struct FactoryImpl<AP, Id, LOKI_TYPELIST_10( P1, P2, P3, P4, P5, P6, P7, P8, P9, P10 )> + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9,Parm10) + = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6,typename P7,typename P8,typename P9,typename P10, + typename P11> + struct FactoryImpl<AP, Id, LOKI_TYPELIST_11( P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11 )> + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9,Parm10, + Parm11) + = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6,typename P7,typename P8,typename P9,typename P10, + typename P11,typename P12> + struct FactoryImpl<AP, Id, LOKI_TYPELIST_12( P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12 )> + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + typedef typename TypeTraits<P12>::ParameterType Parm12; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9,Parm10, + Parm11,Parm12) + = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6,typename P7,typename P8,typename P9,typename P10, + typename P11,typename P12,typename P13> + struct FactoryImpl<AP, Id, LOKI_TYPELIST_13( P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13 )> + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + typedef typename TypeTraits<P12>::ParameterType Parm12; + typedef typename TypeTraits<P13>::ParameterType Parm13; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9,Parm10, + Parm11,Parm12,Parm13) + = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6,typename P7,typename P8,typename P9,typename P10, + typename P11,typename P12,typename P13,typename P14> + struct FactoryImpl<AP, Id, LOKI_TYPELIST_14( P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14 )> + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + typedef typename TypeTraits<P12>::ParameterType Parm12; + typedef typename TypeTraits<P13>::ParameterType Parm13; + typedef typename TypeTraits<P14>::ParameterType Parm14; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm8,Parm10, + Parm11,Parm12,Parm13,Parm14) + = 0; + }; + + template<typename AP, typename Id, + typename P1,typename P2,typename P3,typename P4,typename P5, + typename P6,typename P7,typename P8,typename P9,typename P10, + typename P11,typename P12,typename P13,typename P14,typename P15 > + struct FactoryImpl<AP, Id, LOKI_TYPELIST_15( P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15 )> + : public FactoryImplBase + { + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + typedef typename TypeTraits<P12>::ParameterType Parm12; + typedef typename TypeTraits<P13>::ParameterType Parm13; + typedef typename TypeTraits<P14>::ParameterType Parm14; + typedef typename TypeTraits<P15>::ParameterType Parm15; + virtual ~FactoryImpl() {} + virtual AP* CreateObject(const Id& id,Parm1, Parm2, Parm3, Parm4, Parm5, + Parm6, Parm7, Parm8, Parm9,Parm10, + Parm11,Parm12,Parm13,Parm14,Parm15 ) + = 0; + }; + +#endif //LOKI_DISABLE_TYPELIST_MACROS + + +//////////////////////////////////////////////////////////////////////////////// +/// \class Factory +/// +/// \ingroup FactoryGroup +/// Implements a generic object factory. +/// +/// Create functions can have up to 15 parameters. +/// +/// \par Singleton lifetime when used with Loki::SingletonHolder +/// Because Factory uses internally Functors which inherits from +/// SmallObject you must use the singleton lifetime +/// \code Loki::LongevityLifetime::DieAsSmallObjectChild \endcode +/// Alternatively you could suppress for Functor the inheritance +/// from SmallObject by defining the macro: +/// \code LOKI_FUNCTOR_IS_NOT_A_SMALLOBJECT \endcode +//////////////////////////////////////////////////////////////////////////////// + template + < + class AbstractProduct, + typename IdentifierType, + typename CreatorParmTList = NullType, + template<typename, class> class FactoryErrorPolicy = DefaultFactoryError + > + class Factory : public FactoryErrorPolicy<IdentifierType, AbstractProduct> + { + typedef FactoryImpl< AbstractProduct, IdentifierType, CreatorParmTList > Impl; + + typedef typename Impl::Parm1 Parm1; + typedef typename Impl::Parm2 Parm2; + typedef typename Impl::Parm3 Parm3; + typedef typename Impl::Parm4 Parm4; + typedef typename Impl::Parm5 Parm5; + typedef typename Impl::Parm6 Parm6; + typedef typename Impl::Parm7 Parm7; + typedef typename Impl::Parm8 Parm8; + typedef typename Impl::Parm9 Parm9; + typedef typename Impl::Parm10 Parm10; + typedef typename Impl::Parm11 Parm11; + typedef typename Impl::Parm12 Parm12; + typedef typename Impl::Parm13 Parm13; + typedef typename Impl::Parm14 Parm14; + typedef typename Impl::Parm15 Parm15; + + typedef Functor<AbstractProduct*, CreatorParmTList> ProductCreator; + + typedef AssocVector<IdentifierType, ProductCreator> IdToProductMap; + + IdToProductMap associations_; + + public: + + Factory() + : associations_() + { + } + + ~Factory() + { + associations_.erase(associations_.begin(), associations_.end()); + } + + bool Register(const IdentifierType& id, ProductCreator creator) + { + return associations_.insert( + typename IdToProductMap::value_type(id, creator)).second != 0; + } + + template <class PtrObj, typename CreaFn> + bool Register(const IdentifierType& id, const PtrObj& p, CreaFn fn) + { + ProductCreator creator( p, fn ); + return associations_.insert( + typename IdToProductMap::value_type(id, creator)).second != 0; + } + + bool Unregister(const IdentifierType& id) + { + return associations_.erase(id) != 0; + } + + std::vector<IdentifierType> RegisteredIds() + { + std::vector<IdentifierType> ids; + for(typename IdToProductMap::iterator it = associations_.begin(); + it != associations_.end(); ++it) + { + ids.push_back(it->first); + } + return ids; + } + + AbstractProduct* CreateObject(const IdentifierType& id) + { + typename IdToProductMap::iterator i = associations_.find(id); + if (i != associations_.end()) + return (i->second)( ); + return this->OnUnknownType(id); + } + + AbstractProduct* CreateObject(const IdentifierType& id, + Parm1 p1) + { + typename IdToProductMap::iterator i = associations_.find(id); + if (i != associations_.end()) + return (i->second)( p1 ); + return this->OnUnknownType(id); + } + + AbstractProduct* CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2) + { + typename IdToProductMap::iterator i = associations_.find(id); + if (i != associations_.end()) + return (i->second)( p1,p2 ); + return this->OnUnknownType(id); + } + + AbstractProduct* CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3) + { + typename IdToProductMap::iterator i = associations_.find(id); + if (i != associations_.end()) + return (i->second)( p1,p2,p3 ); + return this->OnUnknownType(id); + } + + AbstractProduct* CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4) + { + typename IdToProductMap::iterator i = associations_.find(id); + if (i != associations_.end()) + return (i->second)( p1,p2,p3,p4 ); + return this->OnUnknownType(id); + } + + AbstractProduct* CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5) + { + typename IdToProductMap::iterator i = associations_.find(id); + if (i != associations_.end()) + return (i->second)( p1,p2,p3,p4,p5 ); + return this->OnUnknownType(id); + } + + AbstractProduct* CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6) + { + typename IdToProductMap::iterator i = associations_.find(id); + if (i != associations_.end()) + return (i->second)( p1,p2,p3,p4,p5,p6 ); + return this->OnUnknownType(id); + } + + AbstractProduct* CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7 ) + { + typename IdToProductMap::iterator i = associations_.find(id); + if (i != associations_.end()) + return (i->second)( p1,p2,p3,p4,p5,p6,p7 ); + return this->OnUnknownType(id); + } + + AbstractProduct* CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8) + { + typename IdToProductMap::iterator i = associations_.find(id); + if (i != associations_.end()) + return (i->second)( p1,p2,p3,p4,p5,p6,p7,p8 ); + return this->OnUnknownType(id); + } + + AbstractProduct* CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9) + { + typename IdToProductMap::iterator i = associations_.find(id); + if (i != associations_.end()) + return (i->second)( p1,p2,p3,p4,p5,p6,p7,p8,p9 ); + return this->OnUnknownType(id); + } + AbstractProduct* CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9,Parm10 p10) + { + typename IdToProductMap::iterator i = associations_.find(id); + if (i != associations_.end()) + return (i->second)( p1,p2,p3,p4,p5,p6,p7,p8,p9,p10 ); + return this->OnUnknownType(id); + } + + AbstractProduct* CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, + Parm11 p11) + { + typename IdToProductMap::iterator i = associations_.find(id); + if (i != associations_.end()) + return (i->second)( p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11 ); + return this->OnUnknownType(id); + } + + AbstractProduct* CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, + Parm11 p11, Parm12 p12) + { + typename IdToProductMap::iterator i = associations_.find(id); + if (i != associations_.end()) + return (i->second)( p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12 ); + return this->OnUnknownType(id); + } + + AbstractProduct* CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, + Parm11 p11, Parm12 p12, Parm13 p13) + { + typename IdToProductMap::iterator i = associations_.find(id); + if (i != associations_.end()) + return (i->second)( p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13 ); + return this->OnUnknownType(id); + } + + AbstractProduct* CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, + Parm11 p11, Parm12 p12, Parm13 p13, Parm14 p14) + { + typename IdToProductMap::iterator i = associations_.find(id); + if (i != associations_.end()) + return (i->second)( p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14 ); + return this->OnUnknownType(id); + } + + AbstractProduct* CreateObject(const IdentifierType& id, + Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, + Parm11 p11, Parm12 p12, Parm13 p13, Parm14 p14, Parm15 p15) + { + typename IdToProductMap::iterator i = associations_.find(id); + if (i != associations_.end()) + return (i->second)( p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15 ); + return this->OnUnknownType(id); + } + + }; + +#else + + template + < + class AbstractProduct, + typename IdentifierType, + typename ProductCreator = AbstractProduct* (*)(), + template<typename, class> + class FactoryErrorPolicy = DefaultFactoryError + > + class Factory + : public FactoryErrorPolicy<IdentifierType, AbstractProduct> + { + public: + bool Register(const IdentifierType& id, ProductCreator creator) + { + return associations_.insert( + typename IdToProductMap::value_type(id, creator)).second != 0; + } + + bool Unregister(const IdentifierType& id) + { + return associations_.erase(id) != 0; + } + + AbstractProduct* CreateObject(const IdentifierType& id) + { + typename IdToProductMap::iterator i = associations_.find(id); + if (i != associations_.end()) + { + return (i->second)(); + } + return this->OnUnknownType(id); + } + + private: + typedef AssocVector<IdentifierType, ProductCreator> IdToProductMap; + IdToProductMap associations_; + }; + +#endif //#define ENABLE_NEW_FACTORY_CODE + +/** + * \defgroup CloneFactoryGroup Clone Factory + * \ingroup FactoriesGroup + * \brief Creates a copy from a polymorphic object. + * + * \class CloneFactory + * \ingroup CloneFactoryGroup + * \brief Creates a copy from a polymorphic object. + */ + + template + < + class AbstractProduct, + class ProductCreator = + AbstractProduct* (*)(const AbstractProduct*), + template<typename, class> + class FactoryErrorPolicy = DefaultFactoryError + > + class CloneFactory + : public FactoryErrorPolicy<TypeInfo, AbstractProduct> + { + public: + bool Register(const TypeInfo& ti, ProductCreator creator) + { + return associations_.insert( + typename IdToProductMap::value_type(ti, creator)).second != 0; + } + + bool Unregister(const TypeInfo& id) + { + return associations_.erase(id) != 0; + } + + AbstractProduct* CreateObject(const AbstractProduct* model) + { + if (model == NULL) + { + return NULL; + } + + typename IdToProductMap::iterator i = + associations_.find(typeid(*model)); + + if (i != associations_.end()) + { + return (i->second)(model); + } + return this->OnUnknownType(typeid(*model)); + } + + private: + typedef AssocVector<TypeInfo, ProductCreator> IdToProductMap; + IdToProductMap associations_; + }; + +} // namespace Loki + + +#ifdef _MSC_VER +#pragma warning( pop ) +#endif + +#endif // end file guardian + diff --git a/shared/loki/Function.h b/shared/loki/Function.h new file mode 100644 index 00000000..2d0ad4bb --- /dev/null +++ b/shared/loki/Function.h @@ -0,0 +1,373 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2005 Peter Kümmel +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_FUNCTION_INC_ +#define LOKI_FUNCTION_INC_ + +// $Id: Function.h 841 2008-03-24 23:58:28Z rich_sposato $ + + +#define LOKI_ENABLE_FUNCTION + +#include <stdexcept> + +#include <loki/Functor.h> +#include <loki/Sequence.h> + +namespace Loki +{ + + //////////////////////////////////////////////////////////////////////////////// + /// \struct Function + /// + /// \ingroup FunctorGroup + /// Allows a boost/TR1 like usage of Functor. + /// + /// \par Usage + /// + /// - free functions: e.g. \code Function<int(int,int)> f(&freeFunction); + /// \endcode + /// - member functions: e.g \code Function<int()> f(&object,&ObjectType::memberFunction); + /// \endcode + /// + /// see also test/Function/FunctionTest.cpp (the modified test program from boost) + //////////////////////////////////////////////////////////////////////////////// + + template<class R = void()> + struct Function; + + + template<class R> + struct Function<R()> : public Functor<R> + { + typedef Functor<R> FBase; + + Function() : FBase() {} + + Function(const Function& func) : FBase() + { + if( !func.empty()) + FBase::operator=(func); + } + + // test on emptiness + template<class R2> + Function(Function<R2()> func) : FBase() + { + if(!func.empty()) + FBase::operator=(func); + } + + // clear by '= 0' + Function(const int i) : FBase() + { + if(i==0) + FBase::clear(); + else + throw std::runtime_error("Loki::Function(const int i): i!=0"); + } + + template<class Func> + Function(Func func) : FBase(func) {} + + template<class Host, class Func> + Function(const Host& host, const Func& func) : FBase(host,func) {} + + }; + + +//////////////////////////////////////////////////////////////////////////////// +// macros for the repetitions +//////////////////////////////////////////////////////////////////////////////// + +#define LOKI_FUNCTION_BODY \ + \ + Function() : FBase() {} \ + \ + Function(const Function& func) : FBase() \ + { \ + if( !func.empty()) \ + FBase::operator=(func); \ + } \ + \ + Function(const int i) : FBase() \ + { \ + if(i==0) \ + FBase::clear(); \ + else \ + throw std::runtime_error( \ + "Loki::Function(const int i): i!=0"); \ + } \ + \ + template<class Func> \ + Function(Func func) : FBase(func) {} \ + \ + template<class Host, class Func> \ + Function(const Host& host, const Func& func): FBase(host,func) {} + + +#define LOKI_FUNCTION_R2_CTOR_BODY \ + \ + : FBase() \ + { \ + if(!func.empty()) \ + FBase::operator=(func); \ + } + + +//////////////////////////////////////////////////////////////////////////////// +// repetitions +//////////////////////////////////////////////////////////////////////////////// + + template<> + struct Function<> + : public Loki::Functor<> + { + typedef Functor<> FBase; + + template<class R2> + Function(Function<R2()> func) + LOKI_FUNCTION_R2_CTOR_BODY + + LOKI_FUNCTION_BODY // if compilation breaks here then + // Function.h was not included before + // Functor.h, check your include order + // or define LOKI_ENABLE_FUNCTION + }; + + template<class R,class P01> + struct Function<R(P01)> + : public Loki::Functor<R, Seq<P01> > + { + typedef Functor<R, Seq<P01> > FBase; + + template<class R2,class Q01> + Function(Function<R2(Q01)> func) + LOKI_FUNCTION_R2_CTOR_BODY + + LOKI_FUNCTION_BODY + }; + + template<class R,class P01,class P02> + struct Function<R(P01,P02)> + : public Functor<R, Seq<P01,P02> > + { + typedef Functor<R, Seq<P01,P02> > FBase; + + template<class R2,class Q01, class Q02> + Function(Function<R2(Q01,Q02)> func) + LOKI_FUNCTION_R2_CTOR_BODY + + LOKI_FUNCTION_BODY + }; + + template<class R,class P01,class P02, class P03> + struct Function<R(P01,P02,P03)> + : public Functor<R, Seq<P01,P02,P03> > + { + typedef Functor<R, Seq<P01,P02,P03> > FBase; + + template<class R2,class Q01, class Q02,class Q03> + Function(Function<R2(Q01,Q02,Q03)> func) + LOKI_FUNCTION_R2_CTOR_BODY + + LOKI_FUNCTION_BODY + }; + + template<class R,class P01,class P02, class P03,class P04> + struct Function<R(P01,P02,P03,P04)> + : public Functor<R, Seq<P01,P02,P03,P04> > + { + typedef Functor<R, Seq<P01,P02,P03,P04> > FBase; + + template<class R2,class Q01,class Q02, class Q03,class Q04> + Function(Function<R2(Q01,Q02,Q03,Q04)> func) + LOKI_FUNCTION_R2_CTOR_BODY + + LOKI_FUNCTION_BODY + }; + + template<class R,class P01,class P02, class P03,class P04,class P05> + struct Function<R(P01,P02,P03,P04,P05)> + : public Functor<R, Seq<P01,P02,P03,P04,P05> > + { + typedef Functor<R, Seq<P01,P02,P03,P04,P05> > FBase; + + template<class R2,class Q01,class Q02, class Q03,class Q04,class Q05> + Function(Function<R2(Q01,Q02,Q03,Q04,Q05)> func) + LOKI_FUNCTION_R2_CTOR_BODY + + LOKI_FUNCTION_BODY + }; + + template<class R, class P01,class P02, class P03,class P04,class P05, + class P06> + struct Function<R(P01,P02,P03,P04,P05,P06)> + : public Functor<R, Seq<P01,P02,P03,P04,P05,P06> > + { + typedef Functor<R, Seq<P01,P02,P03,P04,P05,P06> > FBase; + + template<class R2, class Q01,class Q02, class Q03,class Q04,class Q05, + class Q06> + Function(Function<R2(Q01,Q02,Q03,Q04,Q05,Q06)> func) + LOKI_FUNCTION_R2_CTOR_BODY + + LOKI_FUNCTION_BODY + }; + + template<class R, class P01,class P02, class P03,class P04,class P05, + class P06,class P07> + struct Function<R(P01,P02,P03,P04,P05,P06,P07)> + : public Functor<R, Seq<P01,P02,P03,P04,P05,P06,P07> > + { + typedef Functor<R, Seq<P01,P02,P03,P04,P05,P06,P07> > FBase; + + template<class R2, class Q01,class Q02, class Q03,class Q04,class Q05, + class Q06,class Q07> + Function(Function<R2(Q01,Q02,Q03,Q04,Q05,Q06,Q07)> func) + LOKI_FUNCTION_R2_CTOR_BODY + + LOKI_FUNCTION_BODY + }; + + template<class R, class P01,class P02, class P03,class P04,class P05, + class P06,class P07, class P08> + struct Function<R(P01,P02,P03,P04,P05,P06,P07,P08)> + : public Functor<R, Seq<P01,P02,P03,P04,P05,P06,P07,P08> > + { + typedef Functor<R, Seq<P01,P02,P03,P04,P05,P06,P07,P08> > FBase; + + template<class R2, class Q01,class Q02, class Q03,class Q04,class Q05, + class Q06,class Q07, class Q08> + Function(Function<R2(Q01,Q02,Q03,Q04,Q05,Q06,Q07,Q08)> func) + LOKI_FUNCTION_R2_CTOR_BODY + + LOKI_FUNCTION_BODY + }; + + template<class R, class P01,class P02, class P03,class P04,class P05, + class P06,class P07, class P08,class P09> + struct Function<R(P01,P02,P03,P04,P05,P06,P07,P08,P09)> + : public Functor<R, Seq<P01,P02,P03,P04,P05,P06,P07,P08,P09> > + { + typedef Functor<R, Seq<P01,P02,P03,P04,P05,P06,P07,P08,P09 > > FBase; + + template<class R2, class Q01,class Q02, class Q03,class Q04,class Q05, + class Q06,class Q07, class Q08,class Q09> + Function(Function<R2(Q01,Q02,Q03,Q04,Q05,Q06,Q07,Q08,Q09)> func) + LOKI_FUNCTION_R2_CTOR_BODY + + LOKI_FUNCTION_BODY + }; + + template<class R, class P01,class P02, class P03,class P04,class P05, + class P06,class P07, class P08,class P09,class P10> + struct Function<R(P01,P02,P03,P04,P05,P06,P07,P08,P09,P10)> + : public Functor<R, Seq<P01,P02,P03,P04,P05,P06,P07,P08,P09,P10> > + { + typedef Functor<R, Seq<P01,P02,P03,P04,P05,P06,P07,P08,P09,P10> > FBase; + + template<class R2, class Q01,class Q02, class Q03,class Q04,class Q05, + class Q06,class Q07, class Q08,class Q09,class Q10> + Function(Function<R2(Q01,Q02,Q03,Q04,Q05,Q06,Q07,Q08,Q09,Q10)> func) + LOKI_FUNCTION_R2_CTOR_BODY + + LOKI_FUNCTION_BODY + }; + + template<class R, class P01,class P02, class P03,class P04,class P05, + class P06,class P07, class P08,class P09,class P10, + class P11> + struct Function<R(P01,P02,P03,P04,P05,P06,P07,P08,P09,P10,P11)> + : public Functor<R, Seq<P01,P02,P03,P04,P05,P06,P07,P08,P09,P10,P11> > + { + typedef Functor<R, Seq<P01,P02,P03,P04,P05,P06,P07,P08,P09,P10,P11> >FBase; + + template<class R2, class Q01,class Q02, class Q03,class Q04,class Q05, + class Q06,class Q07, class Q08,class Q09,class Q10, + class Q11> + Function(Function<R2(Q01,Q02,Q03,Q04,Q05,Q06,Q07,Q08,Q09,Q10,Q11)> func) + LOKI_FUNCTION_R2_CTOR_BODY + + LOKI_FUNCTION_BODY + }; + + template<class R, class P01,class P02, class P03,class P04,class P05, + class P06,class P07, class P08,class P09,class P10, + class P11,class P12> + struct Function<R(P01,P02,P03,P04,P05,P06,P07,P08,P09,P10,P11,P12)> + : public Functor<R, Seq<P01,P02,P03,P04,P05,P06,P07,P08,P09,P10,P11,P12> > + { + typedef Functor<R, Seq<P01,P02,P03,P04,P05,P06,P07,P08,P09,P10,P11,P12> > FBase; + + template<class R2, class Q01,class Q02, class Q03,class Q04,class Q05, + class Q06,class Q07, class Q08,class Q09,class Q10, + class Q11,class Q12> + Function(Function<R2(Q01,Q02,Q03,Q04,Q05,Q06,Q07,Q08,Q09,Q10,Q11,Q12)> func) + LOKI_FUNCTION_R2_CTOR_BODY + + LOKI_FUNCTION_BODY + }; + + template<class R, class P01,class P02, class P03,class P04,class P05, + class P06,class P07, class P08,class P09,class P10, + class P11,class P12, class P13> + struct Function<R(P01,P02,P03,P04,P05,P06,P07,P08,P09,P10,P11,P12,P13)> + : public Functor<R, Seq<P01,P02,P03,P04,P05,P06,P07,P08,P09,P10,P11,P12,P13> > + { + typedef Functor<R, Seq<P01,P02,P03,P04,P05,P06,P07,P08,P09,P10,P11,P12,P13> > FBase; + + template<class R2, class Q01,class Q02, class Q03,class Q04,class Q05, + class Q06,class Q07, class Q08,class Q09,class Q10, + class Q11,class Q12, class Q13> + Function(Function<R2(Q01,Q02,Q03,Q04,Q05,Q06,Q07,Q08,Q09,Q10,Q11,Q12,Q13)> func) + LOKI_FUNCTION_R2_CTOR_BODY + + LOKI_FUNCTION_BODY + }; + + template<class R, class P01,class P02, class P03,class P04,class P05, + class P06,class P07, class P08,class P09,class P10, + class P11,class P12, class P13,class P14> + struct Function<R(P01,P02,P03,P04,P05,P06,P07,P08,P09,P10,P11,P12,P13,P14)> + : public Functor<R, Seq<P01,P02,P03,P04,P05,P06,P07,P08,P09,P10,P11,P12,P13,P14> > + { + typedef Functor<R, Seq<P01,P02,P03,P04,P05,P06,P07,P08,P09,P10,P11,P12,P13,P14> > FBase; + template<class R2, class Q01,class Q02, class Q03,class Q04,class Q05, + class Q06,class Q07, class Q08,class Q09,class Q10, + class Q11,class Q12, class Q13,class Q14> + Function(Function<R2(Q01,Q02,Q03,Q04,Q05,Q06,Q07,Q08,Q09,Q10,Q11,Q12,Q13,Q14)> func) + LOKI_FUNCTION_R2_CTOR_BODY + + LOKI_FUNCTION_BODY + }; + + template<class R, class P01,class P02, class P03,class P04,class P05, + class P06,class P07, class P08,class P09,class P10, + class P11,class P12, class P13,class P14,class P15> + struct Function<R(P01,P02,P03,P04,P05,P06,P07,P08,P09,P10,P11,P12,P13,P14,P15)> + : public Functor<R, Seq<P01,P02,P03,P04,P05,P06,P07,P08,P09,P10,P11,P12,P13,P14,P15> > + { + typedef Functor<R, Seq<P01,P02,P03,P04,P05,P06,P07,P08,P09,P10,P11,P12,P13,P14,P15> > FBase; + + template<class R2, class Q01,class Q02, class Q03,class Q04,class Q05, + class Q06,class Q07, class Q08,class Q09,class Q10, + class Q11,class Q12, class Q13,class Q14,class Q15> + Function(Function<R2(Q01,Q02,Q03,Q04,Q05,Q06,Q07,Q08,Q09,Q10,Q11,Q12,Q13,Q14,Q15)> func) + LOKI_FUNCTION_R2_CTOR_BODY + + LOKI_FUNCTION_BODY + }; + +}// namespace Loki + +#endif // end file guardian + diff --git a/shared/loki/Functor.h b/shared/loki/Functor.h new file mode 100644 index 00000000..bcba855d --- /dev/null +++ b/shared/loki/Functor.h @@ -0,0 +1,1789 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_FUNCTOR_INC_ +#define LOKI_FUNCTOR_INC_ + +// $Id: Functor.h 750 2006-10-17 19:50:02Z syntheticpp $ + + +#include "Typelist.h" +#include "Sequence.h" +#include "EmptyType.h" +#include "SmallObj.h" +#include "TypeTraits.h" +#include <typeinfo> +#include <memory> + +/// \defgroup FunctorGroup Function objects + +#ifndef LOKI_FUNCTOR_IS_NOT_A_SMALLOBJECT +//#define LOKI_FUNCTOR_IS_NOT_A_SMALLOBJECT +#endif + +#ifndef LOKI_FUNCTORS_ARE_COMPARABLE +//#define LOKI_FUNCTORS_ARE_COMPARABLE +#endif + + +/// \namespace Loki +/// All classes of Loki are in the Loki namespace +namespace Loki +{ +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl (internal) +//////////////////////////////////////////////////////////////////////////////// + + namespace Private + { + template <typename R, template <class, class> class ThreadingModel> + struct FunctorImplBase +#ifdef LOKI_FUNCTOR_IS_NOT_A_SMALLOBJECT + { +#else + : public SmallValueObject<ThreadingModel> + { + inline FunctorImplBase() : + SmallValueObject<ThreadingModel>() {} + inline FunctorImplBase(const FunctorImplBase&) : + SmallValueObject<ThreadingModel>() {} +#endif + + typedef R ResultType; + typedef FunctorImplBase<R, ThreadingModel> FunctorImplBaseType; + + typedef EmptyType Parm1; + typedef EmptyType Parm2; + typedef EmptyType Parm3; + typedef EmptyType Parm4; + typedef EmptyType Parm5; + typedef EmptyType Parm6; + typedef EmptyType Parm7; + typedef EmptyType Parm8; + typedef EmptyType Parm9; + typedef EmptyType Parm10; + typedef EmptyType Parm11; + typedef EmptyType Parm12; + typedef EmptyType Parm13; + typedef EmptyType Parm14; + typedef EmptyType Parm15; + + + virtual ~FunctorImplBase() + {} + + virtual FunctorImplBase* DoClone() const = 0; + + template <class U> + static U* Clone(U* pObj) + { + if (!pObj) return 0; + U* pClone = static_cast<U*>(pObj->DoClone()); + assert(typeid(*pClone) == typeid(*pObj)); + return pClone; + } + + +#ifdef LOKI_FUNCTORS_ARE_COMPARABLE + + virtual bool operator==(const FunctorImplBase&) const = 0; + +#endif + + }; + } + +//////////////////////////////////////////////////////////////////////////////// +// macro LOKI_DEFINE_CLONE_FUNCTORIMPL +// Implements the DoClone function for a functor implementation +//////////////////////////////////////////////////////////////////////////////// + +#define LOKI_DEFINE_CLONE_FUNCTORIMPL(Cls) \ + virtual Cls* DoClone() const { return new Cls(*this); } + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// The base class for a hierarchy of functors. The FunctorImpl class is not used +// directly; rather, the Functor class manages and forwards to a pointer to +// FunctorImpl +// You may want to derive your own functors from FunctorImpl. +// Specializations of FunctorImpl for up to 15 parameters follow +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, class TList, + template <class, class> class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL> + class FunctorImpl; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 0 (zero) parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, template <class, class> class ThreadingModel> + class FunctorImpl<R, NullType, ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + virtual R operator()() = 0; + }; + + //////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 1 parameter +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, template <class, class> class ThreadingModel> + class FunctorImpl<R, Seq<P1>, ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + virtual R operator()(Parm1) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 2 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, + template <class, class> class ThreadingModel> + class FunctorImpl<R, Seq<P1, P2>, ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + virtual R operator()(Parm1, Parm2) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 3 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, + template <class, class> class ThreadingModel> + class FunctorImpl<R, Seq<P1, P2, P3>, ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + virtual R operator()(Parm1, Parm2, Parm3) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 4 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + template <class, class> class ThreadingModel> + class FunctorImpl<R, Seq<P1, P2, P3, P4>, ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + virtual R operator()(Parm1, Parm2, Parm3, Parm4) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 5 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, + template <class, class> class ThreadingModel> + class FunctorImpl<R, Seq<P1, P2, P3, P4, P5>, ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 6 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, + template <class, class> class ThreadingModel> + class FunctorImpl<R, Seq<P1, P2, P3, P4, P5, P6>, ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 7 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, typename P7, + template <class, class> class ThreadingModel> + class FunctorImpl<R, Seq<P1, P2, P3, P4, P5, P6, P7>, ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, + Parm7) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 8 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, typename P7, typename P8, + template <class, class> class ThreadingModel> + class FunctorImpl<R, Seq<P1, P2, P3, P4, P5, P6, P7, P8>, + ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, + Parm7, Parm8) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 9 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, typename P7, typename P8, typename P9, + template <class, class> class ThreadingModel> + class FunctorImpl<R, Seq<P1, P2, P3, P4, P5, P6, P7, P8, P9>, + ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, + Parm7, Parm8, Parm9) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 10 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, typename P7, typename P8, typename P9, + typename P10, + template <class, class> class ThreadingModel> + class FunctorImpl<R, Seq<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10>, + ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, + Parm7, Parm8, Parm9, Parm10) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 11 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, typename P7, typename P8, typename P9, + typename P10, typename P11, + template <class, class> class ThreadingModel> + class FunctorImpl<R, + Seq<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11>, + ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, + Parm7, Parm8, Parm9, Parm10, Parm11) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 12 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, typename P7, typename P8, typename P9, + typename P10, typename P11, typename P12, + template <class, class> class ThreadingModel> + class FunctorImpl<R, + Seq<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12>, + ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + typedef typename TypeTraits<P12>::ParameterType Parm12; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, + Parm7, Parm8, Parm9, Parm10, Parm11, Parm12) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 13 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, typename P7, typename P8, typename P9, + typename P10, typename P11, typename P12, typename P13, + template <class, class> class ThreadingModel> + class FunctorImpl<R, + Seq<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13>, + ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + typedef typename TypeTraits<P12>::ParameterType Parm12; + typedef typename TypeTraits<P13>::ParameterType Parm13; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, + Parm7, Parm8, Parm9, Parm10, Parm11, Parm12, Parm13) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 14 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, typename P7, typename P8, typename P9, + typename P10, typename P11, typename P12, typename P13, typename P14, + template <class, class> class ThreadingModel> + class FunctorImpl<R, + Seq<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, + P14>, + ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + typedef typename TypeTraits<P12>::ParameterType Parm12; + typedef typename TypeTraits<P13>::ParameterType Parm13; + typedef typename TypeTraits<P14>::ParameterType Parm14; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, + Parm7, Parm8, Parm9, Parm10, Parm11, Parm12, Parm13, Parm14) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 15 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, typename P7, typename P8, typename P9, + typename P10, typename P11, typename P12, typename P13, typename P14, + typename P15, template <class, class> class ThreadingModel> + class FunctorImpl<R, + Seq<P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, + P14, P15>, + ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + typedef typename TypeTraits<P12>::ParameterType Parm12; + typedef typename TypeTraits<P13>::ParameterType Parm13; + typedef typename TypeTraits<P14>::ParameterType Parm14; + typedef typename TypeTraits<P15>::ParameterType Parm15; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, + Parm7, Parm8, Parm9, Parm10, Parm11, Parm12, Parm13, Parm14, + Parm15) = 0; + }; + +#ifndef LOKI_DISABLE_TYPELIST_MACROS + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 1 parameter +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, template <class, class> class ThreadingModel> + class FunctorImpl<R, LOKI_TYPELIST_1(P1), ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + virtual R operator()(Parm1) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 2 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, + template <class, class> class ThreadingModel> + class FunctorImpl<R, LOKI_TYPELIST_2(P1, P2), ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + virtual R operator()(Parm1, Parm2) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 3 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, + template <class, class> class ThreadingModel> + class FunctorImpl<R, LOKI_TYPELIST_3(P1, P2, P3), ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + virtual R operator()(Parm1, Parm2, Parm3) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 4 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + template <class, class> class ThreadingModel> + class FunctorImpl<R, LOKI_TYPELIST_4(P1, P2, P3, P4), ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + virtual R operator()(Parm1, Parm2, Parm3, Parm4) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 5 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, + template <class, class> class ThreadingModel> + class FunctorImpl<R, LOKI_TYPELIST_5(P1, P2, P3, P4, P5), ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 6 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, + template <class, class> class ThreadingModel> + class FunctorImpl<R, LOKI_TYPELIST_6(P1, P2, P3, P4, P5, P6), ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 7 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, typename P7, + template <class, class> class ThreadingModel> + class FunctorImpl<R, LOKI_TYPELIST_7(P1, P2, P3, P4, P5, P6, P7), ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, + Parm7) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 8 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, typename P7, typename P8, + template <class, class> class ThreadingModel> + class FunctorImpl<R, LOKI_TYPELIST_8(P1, P2, P3, P4, P5, P6, P7, P8), + ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, + Parm7, Parm8) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 9 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, typename P7, typename P8, typename P9, + template <class, class> class ThreadingModel> + class FunctorImpl<R, LOKI_TYPELIST_9(P1, P2, P3, P4, P5, P6, P7, P8, P9), + ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, + Parm7, Parm8, Parm9) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 10 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, typename P7, typename P8, typename P9, + typename P10, + template <class, class> class ThreadingModel> + class FunctorImpl<R, LOKI_TYPELIST_10(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10), + ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, + Parm7, Parm8, Parm9, Parm10) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 11 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, typename P7, typename P8, typename P9, + typename P10, typename P11, + template <class, class> class ThreadingModel> + class FunctorImpl<R, + LOKI_TYPELIST_11(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11), + ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, + Parm7, Parm8, Parm9, Parm10, Parm11) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 12 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, typename P7, typename P8, typename P9, + typename P10, typename P11, typename P12, + template <class, class> class ThreadingModel> + class FunctorImpl<R, + LOKI_TYPELIST_12(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12), + ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + typedef typename TypeTraits<P12>::ParameterType Parm12; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, + Parm7, Parm8, Parm9, Parm10, Parm11, Parm12) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 13 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, typename P7, typename P8, typename P9, + typename P10, typename P11, typename P12, typename P13, + template <class, class> class ThreadingModel> + class FunctorImpl<R, + LOKI_TYPELIST_13(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13), + ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + typedef typename TypeTraits<P12>::ParameterType Parm12; + typedef typename TypeTraits<P13>::ParameterType Parm13; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, + Parm7, Parm8, Parm9, Parm10, Parm11, Parm12, Parm13) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 14 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, typename P7, typename P8, typename P9, + typename P10, typename P11, typename P12, typename P13, typename P14, + template <class, class> class ThreadingModel> + class FunctorImpl<R, + LOKI_TYPELIST_14(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, + P14), + ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + typedef typename TypeTraits<P12>::ParameterType Parm12; + typedef typename TypeTraits<P13>::ParameterType Parm13; + typedef typename TypeTraits<P14>::ParameterType Parm14; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, + Parm7, Parm8, Parm9, Parm10, Parm11, Parm12, Parm13, Parm14) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorImpl +// Specialization for 15 parameters +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, typename P1, typename P2, typename P3, typename P4, + typename P5, typename P6, typename P7, typename P8, typename P9, + typename P10, typename P11, typename P12, typename P13, typename P14, + typename P15, template <class, class> class ThreadingModel> + class FunctorImpl<R, + LOKI_TYPELIST_15(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, + P14, P15), + ThreadingModel> + : public Private::FunctorImplBase<R, ThreadingModel> + { + public: + typedef R ResultType; + typedef typename TypeTraits<P1>::ParameterType Parm1; + typedef typename TypeTraits<P2>::ParameterType Parm2; + typedef typename TypeTraits<P3>::ParameterType Parm3; + typedef typename TypeTraits<P4>::ParameterType Parm4; + typedef typename TypeTraits<P5>::ParameterType Parm5; + typedef typename TypeTraits<P6>::ParameterType Parm6; + typedef typename TypeTraits<P7>::ParameterType Parm7; + typedef typename TypeTraits<P8>::ParameterType Parm8; + typedef typename TypeTraits<P9>::ParameterType Parm9; + typedef typename TypeTraits<P10>::ParameterType Parm10; + typedef typename TypeTraits<P11>::ParameterType Parm11; + typedef typename TypeTraits<P12>::ParameterType Parm12; + typedef typename TypeTraits<P13>::ParameterType Parm13; + typedef typename TypeTraits<P14>::ParameterType Parm14; + typedef typename TypeTraits<P15>::ParameterType Parm15; + virtual R operator()(Parm1, Parm2, Parm3, Parm4, Parm5, Parm6, + Parm7, Parm8, Parm9, Parm10, Parm11, Parm12, Parm13, Parm14, + Parm15) = 0; + }; + +#endif //LOKI_DISABLE_TYPELIST_MACROS + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorHandler +// Wraps functors and pointers to functions +//////////////////////////////////////////////////////////////////////////////// + + template <class ParentFunctor, typename Fun> + class FunctorHandler + : public ParentFunctor::Impl + { + typedef typename ParentFunctor::Impl Base; + + public: + typedef typename Base::ResultType ResultType; + typedef typename Base::Parm1 Parm1; + typedef typename Base::Parm2 Parm2; + typedef typename Base::Parm3 Parm3; + typedef typename Base::Parm4 Parm4; + typedef typename Base::Parm5 Parm5; + typedef typename Base::Parm6 Parm6; + typedef typename Base::Parm7 Parm7; + typedef typename Base::Parm8 Parm8; + typedef typename Base::Parm9 Parm9; + typedef typename Base::Parm10 Parm10; + typedef typename Base::Parm11 Parm11; + typedef typename Base::Parm12 Parm12; + typedef typename Base::Parm13 Parm13; + typedef typename Base::Parm14 Parm14; + typedef typename Base::Parm15 Parm15; + + FunctorHandler(const Fun& fun) : f_(fun) {} + + LOKI_DEFINE_CLONE_FUNCTORIMPL(FunctorHandler) + + +#ifdef LOKI_FUNCTORS_ARE_COMPARABLE + + + bool operator==(const typename Base::FunctorImplBaseType& rhs) const + { + // there is no static information if Functor holds a member function + // or a free function; this is the main difference to tr1::function + if(typeid(*this) != typeid(rhs)) + return false; // cannot be equal + + const FunctorHandler& fh = static_cast<const FunctorHandler&>(rhs); + // if this line gives a compiler error, you are using a function object. + // you need to implement bool MyFnObj::operator == (const MyFnObj&) const; + return f_==fh.f_; + } +#endif + // operator() implementations for up to 15 arguments + + ResultType operator()() + { return f_(); } + + ResultType operator()(Parm1 p1) + { return f_(p1); } + + ResultType operator()(Parm1 p1, Parm2 p2) + { return f_(p1, p2); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3) + { return f_(p1, p2, p3); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4) + { return f_(p1, p2, p3, p4); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5) + { return f_(p1, p2, p3, p4, p5); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6) + { return f_(p1, p2, p3, p4, p5, p6); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7) + { return f_(p1, p2, p3, p4, p5, p6, p7); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8) + { return f_(p1, p2, p3, p4, p5, p6, p7, p8); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9) + { return f_(p1, p2, p3, p4, p5, p6, p7, p8, p9); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10) + { return f_(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11) + { return f_(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, + Parm12 p12) + { return f_(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, + Parm12 p12, Parm13 p13) + { return f_(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, + Parm12 p12, Parm13 p13, Parm14 p14) + { + return f_(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, + p14); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, + Parm12 p12, Parm13 p13, Parm14 p14, Parm15 p15) + { + return f_(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, + p14, p15); + } + + private: + Fun f_; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorHandler +// Wraps pointers to member functions +//////////////////////////////////////////////////////////////////////////////// + + template <class ParentFunctor, typename PointerToObj, + typename PointerToMemFn> + class MemFunHandler : public ParentFunctor::Impl + { + typedef typename ParentFunctor::Impl Base; + + public: + typedef typename Base::ResultType ResultType; + typedef typename Base::Parm1 Parm1; + typedef typename Base::Parm2 Parm2; + typedef typename Base::Parm3 Parm3; + typedef typename Base::Parm4 Parm4; + typedef typename Base::Parm5 Parm5; + typedef typename Base::Parm6 Parm6; + typedef typename Base::Parm7 Parm7; + typedef typename Base::Parm8 Parm8; + typedef typename Base::Parm9 Parm9; + typedef typename Base::Parm10 Parm10; + typedef typename Base::Parm11 Parm11; + typedef typename Base::Parm12 Parm12; + typedef typename Base::Parm13 Parm13; + typedef typename Base::Parm14 Parm14; + typedef typename Base::Parm15 Parm15; + + MemFunHandler(const PointerToObj& pObj, PointerToMemFn pMemFn) + : pObj_(pObj), pMemFn_(pMemFn) + {} + + LOKI_DEFINE_CLONE_FUNCTORIMPL(MemFunHandler) + + +#ifdef LOKI_FUNCTORS_ARE_COMPARABLE + + bool operator==(const typename Base::FunctorImplBaseType& rhs) const + { + if(typeid(*this) != typeid(rhs)) + return false; // cannot be equal + + const MemFunHandler& mfh = static_cast<const MemFunHandler&>(rhs); + // if this line gives a compiler error, you are using a function object. + // you need to implement bool MyFnObj::operator == (const MyFnObj&) const; + return pObj_==mfh.pObj_ && pMemFn_==mfh.pMemFn_; + } +#endif + + ResultType operator()() + { return ((*pObj_).*pMemFn_)(); } + + ResultType operator()(Parm1 p1) + { return ((*pObj_).*pMemFn_)(p1); } + + ResultType operator()(Parm1 p1, Parm2 p2) + { return ((*pObj_).*pMemFn_)(p1, p2); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3) + { return ((*pObj_).*pMemFn_)(p1, p2, p3); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4) + { return ((*pObj_).*pMemFn_)(p1, p2, p3, p4); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5) + { return ((*pObj_).*pMemFn_)(p1, p2, p3, p4, p5); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6) + { return ((*pObj_).*pMemFn_)(p1, p2, p3, p4, p5, p6); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7) + { return ((*pObj_).*pMemFn_)(p1, p2, p3, p4, p5, p6, p7); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8) + { return ((*pObj_).*pMemFn_)(p1, p2, p3, p4, p5, p6, p7, p8); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9) + { return ((*pObj_).*pMemFn_)(p1, p2, p3, p4, p5, p6, p7, p8, p9); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10) + { return ((*pObj_).*pMemFn_)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11) + { + return ((*pObj_).*pMemFn_)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, + p11); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, + Parm12 p12) + { + return ((*pObj_).*pMemFn_)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, + p11, p12); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, + Parm12 p12, Parm13 p13) + { + return ((*pObj_).*pMemFn_)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, + p11, p12, p13); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, + Parm12 p12, Parm13 p13, Parm14 p14) + { + return ((*pObj_).*pMemFn_)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, + p11, p12, p13, p14); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, + Parm12 p12, Parm13 p13, Parm14 p14, Parm15 p15) + { + return ((*pObj_).*pMemFn_)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, + p11, p12, p13, p14, p15); + } + + private: + PointerToObj pObj_; + PointerToMemFn pMemFn_; + }; + +//////////////////////////////////////////////////////////////////////////////// +// TR1 exception +////////////////////////////////////////////////////////////////////////////////// + +#ifdef LOKI_ENABLE_FUNCTION + + class bad_function_call : public std::runtime_error + { + public: + bad_function_call() : std::runtime_error("bad_function_call in Loki::Functor") + {} + }; + +#define LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL if(empty()) throw bad_function_call(); + +#else + +#define LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL + +#endif + +//////////////////////////////////////////////////////////////////////////////// +/// \class Functor +/// +/// \ingroup FunctorGroup +/// A generalized functor implementation with value semantics +/// +/// \par Macro: LOKI_FUNCTOR_IS_NOT_A_SMALLOBJECT +/// Define +/// \code LOKI_FUNCTOR_IS_NOT_A_SMALLOBJECT \endcode +/// to avoid static instantiation/delete +/// order problems. +/// It often helps against crashes when using static Functors and multi threading. +/// Defining also removes problems when unloading Dlls which hosts +/// static Functor objects. +/// +/// \par Macro: LOKI_FUNCTORS_ARE_COMPARABLE +/// To enable the operator== define the macro +/// \code LOKI_FUNCTORS_ARE_COMPARABLE \endcode +/// The macro is disabled by default, because it breaks compiling functor +/// objects which have no operator== implemented, keep in mind when you enable +/// operator==. +//////////////////////////////////////////////////////////////////////////////// + template <typename R = void, class TList = NullType, + template<class, class> class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL> + class Functor + { + public: + // Handy type definitions for the body type + typedef FunctorImpl<R, TList, ThreadingModel> Impl; + typedef R ResultType; + typedef TList ParmList; + typedef typename Impl::Parm1 Parm1; + typedef typename Impl::Parm2 Parm2; + typedef typename Impl::Parm3 Parm3; + typedef typename Impl::Parm4 Parm4; + typedef typename Impl::Parm5 Parm5; + typedef typename Impl::Parm6 Parm6; + typedef typename Impl::Parm7 Parm7; + typedef typename Impl::Parm8 Parm8; + typedef typename Impl::Parm9 Parm9; + typedef typename Impl::Parm10 Parm10; + typedef typename Impl::Parm11 Parm11; + typedef typename Impl::Parm12 Parm12; + typedef typename Impl::Parm13 Parm13; + typedef typename Impl::Parm14 Parm14; + typedef typename Impl::Parm15 Parm15; + + // Member functions + + Functor() : spImpl_(0) + {} + + Functor(const Functor& rhs) : spImpl_(Impl::Clone(rhs.spImpl_.get())) + {} + + Functor(std::auto_ptr<Impl> spImpl) : spImpl_(spImpl) + {} + + template <typename Fun> + Functor(Fun fun) + : spImpl_(new FunctorHandler<Functor, Fun>(fun)) + {} + + template <class PtrObj, typename MemFn> + Functor(const PtrObj& p, MemFn memFn) + : spImpl_(new MemFunHandler<Functor, PtrObj, MemFn>(p, memFn)) + {} + + typedef Impl * (std::auto_ptr<Impl>::*unspecified_bool_type)() const; + + operator unspecified_bool_type() const + { + return spImpl_.get() ? &std::auto_ptr<Impl>::get : 0; + } + + Functor& operator=(const Functor& rhs) + { + Functor copy(rhs); + // swap auto_ptrs by hand + Impl* p = spImpl_.release(); + spImpl_.reset(copy.spImpl_.release()); + copy.spImpl_.reset(p); + return *this; + } + +#ifdef LOKI_ENABLE_FUNCTION + + bool empty() const + { + return spImpl_.get() == 0; + } + + void clear() + { + spImpl_.reset(0); + } +#endif + +#ifdef LOKI_FUNCTORS_ARE_COMPARABLE + + bool operator==(const Functor& rhs) const + { + if(spImpl_.get()==0 && rhs.spImpl_.get()==0) + return true; + if(spImpl_.get()!=0 && rhs.spImpl_.get()!=0) + return *spImpl_.get() == *rhs.spImpl_.get(); + else + return false; + } + + bool operator!=(const Functor& rhs) const + { + return !(*this==rhs); + } +#endif + + // operator() implementations for up to 15 arguments + + ResultType operator()() const + { + LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL + return (*spImpl_)(); + } + + ResultType operator()(Parm1 p1) const + { + LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL + return (*spImpl_)(p1); + } + + ResultType operator()(Parm1 p1, Parm2 p2) const + { + LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL + return (*spImpl_)(p1, p2); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3) const + { + LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL + return (*spImpl_)(p1, p2, p3); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4) const + { + LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL + return (*spImpl_)(p1, p2, p3, p4); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5) const + { + LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL + return (*spImpl_)(p1, p2, p3, p4, p5); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6) const + { + LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL + return (*spImpl_)(p1, p2, p3, p4, p5, p6); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7) const + { + LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL + return (*spImpl_)(p1, p2, p3, p4, p5, p6, p7); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8) const + { + LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL + return (*spImpl_)(p1, p2, p3, p4, p5, p6, p7, p8); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9) const + { + LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL + return (*spImpl_)(p1, p2, p3, p4, p5, p6, p7, p8, p9); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10) const + { + LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL + return (*spImpl_)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11) const + { + LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL + return (*spImpl_)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, + Parm12 p12) const + { + LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL + return (*spImpl_)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, + p12); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, + Parm12 p12, Parm13 p13) const + { + LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL + return (*spImpl_)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, + p12, p13); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, + Parm12 p12, Parm13 p13, Parm14 p14) const + { + LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL + return (*spImpl_)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, + p12, p13, p14); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, + Parm12 p12, Parm13 p13, Parm14 p14, Parm15 p15) const + { + LOKI_FUNCTION_THROW_BAD_FUNCTION_CALL + return (*spImpl_)(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, + p12, p13, p14, p15); + } + + private: + std::auto_ptr<Impl> spImpl_; + }; + + +//////////////////////////////////////////////////////////////////////////////// +// +// BindersFirst and Chainer +// +//////////////////////////////////////////////////////////////////////////////// + + namespace Private + { + template <class Fctor> struct BinderFirstTraits; + + template <typename R, class TList, template <class, class> class ThreadingModel> + struct BinderFirstTraits< Functor<R, TList, ThreadingModel> > + { + typedef Functor<R, TList, ThreadingModel> OriginalFunctor; + + typedef typename TL::Erase<TList,typename TL::TypeAt<TList, 0>::Result> + ::Result + ParmList; + + typedef typename TL::TypeAt<TList, 0>::Result OriginalParm1; + + typedef Functor<R, ParmList, ThreadingModel> BoundFunctorType; + + typedef typename BoundFunctorType::Impl Impl; + + }; + + + template<class T> + struct BinderFirstBoundTypeStorage; + + template<class T> + struct BinderFirstBoundTypeStorage + { + typedef typename TypeTraits<T>::ParameterType RefOrValue; + }; + + template <typename R, class TList, template <class, class> class ThreadingModel> + struct BinderFirstBoundTypeStorage< Functor<R, TList, ThreadingModel> > + { + typedef Functor<R, TList, ThreadingModel> OriginalFunctor; + typedef const typename TypeTraits<OriginalFunctor>::ReferredType RefOrValue; + }; + + + } // namespace Private + +//////////////////////////////////////////////////////////////////////////////// +/// \class BinderFirst +/// +/// \ingroup FunctorGroup +/// Binds the first parameter of a Functor object to a specific value +//////////////////////////////////////////////////////////////////////////////// + + template <class OriginalFunctor> + class BinderFirst + : public Private::BinderFirstTraits<OriginalFunctor>::Impl + { + typedef typename Private::BinderFirstTraits<OriginalFunctor>::Impl Base; + typedef typename OriginalFunctor::ResultType ResultType; + + typedef typename OriginalFunctor::Parm1 BoundType; + + typedef typename Private::BinderFirstBoundTypeStorage< + typename Private::BinderFirstTraits<OriginalFunctor> + ::OriginalParm1> + ::RefOrValue + BoundTypeStorage; + + typedef typename OriginalFunctor::Parm2 Parm1; + typedef typename OriginalFunctor::Parm3 Parm2; + typedef typename OriginalFunctor::Parm4 Parm3; + typedef typename OriginalFunctor::Parm5 Parm4; + typedef typename OriginalFunctor::Parm6 Parm5; + typedef typename OriginalFunctor::Parm7 Parm6; + typedef typename OriginalFunctor::Parm8 Parm7; + typedef typename OriginalFunctor::Parm9 Parm8; + typedef typename OriginalFunctor::Parm10 Parm9; + typedef typename OriginalFunctor::Parm11 Parm10; + typedef typename OriginalFunctor::Parm12 Parm11; + typedef typename OriginalFunctor::Parm13 Parm12; + typedef typename OriginalFunctor::Parm14 Parm13; + typedef typename OriginalFunctor::Parm15 Parm14; + typedef EmptyType Parm15; + + public: + + BinderFirst(const OriginalFunctor& fun, BoundType bound) + : f_(fun), b_(bound) + {} + + LOKI_DEFINE_CLONE_FUNCTORIMPL(BinderFirst) + +#ifdef LOKI_FUNCTORS_ARE_COMPARABLE + + bool operator==(const typename Base::FunctorImplBaseType& rhs) const + { + if(typeid(*this) != typeid(rhs)) + return false; // cannot be equal + // if this line gives a compiler error, you are using a function object. + // you need to implement bool MyFnObj::operator == (const MyFnObj&) const; + return f_ == ((static_cast<const BinderFirst&> (rhs)).f_) && + b_ == ((static_cast<const BinderFirst&> (rhs)).b_); + } +#endif + + // operator() implementations for up to 15 arguments + + ResultType operator()() + { return f_(b_); } + + ResultType operator()(Parm1 p1) + { return f_(b_, p1); } + + ResultType operator()(Parm1 p1, Parm2 p2) + { return f_(b_, p1, p2); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3) + { return f_(b_, p1, p2, p3); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4) + { return f_(b_, p1, p2, p3, p4); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5) + { return f_(b_, p1, p2, p3, p4, p5); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6) + { return f_(b_, p1, p2, p3, p4, p5, p6); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7) + { return f_(b_, p1, p2, p3, p4, p5, p6, p7); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8) + { return f_(b_, p1, p2, p3, p4, p5, p6, p7, p8); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9) + { return f_(b_, p1, p2, p3, p4, p5, p6, p7, p8, p9); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10) + { return f_(b_, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11) + { return f_(b_, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, + Parm12 p12) + { return f_(b_, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, + Parm12 p12, Parm13 p13) + { return f_(b_, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, + Parm12 p12, Parm13 p13, Parm14 p14) + { + return f_(b_, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, + p14); + } + + private: + OriginalFunctor f_; + BoundTypeStorage b_; + }; + +//////////////////////////////////////////////////////////////////////////////// +/// Binds the first parameter of a Functor object to a specific value +/// \ingroup FunctorGroup +//////////////////////////////////////////////////////////////////////////////// + + template <class Fctor> + typename Private::BinderFirstTraits<Fctor>::BoundFunctorType + BindFirst( + const Fctor& fun, + typename Fctor::Parm1 bound) + { + typedef typename Private::BinderFirstTraits<Fctor>::BoundFunctorType + Outgoing; + + return Outgoing(std::auto_ptr<typename Outgoing::Impl>( + new BinderFirst<Fctor>(fun, bound))); + } + +//////////////////////////////////////////////////////////////////////////////// +/// \class Chainer +/// +/// \ingroup FunctorGroup +/// Chains two functor calls one after another +//////////////////////////////////////////////////////////////////////////////// + + template <typename Fun1, typename Fun2> + class Chainer : public Fun2::Impl + { + typedef Fun2 Base; + + public: + typedef typename Base::ResultType ResultType; + typedef typename Base::Parm1 Parm1; + typedef typename Base::Parm2 Parm2; + typedef typename Base::Parm3 Parm3; + typedef typename Base::Parm4 Parm4; + typedef typename Base::Parm5 Parm5; + typedef typename Base::Parm6 Parm6; + typedef typename Base::Parm7 Parm7; + typedef typename Base::Parm8 Parm8; + typedef typename Base::Parm9 Parm9; + typedef typename Base::Parm10 Parm10; + typedef typename Base::Parm11 Parm11; + typedef typename Base::Parm12 Parm12; + typedef typename Base::Parm13 Parm13; + typedef typename Base::Parm14 Parm14; + typedef typename Base::Parm15 Parm15; + + Chainer(const Fun1& fun1, const Fun2& fun2) : f1_(fun1), f2_(fun2) {} + + LOKI_DEFINE_CLONE_FUNCTORIMPL(Chainer) + +#ifdef LOKI_FUNCTORS_ARE_COMPARABLE + + bool operator==(const typename Base::Impl::FunctorImplBaseType& rhs) const + { + if(typeid(*this) != typeid(rhs)) + return false; // cannot be equal + // if this line gives a compiler error, you are using a function object. + // you need to implement bool MyFnObj::operator == (const MyFnObj&) const; + return f1_ == ((static_cast<const Chainer&> (rhs)).f2_) && + f2_ == ((static_cast<const Chainer&> (rhs)).f1_); + } +#endif + + // operator() implementations for up to 15 arguments + + ResultType operator()() + { return f1_(), f2_(); } + + ResultType operator()(Parm1 p1) + { return f1_(p1), f2_(p1); } + + ResultType operator()(Parm1 p1, Parm2 p2) + { return f1_(p1, p2), f2_(p1, p2); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3) + { return f1_(p1, p2, p3), f2_(p1, p2, p3); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4) + { return f1_(p1, p2, p3, p4), f2_(p1, p2, p3, p4); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5) + { return f1_(p1, p2, p3, p4, p5), f2_(p1, p2, p3, p4, p5); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6) + { return f1_(p1, p2, p3, p4, p5, p6), f2_(p1, p2, p3, p4, p5, p6); } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7) + { + return f1_(p1, p2, p3, p4, p5, p6, p7), + f2_(p1, p2, p3, p4, p5, p6, p7); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8) + { + return f1_(p1, p2, p3, p4, p5, p6, p7, p8), + f2_(p1, p2, p3, p4, p5, p6, p7, p8); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9) + { + return f1_(p1, p2, p3, p4, p5, p6, p7, p8, p9), + f2_(p1, p2, p3, p4, p5, p6, p7, p8, p9); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10) + { + return f1_(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10), + f2_(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11) + { + return f1_(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11), + f2_(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, + Parm12 p12) + { + return f1_(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12), + f2_(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, + Parm12 p12, Parm13 p13) + { + return f1_(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13), + f2_(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, + Parm12 p12, Parm13 p13, Parm14 p14) + { + return f1_(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, + p14), + f2_(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, + p14); + } + + ResultType operator()(Parm1 p1, Parm2 p2, Parm3 p3, Parm4 p4, Parm5 p5, + Parm6 p6, Parm7 p7, Parm8 p8, Parm9 p9, Parm10 p10, Parm11 p11, + Parm12 p12, Parm13 p13, Parm14 p14, Parm15 p15) + { + return f1_(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, + p14, p15), + f2_(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, + p14, p15); + } + + private: + Fun1 f1_; + Fun2 f2_; + }; + +//////////////////////////////////////////////////////////////////////////////// +/// Chains two functor calls one after another +/// \ingroup FunctorGroup +//////////////////////////////////////////////////////////////////////////////// + + + template <class Fun1, class Fun2> + Fun2 Chain( + const Fun1& fun1, + const Fun2& fun2) + { + return Fun2(std::auto_ptr<typename Fun2::Impl>( + new Chainer<Fun1, Fun2>(fun1, fun2))); + } + +} // namespace Loki + + +#endif // end file guardian + diff --git a/shared/loki/HierarchyGenerators.h b/shared/loki/HierarchyGenerators.h new file mode 100644 index 00000000..3fa11ffc --- /dev/null +++ b/shared/loki/HierarchyGenerators.h @@ -0,0 +1,291 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_HIERARCHYGENERATORS_INC_ +#define LOKI_HIERARCHYGENERATORS_INC_ + +// $Id: HierarchyGenerators.h 751 2006-10-17 19:50:37Z syntheticpp $ + + +#include "Typelist.h" +#include "TypeTraits.h" +#include "EmptyType.h" + +namespace Loki +{ +#if defined(_MSC_VER) && _MSC_VER >= 1300 +#pragma warning( push ) + // 'class1' : base-class 'class2' is already a base-class of 'class3' +#pragma warning( disable : 4584 ) +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// class template GenScatterHierarchy +// Generates a scattered hierarchy starting from a typelist and a template +// Invocation (TList is a typelist, Unit is a template of one arg): +// GenScatterHierarchy<TList, Unit> +// The generated class inherits all classes generated by instantiating the +// template 'Unit' with the types contained in TList +//////////////////////////////////////////////////////////////////////////////// + + namespace Private + { + // The following type helps to overcome subtle flaw in the original + // implementation of GenScatterHierarchy. + // The flaw is revealed when the input type list of GenScatterHierarchy + // contains more then one element of the same type (e.g. LOKI_TYPELIST_2(int, int)). + // In this case GenScatterHierarchy will contain multiple bases of the same + // type and some of them will not be reachable (per 10.3). + // For example before the fix the first element of Tuple<LOKI_TYPELIST_2(int, int)> + // is not reachable in any way! + template<class, class> + struct ScatterHierarchyTag; + } + + template <class TList, template <class> class Unit> + class GenScatterHierarchy; + + template <class T1, class T2, template <class> class Unit> + class GenScatterHierarchy<Typelist<T1, T2>, Unit> + : public GenScatterHierarchy<Private::ScatterHierarchyTag<T1, T2>, Unit> + , public GenScatterHierarchy<T2, Unit> + { + public: + typedef Typelist<T1, T2> TList; + // Insure that LeftBase is unique and therefore reachable + typedef GenScatterHierarchy<Private::ScatterHierarchyTag<T1, T2>, Unit> LeftBase; + typedef GenScatterHierarchy<T2, Unit> RightBase; + template <typename T> struct Rebind + { + typedef Unit<T> Result; + }; + }; + + // In the middle *unique* class that resolve possible ambiguity + template <class T1, class T2, template <class> class Unit> + class GenScatterHierarchy<Private::ScatterHierarchyTag<T1, T2>, Unit> + : public GenScatterHierarchy<T1, Unit> + { + }; + + template <class AtomicType, template <class> class Unit> + class GenScatterHierarchy : public Unit<AtomicType> + { + typedef Unit<AtomicType> LeftBase; + template <typename T> struct Rebind + { + typedef Unit<T> Result; + }; + }; + + template <template <class> class Unit> + class GenScatterHierarchy<NullType, Unit> + { + template <typename T> struct Rebind + { + typedef Unit<T> Result; + }; + }; + +//////////////////////////////////////////////////////////////////////////////// +// function template Field +// Accesses a field in an object of a type generated with GenScatterHierarchy +// Invocation (obj is an object of a type H generated with GenScatterHierarchy, +// T is a type in the typelist used to generate H): +// Field<T>(obj) +// returns a reference to Unit<T>, where Unit is the template used to generate H +//////////////////////////////////////////////////////////////////////////////// + + template <class T, class H> + typename H::template Rebind<T>::Result& Field(H& obj) + { + return obj; + } + + template <class T, class H> + const typename H::template Rebind<T>::Result& Field(const H& obj) + { + return obj; + } + +//////////////////////////////////////////////////////////////////////////////// +// function template TupleUnit +// The building block of tuples +//////////////////////////////////////////////////////////////////////////////// + + template <class T> + struct TupleUnit + { + T value_; + operator T&() { return value_; } + operator const T&() const { return value_; } + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template Tuple +// Implements a tuple class that holds a number of values and provides field +// access to them via the Field function (below) +//////////////////////////////////////////////////////////////////////////////// + + template <class TList> + struct Tuple : public GenScatterHierarchy<TList, TupleUnit> + { + }; + +//////////////////////////////////////////////////////////////////////////////// +// helper class template FieldHelper +// See Field below +//////////////////////////////////////////////////////////////////////////////// + + template <class H, unsigned int i> struct FieldHelper; + + template <class H> + struct FieldHelper<H, 0> + { + typedef typename H::TList::Head ElementType; + typedef typename H::template Rebind<ElementType>::Result UnitType; + + enum + { + isTuple = Conversion<UnitType, TupleUnit<ElementType> >::sameType, + isConst = TypeTraits<H>::isConst + }; + + typedef const typename H::LeftBase ConstLeftBase; + + typedef typename Select<isConst, ConstLeftBase, + typename H::LeftBase>::Result LeftBase; + + typedef typename Select<isTuple, ElementType, + UnitType>::Result UnqualifiedResultType; + + typedef typename Select<isConst, const UnqualifiedResultType, + UnqualifiedResultType>::Result ResultType; + + static ResultType& Do(H& obj) + { + LeftBase& leftBase = obj; + return leftBase; + } + }; + + template <class H, unsigned int i> + struct FieldHelper + { + typedef typename TL::TypeAt<typename H::TList, i>::Result ElementType; + typedef typename H::template Rebind<ElementType>::Result UnitType; + + enum + { + isTuple = Conversion<UnitType, TupleUnit<ElementType> >::sameType, + isConst = TypeTraits<H>::isConst + }; + + typedef const typename H::RightBase ConstRightBase; + + typedef typename Select<isConst, ConstRightBase, + typename H::RightBase>::Result RightBase; + + typedef typename Select<isTuple, ElementType, + UnitType>::Result UnqualifiedResultType; + + typedef typename Select<isConst, const UnqualifiedResultType, + UnqualifiedResultType>::Result ResultType; + + static ResultType& Do(H& obj) + { + RightBase& rightBase = obj; + return FieldHelper<RightBase, i - 1>::Do(rightBase); + } + }; + +//////////////////////////////////////////////////////////////////////////////// +// function template Field +// Accesses a field in an object of a type generated with GenScatterHierarchy +// Invocation (obj is an object of a type H generated with GenScatterHierarchy, +// i is the index of a type in the typelist used to generate H): +// Field<i>(obj) +// returns a reference to Unit<T>, where Unit is the template used to generate H +// and T is the i-th type in the typelist +//////////////////////////////////////////////////////////////////////////////// + + template <int i, class H> + typename FieldHelper<H, i>::ResultType& + Field(H& obj) + { + return FieldHelper<H, i>::Do(obj); + } + +// template <int i, class H> +// const typename FieldHelper<H, i>::ResultType& +// Field(const H& obj) +// { +// return FieldHelper<H, i>::Do(obj); +// } + +//////////////////////////////////////////////////////////////////////////////// +// class template GenLinearHierarchy +// Generates a linear hierarchy starting from a typelist and a template +// Invocation (TList is a typelist, Unit is a template of two args): +// GenScatterHierarchy<TList, Unit> +//////////////////////////////////////////////////////////////////////////////// + + template + < + class TList, + template <class AtomicType, class Base> class Unit, + class Root = EmptyType + > + class GenLinearHierarchy; + + template + < + class T1, + class T2, + template <class, class> class Unit, + class Root + > + class GenLinearHierarchy<Typelist<T1, T2>, Unit, Root> + : public Unit< T1, GenLinearHierarchy<T2, Unit, Root> > + { + }; + + template + < + class T, + template <class, class> class Unit, + class Root + > + class GenLinearHierarchy<Typelist<T, NullType>, Unit, Root> + : public Unit<T, Root> + { + }; + + template + < + template <class, class> class Unit, + class Root + > + class GenLinearHierarchy<NullType , Unit, Root> + : public Root // is this better: Unit<NullType, Root> ? + { + }; + +#if defined(_MSC_VER) && _MSC_VER >= 1300 +#pragma warning( pop ) +#endif +} // namespace Loki + +#endif // end file guardian + diff --git a/shared/loki/Key.h b/shared/loki/Key.h new file mode 100644 index 00000000..4daaa603 --- /dev/null +++ b/shared/loki/Key.h @@ -0,0 +1,764 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2006 by Guillaume Chatelet +// +// Code covered by the MIT License +// +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// +// The authors make no representations about the suitability of this software +// for any purpose. It is provided "as is" without express or implied warranty. +// +// This code DOES NOT accompany the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_KEY_INC_ +#define LOKI_KEY_INC_ + +// $Id: Key.h 771 2006-10-27 18:05:03Z clitte_bbt $ + + +#include <loki/Factory.h> + +namespace Loki +{ + + template< + class Factory, + typename IdentifierType + > + class Key; + + template<class F, typename I> + bool operator==(const Key<F, I> &k1, const Key<F, I> &k2); + + template<class F, typename I> + bool operator<(const Key<F, I> &k1, const Key<F, I> &k2); + + + /** + * A Key class + */ + template< + class Factory, + typename IdentifierType + > + class Key + { + typedef typename Factory::Parm1 Parm1; + typedef typename Factory::Parm2 Parm2; + typedef typename Factory::Parm3 Parm3; + typedef typename Factory::Parm4 Parm4; + typedef typename Factory::Parm5 Parm5; + typedef typename Factory::Parm6 Parm6; + typedef typename Factory::Parm7 Parm7; + typedef typename Factory::Parm8 Parm8; + typedef typename Factory::Parm9 Parm9; + typedef typename Factory::Parm10 Parm10; + typedef typename Factory::Parm11 Parm11; + typedef typename Factory::Parm12 Parm12; + typedef typename Factory::Parm13 Parm13; + typedef typename Factory::Parm14 Parm14; + typedef typename Factory::Parm15 Parm15; + public: + // member variables + int count; // should be const, but constness prevent default copy ctor + IdentifierType id; + Parm1 p1; + Parm2 p2; + Parm3 p3; + Parm4 p4; + Parm5 p5; + Parm6 p6; + Parm7 p7; + Parm8 p8; + Parm9 p9; + Parm10 p10; + Parm11 p11; + Parm12 p12; + Parm13 p13; + Parm14 p14; + Parm15 p15; + + // member functions + Key() : count(-1) + { + } + + Key(const IdentifierType& id) : count(0) + { + this->id = id; + } + + Key(const IdentifierType& id, + Parm1 &p1) : count(1) + { + this->id = id; + this->p1 = p1; + } + + Key(const IdentifierType& id, + Parm1 &p1, Parm2 &p2) : count(2) + { + this->id = id; + this->p1 = p1; + this->p2 = p2; + } + + Key(const IdentifierType& id, + Parm1 &p1, Parm2 &p2, Parm3 &p3) : count(3) + { + this->id = id; + this->p1 = p1; + this->p2 = p2; + this->p3 = p3; + } + + Key(const IdentifierType& id, + Parm1 &p1, Parm2 &p2, Parm3 &p3, Parm4 &p4) : count(4) + { + this->id = id; + this->p1 = p1; + this->p2 = p2; + this->p3 = p3; + this->p4 = p4; + } + + Key(const IdentifierType& id, + Parm1 &p1, Parm2 &p2, Parm3 &p3, Parm4 &p4, Parm5 &p5) : count(5) + { + this->id = id; + this->p1 = p1; + this->p2 = p2; + this->p3 = p3; + this->p4 = p4; + this->p5 = p5; + } + + Key(const IdentifierType& id, + Parm1 &p1, Parm2 &p2, Parm3 &p3, Parm4 &p4, Parm5 &p5, + Parm6 &p6) : count(6) + { + this->id = id; + this->p1 = p1; + this->p2 = p2; + this->p3 = p3; + this->p4 = p4; + this->p5 = p5; + this->p6 = p6; + } + + Key(const IdentifierType& id, + Parm1 &p1, Parm2 &p2, Parm3 &p3, Parm4 &p4, Parm5 &p5, + Parm6 &p6, Parm7 &p7 ) : count(7) + { + this->id = id; + this->p1 = p1; + this->p2 = p2; + this->p3 = p3; + this->p4 = p4; + this->p5 = p5; + this->p6 = p6; + this->p7 = p7; + } + + Key(const IdentifierType& id, + Parm1 &p1, Parm2 &p2, Parm3 &p3, Parm4 &p4, Parm5 &p5, + Parm6 &p6, Parm7 &p7, Parm8 &p8) : count(8) + { + this->id = id; + this->p1 = p1; + this->p2 = p2; + this->p3 = p3; + this->p4 = p4; + this->p5 = p5; + this->p6 = p6; + this->p7 = p7; + this->p8 = p8; + } + + Key(const IdentifierType& id, + Parm1 &p1, Parm2 &p2, Parm3 &p3, Parm4 &p4, Parm5 &p5, + Parm6 &p6, Parm7 &p7, Parm8 &p8, Parm9 &p9) : count(9) + { + this->id = id; + this->p1 = p1; + this->p2 = p2; + this->p3 = p3; + this->p4 = p4; + this->p5 = p5; + this->p6 = p6; + this->p7 = p7; + this->p8 = p8; + this->p9 = p9; + } + + Key(const IdentifierType& id, + Parm1 &p1, Parm2 &p2, Parm3 &p3, Parm4 &p4, Parm5 &p5, + Parm6 &p6, Parm7 &p7, Parm8 &p8, Parm9 &p9,Parm10 &p10) : count(10) + { + this->id = id; + this->p1 = p1; + this->p2 = p2; + this->p3 = p3; + this->p4 = p4; + this->p5 = p5; + this->p6 = p6; + this->p7 = p7; + this->p8 = p8; + this->p9 = p9; + this->p10 = p10; + } + + Key(const IdentifierType& id, + Parm1 &p1, Parm2 &p2, Parm3 &p3, Parm4 &p4, Parm5 &p5, + Parm6 &p6, Parm7 &p7, Parm8 &p8, Parm9 &p9, Parm10 &p10, + Parm11 &p11) : count(11) + { + this->id = id; + this->p1 = p1; + this->p2 = p2; + this->p3 = p3; + this->p4 = p4; + this->p5 = p5; + this->p6 = p6; + this->p7 = p7; + this->p8 = p8; + this->p9 = p9; + this->p10 = p10; + this->p11 = p11; + } + + Key(const IdentifierType& id, + Parm1 &p1, Parm2 &p2, Parm3 &p3, Parm4 &p4, Parm5 &p5, + Parm6 &p6, Parm7 &p7, Parm8 &p8, Parm9 &p9, Parm10 &p10, + Parm11 &p11, Parm12 &p12) : count(12) + { + this->id = id; + this->p1 = p1; + this->p2 = p2; + this->p3 = p3; + this->p4 = p4; + this->p5 = p5; + this->p6 = p6; + this->p7 = p7; + this->p8 = p8; + this->p9 = p9; + this->p10 = p10; + this->p11 = p11; + this->p12 = p12; + } + + Key(const IdentifierType& id, + Parm1 &p1, Parm2 &p2, Parm3 &p3, Parm4 &p4, Parm5 &p5, + Parm6 &p6, Parm7 &p7, Parm8 &p8, Parm9 &p9, Parm10 &p10, + Parm11 &p11, Parm12 &p12, Parm13 &p13) : count(13) + { + this->id = id; + this->p1 = p1; + this->p2 = p2; + this->p3 = p3; + this->p4 = p4; + this->p5 = p5; + this->p6 = p6; + this->p7 = p7; + this->p8 = p8; + this->p9 = p9; + this->p10 = p10; + this->p11 = p11; + this->p12 = p12; + this->p13 = p13; + } + + Key(const IdentifierType& id, + Parm1 &p1, Parm2 &p2, Parm3 &p3, Parm4 &p4, Parm5 &p5, + Parm6 &p6, Parm7 &p7, Parm8 &p8, Parm9 &p9, Parm10 &p10, + Parm11 &p11, Parm12 &p12, Parm13 &p13, Parm14 &p14) : count(14) + { + this->id = id; + this->p1 = p1; + this->p2 = p2; + this->p3 = p3; + this->p4 = p4; + this->p5 = p5; + this->p6 = p6; + this->p7 = p7; + this->p8 = p8; + this->p9 = p9; + this->p10 = p10; + this->p11 = p11; + this->p12 = p12; + this->p13 = p13; + this->p14 = p14; + } + + Key(const IdentifierType& id, + Parm1 &p1, Parm2 &p2, Parm3 &p3, Parm4 &p4, Parm5 &p5, + Parm6 &p6, Parm7 &p7, Parm8 &p8, Parm9 &p9, Parm10 &p10, + Parm11 &p11, Parm12 &p12, Parm13 &p13, Parm14 &p14, Parm15 &p15) : count(15) + { + this->id = id; + this->p1 = p1; + this->p2 = p2; + this->p3 = p3; + this->p4 = p4; + this->p5 = p5; + this->p6 = p6; + this->p7 = p7; + this->p8 = p8; + this->p9 = p9; + this->p10 = p10; + this->p11 = p11; + this->p12 = p12; + this->p13 = p13; + this->p14 = p14; + this->p15 = p15; + } + + template<class F, typename I> + friend bool operator==(const Key<F, I> &k1, const Key<F, I> &k2); + + template<class F, typename I> + friend bool operator<(const Key<F, I> &k1, const Key<F, I> &k2); + }; + + + template<class F, typename I> + bool operator==(const Key<F, I> &k1, const Key<F, I> &k2) + { + if( k1.count != k2.count ) + return false; + switch(k1.count){ + case -1: + return true; + case 0: + if( k1.id == k2.id ) + return true; + else + return false; + case 1: + if( (k1.id == k2.id) && + (k1.p1 == k2.p1) ) + return true; + else + return false; + case 2: + if( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) ) + return true; + else + return false; + case 3: + if( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) ) + return true; + else + return false; + case 4: + if( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) ) + return true; + else + return false; + case 5: + if( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) ) + return true; + else + return false; + case 6: + if( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) ) + return true; + else + return false; + case 7: + if( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) && + (k1.p7 == k2.p7) ) + return true; + else + return false; + case 8: + if( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) && + (k1.p7 == k2.p7) && + (k1.p8 == k2.p8) ) + return true; + else + return false; + case 9: + if( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) && + (k1.p7 == k2.p7) && + (k1.p8 == k2.p8) && + (k1.p9 == k2.p9) ) + return true; + else + return false; + case 10: + if( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) && + (k1.p7 == k2.p7) && + (k1.p8 == k2.p8) && + (k1.p9 == k2.p9) && + (k1.p10 == k2.p10) ) + return true; + else + return false; + case 11: + if( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) && + (k1.p7 == k2.p7) && + (k1.p8 == k2.p8) && + (k1.p9 == k2.p9) && + (k1.p10 == k2.p10) && + (k1.p11 == k2.p11) ) + return true; + else + return false; + case 12: + if( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) && + (k1.p7 == k2.p7) && + (k1.p8 == k2.p8) && + (k1.p9 == k2.p9) && + (k1.p10 == k2.p10) && + (k1.p11 == k2.p11) && + (k1.p12 == k2.p12) ) + return true; + else + return false; + case 13: + if( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) && + (k1.p7 == k2.p7) && + (k1.p8 == k2.p8) && + (k1.p9 == k2.p9) && + (k1.p10 == k2.p10) && + (k1.p11 == k2.p11) && + (k1.p12 == k2.p12) && + (k1.p13 == k2.p13) ) + return true; + else + return false; + case 14: + if( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) && + (k1.p7 == k2.p7) && + (k1.p8 == k2.p8) && + (k1.p9 == k2.p9) && + (k1.p10 == k2.p10) && + (k1.p11 == k2.p11) && + (k1.p12 == k2.p12) && + (k1.p13 == k2.p13) && + (k1.p14 == k2.p14) ) + return true; + else + return false; + case 15: + if( (k1.id == k2.id) && + (k1.p1 == k2.p1) && + (k1.p2 == k2.p2) && + (k1.p3 == k2.p3) && + (k1.p4 == k2.p4) && + (k1.p5 == k2.p5) && + (k1.p6 == k2.p6) && + (k1.p7 == k2.p7) && + (k1.p8 == k2.p8) && + (k1.p9 == k2.p9) && + (k1.p10 == k2.p10) && + (k1.p11 == k2.p11) && + (k1.p12 == k2.p12) && + (k1.p13 == k2.p13) && + (k1.p14 == k2.p14) && + (k1.p15 == k2.p15) ) + return true; + else + return false; + default: + return false; + } + } + + + + template<class F, typename I> + bool operator<(const Key<F, I> &k1, const Key<F, I> &k2) + { + if( k1.count < k2.count ) + return true; + switch(k1.count){ + case -1: + return false; + case 0: + if( k1.id < k2.id ) + return true; + else + return false; + case 1: + if( (k1.id < k2.id) || + (k1.p1 < k2.p1) ) + return true; + else + return false; + case 2: + if( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) ) + return true; + else + return false; + case 3: + if( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) ) + return true; + else + return false; + case 4: + if( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) ) + return true; + else + return false; + case 5: + if( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) ) + return true; + else + return false; + case 6: + if( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) ) + return true; + else + return false; + case 7: + if( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) || + (k1.p7 < k2.p7) ) + return true; + else + return false; + case 8: + if( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) || + (k1.p7 < k2.p7) || + (k1.p8 < k2.p8) ) + return true; + else + return false; + case 9: + if( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) || + (k1.p7 < k2.p7) || + (k1.p8 < k2.p8) || + (k1.p9 < k2.p9) ) + return true; + else + return false; + case 10: + if( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) || + (k1.p7 < k2.p7) || + (k1.p8 < k2.p8) || + (k1.p9 < k2.p9) || + (k1.p10 < k2.p10) ) + return true; + else + return false; + case 11: + if( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) || + (k1.p7 < k2.p7) || + (k1.p8 < k2.p8) || + (k1.p9 < k2.p9) || + (k1.p10 < k2.p10) || + (k1.p11 < k2.p11) ) + return true; + else + return false; + case 12: + if( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) || + (k1.p7 < k2.p7) || + (k1.p8 < k2.p8) || + (k1.p9 < k2.p9) || + (k1.p10 < k2.p10) || + (k1.p11 < k2.p11) || + (k1.p12 < k2.p12) ) + return true; + else + return false; + case 13: + if( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) || + (k1.p7 < k2.p7) || + (k1.p8 < k2.p8) || + (k1.p9 < k2.p9) || + (k1.p10 < k2.p10) || + (k1.p11 < k2.p11) || + (k1.p12 < k2.p12) || + (k1.p13 < k2.p13) ) + return true; + else + return false; + case 14: + if( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) || + (k1.p7 < k2.p7) || + (k1.p8 < k2.p8) || + (k1.p9 < k2.p9) || + (k1.p10 < k2.p10) || + (k1.p11 < k2.p11) || + (k1.p12 < k2.p12) || + (k1.p13 < k2.p13) || + (k1.p14 < k2.p14) ) + return true; + else + return false; + case 15: + if( (k1.id < k2.id) || + (k1.p1 < k2.p1) || + (k1.p2 < k2.p2) || + (k1.p3 < k2.p3) || + (k1.p4 < k2.p4) || + (k1.p5 < k2.p5) || + (k1.p6 < k2.p6) || + (k1.p7 < k2.p7) || + (k1.p8 < k2.p8) || + (k1.p9 < k2.p9) || + (k1.p10 < k2.p10) || + (k1.p11 < k2.p11) || + (k1.p12 < k2.p12) || + (k1.p13 < k2.p13) || + (k1.p14 < k2.p14) || + (k1.p15 < k2.p15) ) + return true; + else + return false; + default: + return false; + } + } + + + +} // namespace Loki + +#endif // end file guardian + diff --git a/shared/loki/LevelMutex.h b/shared/loki/LevelMutex.h new file mode 100644 index 00000000..c048000f --- /dev/null +++ b/shared/loki/LevelMutex.h @@ -0,0 +1,1211 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// LevelMutex facility for the Loki Library +// Copyright (c) 2008 Richard Sposato +// The copyright on this file is protected under the terms of the MIT license. +// +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// +// The author makes no representations about the suitability of this software +// for any purpose. It is provided "as is" without express or implied warranty. +// +//////////////////////////////////////////////////////////////////////////////// + +// $Id$ + +/// @file LevelMutex.h Defines classes and functions for LevelMutex facility. + +#ifndef LOKI_LEVEL_MUTEX_H_INCLUDED +#define LOKI_LEVEL_MUTEX_H_INCLUDED + + +// ---------------------------------------------------------------------------- + +#include <vector> +#include <assert.h> +#include <time.h> + +#if defined( _MSC_VER ) + #include <Windows.h> +#else + #include <pthread.h> +#endif + +#if !defined(_WIN32) && !defined(_WIN64) + #include <unistd.h> // declares sleep under Linux +#endif + +/** @par thread_local Keyword + The mutexes require compilers to provide thread local storage - meaning each + thread gets its own copy of the data. The next version of C++ will have a + new keyword, thread_local for that purpose. Some existing compilers already + provide thread local storage using different syntax, so these lines use + thread_local to mimic that syntax. If your compiler provides thread local + storage but using different syntax besides "thread_local", you may want to + modify these lines. If your compiler does not support thread local storage, + you can't use LevelMutex. + */ +#ifndef LOKI_THREAD_LOCAL + #if defined( _MSC_VER ) + #if ( _MSC_VER >= 1300 ) + #define LOKI_THREAD_LOCAL __declspec( thread ) + #else + #error "Only Visual Studio versions 7.0 and after supported." + #endif + + #elif ( __GNUC__ ) + #define LOKI_THREAD_LOCAL __thread + + #else + #warning "Check if your compiler provides thread local storage." + #define LOKI_THREAD_LOCAL thread_local + #endif +#endif + +#if defined( DEBUG ) || defined( _DEBUG ) + #define LOKI_MUTEX_DEBUG_CODE( x ) x +#else + #define LOKI_MUTEX_DEBUG_CODE( x ) +#endif + + +namespace Loki +{ + + +// ---------------------------------------------------------------------------- + +class MutexErrors +{ +public: + + /// @enum Type Possible error conditions detected by LevelMutex functions. + enum Type + { + Success = 0, ///< Operation occurred correctly. + NoProblem, ///< Pre-lock and pre-unlock checks passed. + WrongLevel, ///< All mutexes in container must have same level. + LevelTooLow, ///< Trying to unlock a mutex lower than current level. + LevelTooHigh, ///< Trying to lock a mutex higher than current level. + TryFailed, ///< TryLock call failed to lock mutex. + NullMutexPointer, ///< Container has a NULL pointer in it. + DuplicateMutex, ///< Container must have unique pointers - no duplicates. + EmptyContainer, ///< Container must have at least 1 pointer in it. + AlreadyLocked, ///< TryLock call failed because mutex already locked. + WasntLocked, ///< Unlock failed because mutex was not even locked. + NotRecentLock, ///< Mutex in container was not recently locked by this thread. + NotLockedByThread, ///< Can't unlock a mutex not locked by this thread. + MultiUnlockFailed, ///< MultiUnlock can't unlock at least 1 mutex in container. + TimedOut, ///< Wait time elapsed without locking mutex. + TooMuchRecursion, ///< Tried to relock a PThread mutex which is not re-entrant. + NotInitialized, ///< Tried to lock a PThread mutex which did not get setup. + AlreadyInitialized, ///< PThread mutex initialized before ctor called. + InvalidAttribute, ///< PThread mutex improperly initialized. + InvalidAddress, ///< Bad pointer used to initialize a PThread mutex. + ExceptionThrown, ///< Exception caught in mutex operation. + MayDeadlock, ///< Locking this mutex may cause a deadlock. + OtherError ///< Unknown error occurred. + }; +}; + +// ---------------------------------------------------------------------------- + +/** @class LevelMutexInfo + This monolithic base class stores common info for a template class used to + control mutexes. The template class, LevelMutex, is policy-based class. + + @par Implementation + Each thread has a list of mutexes it locked. When a mutex first gets locked, it + gets added to the head of the list. If locked again, LevelMutex merely increments + a count. When unlocked, the count gets decremented until it reaches zero, and + then it gets removed from the list. Each mutex has a pointer to the mutex most + recently locked by the current thread. The current level of a thread is always + the level of the most recently locked mutex, or UnlockedLevel if the thread does + not have any mutexes locked now. A mutex is considered "recently" locked if it is at + the head of the list, or the same level as the current mutex and also locked by the + current thread. + + @par Class Invariants + This class maintains invariants for each LevelMutexInfo so that no function + calls corrupt a mutex. Each function makes a call to IsValid at the start so + that LevelMutex knows it acts on valid internal data. Many functions call + IsValid again when they return to insure the function did not leave any data in + an invalid state. The exit call to IsValid occurs through a tiny helper class + called Checker to insure all data remain valid even when exceptions occur. + Another helper class, MutexUndoer, unlocks mutexes in a container if an + exception occurs during calls to MultiLock. + + @par Error Results + Many functions return an enum value to indicate an error status. Many enum values + indicate errors detected within LevelMutex, but some indicate errors found in policy + classes, SpinLevelMutex and SleepLevelMutex. + */ + +class LevelMutexInfo +{ +public: + + /** Level for thread that has not locked any mutex. Maximum possible level + for a mutex is UnlockedLevel-1; No mutex may have a level of UnlockedLevel. + */ + static const unsigned int UnlockedLevel = 0xFFFFFFFF; + + /// Container for locking multiple mutexes at once. + typedef ::std::vector< volatile LevelMutexInfo * > MutexContainer; + typedef MutexContainer::iterator LevelMutexContainerIter; + typedef MutexContainer::const_iterator LevelMutexContainerCIter; + typedef MutexContainer::reverse_iterator LevelMutexContainerRIter; + typedef MutexContainer::const_reverse_iterator LevelMutexContainerCRIter; + + /** Locks several mutexes at once. Requires O(m + n*n) actions where m is the + number of mutexes currently locked by the thread and n is the number of mutexes + in the container. This provides strong exception safety. If an exception occurs, + any mutexes that were locked during this call will get unlocked. + @param mutexes Container of pointers to mutexes. Container must have at + least 1 mutex, all mutexes must have the same level, no NULL pointers, and all + mutexes must not exceed the thread's current level. This sorts the container + by address order. + @return Enum value indicating success or error. + */ + static MutexErrors::Type MultiLock( MutexContainer & mutexes ); + + /** Locks several mutexes at once. Requires O(m + n*n + n*t) actions where m is + the number of mutexes currently locked by the thread, n is the number of mutexes + in the container, and t is the wait time for each mutex. This provides strong + exception safety. If an exception occurs, any mutexes that were locked during + this call will ge unlocked. + @param mutexes Container of pointers to mutexes. Container must have at + least 1 mutex, all mutexes must have the same level, no NULL pointers, and all + mutexes must not exceed the thread's current level. This sorts the container + by address order. + @param milliSeconds Amount of time to wait for each mutex. + @return Enum value indicating success or error. + */ + static MutexErrors::Type MultiLock( MutexContainer & mutexes, + unsigned int milliSeconds ); + + /** Unlocks several mutexes at once. Requires O(m) actions where m is the number of + mutexes in the container. This provides strong exception safety. If an exception + occurs when unlocking one mutex, other mutexes in the container get unlocked anyway. + @param mutexes Container of pointers to mutexes. Container must have at least 1 + mutex, all mutexes must have the same level, no NULL pointers, and all mutexes must + be locked by the current thread. This sorts the container dby address order. + @return Enum value indicating success or error. + */ + static MutexErrors::Type MultiUnlock( MutexContainer & mutexes ); + + /** Gives pointer to most recently locked mutex, or NULL if nothing locked. + The pointer is for a const mutex so the mutex can't be modified inappropriately. + The pointer is for a volatile mutex so callers can call volatile member + functions to get info about the mutex. + */ + static const volatile LevelMutexInfo * GetCurrentMutex( void ); + + /// Returns the level of this mutex. + inline unsigned int GetLevel( void ) const volatile { return m_level; } + + /// Returns true if this mutex was locked at least once. + inline bool IsLocked( void ) const volatile { return ( 0 < m_count ); } + + /// Returns count of how many times this mutex got locked. + inline unsigned int GetLockCount( void ) const volatile { return m_count; } + + /// Returns pointer to mutex previously locked by the thread which locked this. + inline const volatile LevelMutexInfo * GetPrevious( void ) const volatile + { + return m_previous; + } + + /** Tries to lock mutex, and returns immediately if mutex already locked by + another thread. It will return immediately with a value of AlreadyLocked + if the mutex was locked by a different thread. It may throw an exception + or assert when errors occur if the ErrorPolicy class implements that behavior. + @return An error condition if any occurred, else Success. + */ + virtual MutexErrors::Type TryLock( void ) volatile = 0; + + /** Blocking call will attempt to lock mutex and wait until it can lock. + This may throw an exception if the lock failed or an error occurred - if + that is what the error policy specifies. + @return An error condition if any occurred, else Success. + */ + virtual MutexErrors::Type Lock( void ) volatile = 0; + + /** Attempts to lock mutex, but only waits for a limited amount of time + before it gives up. Will return quickly if an error occurs before any + attempt to lock. This may throw an exception if the lock failed or an + error occurred - if that is what the error policy specifies. + @param milliSeconds How long to wait. + @return An error condition if any occurred, else Success. + */ + virtual MutexErrors::Type Lock( unsigned int milliSeconds ) volatile = 0; + + /** Unlocks the mutex, or returns an error condition. This may throw an + exception if the lock failed or an error occurred - if that is what the + error policy specifies. + @return An error condition if any occurred, else Success. + */ + virtual MutexErrors::Type Unlock( void ) volatile = 0; + + /** Returns true if this mutex was locked by current thread, and level is the same + as the current thread's level. Which means this was the most recently locked + mutex, or it was locked along with several others of the same level recently. + */ + bool IsRecentLock( void ) const volatile; + + /** Returns true if this mutex was locked within the last count mutexes. + @param count How many recent mutexes to look through to find this mutex. + */ + bool IsRecentLock( unsigned int count ) const volatile; + + /// Returns true if this was locked by current thread. + bool IsLockedByCurrentThread( void ) const volatile; + + /// Returns true if this was locked by another thread. + bool IsLockedByAnotherThread( void ) const volatile; + +protected: + + /** @class Checker Performs validity check on mutex to insure no class invariants + were violated inside any member function. This class only gets used in debug + builds, and any instance of it gets optimized away in release builds. A checker + is created inside many of member functions so that it's destructor gets called + when the function exits. It determines if any class invariants were violated + during the function call. + */ + class Checker + { + public: + inline explicit Checker( const volatile LevelMutexInfo * mutex ) : + m_mutex( mutex ) {} + inline ~Checker( void ) { m_mutex->IsValid(); } + private: + Checker( void ); + Checker( const Checker & ); + Checker & operator = ( const Checker & ); + const volatile LevelMutexInfo * m_mutex; + }; + + /** @class MutexUndoer + Undoes actions by MultiLock if an exception occurs. It keeps track of + which mutexes in a container got locked, and if an exception occurs, then + the destructor unlocks them. If MultiLock succeeds, then it cancels the + undoer so nothing gets unlocked inadvertently. + */ + class MutexUndoer + { + public: + + explicit MutexUndoer( MutexContainer & mutexes ); + ~MutexUndoer( void ); + void SetPlace( LevelMutexContainerIter & here ); + void Cancel( void ); + + private: + + MutexUndoer( void ); + MutexUndoer( const MutexUndoer & ); + MutexUndoer & operator = ( const MutexUndoer & ); + + MutexContainer & m_mutexes; + LevelMutexContainerIter m_here; + }; + + /** Returns true if linked-list of locked mutexes in this thread is valid. + Which means the list has no loops, and each previous mutex on the list has a + higher or same level as the current mutex. Called by IsValid. + */ + static bool IsValidList( void ); + + /** This is the only available constructor, and it forces any derived class to set + a level for each mutex. + */ + explicit LevelMutexInfo( unsigned int level ); + + /// The destructor only gets called by the derived class. + virtual ~LevelMutexInfo( void ); + + MutexErrors::Type PreLockCheck( bool forTryLock ) volatile; + + MutexErrors::Type PreUnlockCheck( void ) volatile; + + /** This gets called after each call to DoLock and DoTryLock to make sure the data + members in this object get set correctly. + */ + void PostLock( void ) volatile; + + /// Gets called just before an attempt to unlock a mutex. + void PreUnlock( void ) volatile; + + /// Called to relock a mutex already locked by the current thread. + void IncrementCount( void ) volatile; + + /// Called to unlock a mutex locked multiple times by the current thread. + void DecrementCount( void ) volatile; + + /** Returns true if no class invariant broken, otherwise asserts. This function + only gets called in debug builds. + */ + bool IsValid( void ) const volatile; + +private: + + /// Copy constructor is not implemented. + LevelMutexInfo( const LevelMutexInfo & ); + /// Copy-assignment operator is not implemented. + LevelMutexInfo & operator = ( const LevelMutexInfo & ); + + /** Called only by MultiLock & MultiUnlock to pass a result through an + error checking policy. + @param result What error condition to check. + @return Result or assertion or an exception - depending on error policy. + */ + virtual MutexErrors::Type DoErrorCheck( MutexErrors::Type result ) const volatile = 0; + + /// Called only by MultiLock to Lock each particular mutex within a container. + virtual MutexErrors::Type LockThis( void ) volatile = 0; + + /** Called only by MultiLock to lock each particular mutex within a container. + @param milliSeconds How much time to wait before giving up on locking a mutex. + */ + virtual MutexErrors::Type LockThis( unsigned int milliSeconds ) volatile = 0; + + /// Called only by MultiUnlock to unlock each particular mutex within a container. + virtual MutexErrors::Type UnlockThis( void ) volatile = 0; + + /// Pointer to singly-linked list of mutexes locked by the current thread. + static LOKI_THREAD_LOCAL volatile LevelMutexInfo * s_currentMutex; + + /// Level of this mutex. + const unsigned int m_level; + + /// How many times this mutex got locked. + unsigned int m_count; + + /// Pointer to mutex locked before this one. + volatile LevelMutexInfo * m_previous; + +}; + +// ---------------------------------------------------------------------------- + +/** @class ThrowOnAnyMutexError + Implements the ErrorPolicy for LevelMutex and throws an exception for any + error condition. Only allows MutexErrors::Success and MutexErrors::NoProblem + to get through. Useful for release builds. + */ +class ThrowOnAnyMutexError +{ +public: + static MutexErrors::Type CheckError( MutexErrors::Type error, + unsigned int level ); +}; + +// ---------------------------------------------------------------------------- + +/** @class ThrowOnBadDesignMutexError + Implements the ErrorPolicy for LevelMutex and throws an exception if the error + indicates the programmer did not levelize the calls to mutexes. Otherwise + returns the error result. Useful for release builds. + */ +class ThrowOnBadDesignMutexError +{ +public: + static MutexErrors::Type CheckError( MutexErrors::Type error, + unsigned int level ); +}; + +// ---------------------------------------------------------------------------- + +/** @class AssertAnyMutexError + Implements the ErrorPolicy for LevelMutex and asserts for any error condition. + Only allows MutexErrors::Success and MutexErrors::NoProblem to get through. + Useful for testing mutexes in debug builds. + */ +class AssertAnyMutexError +{ +public: + static inline MutexErrors::Type CheckError( MutexErrors::Type error, + unsigned int level ) + { + (void)level; + assert( ( error == MutexErrors::Success ) + || ( error == MutexErrors::NoProblem ) ); + return error; + } +}; + +// ---------------------------------------------------------------------------- + +/** @class AssertBadDesignMutexError + Implements the ErrorPolicy for LevelMutex and asserts if the error + indicates the programmer did not levelize the calls to mutexes. Otherwise + returns the error result. Useful for testing mutexes in debug builds. + */ +class AssertBadDesignMutexError +{ +public: + static inline MutexErrors::Type CheckError( MutexErrors::Type error, + unsigned int level ) + { + (void)level; + assert( ( error != MutexErrors::LevelTooHigh ) + && ( error != MutexErrors::LevelTooLow ) ); + return error; + } +}; + +// ---------------------------------------------------------------------------- + +/** @class JustReturnMutexError + Implements the ErrorPolicy for LevelMutex and does nothing no matter how bad + the error condition. Only recommended use is for automated unit-testing of + mutex policies. + */ +class JustReturnMutexError +{ +public: + static inline MutexErrors::Type CheckError( MutexErrors::Type error, + unsigned int level ) + { + (void)level; + return error; + } +}; + +// ---------------------------------------------------------------------------- + +/** @class NoMutexWait + Implements the WaitPolicy for LevelMutex. Does nothing at all so it turns + all wait loops into spin loops. Useful for low-level mutexes. + */ +class NoMutexWait +{ +public: + static inline void Wait( void ) {} +}; + +// ---------------------------------------------------------------------------- + +/** @class MutexSleepWaits + Implements the WaitPolicy for LevelMutex. Sleeps for a moment so thread won't + consume idle CPU cycles. Useful for high-level mutexes. + */ +class MutexSleepWaits +{ +public: + static void Wait( void ); + static unsigned int sleepTime; +}; + +// ---------------------------------------------------------------------------- + +/** @class SpinLevelMutex + Implements a spin-loop to wait for the mutex to unlock. Since this class makes + the thread wait in a tight spin-loop, it can cause the thread to remain busy + while waiting and thus consume CPU cycles. For that reason, this mutex is best + used only for very low-level resources - especially resources which do not + require much CPU time to exercise. Rule of thumb: Use this only if all actions + on the resource consume a very small number of CPU cycles. Otherwise, use the + SleepLevelMutex instead. + */ +class SpinLevelMutex +{ +public: + + /// Constructs a spin-level mutex. + explicit SpinLevelMutex( unsigned int level ); + + /// Destructs the mutex. + virtual ~SpinLevelMutex( void ); + + virtual MutexErrors::Type Lock( void ) volatile; + + virtual MutexErrors::Type TryLock( void ) volatile; + + virtual MutexErrors::Type Unlock( void ) volatile; + + inline unsigned int GetLevel( void ) const volatile { return m_level; } + +private: + + /// Copy constructor is not implemented. + SpinLevelMutex( const SpinLevelMutex & ); + /// Copy-assignment operator is not implemented. + SpinLevelMutex & operator = ( const SpinLevelMutex & ); + +#if defined( _MSC_VER ) + #if ( _MSC_VER >= 1300 ) + /// The actual mutex. + CRITICAL_SECTION m_mutex; + #else + #error "Only Visual Studio versions 7.0 and after supported." + #endif + +#elif ( __GNUC__ ) + /// The actual mutex. + pthread_mutex_t m_mutex; + +#else + #error "Check if any mutex libraries are compatible with your compiler." +#endif + + /// Keep a copy of the mutex level around for error reporting. + const unsigned int m_level; + +}; // end class SpinLevelMutex + +// ---------------------------------------------------------------------------- + +/** @class SleepLevelMutex + Implements a sleeping loop to wait for the mutex to unlock. + + @par Purpose + Since this class puts the thread to sleep for short intervals, you can use this + class for most of your mutexes. Especially for locking any high level resources + where any one operation on the resouce consumes many CPU cycles. The purpose of + this mutex is to reduce the number of CPU cycles spent in idle loops. All + SleepLevelMutex's should have higher levels than all your SpinLevelMutex's. + + @par Dependence on SpinLevelMutex + This utilizes SpinLevelMutex so it does not have to re-implement the DoTryLock + and DoUnlock functions the same way. All it really needs is a DoLock function + and the amount of time it should sleep if an attempt to lock a function fails. + */ +class SleepLevelMutex : public SpinLevelMutex +{ +public: + + /** Constructs a levelized mutex that puts threads to sleep while they wait + for another thread to unlock the mutex. + @param level Level of this mutex. + */ + explicit SleepLevelMutex( unsigned int level ); + + SleepLevelMutex( unsigned int level, unsigned int sleepTime ); + + /// Destructs the mutex. + virtual ~SleepLevelMutex( void ); + + inline unsigned int GetSleepTime( void ) const volatile { return m_sleepTime; } + + inline void SetSleepTime( unsigned int sleepTime ) volatile + { + if ( 0 != sleepTime ) + m_sleepTime = sleepTime; + } + +#if defined( _MSC_VER ) + inline bool GetWakable( void ) const volatile { return m_wakable; } + inline void SetWakable( bool wakable ) volatile { m_wakable = wakable; } +#endif + + /** Attempts to lock a mutex, and if it fails, then sleeps for a while + before attempting again. + */ + virtual MutexErrors::Type Lock( void ) volatile; + +private: + + /// Default constructor is not implemented. + SleepLevelMutex( void ); + /// Copy constructor is not implemented. + SleepLevelMutex( const SleepLevelMutex & ); + /// Copy-assignment operator is not implemented. + SleepLevelMutex & operator = ( const SleepLevelMutex & ); + +#if defined( _MSC_VER ) + #if ( _MSC_VER >= 1300 ) + /// True if operating system may wake thread to respond to events. + bool m_wakable; + #else + #error "Only Visual Studio versions 7.0 and after supported." + #endif +#endif + + /// How many milli-seconds to sleep before trying to lock mutex again. + unsigned int m_sleepTime; + +}; // end class SleepLevelMutex + +// ---------------------------------------------------------------------------- + +/** @class LevelMutex + Levelized mutex class prevents deadlocks by requiring programs to lock mutexes in + the same order, and unlock them in reverse order. This is accomplished by forcing + each mutex to have a level and forcing code to lock mutexes with higher levels + before locking mutexes at lower levels. If you want to lock several mutexes, they + must be locked in decreasing order by level, or if they are all of the same level, + then locked by LevelMutex::MultiLock. + + @par Features + - Immune: Very unlikely to deadlock since all mutexes are locked in the same + order and unlocked in reverse order. + - Scalable: Can handle any number of mutexes. + - Efficient: Many operations occur in constant time, and most operations require + no more than O(m) steps. + - Exception safe: All operations provide strong safety or don't throw. + - Extendable: Can work with existing mutexes through policy-based design. + - Easily Extended: Derived classes only need to implement 5 functions and a mutex + to get all the features of this class. + - Re-Entrant: Allows for re-entrancy even if mutexes in policy classes don't. + - Cost-Free: No resource allocations occur in LevelMutex - although user-defined + policy classes may allocate resources. + - Compact: Each LevelMutex object is small. + - Portable: As long as your compiler and libraries can meet the requirements. + - Robust: Maintains data integrity even if exceptions occur in policy classes. + - Affording: Several functions provide information about a mutex which allows + client code to easily choose correct actions. + + @par Requirements + - Your compiler must allow for thread-specific data. + - You must have a threading or mutex library. + + @par Policy-Based Design + This class hosts 3 policies and a default level. The policy-based design allows + users to write their own policies to extend the behaviors of LevelMutex. The + paragraphs below say how to design a class for each policy. + - MutexPolicy The mutex policy class. + - defaultLevel A level for existing client code that calls a default constructor. + - ErrorPolicy How the mutex should handle error conditions. + - WaitPolicy Whether a thread should wait, and how long in some internal loops. + + @par MutexPolicy + A policy class that wraps a low-level mutex. Loki provides two policy classes + for the actual mutex (SpinLevelMutex and SleepLevelMutex), both of which wrap + either pthreads or the Windows CRITICAL_SECTION. If you want to use a mutex + mechanism besides one of those, then all you have to do is provide a class + which wraps the mutex and implements these functions. + explicit SpinLevelMutex( unsigned int level ); + virtual ~SpinLevelMutex( void ); + virtual MutexErrors::Type Lock( void ) volatile; + virtual MutexErrors::Type TryLock( void ) volatile; + virtual MutexErrors::Type Unlock( void ) volatile; + Indeed, since the base class does most of the work, and provides all the interace + and functionality to client classes, a derived class has very few requirements. + It only needs to implement a single constructor, the destructor, some virtual + functions, and whatever data members it requires. You don't actually need to + declare those functions as virtual if the policy class is not a base or child + class. In the parlance of design patterns, LevelMutex is a Template, and the + MutexPolicy is a Strategy. + + @par DefaultLevel + The template class requires a default level to use inside the default constructor. + Some existing code calls instantiates mutexes with a default constructor, so the + mutex must know what level to use there. Please do not use zero or UnlockedLevel + as the default level. + + @par ErrorPolicy + This policy specifies how to handle error conditions. The mutexes can return + errors, assert, or throw exceptions. I recommend that debug code use asserts, + release code use exceptions, and unit-testing code just return errors. The + error policy class only needs to implement one function: + static MutexErrors::Type CheckError( MutexErrors::Type error, unsigned int level ); + + @par WaitPolicy + This states whether the mutex should wait within some tight internal loops, + how the waiting is done, and for how long. A wait policy class could sleep, + do nothing, check if other objects need attention, or check if the program + received events or notices from the operating system. It only needs to + implement one function: + static void Wait( void ); + + @par Per-Function Usage + If you implement a function with a static local mutex, then you have to insure + the function is not called from a lower level via call-backs, virtual functions in + interface classes. If the function does get called from a lower level, you are + setting up a potential deadlock. LevelMutex will detect that by checking the + current level and the local mutex's level, so it will refuse to lock the local mutex. + + @par Per-Object Usage + If you use a mutex as a data member of an object to protect that object, then I + recommend specifying which functions are volatile and which are not, and then only + use the mutex within the volatile functions. You may also want to provide accessor + functions so that client code can lock and unlock the mutex either to allow for + calling multiple operations without having to lock and unlock before and after each + operation, or so they can lock it along with several other objects at the same + level. + + @par Per-Class Usage + If you make a static data member within a class, you can use that to lock any + resources shared by those objects, or to require threads to act on only one object + at a time. You may also want to provide static accessor functions so that client + code can lock several other resources at the same level. + */ + +template +< + class MutexPolicy, + unsigned int DefaultLevel, + class ErrorPolicy = ::Loki::ThrowOnBadDesignMutexError, + class WaitPolicy = ::Loki::NoMutexWait +> +class LevelMutex : public LevelMutexInfo +{ +public: + + typedef ErrorPolicy EP; + typedef WaitPolicy WP; + typedef MutexPolicy MP; + + /** This constructor allows callers to replace the default level with another + value. It also acts as the default constructor for existing code which uses + default construction for mutexes. This is the only time the DefaultLevel + template parameter gets used. + */ + explicit LevelMutex( unsigned int level = DefaultLevel ) : + LevelMutexInfo( level ), + m_mutex( level ) + { + assert( IsValid() ); + } + + /// The destructor. + ~LevelMutex( void ) + { + assert( IsValid() ); + } + + /** These functions allow callers to access the mutex in case they need to + modify specific values in the MutexPolicy (e.g. - sleep time, functors to + call as tasks, etc...) There is one function for every combination of + const and volatile qualifiers so callers get a reference to a MutexPolicy + with the proper qualifiers. + */ + inline const volatile MutexPolicy & GetMutexPolicy( void ) const volatile { return m_mutex; } + inline volatile MutexPolicy & GetMutexPolicy( void ) volatile { return m_mutex; } + inline const MutexPolicy & GetMutexPolicy( void ) const { return m_mutex; } + inline MutexPolicy & GetMutexPolicy( void ) { return m_mutex; } + + virtual MutexErrors::Type TryLock( void ) volatile + { + assert( IsValid() ); + LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; ) + + MutexErrors::Type result = LevelMutexInfo::PreLockCheck( true ); + if ( MutexErrors::Success == result ) + return MutexErrors::Success; + else if ( MutexErrors::AlreadyLocked == result ) + return result; + else if ( MutexErrors::NoProblem != result ) + return EP::CheckError( result, GetLevel() ); + + assert( 0 == LevelMutexInfo::GetLockCount() ); + result = m_mutex.TryLock(); + if ( MutexErrors::Success != result ) + return EP::CheckError( result, GetLevel() ); + LevelMutexInfo::PostLock(); + + return MutexErrors::Success; + } + + virtual MutexErrors::Type Lock( void ) volatile + { + assert( IsValid() ); + LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; ) + + MutexErrors::Type result = LevelMutexInfo::PreLockCheck( false ); + if ( MutexErrors::Success == result ) + return MutexErrors::Success; + else if ( MutexErrors::NoProblem != result ) + return EP::CheckError( result, GetLevel() ); + + assert( !LevelMutexInfo::IsLockedByCurrentThread() ); + result = m_mutex.Lock(); + if ( MutexErrors::Success != result ) + return EP::CheckError( result, GetLevel() ); + PostLock(); + + return MutexErrors::Success; + } + + virtual MutexErrors::Type Lock( unsigned int milliSeconds ) volatile + { + assert( IsValid() ); + LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; ) + + MutexErrors::Type result = LevelMutexInfo::PreLockCheck( false ); + if ( MutexErrors::Success == result ) + return MutexErrors::Success; + else if ( MutexErrors::NoProblem != result ) + return EP::CheckError( result, GetLevel() ); + + assert( !LevelMutexInfo::IsLockedByCurrentThread() ); + clock_t timeOut = clock() + milliSeconds; + while ( clock() < timeOut ) + { + WP::Wait(); + result = m_mutex.TryLock(); + switch ( result ) + { + case MutexErrors::Success: + { + PostLock(); + return MutexErrors::Success; + } + case MutexErrors::AlreadyLocked: + return MutexErrors::AlreadyLocked; + case MutexErrors::TryFailed: + break; + default: + return EP::CheckError( result, GetLevel() ); + } + } + + return MutexErrors::TimedOut; + } + + virtual MutexErrors::Type Unlock( void ) volatile + { + assert( IsValid() ); + LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; ) + + MutexErrors::Type result = LevelMutexInfo::PreUnlockCheck(); + if ( MutexErrors::Success == result ) + return MutexErrors::Success; + else if ( MutexErrors::NoProblem != result ) + return EP::CheckError( result, GetLevel() ); + + LevelMutexInfo::PreUnlock(); + result = MutexErrors::OtherError; + try + { + result = m_mutex.Unlock(); + if ( MutexErrors::Success != result ) + PostLock(); + } + catch ( ... ) + { + PostLock(); + result = MutexErrors::ExceptionThrown; + } + + return result; + } + +private: + + /// Copy constructor is not implemented since mutexes don't get copied. + LevelMutex( const LevelMutex & ); + /// Copy-assignment operator is not implemented since mutexes don't get copied. + LevelMutex & operator = ( const LevelMutex & ); + + virtual MutexErrors::Type DoErrorCheck( MutexErrors::Type result ) const volatile + { + return EP::CheckError( result, GetLevel() ); + } + + /** Called only by MultiLock to lock each particular mutex within a container. + This does not do pre-lock error checking since MultiLock does that. Since + this skips the error checking, that means that callers of LevelMutex should + not call this function directly, and so this will not be publicly available. + @return Error status indicating success or reason for failure. + */ + virtual MutexErrors::Type LockThis( void ) volatile + { + assert( IsValid() ); + LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; ) + assert( this != LevelMutexInfo::GetCurrentMutex() ); + + const MutexErrors::Type result = m_mutex.Lock(); + if ( MutexErrors::Success != result ) + return result; + PostLock(); + + return MutexErrors::Success; + } + + /** Called only by MultiLock to lock each particular mutex within a container. + This does not do pre-lock error checking since MultiLock does that. Since + this skips the error checking, callers of LevelMutex should not call this + function directly, and so this will not be publicly available. + @param milliSeconds How much time to wait before giving up on locking a mutex. + @return Error status indicating success or reason for failure. + */ + virtual MutexErrors::Type LockThis( unsigned int milliSeconds ) volatile + { + assert( IsValid() ); + LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; ) + + clock_t timeOut = clock() + milliSeconds; + while ( clock() < timeOut ) + { + WP::Wait(); + const bool locked = ( MutexErrors::Success == m_mutex.TryLock() ); + if ( locked ) + { + PostLock(); + return MutexErrors::Success; + } + } + + return MutexErrors::TimedOut; + } + + /** Called only by MultiUnlock to unlock each mutex within a container. + This does not do pre-unlock error checking since MultiLock does that. Since + this skips the error checking, callers of LevelMutex should not call this + function directly, and so this will not be publicly available. + @return Error status indicating success or reason for failure. + */ + virtual MutexErrors::Type UnlockThis( void ) volatile + { + assert( IsValid() ); + assert( NULL != LevelMutexInfo::GetCurrentMutex() ); + LOKI_MUTEX_DEBUG_CODE( Checker checker( this ); (void)checker; ) + + if ( 1 < LevelMutexInfo::GetLockCount() ) + { + LevelMutexInfo::DecrementCount(); + return MutexErrors::Success; + } + + LevelMutexInfo::PreUnlock(); + MutexErrors::Type result = m_mutex.Unlock(); + + return result; + } + + /// An instance of an unleveled mutex wrapped to match LevelMutex's needs. + MutexPolicy m_mutex; + +}; // end class LevelMutex + +// ---------------------------------------------------------------------------- + +/** Returns level of most recently locked mutex by this thread, or UnlockedLevel + if no mutexes are locked. Runs in constant time, and never throws exceptions. + */ +unsigned int GetCurrentThreadsLevel( void ); + +/** Returns count of how mutexes the current thread locked. Requires O(m) + actions where m is the number of mutexes in the thread. Never throws exceptions. + */ +unsigned int CountMutexesInCurrentThread( void ); + +/** Returns count of how mutexes the current thread locked. The lock count + exceeds the number of mutexes locked by current thread if any mutex got locked + more than once. Requires O(m) actions where m is the number of mutexes in the + thread. Never throws exceptions. + */ +unsigned int CountLocksInCurrentThread( void ); + +/** Returns count of mutexes locked by current thread which have the same level + as GetCurrentThreadsLevel. Requires O(m) actions where m is the number of + mutexes in the thread at current level. Never throws exceptions. + */ +unsigned int CountMutexesAtCurrentLevel( void ); + +/** Determines if container of mutexes matches the recently locked mutexes. + If they do match, it returns success, otherwise an error condition. + */ +MutexErrors::Type DoMutexesMatchContainer( const LevelMutexInfo::MutexContainer & mutexes ); + +// ---------------------------------------------------------------------------- + +/** @class MutexException + Exception class used to throw error statuses about LevelMutex's up to code that + can respond to mutex problems. This class exists because it conveys more info + about the error condition than just ::std::exception. + */ +class MutexException : public ::std::exception +{ +public: + + /** Constructs an exception which stores information about a mutex and the + reason an attempt to use a mutex failed. + */ + MutexException( const char * message, unsigned int level, MutexErrors::Type reason ); + + /// Copy constructor performs a member-by-member copy of an exception. + MutexException( const MutexException & that ) throw (); + + /// Copy-assignment operator performs a member-by-member copy of an exception. + MutexException & operator = ( const MutexException & that ) throw (); + + /// Destroys the exception. + virtual ~MutexException( void ) throw(); + + /// Returns a simple message about which operation failed. + virtual const char * what( void ) const throw(); + + /// Returns level of mutex(es) used when problem occurred. + unsigned int GetLevel( void ) const { return m_level; } + + /// Returns an error status for why operation failed. + MutexErrors::Type GetReason( void ) const { return m_reason; } + +private: + + /// Default constructor is not implemented. + MutexException( void ) throw (); + + /// Simple message about operation that failed. + const char * m_message; + /// Level of mutex(es) used when problem occurred. + unsigned int m_level; + /// Error status for why operation failed. + MutexErrors::Type m_reason; + +}; // end class MutexException + +// ---------------------------------------------------------------------------- + +/** @class MutexLocker + You can place an instance of this as a local variable inside a function to lock + a single mutex. It will lock the mutex if no error occurs, or throw if one + does happen. When the function ends, the destructor will determine if it needs + to unlock the mutex. This RAII technique insures the mutex gets unlocked even + when exceptions occur. + */ +class MutexLocker +{ +public: + + /** Creates an object to lock an unlock a mutex for a function. This + will throw if an attempt to lock the mutex fails. + @param mutex Reference to the mutex. + @param lock True if function wants to lock the mutex as this gets + constructed. + */ + explicit MutexLocker( volatile LevelMutexInfo & mutex, bool lock = true ); + + /** Creates an object to lock an unlock a mutex for a function. This waits + a specified amount of time for another thread to unlock the mutex if it is + locked. This will throw if an attempt to lock the mutex fails. + @param mutex Reference to the mutex. + @param milliSeconds Amount of time to wait for another thread to unlock + the mutex. + @param lock True if function wants to lock the mutex as this gets + constructed. + */ + MutexLocker( volatile LevelMutexInfo & mutex, unsigned int milliSeconds, + bool lock = true ); + + /// Destructs the locker, and determines if it needs to unlock the mutex. + ~MutexLocker( void ); + + /** You can call this to lock (or relock) a mutex. In theory, you can lock + and unlock a mutex several times within a function in order to give other + threads access to a resource while this function does not need it. + @return True if mutex is locked by this, else false if not locked. + */ + bool Lock( void ); + + /** You can call this to unlock a mutex before the destructor does it. + By unlocking the mutexes before returning, the function can do other + operations without making other threads wait too long. + @return True if unlocked by this, else false if not unlocked by this. + (Which is not the same as whether the mutex itself is locked or not by + another thread.) + */ + bool Unlock( void ); + + /// Returns true if the mutex is locked by this object. + inline bool IsLocked( void ) const { return m_locked; } + + /// Provides access to mutex controlled by this. + const volatile LevelMutexInfo & GetMutex( void ) const { return m_mutex; } + +private: + + /// Default constructor is not implemented. + MutexLocker( void ); + /// Copy constructor is not implemented. + MutexLocker( const MutexLocker & ); + /// Copy-assignment operator is not implemented. + MutexLocker & operator = ( const MutexLocker & ); + + /// True if mutex got locked. + bool m_locked; + + /// Reference to mutex. + volatile LevelMutexInfo & m_mutex; +}; + +// ---------------------------------------------------------------------------- + +/** @class MultiMutexLocker + You can place an instance of this as a local variable inside a function to lock + a collection of mutexes. It locks them if no error occurs, or throws an + exception if one does happen. When the function ends, the destructor determines + if it needs to unlock the mutexes. This RAII technique insures the mutexes get + unlocked even when exceptions occur. You will also have to construct a + MutexContainer as a local object within the same function. + */ +class MultiMutexLocker +{ +public: + + /** Creates an object to lock and unlock a collection of mutexes for a function. + This will throw if an attempt to lock any mutex fails. If an exception occurs, + it unlocks mutexes it previously locked. + @param mutex Reference to a collection of mutexes. + @param lock True if function wants to lock the mutex as this gets + constructed. + */ + explicit MultiMutexLocker( LevelMutexInfo::MutexContainer & mutexes, + bool lock = true ); + + /** Creates an object to lock and unlock a collection of mutexes for a function. + This waits a specified amount of time for other threads to unlock each mutex + that is locked. This will throw if an attempt to lock any mutex fails. If an + exception occurs, it unlocks mutexes it previously locked. + @param mutexes Reference to a collection of mutexes. + @param milliSeconds Amount of time to wait for another thread to unlock + the mutex. + @param lock True if function wants to lock the mutexes as this gets + constructed. + */ + MultiMutexLocker( LevelMutexInfo::MutexContainer & mutexes, + unsigned int milliSeconds, bool lock = true ); + + /// Destructs the locker, and determines if it needs to unlock the mutexes. + ~MultiMutexLocker( void ); + + /** You can call this to lock (or relock) the mutexes. In theory, you can lock + and unlock mutexes several times within a function in order to give other + threads access to resources while this function does not need them. + @return True if mutex is locked by this, else false if not locked. + */ + bool Lock( void ); + + /** You can call this to unlock the mutexes before the destructor does it. + By unlocking the mutexes before returning, the function can do other + operations without making other threads wait too long. + @return True if unlocked by this, else false if not unlocked by this. + (Which is not the same as whether the mutex itself is locked or not by + another thread.) + */ + bool Unlock( void ); + + /// Returns true if the mutexes are locked by this object. + inline bool IsLocked( void ) const { return m_locked; } + + /// Provides access to the collection of mutexes controlled by this. + const LevelMutexInfo::MutexContainer & GetMutexes( void ) const { return m_mutexes; } + +private: + + /// Default constructor is not implemented. + MultiMutexLocker( void ); + /// Copy constructor is not implemented. + MultiMutexLocker( const MultiMutexLocker & ); + /// Copy-assignment operator is not implemented. + MultiMutexLocker & operator = ( const MultiMutexLocker & ); + + /// True if mutexes got locked. + bool m_locked; + + /// Reference to external container of mutexes; + LevelMutexInfo::MutexContainer & m_mutexes; +}; + +// ---------------------------------------------------------------------------- + +} // end namespace Loki + +#endif // end file guardian diff --git a/shared/loki/LockingPtr.h b/shared/loki/LockingPtr.h new file mode 100644 index 00000000..a50f5d6d --- /dev/null +++ b/shared/loki/LockingPtr.h @@ -0,0 +1,110 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code is from the article: +// "Generic<Programming>: volatile — Multithreaded Programmer’s Best Friend +// Volatile-Correctness or How to Have Your Compiler Detect Race Conditions +// for You" by Alexandrescu, Andrei. +// Published in the February 2001 issue of the C/C++ Users Journal. +// http://www.cuj.com/documents/s=7998/cujcexp1902alexandr/ +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +// Prepared for Loki library by Richard Sposato +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_LOCKING_PTR_INC_ +#define LOKI_LOCKING_PTR_INC_ + +// $Id: LockingPtr.h 840 2008-03-19 19:44:38Z rich_sposato $ + + +#include <loki/ConstPolicy.h> +#include <loki/Threads.h> + + +namespace Loki +{ + /** @class LockingPtr + Locks a volatile object and casts away volatility so that the object + can be safely used in a single-threaded region of code. + Original version of LockingPtr had only one template - for the shared + object, but not the mutex type. This version allows users to specify a + the mutex type as a LockingPolicy class. The only requirements for a + LockingPolicy class are to provide Lock and Unlock methods. + */ + template < typename SharedObject, typename LockingPolicy = LOKI_DEFAULT_MUTEX, + template<class> class ConstPolicy = LOKI_DEFAULT_CONSTNESS > + class LockingPtr + { + public: + + typedef typename ConstPolicy<SharedObject>::Type ConstOrNotType; + + /** Constructor locks mutex associated with an object. + @param object Reference to object. + @param mutex Mutex used to control thread access to object. + */ + LockingPtr( volatile ConstOrNotType & object, LockingPolicy & mutex ) + : pObject_( const_cast< SharedObject * >( &object ) ), + pMutex_( &mutex ) + { + mutex.Lock(); + } + + typedef typename std::pair<volatile ConstOrNotType *, LockingPolicy *> Pair; + + /** Constructor locks mutex associated with an object. + @param lockpair a std::pair of pointers to the object and the mutex + */ + LockingPtr( Pair lockpair ) + : pObject_( const_cast< SharedObject * >( lockpair.first ) ), + pMutex_( lockpair.second ) + { + lockpair.second->Lock(); + } + + /// Destructor unlocks the mutex. + ~LockingPtr() + { + pMutex_->Unlock(); + } + + /// Star-operator dereferences pointer. + ConstOrNotType & operator * () + { + return *pObject_; + } + + /// Point-operator returns pointer to object. + ConstOrNotType * operator -> () + { + return pObject_; + } + + private: + + /// Default constructor is not implemented. + LockingPtr(); + + /// Copy-constructor is not implemented. + LockingPtr( const LockingPtr & ); + + /// Copy-assignment-operator is not implemented. + LockingPtr & operator = ( const LockingPtr & ); + + /// Pointer to the shared object. + ConstOrNotType * pObject_; + + /// Pointer to the mutex. + LockingPolicy * pMutex_; + + }; // end class LockingPtr + +} // namespace Loki + +#endif // end file guardian + diff --git a/shared/loki/LokiExport.h b/shared/loki/LokiExport.h new file mode 100644 index 00000000..625449f2 --- /dev/null +++ b/shared/loki/LokiExport.h @@ -0,0 +1,69 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2006 by Peter Kümmel +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_LOKIEXPORT_INC_ +#define LOKI_LOKIEXPORT_INC_ + +// $Id: LokiExport.h 748 2006-10-17 19:49:08Z syntheticpp $ + + +#ifdef __GNUC__ + +#ifdef _HAVE_GCC_VISIBILITY +#define LOKI_EXPORT_SPEC __attribute__ ((visibility("default"))) +#define LOKI_IMPORT_SPEC +#else +#define LOKI_EXPORT_SPEC +#define LOKI_IMPORT_SPEC +#endif + +#else + +#ifdef _WIN32 +#define LOKI_EXPORT_SPEC __declspec(dllexport) +#define LOKI_IMPORT_SPEC __declspec(dllimport) +#else +#define LOKI_EXPORT_SPEC +#define LOKI_IMPORT_SPEC +#endif + +#endif + + +#if (defined(LOKI_MAKE_DLL) && defined(LOKI_DLL)) || \ + (defined(LOKI_MAKE_DLL) && defined(LOKI_STATIC)) || \ + (defined(LOKI_DLL) && defined(LOKI_STATIC)) +#error export macro error: you could not build AND use the library +#endif + +#ifdef LOKI_MAKE_DLL +#define LOKI_EXPORT LOKI_EXPORT_SPEC +#endif + +#ifdef LOKI_DLL +#define LOKI_EXPORT LOKI_IMPORT_SPEC +#endif + +#ifdef LOKI_STATIC +#define LOKI_EXPORT +#endif + +#if !defined(LOKI_EXPORT) && !defined(EXPLICIT_EXPORT) +#define LOKI_EXPORT +#endif + +#ifndef LOKI_EXPORT +#error export macro error: LOKI_EXPORT was not defined, disable EXPLICIT_EXPORT or define a export specification +#endif + + +#endif // end file guardian + diff --git a/shared/loki/LokiTypeInfo.h b/shared/loki/LokiTypeInfo.h new file mode 100644 index 00000000..715dab1a --- /dev/null +++ b/shared/loki/LokiTypeInfo.h @@ -0,0 +1,103 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_LOKITYPEINFO_INC_ +#define LOKI_LOKITYPEINFO_INC_ + +// $Id: LokiTypeInfo.h 748 2006-10-17 19:49:08Z syntheticpp $ + + +#include <typeinfo> +#include <cassert> +#include "Typelist.h" + +namespace Loki +{ +//////////////////////////////////////////////////////////////////////////////// +// class TypeInfo +// Purpose: offer a first-class, comparable wrapper over std::type_info +//////////////////////////////////////////////////////////////////////////////// + + class TypeInfo + { + public: + // Constructors + TypeInfo(); // needed for containers + TypeInfo(const std::type_info&); // non-explicit + + // Access for the wrapped std::type_info + const std::type_info& Get() const; + // Compatibility functions + bool before(const TypeInfo& rhs) const; + const char* name() const; + + private: + const std::type_info* pInfo_; + }; + +// Implementation + + inline TypeInfo::TypeInfo() + { + class Nil {}; + pInfo_ = &typeid(Nil); + assert(pInfo_); + } + + inline TypeInfo::TypeInfo(const std::type_info& ti) + : pInfo_(&ti) + { assert(pInfo_); } + + inline bool TypeInfo::before(const TypeInfo& rhs) const + { + assert(pInfo_); + // type_info::before return type is int in some VC libraries + return pInfo_->before(*rhs.pInfo_) != 0; + } + + inline const std::type_info& TypeInfo::Get() const + { + assert(pInfo_); + return *pInfo_; + } + + inline const char* TypeInfo::name() const + { + assert(pInfo_); + return pInfo_->name(); + } + +// Comparison operators + + inline bool operator==(const TypeInfo& lhs, const TypeInfo& rhs) + // type_info::operator== return type is int in some VC libraries + { return (lhs.Get() == rhs.Get()) != 0; } + + inline bool operator<(const TypeInfo& lhs, const TypeInfo& rhs) + { return lhs.before(rhs); } + + inline bool operator!=(const TypeInfo& lhs, const TypeInfo& rhs) + { return !(lhs == rhs); } + + inline bool operator>(const TypeInfo& lhs, const TypeInfo& rhs) + { return rhs < lhs; } + + inline bool operator<=(const TypeInfo& lhs, const TypeInfo& rhs) + { return !(lhs > rhs); } + + inline bool operator>=(const TypeInfo& lhs, const TypeInfo& rhs) + { return !(lhs < rhs); } +} + +#endif // end file guardian diff --git a/shared/loki/MultiMethods.h b/shared/loki/MultiMethods.h new file mode 100644 index 00000000..d095cfae --- /dev/null +++ b/shared/loki/MultiMethods.h @@ -0,0 +1,415 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_MULTIMETHODS_INC_ +#define LOKI_MULTIMETHODS_INC_ + +// $Id: MultiMethods.h 751 2006-10-17 19:50:37Z syntheticpp $ + + +#include "Typelist.h" +#include "LokiTypeInfo.h" +#include "Functor.h" +#include "AssocVector.h" + +//////////////////////////////////////////////////////////////////////////////// +// IMPORTANT NOTE: +// The double dispatchers implemented below differ from the excerpts shown in +// the book - they are simpler while respecting the same interface. +//////////////////////////////////////////////////////////////////////////////// + +namespace Loki +{ +//////////////////////////////////////////////////////////////////////////////// +// class template InvocationTraits (helper) +// Helps implementing optional symmetry +//////////////////////////////////////////////////////////////////////////////// + + namespace Private + { + template <class SomeLhs, class SomeRhs, + class Executor, typename ResultType> + struct InvocationTraits + { + static ResultType + DoDispatch(SomeLhs& lhs, SomeRhs& rhs, + Executor& exec, Int2Type<false>) + { + return exec.Fire(lhs, rhs); + } + static ResultType + DoDispatch(SomeLhs& lhs, SomeRhs& rhs, + Executor& exec, Int2Type<true>) + { + return exec.Fire(rhs, lhs); + } + }; + } + +//////////////////////////////////////////////////////////////////////////////// +// class template StaticDispatcher +// Implements an automatic static double dispatcher based on two typelists +//////////////////////////////////////////////////////////////////////////////// + + template + < + class Executor, + class BaseLhs, + class TypesLhs, + bool symmetric = true, + class BaseRhs = BaseLhs, + class TypesRhs = TypesLhs, + typename ResultType = void + > + class StaticDispatcher + { + template <class SomeLhs> + static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs, + Executor exec, NullType) + { return exec.OnError(lhs, rhs); } + + template <class Head, class Tail, class SomeLhs> + static ResultType DispatchRhs(SomeLhs& lhs, BaseRhs& rhs, + Executor exec, Typelist<Head, Tail>) + { + if (Head* p2 = dynamic_cast<Head*>(&rhs)) + { + Int2Type<(symmetric && + int(TL::IndexOf<TypesRhs, Head>::value) < + int(TL::IndexOf<TypesLhs, SomeLhs>::value))> i2t; + + typedef Private::InvocationTraits< + SomeLhs, Head, Executor, ResultType> CallTraits; + + return CallTraits::DoDispatch(lhs, *p2, exec, i2t); + } + return DispatchRhs(lhs, rhs, exec, Tail()); + } + + static ResultType DispatchLhs(BaseLhs& lhs, BaseRhs& rhs, + Executor exec, NullType) + { return exec.OnError(lhs, rhs); } + + template <class Head, class Tail> + static ResultType DispatchLhs(BaseLhs& lhs, BaseRhs& rhs, + Executor exec, Typelist<Head, Tail>) + { + if (Head* p1 = dynamic_cast<Head*>(&lhs)) + { + return DispatchRhs(*p1, rhs, exec, TypesRhs()); + } + return DispatchLhs(lhs, rhs, exec, Tail()); + } + + public: + static ResultType Go(BaseLhs& lhs, BaseRhs& rhs, + Executor exec) + { return DispatchLhs(lhs, rhs, exec, TypesLhs()); } + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template BasicDispatcher +// Implements a logarithmic double dispatcher for functors (or functions) +// Doesn't offer automated casts or symmetry +//////////////////////////////////////////////////////////////////////////////// + + template + < + class BaseLhs, + class BaseRhs = BaseLhs, + typename ResultType = void, + typename CallbackType = ResultType (*)(BaseLhs&, BaseRhs&) + > + class BasicDispatcher + { + typedef std::pair<TypeInfo,TypeInfo> KeyType; + typedef CallbackType MappedType; + typedef AssocVector<KeyType, MappedType> MapType; + MapType callbackMap_; + + void DoAdd(TypeInfo lhs, TypeInfo rhs, CallbackType fun); + bool DoRemove(TypeInfo lhs, TypeInfo rhs); + + public: + template <class SomeLhs, class SomeRhs> + void Add(CallbackType fun) + { + DoAdd(typeid(SomeLhs), typeid(SomeRhs), fun); + } + + template <class SomeLhs, class SomeRhs> + bool Remove() + { + return DoRemove(typeid(SomeLhs), typeid(SomeRhs)); + } + + ResultType Go(BaseLhs& lhs, BaseRhs& rhs); + }; + + // Non-inline to reduce compile time overhead... + template <class BaseLhs, class BaseRhs, + typename ResultType, typename CallbackType> + void BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType> + ::DoAdd(TypeInfo lhs, TypeInfo rhs, CallbackType fun) + { + callbackMap_[KeyType(lhs, rhs)] = fun; + } + + template <class BaseLhs, class BaseRhs, + typename ResultType, typename CallbackType> + bool BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType> + ::DoRemove(TypeInfo lhs, TypeInfo rhs) + { + return callbackMap_.erase(KeyType(lhs, rhs)) == 1; + } + + template <class BaseLhs, class BaseRhs, + typename ResultType, typename CallbackType> + ResultType BasicDispatcher<BaseLhs,BaseRhs,ResultType,CallbackType> + ::Go(BaseLhs& lhs, BaseRhs& rhs) + { + typename MapType::key_type k(typeid(lhs),typeid(rhs)); + typename MapType::iterator i = callbackMap_.find(k); + if (i == callbackMap_.end()) + { + throw std::runtime_error("Function not found"); + } + return (i->second)(lhs, rhs); + } + +//////////////////////////////////////////////////////////////////////////////// +// class template StaticCaster +// Implementation of the CastingPolicy used by FunctorDispatcher +//////////////////////////////////////////////////////////////////////////////// + + template <class To, class From> + struct StaticCaster + { + static To& Cast(From& obj) + { + return static_cast<To&>(obj); + } + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template DynamicCaster +// Implementation of the CastingPolicy used by FunctorDispatcher +//////////////////////////////////////////////////////////////////////////////// + + template <class To, class From> + struct DynamicCaster + { + static To& Cast(From& obj) + { + return dynamic_cast<To&>(obj); + } + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template Private::FnDispatcherHelper +// Implements trampolines and argument swapping used by FnDispatcher +//////////////////////////////////////////////////////////////////////////////// + + namespace Private + { + template <class BaseLhs, class BaseRhs, + class SomeLhs, class SomeRhs, + typename ResultType, + class CastLhs, class CastRhs, + ResultType (*Callback)(SomeLhs&, SomeRhs&)> + struct FnDispatcherHelper + { + static ResultType Trampoline(BaseLhs& lhs, BaseRhs& rhs) + { + return Callback(CastLhs::Cast(lhs), CastRhs::Cast(rhs)); + } + static ResultType TrampolineR(BaseRhs& rhs, BaseLhs& lhs) + { + return Trampoline(lhs, rhs); + } + }; + } + +//////////////////////////////////////////////////////////////////////////////// +// class template FnDispatcher +// Implements an automatic logarithmic double dispatcher for functions +// Features automated conversions +//////////////////////////////////////////////////////////////////////////////// + + template <class BaseLhs, class BaseRhs = BaseLhs, + typename ResultType = void, + template <class, class> class CastingPolicy = DynamicCaster, + template <class, class, class, class> + class DispatcherBackend = BasicDispatcher> + class FnDispatcher + { + DispatcherBackend<BaseLhs, BaseRhs, ResultType, + ResultType (*)(BaseLhs&, BaseRhs&)> backEnd_; + + public: + template <class SomeLhs, class SomeRhs> + void Add(ResultType (*pFun)(BaseLhs&, BaseRhs&)) + { + return backEnd_.template Add<SomeLhs, SomeRhs>(pFun); + } + + template <class SomeLhs, class SomeRhs, + ResultType (*callback)(SomeLhs&, SomeRhs&)> + void Add() + { + typedef Private::FnDispatcherHelper< + BaseLhs, BaseRhs, + SomeLhs, SomeRhs, + ResultType, + CastingPolicy<SomeLhs,BaseLhs>, + CastingPolicy<SomeRhs,BaseRhs>, + callback> Local; + + Add<SomeLhs, SomeRhs>(&Local::Trampoline); + } + + template <class SomeLhs, class SomeRhs, + ResultType (*callback)(SomeLhs&, SomeRhs&), + bool symmetric> + void Add(bool = true) // [gcc] dummy bool + { + typedef Private::FnDispatcherHelper< + BaseLhs, BaseRhs, + SomeLhs, SomeRhs, + ResultType, + CastingPolicy<SomeLhs,BaseLhs>, + CastingPolicy<SomeRhs,BaseRhs>, + callback> Local; + + Add<SomeLhs, SomeRhs>(&Local::Trampoline); + if (symmetric) + { + Add<SomeRhs, SomeLhs>(&Local::TrampolineR); + } + } + + template <class SomeLhs, class SomeRhs> + void Remove() + { + backEnd_.template Remove<SomeLhs, SomeRhs>(); + } + + ResultType Go(BaseLhs& lhs, BaseRhs& rhs) + { + return backEnd_.Go(lhs, rhs); + } + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorDispatcherAdaptor +// permits use of FunctorDispatcher under gcc.2.95.2/3 +/////////////////////////////////////////////////////////////////////////////// + + namespace Private + { + template <class BaseLhs, class BaseRhs, + class SomeLhs, class SomeRhs, + typename ResultType, + class CastLhs, class CastRhs, + class Fun, bool SwapArgs> + class FunctorDispatcherHelper + { + Fun fun_; + ResultType Fire(BaseLhs& lhs, BaseRhs& rhs,Int2Type<false>) + { + return fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs)); + } + ResultType Fire(BaseLhs& rhs, BaseRhs& lhs,Int2Type<true>) + { + return fun_(CastLhs::Cast(lhs), CastRhs::Cast(rhs)); + } + public: + FunctorDispatcherHelper(const Fun& fun) : fun_(fun) {} + + ResultType operator()(BaseLhs& lhs, BaseRhs& rhs) + { + return Fire(lhs,rhs,Int2Type<SwapArgs>()); + } + }; + } + +//////////////////////////////////////////////////////////////////////////////// +// class template FunctorDispatcher +// Implements a logarithmic double dispatcher for functors +// Features automated casting +//////////////////////////////////////////////////////////////////////////////// + + template <class BaseLhs, class BaseRhs = BaseLhs, + typename ResultType = void, + template <class, class> class CastingPolicy = DynamicCaster, + template <class, class, class, class> + class DispatcherBackend = BasicDispatcher> + class FunctorDispatcher + { + typedef LOKI_TYPELIST_2(BaseLhs&, BaseRhs&) ArgsList; + typedef Functor<ResultType, ArgsList, LOKI_DEFAULT_THREADING> FunctorType; + + DispatcherBackend<BaseLhs, BaseRhs, ResultType, FunctorType> backEnd_; + + public: + template <class SomeLhs, class SomeRhs, class Fun> + void Add(const Fun& fun) + { + typedef Private::FunctorDispatcherHelper< + BaseLhs, BaseRhs, + SomeLhs, SomeRhs, + ResultType, + CastingPolicy<SomeLhs, BaseLhs>, + CastingPolicy<SomeRhs, BaseRhs>, + Fun, false> Adapter; + + backEnd_.template Add<SomeLhs, SomeRhs>(FunctorType(Adapter(fun))); + } + template <class SomeLhs, class SomeRhs, bool symmetric, class Fun> + void Add(const Fun& fun) + { + Add<SomeLhs,SomeRhs>(fun); + + if (symmetric) + { + // Note: symmetry only makes sense where BaseLhs==BaseRhs + typedef Private::FunctorDispatcherHelper< + BaseLhs, BaseLhs, + SomeLhs, SomeRhs, + ResultType, + CastingPolicy<SomeLhs, BaseLhs>, + CastingPolicy<SomeRhs, BaseLhs>, + Fun, true> AdapterR; + + backEnd_.template Add<SomeRhs, SomeLhs>(FunctorType(AdapterR(fun))); + } + } + + template <class SomeLhs, class SomeRhs> + void Remove() + { + backEnd_.template Remove<SomeLhs, SomeRhs>(); + } + + ResultType Go(BaseLhs& lhs, BaseRhs& rhs) + { + return backEnd_.Go(lhs, rhs); + } + }; +} // namespace Loki + + + +#endif // end file guardian + diff --git a/shared/loki/NullType.h b/shared/loki/NullType.h new file mode 100644 index 00000000..9403901a --- /dev/null +++ b/shared/loki/NullType.h @@ -0,0 +1,34 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_NULLTYPE_INC_ +#define LOKI_NULLTYPE_INC_ + +// $Id: NullType.h 751 2006-10-17 19:50:37Z syntheticpp $ + + +namespace Loki +{ +//////////////////////////////////////////////////////////////////////////////// +// class NullType +// Used as a placeholder for "no type here" +// Useful as an end marker in typelists +//////////////////////////////////////////////////////////////////////////////// + + class NullType {}; + +} // namespace Loki + + +#endif // end file guardian diff --git a/shared/loki/OrderedStatic.h b/shared/loki/OrderedStatic.h new file mode 100644 index 00000000..6eaa20b9 --- /dev/null +++ b/shared/loki/OrderedStatic.h @@ -0,0 +1,225 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2005 Peter Kümmel +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_ORDEREDSTATIC_INC_ +#define LOKI_ORDEREDSTATIC_INC_ + +// $Id: OrderedStatic.h 751 2006-10-17 19:50:37Z syntheticpp $ + + +#include <vector> +#include <iostream> + +#include "LokiExport.h" +#include "Singleton.h" +#include "Typelist.h" +#include "Sequence.h" + +// usage: see test/OrderedStatic + +namespace Loki +{ + namespace Private + { + //////////////////////////////////////////////////////////////////////////////// + // polymorph base class for OrderedStatic template, + // necessary because of the creator + //////////////////////////////////////////////////////////////////////////////// + class LOKI_EXPORT OrderedStaticCreatorFunc + { + public: + virtual void createObject() = 0; + + protected: + OrderedStaticCreatorFunc(); + virtual ~OrderedStaticCreatorFunc(); + + private: + OrderedStaticCreatorFunc(const OrderedStaticCreatorFunc&); + }; + + //////////////////////////////////////////////////////////////////////////////// + // template base clase for OrderedStatic template, + // common for all specializations + //////////////////////////////////////////////////////////////////////////////// + template<class T> + class OrderedStaticBase : public OrderedStaticCreatorFunc + { + public: + T& operator*() + { + return *val_; + } + + T* operator->() + { + return val_; + } + + protected: + + OrderedStaticBase(unsigned int longevity) : val_(0), longevity_(longevity) + { + } + + virtual ~OrderedStaticBase() + { + } + + void SetLongevity(T* ptr) + { + val_=ptr; + Loki::SetLongevity(val_,longevity_); + } + + private: + OrderedStaticBase(); + OrderedStaticBase(const OrderedStaticBase&); + OrderedStaticBase& operator=(const OrderedStaticBase&); + T* val_; + unsigned int longevity_; + + }; + + //////////////////////////////////////////////////////////////////////////////// + // OrderedStaticManagerClass implements details + // OrderedStaticManager is then defined as a Singleton + //////////////////////////////////////////////////////////////////////////////// + class LOKI_EXPORT OrderedStaticManagerClass + { + public: + OrderedStaticManagerClass(); + virtual ~OrderedStaticManagerClass(); + + typedef void (OrderedStaticCreatorFunc::*Creator)(); + + void createObjects(); + void registerObject(unsigned int longevity,OrderedStaticCreatorFunc*,Creator); + + private: + OrderedStaticManagerClass(const OrderedStaticManagerClass&); + OrderedStaticManagerClass& operator=(const OrderedStaticManagerClass&); + + struct Data + { + Data(unsigned int,OrderedStaticCreatorFunc*, Creator); + unsigned int longevity; + OrderedStaticCreatorFunc* object; + Creator creator; + }; + + std::vector<Data> staticObjects_; + unsigned int max_longevity_; + unsigned int min_longevity_; + }; + + }// namespace Private + + //////////////////////////////////////////////////////////////////////////////// + // OrderedStaticManager is only a Singleton typedef + //////////////////////////////////////////////////////////////////////////////// + + typedef Loki::SingletonHolder + < + Loki::Private::OrderedStaticManagerClass, + Loki::CreateUsingNew, + Loki::NoDestroy, + Loki::SingleThreaded + > + OrderedStaticManager; + + //////////////////////////////////////////////////////////////////////////////// + // template OrderedStatic template: + // L : longevity + // T : object type + // TList : creator parameters + //////////////////////////////////////////////////////////////////////////////// + + template<unsigned int L, class T, class TList = Loki::NullType> + class OrderedStatic; + + + //////////////////////////////////////////////////////////////////////////////// + // OrderedStatic specializations + //////////////////////////////////////////////////////////////////////////////// + + template<unsigned int L, class T> + class OrderedStatic<L, T, Loki::NullType> : public Private::OrderedStaticBase<T> + { + public: + OrderedStatic() : Private::OrderedStaticBase<T>(L) + { + OrderedStaticManager::Instance().registerObject + (L,this,&Private::OrderedStaticCreatorFunc::createObject); + } + + void createObject() + { + Private::OrderedStaticBase<T>::SetLongevity(new T); + } + + private: + OrderedStatic(const OrderedStatic&); + OrderedStatic& operator=(const OrderedStatic&); + }; + + template<unsigned int L, class T, typename P1> + class OrderedStatic<L, T, Loki::Seq<P1> > : public Private::OrderedStaticBase<T> + { + public: + OrderedStatic(P1 p) : Private::OrderedStaticBase<T>(L), para_(p) + { + OrderedStaticManager::Instance().registerObject + (L,this,&Private::OrderedStaticCreatorFunc::createObject); + } + + void createObject() + { + Private::OrderedStaticBase<T>::SetLongevity(new T(para_)); + } + + private: + OrderedStatic(); + OrderedStatic(const OrderedStatic&); + OrderedStatic& operator=(const OrderedStatic&); + P1 para_; + }; + + template<unsigned int L, class T, typename P1> + class OrderedStatic<L, T, P1(*)() > : public Private::OrderedStaticBase<T> + { + public: + + typedef P1(*Func)(); + + OrderedStatic(Func p) : Private::OrderedStaticBase<T>(L), para_(p) + { + OrderedStaticManager::Instance().registerObject + (L,this,&Private::OrderedStaticCreatorFunc::createObject); + } + + void createObject() + { + Private::OrderedStaticBase<T>::SetLongevity(new T(para_())); + } + + private: + OrderedStatic(); + OrderedStatic(const OrderedStatic&); + OrderedStatic& operator=(const OrderedStatic&); + Func para_; + }; + +}// namespace Loki + + +#endif // end file guardian + diff --git a/shared/loki/Pimpl.h b/shared/loki/Pimpl.h new file mode 100644 index 00000000..ed0d1c7b --- /dev/null +++ b/shared/loki/Pimpl.h @@ -0,0 +1,198 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2006 Peter Kümmel +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_PIMPL_INC_ +#define LOKI_PIMPL_INC_ + +// $Id: Pimpl.h 751 2006-10-17 19:50:37Z syntheticpp $ + + +/// \defgroup PimplGroup Pimpl + +#ifndef LOKI_INHERITED_PIMPL_NAME +#define LOKI_INHERITED_PIMPL_NAME d +#endif + +#ifndef LOKI_INHERITED_RIMPL_NAME +#define LOKI_INHERITED_RIMPL_NAME d +#endif + +namespace Loki +{ + + ////////////////////////////////////////// + /// \class ConstPropPtr + /// + /// \ingroup PimplGroup + /// Simple const propagating smart pointer + /// Is the default smart pointer of Pimpl. + ////////////////////////////////////////// + + template<class T> + struct ConstPropPtr + { + explicit ConstPropPtr(T* p) : ptr_(p) {} + ~ConstPropPtr() { delete ptr_; ptr_ = 0; } + T* operator->() { return ptr_; } + T& operator*() { return *ptr_; } + const T* operator->() const { return ptr_; } + const T& operator*() const { return *ptr_; } + + private: + ConstPropPtr(); + ConstPropPtr(const ConstPropPtr&); + ConstPropPtr& operator=(const ConstPropPtr&); + T* ptr_; + }; + + + //////////////////////////////////////////////////////////////////////////////// + /// \class Pimpl + /// + /// \ingroup PimplGroup + /// + /// Implements the Pimpl idiom. It's a wrapper for a smart pointer which + /// automatically creates and deletes the implementation object and adds + /// const propagation to the smart pointer. + /// + /// \par Usage + /// see test/Pimpl + //////////////////////////////////////////////////////////////////////////////// + + template + < + class T, + typename Pointer = ConstPropPtr<T> + > + class Pimpl + { + public: + + typedef T Impl; + + Pimpl() : ptr_(new T) + {} + + ~Pimpl() + { + // Don't compile with incomplete type + // + // If compilation breaks here make sure + // the compiler does not auto-generate the + // destructor of the class hosting the pimpl: + // - implement the destructor of the class + // - don't inline the destructor + typedef char T_must_be_defined[sizeof(T) ? 1 : -1 ]; + } + + + T* operator->() + { + return ptr_.operator->(); + } + + T& operator*() + { + return ptr_.operator*(); + } + + const T* operator->() const + { + return ptr_.operator->(); + } + + const T& operator*() const + { + return ptr_.operator*(); + } + + Pointer& wrapped() + { + return ptr_; + } + + const Pointer& wrapped() const + { + return ptr_; + } + + + private: + Pimpl(const Pimpl&); + Pimpl& operator=(const Pimpl&); + + Pointer ptr_; + }; + + + template<class T, typename Pointer = ConstPropPtr<T> > + struct PimplOwner + { + Pimpl<T,Pointer> LOKI_INHERITED_PIMPL_NAME; + }; + + + ////////////////////////////////////////// + /// \class ImplOf + /// + /// \ingroup PimplGroup + /// Convenience template for the + /// implementations which Pimpl points to. + ////////////////////////////////////////// + + template<class T> + struct ImplOf; + + + ////////////////////////////////////////// + /// \class PImplOf + /// + /// \ingroup PimplGroup + /// Convenience template which uses ImplOf + /// as implementation structure + ////////////////////////////////////////// + + + template<class T, template<class> class Ptr = ConstPropPtr> + struct PimplOf + { + typedef T Impl; + + // declare pimpl + typedef Pimpl<ImplOf<T>, Ptr<ImplOf<T> > > Type; + + // inherit pimpl + typedef PimplOwner<ImplOf<T>, Ptr<ImplOf<T> > > Owner; + }; + + + template<class T, class UsedPimpl = typename PimplOf<T>::Type > + struct RimplOf + { + typedef typename UsedPimpl::Impl & Type; + + class Owner + { + UsedPimpl pimpl; + + public: + Owner() : LOKI_INHERITED_RIMPL_NAME(*pimpl) + {} + + Type LOKI_INHERITED_RIMPL_NAME; + }; + + }; + +} + +#endif // end file guardian + diff --git a/shared/loki/RefToValue.h b/shared/loki/RefToValue.h new file mode 100644 index 00000000..248de792 --- /dev/null +++ b/shared/loki/RefToValue.h @@ -0,0 +1,70 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2006 Richard Sposato +// Copyright (c) 2006 Peter Kümmel +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The authors make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_REFTOVALUE_INC_ +#define LOKI_REFTOVALUE_INC_ + +// $Id: RefToValue.h 751 2006-10-17 19:50:37Z syntheticpp $ + + +namespace Loki +{ + + //////////////////////////////////////////////////////////////////////////////// + /// \class RefToValue + /// + /// \ingroup SmartPointerGroup + /// Transports a reference as a value + /// Serves to implement the Colvin/Gibbons trick for SmartPtr/ScopeGuard + //////////////////////////////////////////////////////////////////////////////// + + template <class T> + class RefToValue + { + public: + + RefToValue(T& ref) : ref_(ref) + {} + + RefToValue(const RefToValue& rhs) : ref_(rhs.ref_) + {} + + operator T& () const + { + return ref_; + } + + private: + // Disable - not implemented + RefToValue(); + RefToValue& operator=(const RefToValue&); + + T& ref_; + }; + + + //////////////////////////////////////////////////////////////////////////////// + /// \ingroup ExceptionGroup + /// RefToValue creator. + //////////////////////////////////////////////////////////////////////////////// + + template <class T> + inline RefToValue<T> ByRef(T& t) + { + return RefToValue<T>(t); + } + +} + + +#endif // end file guardian + diff --git a/shared/loki/Register.h b/shared/loki/Register.h new file mode 100644 index 00000000..0ad014ab --- /dev/null +++ b/shared/loki/Register.h @@ -0,0 +1,134 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2006 Peter Kümmel +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_REGISTER_INC_ +#define LOKI_REGISTER_INC_ + +// $Id: Register.h 776 2006-11-09 13:12:57Z syntheticpp $ + + +#include "TypeManip.h" +#include "HierarchyGenerators.h" + +/// \defgroup RegisterGroup Register + +namespace Loki +{ + + //////////////////////////////////////////////////////////////////////////////// + // + // Helper classes/functions for RegisterByCreateSet + // + //////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////// + /// \ingroup RegisterGroup + /// Must be specialized be the user + //////////////////////////////////////////////////////////////////////////////// + template<class t> bool RegisterFunction(); + + //////////////////////////////////////////////////////////////////////////////// + /// \ingroup RegisterGroup + /// Must be specialized be the user + //////////////////////////////////////////////////////////////////////////////// + template<class t> bool UnRegisterFunction(); + + namespace Private + { + template<class T> + struct RegisterOnCreate + { + RegisterOnCreate() { RegisterFunction<T>(); } + }; + + template<class T> + struct UnRegisterOnDelete + { + ~UnRegisterOnDelete() { UnRegisterFunction<T>(); } + }; + + template<class T> + struct RegisterOnCreateElement + { + RegisterOnCreate<T> registerObj; + }; + + template<class T> + struct UnRegisterOnDeleteElement + { + UnRegisterOnDelete<T> unregisterObj; + }; + } + + //////////////////////////////////////////////////////////////////////////////// + /// \class RegisterOnCreateSet + /// + /// \ingroup RegisterGroup + /// Implements a generic register class which registers classes of a typelist + /// + /// \par Usage + /// see test/Register + //////////////////////////////////////////////////////////////////////////////// + + template<typename ElementList> + struct RegisterOnCreateSet + : GenScatterHierarchy<ElementList, Private::RegisterOnCreateElement> + {}; + + //////////////////////////////////////////////////////////////////////////////// + /// \class UnRegisterOnDeleteSet + /// + /// \ingroup RegisterGroup + /// Implements a generic register class which unregisters classes of a typelist + /// + /// \par Usage + /// see test/Register + //////////////////////////////////////////////////////////////////////////////// + template<typename ElementList> + struct UnRegisterOnDeleteSet + : GenScatterHierarchy<ElementList, Private::UnRegisterOnDeleteElement> + {}; + + + //////////////////////////////////////////////////////////////////////////////// + /// \def LOKI_CHECK_CLASS_IN_LIST( CLASS , LIST ) + /// + /// \ingroup RegisterGroup + /// Check if CLASS is in the typelist LIST. + /// + /// \par Usage + /// see test/Register + //////////////////////////////////////////////////////////////////////////////// + + +#define LOKI_CONCATE(a,b,c,d) a ## b ## c ## d +#define LOKI_CONCAT(a,b,c,d) LOKI_CONCATE(a,b,c,d) + +#define LOKI_CHECK_CLASS_IN_LIST( CLASS , LIST ) \ + \ + struct LOKI_CONCAT(check_,CLASS,_isInList_,LIST) \ + { \ + typedef int LOKI_CONCAT(ERROR_class_,CLASS,_isNotInList_,LIST); \ + }; \ + typedef Loki::Select<Loki::TL::IndexOf<LIST, CLASS>::value == -1, \ + CLASS, \ + LOKI_CONCAT(check_,CLASS,_isInList_,LIST)> \ + ::Result LOKI_CONCAT(CLASS,isInList,LIST,result); \ + typedef LOKI_CONCAT(CLASS,isInList,LIST,result):: \ + LOKI_CONCAT(ERROR_class_,CLASS,_isNotInList_,LIST) \ + LOKI_CONCAT(ERROR_class_,CLASS,_isNotInList__,LIST); + + +} // namespace Loki + + +#endif // end file guardian + diff --git a/shared/loki/SPCachedFactory.h b/shared/loki/SPCachedFactory.h new file mode 100644 index 00000000..71c72644 --- /dev/null +++ b/shared/loki/SPCachedFactory.h @@ -0,0 +1,204 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2006 by Guillaume Chatelet +// +// Code covered by the MIT License +// +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// +// The authors make no representations about the suitability of this software +// for any purpose. It is provided "as is" without express or implied warranty. +// +// This code DOES NOT accompany the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// +//////////////////////////////////////////////////////////////////////////////// + +// $Id: SPCachedFactory.h 896 2008-08-08 22:20:05Z syntheticpp $ + +#ifndef SPCACHEDFACTORY_H_ +#define SPCACHEDFACTORY_H_ + +/** + * This file is intented to be used if you want a CachedFactory with + * a SmartPointer encapsulation policy. + * It as been defined in a separate file because of the many introduced + * dependencies (SmartPtr.h would depend on Functor.h and CachedFactory.h + * would depend on SmartPtr.h). By defining another header you pay for those + * extra dependencies only if you need it. + * + * This file defines FunctionStorage a new SmartPointer storage policy and + * SmartPointer a new CachedFactory encapsulation policy. + */ + +#include <loki/Functor.h> +#include <loki/SmartPtr.h> +#include <loki/CachedFactory.h> + +namespace Loki +{ + +//////////////////////////////////////////////////////////////////////////////// +/// \class FunctionStorage +/// +/// \ingroup SmartPointerStorageGroup +/// \brief Implementation of the StoragePolicy used by SmartPtr. +/// +/// This storage policy is used by SmartPointer CachedFactory's encapsulation +/// policy. It's purpose is to call a Functor instead of deleting the +/// underlying pointee object. You have to set the callback functor by calling +/// SetCallBackFunction(const FunctorType &functor). +/// +/// Unfortunately, the functor argument is not a reference to the SmartPtr but +/// a void *. Making functor argument a reference to the pointer would require +/// the FunctionStorage template to know the full definition of the SmartPtr. +//////////////////////////////////////////////////////////////////////////////// + + template <class T> + class FunctionStorage + { + public: + /// the type of the pointee_ object + typedef T* StoredType; + /// type used to declare OwnershipPolicy type. + typedef T* InitPointerType; + /// type returned by operator-> + typedef T* PointerType; + /// type returned by operator* + typedef T& ReferenceType; + /// type of the Functor to set + typedef Functor< void , Seq< void* > > FunctorType; + + FunctionStorage() : pointee_(Default()), functor_() + {} + + // The storage policy doesn't initialize the stored pointer + // which will be initialized by the OwnershipPolicy's Clone fn + FunctionStorage(const FunctionStorage& rsh) : pointee_(0), functor_(rsh.functor_) + {} + + template <class U> + FunctionStorage(const FunctionStorage<U>& rsh) : pointee_(0), functor_(rsh.functor_) + {} + + FunctionStorage(const StoredType& p) : pointee_(p), functor_() {} + + PointerType operator->() const { return pointee_; } + + ReferenceType operator*() const { return *pointee_; } + + void Swap(FunctionStorage& rhs) + { + std::swap(pointee_, rhs.pointee_); + std::swap(functor_, rhs.functor_); + } + + /// Sets the callback function to call. You have to specify it or + /// the smartPtr will throw a bad_function_call exception. + void SetCallBackFunction(const FunctorType &functor) + { + functor_ = functor; + } + + // Accessors + template <class F> + friend typename FunctionStorage<F>::PointerType GetImpl(const FunctionStorage<F>& sp); + + template <class F> + friend const typename FunctionStorage<F>::StoredType& GetImplRef(const FunctionStorage<F>& sp); + + template <class F> + friend typename FunctionStorage<F>::StoredType& GetImplRef(FunctionStorage<F>& sp); + + protected: + // Destroys the data stored + // (Destruction might be taken over by the OwnershipPolicy) + void Destroy() + { + functor_(this); + } + + // Default value to initialize the pointer + static StoredType Default() + { return 0; } + + private: + // Data + StoredType pointee_; + FunctorType functor_; + }; + + template <class T> + inline typename FunctionStorage<T>::PointerType GetImpl(const FunctionStorage<T>& sp) + { return sp.pointee_; } + + template <class T> + inline const typename FunctionStorage<T>::StoredType& GetImplRef(const FunctionStorage<T>& sp) + { return sp.pointee_; } + + template <class T> + inline typename FunctionStorage<T>::StoredType& GetImplRef(FunctionStorage<T>& sp) + { return sp.pointee_; } + + /** + * \class SmartPointer + * \ingroup EncapsulationPolicyCachedFactoryGroup + * \brief Encapsulate the object in a SmartPtr with FunctionStorage policy. + * + * The object will come back to the Cache as soon as no more SmartPtr are + * referencing this object. You can customize the SmartPointer with the standard + * SmartPtr policies (OwnershipPolicy, ConversionPolicy, CheckingPolicy, + * ConstnessPolicy) but StoragePolicy is forced to FunctionStorage. + */ + template + < + class AbstractProduct, + template <class> class OwnershipPolicy = RefCounted, + class ConversionPolicy = DisallowConversion, + template <class> class CheckingPolicy = AssertCheck, + template<class> class ConstnessPolicy = LOKI_DEFAULT_CONSTNESS + > + class SmartPointer + { + private: + typedef SmartPtr< AbstractProduct,OwnershipPolicy, + ConversionPolicy, CheckingPolicy, + FunctionStorage, ConstnessPolicy > CallBackSP; + protected: + typedef CallBackSP ProductReturn; + SmartPointer() : fun(this, &SmartPointer::smartPointerCallbackFunction) {} + virtual ~SmartPointer(){} + + ProductReturn encapsulate(AbstractProduct* pProduct) + { + CallBackSP SP(pProduct); + SP.SetCallBackFunction(fun); + return SP; + } + + AbstractProduct* release(ProductReturn &pProduct) + { + return GetImpl(pProduct); + } + + const char* name(){return "smart pointer";} + + private: + SmartPointer& operator=(const SmartPointer&); + SmartPointer(const SmartPointer&); + void smartPointerCallbackFunction(void* pSP) + { + CallBackSP &SP(*reinterpret_cast<CallBackSP*>(pSP)); + ReleaseObject(SP); + } + virtual void ReleaseObject(ProductReturn &object)=0; + const typename CallBackSP::FunctorType fun; + }; + +} // namespace Loki + +#endif /*SPCACHEDFACTORY_H_*/ diff --git a/shared/loki/SafeBits.h b/shared/loki/SafeBits.h new file mode 100644 index 00000000..f45065ed --- /dev/null +++ b/shared/loki/SafeBits.h @@ -0,0 +1,514 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2009 by Fedor Pikus & Rich Sposato +// The copyright on this file is protected under the terms of the MIT license. +// +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// +// The author makes no claims about the suitability of this software for any +// purpose. It is provided "as is" without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// + +// $Id$ + + +#ifndef LOKI_INCLUDED_SAFE_BIT_FIELDS_H +#define LOKI_INCLUDED_SAFE_BIT_FIELDS_H + +#include <cstdlib> +#include <assert.h> +#include <loki/static_check.h> + + +namespace Loki +{ + +/* + ========================================================================================================================================== + SafeBitField - type-safe class for bit fields. + SafeBitConst - type-safe class for bit constants. + SafeBitField is designed to be a [almost] drop-in replacement for integer flags and bit fields where individual bits are set and checked + using symbolic names for flags: + + typedef unsigned long Labels_t; + Labels_t labels; + const Labels_t Label_A = 0x00000001; + const Labels_t Label_B = 0x00000002; + ... + labels |= Label_B; + if ( labels & Label_A ) { ... } + + Such code offers no protection against mismatching bit constants and bit fields: + + typedef unsigned long Kinds_t; + Kinds_t kinds; + const Kinds_t Kind_A = 0x00000004; + ... + if ( kinds & Label_A ) { ... } // Error but compiles + + SafeBitField is a drop-in replacement which generates a unique type for each bit field. Bit fields of different types cannot be applied + to each other: + + LOKI_BIT_FIELD( unsigned long ) Labels_t; + Labels_t labels; + LOKI_BIT_CONST( Labels_t, Label_A, 1 ); // 0x0001 - 1st bit is set + LOKI_BIT_CONST( Labels_t, Label_B, 2 ); // 0x0002 - 1st bit is set + ... + LOKI_BIT_FIELD( unsigned long ) Kinds_t; + Kinds_t kinds; + LOKI_BIT_CONST( Kinds_t, Kind_A, 3 ); // 0x0004 - 1st bit is set + ... + if ( kinds & Label_A ) { ... } // Does not compile + + Several other kinds of bit field misuse are caught by safe bit fields: + + if ( kinds & Kind_A == 0 ) { ... } + if ( kinds && Kind_A ) { ... } + + There are few cases where drop-in replacement does not work: + + 1. Operations involving bit fields and unnamed integers. Usually the integer in question is 0: + + Labels_t labels = 0; // No longer compiles + if ( ( labels & Label_A ) == 0 ) { ... } // Also does not compile + + The solution is to use named bit constants, including the one for 0: + + LOKI_BIT_CONST( Labels_t, Label_None, 0 ); // 0x0000 - No bit is set + Labels_t labels = Label_None; // Or just Labels_t labels; - constructor initializes to 0 + if ( ( labels & Label_A ) == Label_None ) { ... } // // Or just if ( labels & Label_A ) { ... } + + 2. I/O and other operations which require integer variables and cannot be modified: + + void write_to_db( unsigned int word ); + Labels_t labels; + write_to_db( labels ); // No longer compiles + + This problem is solved by reinterpreting the bit fields as an integer, the user is responsible for using the right + type of integer: + + write_to_db( *((Labels_t::bit_word_t*)(&labels)) ); + + ========================================================================================================================================== +*/ + +/// @par Non-Templated Initialization. +/// Not all compilers support template member functions where the template +/// arguments are not deduced but explicitly specified. For these broken +/// compilers, a non-template make_bit_const() function is provided instead of +/// the template one. The only downside is that instead of compile-time checking +/// of the index argument, it does runtime checking. +#if defined(__SUNPRO_CC) || ( defined(__GNUC__) && (__GNUC__ < 3) ) + #define LOKI_BIT_FIELD_NONTEMPLATE_INIT +#endif + +/// @par Forbidding Conversions. +/// This incomplete type prevents compilers from instantiating templates for +/// type conversions which should not happen. This incomplete type must be a +/// template: if the type is incomplete at the point of template definition, +/// the template is illegal (although the standard allows compilers to accept +/// or reject such code, §14.6/, so some compilers will not issue diagnostics +/// unless template is instantiated). The standard-compliant way is to defer +/// binding to the point of instantiation by making the incomplete type itself +/// a template. +template < typename > struct Forbidden_conversion; // This struct must not be defined! + +/// Forward declaration of the field type. +template < + unsigned int unique_index, + typename word_t = unsigned long +> class SafeBitField; + +//////////////////////////////////////////////////////////////////////////////// +/// \class SafeBitConst Bit constants. +/// This class defines a bit-field constant - a collection of unchanging bits +/// used to compare to bit-fields. Instances of this class are intended to act +/// as labels for bit-fields. +/// +/// \par Safety +/// - This class provides operations used for comparisons and conversions, but +/// no operations which may modify the value. +/// - As a templated class, it provides type-safety so bit values and constants +/// used for different reasons may not be unknowingly compared to each other. +/// - The unique_index template parameter insures the unique type of each bit +/// bit-field. It shares the unique_index with a similar SafeBitField. +/// - Its operations only allow comparisons to other bit-constants and +/// bit-fields of the same type. +//////////////////////////////////////////////////////////////////////////////// + +template +< + unsigned int unique_index, + typename word_t = unsigned long +> +class SafeBitConst +{ +public: + + /// Type of the bit field is available if needed. + typedef word_t bit_word_t; + /// Corresponding field type. + typedef SafeBitField< unique_index, word_t > field_t; + /// Typedef is not allowed in friendship declaration. + friend class SafeBitField< unique_index, word_t >; + + // Static factory constructor, creates a bit constant with one bit set. The position of the bit is given by the template parameter, + // bit 1 is the junior bit, i.e. make_bit_const<1>() returns 1. Bit index 0 is a special case and returns 0. + // This function should be used only to initialize the static bit constant objects. + // This function will not compile if the bit index is outside the vaild range. + // There is also a compile-time assert to make sure the size of the class is the same as the size of the underlaying integer type. + // This assert could go into the constructor, but aCC does not seem to understand sizeof(SafeBitConst) in the constructor. + // +#ifndef LOKI_BIT_FIELD_NONTEMPLATE_INIT + template < unsigned int i > static SafeBitConst make_bit_const() + { + LOKI_STATIC_CHECK( i <= ( 8 * sizeof(word_t) ), Index_is_beyond_size_of_data ); + LOKI_STATIC_CHECK( sizeof(SafeBitConst) == sizeof(word_t), Object_size_does_not_match_data_size ); + // Why check for ( i > 0 ) again inside the shift if the shift + // can never be evaluated for i == 0? Some compilers see shift by ( i - 1 ) + // and complain that for i == 0 the number is invalid, without + // checking that shift needs evaluating. + return SafeBitConst( ( i > 0 ) ? ( word_t(1) << ( ( i > 0 ) ? ( i - 1 ) : 0 ) ) : 0 ); + } +#else + static SafeBitConst make_bit_const( unsigned int i ) + { + LOKI_STATIC_CHECK( sizeof(SafeBitConst) == sizeof(word_t), Object_size_does_not_match_data_size ); + assert( i <= ( 8 * sizeof(word_t) ) ); // Index is beyond size of data. + // Why check for ( i > 0 ) again inside the shift if the shift + // can never be evaluated for i == 0? Some compilers see shift by ( i - 1 ) + // and complain that for i == 0 the number is invalid, without + // checking that shift needs evaluating. + return SafeBitConst( ( i > 0 ) ? ( word_t(1) << ( ( i > 0 ) ? ( i - 1 ) : 0 ) ) : 0 ); + } +#endif + + /// Default constructor allows client code to construct bit fields on the stack. + SafeBitConst() : word( 0 ) {} + + /// Copy constructor. + SafeBitConst( const SafeBitConst& rhs ) : word( rhs.word ) {} + + /// Comparison operators which take a constant bit value. + bool operator == ( const SafeBitConst & rhs ) const { return word == rhs.word; } + bool operator != ( const SafeBitConst & rhs ) const { return word != rhs.word; } + bool operator < ( const SafeBitConst & rhs ) const { return word < rhs.word; } + bool operator > ( const SafeBitConst & rhs ) const { return word > rhs.word; } + bool operator <= ( const SafeBitConst & rhs ) const { return word <= rhs.word; } + bool operator >= ( const SafeBitConst & rhs ) const { return word >= rhs.word; } + + /// Comparision operators for mutable bit fields. + bool operator == ( const field_t & rhs ) const { return word == rhs.word; } + bool operator != ( const field_t & rhs ) const { return word != rhs.word; } + bool operator < ( const field_t & rhs ) const { return word < rhs.word; } + bool operator > ( const field_t & rhs ) const { return word > rhs.word; } + bool operator <= ( const field_t & rhs ) const { return word <= rhs.word; } + bool operator >= ( const field_t & rhs ) const { return word >= rhs.word; } + + /// Bitwise operations. Operation-assignment operators are not needed, + /// since bit constants cannot be changed after they are initialized. + const SafeBitConst operator | ( const SafeBitConst & rhs ) const { return SafeBitConst( word | rhs.word ); } + const SafeBitConst operator & ( const SafeBitConst & rhs ) const { return SafeBitConst( word & rhs.word ); } + const SafeBitConst operator ^ ( const SafeBitConst & rhs ) const { return SafeBitConst( word ^ rhs.word ); } + const SafeBitConst operator ~ ( void ) const { return SafeBitConst( ~word ); } + + /// These bitwise operators return a bit-field instead of a bit-const. + field_t operator | ( const field_t & rhs ) const { return field_t( word | rhs.word ); } + field_t operator & ( const field_t & rhs ) const { return field_t( word & rhs.word ); } + field_t operator ^ ( const field_t & rhs ) const { return field_t( word ^ rhs.word ); } + + /// The shift operators move bits inside the bit field. These are useful in + /// loops which act over bit fields and increment them. + const SafeBitConst operator << ( unsigned int s ) const { return SafeBitConst( word << s ); } + const SafeBitConst operator >> ( unsigned int s ) const { return SafeBitConst( word >> s ); } + + /// Word size is also the maximum number of different bit fields for a given word type. + static size_t size() { return ( 8 * sizeof( word_t ) ); } + +private: + + /// Copy-assignment operator is not implemented since it does not make sense + /// for a constant object. + SafeBitConst operator = ( const SafeBitConst & rhs ); + + // Private constructor from an integer type. + explicit SafeBitConst( word_t init ) : word( init ) {} + + /// This data stores a single bit value. It is declared const to enforce + // constness for all functions of this class. + const word_t word; + + // Here comes the interesting stuff: all the operators designed to + // trap unintended conversions and make them not compile. + // Operators below handle code like this: + // SafeBitField<1> label1; + // SafeBitField<2> label2; + // if ( label1 & label2 ) { ... } + + // These operators are private, and will not instantiate in any + // event because of the incomplete Forbidden_conversion struct. + template < typename T > SafeBitConst operator|( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitConst operator&( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitConst operator^( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitConst operator|=( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitConst operator&=( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitConst operator^=( T ) const { Forbidden_conversion< T > wrong; return *this; } + + // And the same thing for comparisons: private and unusable. + // if ( label1 == label2 ) { ... } + template < typename T > bool operator==( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator!=( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator<( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator>( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator<=( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator>=( const T ) const { Forbidden_conversion< T > wrong; return true; } +}; + + +//////////////////////////////////////////////////////////////////////////////// +/// \class SafeBitConst Bit constants. +/// This class defines a bit-field constant - a collection of unchanging bits +/// used to compare to bit-fields. Instances of this class are intended to +/// store bit values. +/// +/// \par Safety +/// - This class provides operations used for comparisons and conversions, and +/// also operations which may safely modify the value. +/// - As a templated class, it provides type-safety so bit values and constants +/// used for different reasons may not be unknowingly compared to each other. +/// - The unique_index template parameter insures the unique type of each bit +/// bit-field. It shares the unique_index with a similar SafeBitConst. +/// - Its operations only allow comparisons to other bit-constants and +/// bit-fields of the same type. +//////////////////////////////////////////////////////////////////////////////// + +template +< + unsigned int unique_index, + typename word_t +> +class SafeBitField +{ +public: + + /// Type of the bit field is available if needed. + typedef word_t bit_word_t; + /// Corresponding field type. + typedef SafeBitConst< unique_index, word_t > const_t; + /// Typedef is not allowed in friendship declaration. + friend class SafeBitConst<unique_index, word_t>; + + /// Default constructor allows client code to construct bit fields on the stack. + SafeBitField() : word( 0 ) {} + + /// Copy constructor and assignment operators. + SafeBitField( const SafeBitField & rhs ) : word( rhs.word ) {} + SafeBitField & operator = ( const SafeBitField & rhs ) { word = rhs.word; return *this; } + + /// Copy constructor and assignment operators from constant bit fields. + SafeBitField( const const_t & rhs ) : word( rhs.word ) {} + SafeBitField & operator = ( const const_t & rhs ) { word = rhs.word; return *this; } + + /// These comparison operators act on bit-fields of the same type. + bool operator == ( const SafeBitField & rhs ) const { return word == rhs.word; } + bool operator != ( const SafeBitField & rhs ) const { return word != rhs.word; } + bool operator < ( const SafeBitField & rhs ) const { return word < rhs.word; } + bool operator > ( const SafeBitField & rhs ) const { return word > rhs.word; } + bool operator <= ( const SafeBitField & rhs ) const { return word <= rhs.word; } + bool operator >= ( const SafeBitField & rhs ) const { return word >= rhs.word; } + + /// These comparison operators act on bit-constants of a similar type. + bool operator == ( const const_t & rhs ) const { return word == rhs.word; } + bool operator != ( const const_t & rhs ) const { return word != rhs.word; } + bool operator < ( const const_t & rhs ) const { return word < rhs.word; } + bool operator > ( const const_t & rhs ) const { return word > rhs.word; } + bool operator <= ( const const_t & rhs ) const { return word <= rhs.word; } + bool operator >= ( const const_t & rhs ) const { return word >= rhs.word; } + + /// Bitwise operations that use bit-fields. + SafeBitField operator | ( const SafeBitField & rhs ) const { return SafeBitField( word | rhs.word ); } + SafeBitField operator & ( const SafeBitField & rhs ) const { return SafeBitField( word & rhs.word ); } + SafeBitField operator ^ ( const SafeBitField & rhs ) const { return SafeBitField( word ^ rhs.word ); } + SafeBitField operator ~ ( void ) const { return SafeBitField( ~word ); } + SafeBitField operator |= ( const SafeBitField & rhs ) { word |= rhs.word; return SafeBitField( *this ); } + SafeBitField operator &= ( const SafeBitField & rhs ) { word &= rhs.word; return SafeBitField( *this ); } + SafeBitField operator ^= ( const SafeBitField & rhs ) { word ^= rhs.word; return SafeBitField( *this ); } + + /// Bitwise operators that use bit-constants. + SafeBitField operator | ( const_t rhs ) const { return SafeBitField( word | rhs.word ); } + SafeBitField operator & ( const_t rhs ) const { return SafeBitField( word & rhs.word ); } + SafeBitField operator ^ ( const_t rhs ) const { return SafeBitField( word ^ rhs.word ); } + SafeBitField operator |= ( const_t rhs ) { word |= rhs.word; return SafeBitField( *this ); } + SafeBitField operator &= ( const_t rhs ) { word &= rhs.word; return SafeBitField( *this ); } + SafeBitField operator ^= ( const_t rhs ) { word ^= rhs.word; return SafeBitField( *this ); } + + // Conversion to bool. + // This is a major source of headaches, but it's required to support code like this: + // const static SafeBitConst<1> Label_value = SafeBitConst<1>::make_bit_const<1>(); + // SafeBitField<1> label; + // if ( label & Label_value ) { ... } // Nice... + // + // The downside is that this allows all sorts of nasty conversions. Without additional precautions, bit fields of different types + // can be converted to bool and then compared or operated on: + // SafeBitField<1> label1; + // SafeBitField<2> label2; + // if ( label1 == label2 ) { ... } // Yuck! + // if ( label1 & label2 ) { ... } // Blech! + // + // It is somewhat safer to convert to a pointer, at least pointers to different types cannot be readilly compared, and there are no + // bitwise operations on pointers, but the conversion from word_t to a pointer can have run-time cost if they are of different size. + // + operator const bool() const { return ( 0 != word ); } + + // Shift operators shift bits inside the bit field. Does not make + // sense, most of the time, except perhaps to loop over labels and + // increment them. + SafeBitField operator << ( unsigned int s ) { return SafeBitField( word << s ); } + SafeBitField operator >> ( unsigned int s ) { return SafeBitField( word >> s ); } + SafeBitField operator <<= ( unsigned int s ) { word <<= s; return *this; } + SafeBitField operator >>= ( unsigned int s ) { word >>= s; return *this; } + + // Word size is also the maximum number of different bit fields for + // a given word type. + static size_t size( void ) { return ( 8 * sizeof( word_t ) ); } + +private: + + /// Private constructor from an integer type. Don't put too much stock into + /// explicit declaration, it's better than nothing but does not solve all + /// problems with undesired conversions because SafeBitField coverts to bool. + explicit SafeBitField( word_t init ) : word( init ) {} + + /// This stores the bits. + word_t word; + + // Here comes the interesting stuff: all the operators designed to + // trap unintended conversions and make them not compile. + // Operators below handle code like this: + // SafeBitField<1> label1; + // SafeBitField<2> label2; + // if ( label1 & label2 ) { ... } + + // These operators are private, and will not instantiate in any + // event because of the incomplete Forbidden_conversion struct. + template < typename T > SafeBitField operator | ( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitField operator & ( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitField operator ^ ( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitField operator |= ( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitField operator &= ( T ) const { Forbidden_conversion< T > wrong; return *this; } + template < typename T > SafeBitField operator ^= ( T ) const { Forbidden_conversion< T > wrong; return *this; } + + // And the same thing for comparisons: + // if ( label1 == label2 ) { ... } + template < typename T > bool operator == ( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator != ( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator < ( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator > ( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator <= ( const T ) const { Forbidden_conversion< T > wrong; return true; } + template < typename T > bool operator >= ( const T ) const { Forbidden_conversion< T > wrong; return true; } +}; + +// The above template member operators catch errors when the first +// argument to a binary operator is a label, but they don't work when +// the first argument is an integer and the second one is a label: the +// label converts to bool and the operator is performed on two integers. +// These operators catch errors like this: +// SafeBitField<1> label1; +// SafeBitField<2> label2; +// if ( !label1 & label2 ) { ... } +// where the first label is converted to bool (these errors cannot be +// caught by member operators of SafeBitField class because the first +// argument is not SafeBitField but bool. +// +// If used, these operators will not instantiate because of the +// incomplete Forbidden_conversion struct. + +template < unsigned int unique_index, typename word_t > +inline SafeBitField< unique_index, word_t > operator & ( bool, SafeBitField< unique_index, word_t > rhs ) +{ + Forbidden_conversion<word_t> wrong; + return rhs; +} + +template < unsigned int unique_index, typename word_t > +inline SafeBitField< unique_index, word_t > operator | ( bool, SafeBitField< unique_index, word_t > rhs ) +{ + Forbidden_conversion< word_t > wrong; + return rhs; +} + +template < unsigned int unique_index, typename word_t > +inline SafeBitField< unique_index, word_t > operator ^ ( bool, SafeBitField< unique_index, word_t > rhs ) +{ + Forbidden_conversion< word_t > wrong; + return rhs; +} + +template < unsigned int unique_index, typename word_t > +inline SafeBitField< unique_index, word_t > operator == ( bool, SafeBitField< unique_index, word_t > rhs ) +{ + Forbidden_conversion< word_t > wrong; + return rhs; +} + +template < unsigned int unique_index, typename word_t > +inline SafeBitField< unique_index, word_t > operator != ( bool, SafeBitField< unique_index, word_t > rhs ) +{ + Forbidden_conversion< word_t > wrong; + return rhs; +} + +// Finally, few macros. All macros are conditionally defined to use the SafeBitField classes if LOKI_SAFE_BIT_FIELD is defined. Otherwise, +// the macros fall back on the use of typedefs and integer constants. This provides no addititonal safety but allows the code to support the +// mixture of compilers which are broken to different degrees. +#define LOKI_SAFE_BIT_FIELD + +// The first macro helps to declare new bit field types: +// LOKI_BIT_FIELD( ulong ) field_t; +// This creates a typedef field_t for SafeBitField<unique_index, ulong> where index is the current line number. Since line numbers __LINE__ are counted +// separately for all header files, this ends up being the same type in all files using the header which defines field_t. +#ifdef LOKI_SAFE_BIT_FIELD + #define LOKI_BIT_FIELD( word_t ) typedef SafeBitField<__LINE__, word_t> +#else + #define LOKI_BIT_FIELD( word_t ) typedef word_t +#endif // LOKI_SAFE_BIT_FIELD + +// The second macro helps to declare static bit constants: +// LOKI_BIT_CONST( field_t, Label_1, 1 ); +// creates new bit field object named Label_1 of type field_t which represents the field with the 1st (junior) bit set. +#ifdef LOKI_SAFE_BIT_FIELD + #ifndef LOKI_BIT_FIELD_NONTEMPLATE_INIT + #define LOKI_BIT_CONST( field_t, label, bit_index ) \ + static const field_t::const_t label = field_t::const_t::make_bit_const<bit_index>() + #else + #define LOKI_BIT_CONST( field_t, label, bit_index ) \ + static const field_t::const_t label = field_t::const_t::make_bit_const( bit_index ) + #endif // LOKI_BIT_FIELD_NONTEMPLATE_INIT +#else + inline size_t make_bit_const( size_t i ) { return ( i > 0 ) ? ( size_t(1) << ( ( i > 0 ) ? ( i - 1 ) : 0 ) ) : 0; } + #define LOKI_BIT_CONST( field_t, label, bit_index ) static const field_t label = make_bit_const( bit_index ) +#endif // LOKI_SAFE_BIT_FIELD + +// The third macro helps to declare complex bit constants which are combination of several bits: +// LOKI_BIT_CONSTS( field_t, Label12 ) = Label_1 | Label_2; +#ifdef LOKI_SAFE_BIT_FIELD + #define LOKI_BIT_CONSTS( field_t, label ) static const field_t::const_t label +#else + #define LOKI_BIT_CONSTS( field_t, label ) static const field_t label +#endif // LOKI_SAFE_BIT_FIELD + +// The fourth macro helps to declare the maximum number of bit constants for a given type: +// static const size_t count = LOKI_BIT_FIELD_COUNT( field_t ); +// declared a variable "count" initialized to field_t::size() +#ifdef LOKI_SAFE_BIT_FIELD + #define LOKI_BIT_FIELD_COUNT( field_t ) field_t::size() +#else + #define LOKI_BIT_FIELD_COUNT( field_t ) ( 8 * sizeof(field_t) ) +#endif // LOKI_SAFE_BIT_FIELD + +} // namespace Loki + +#endif // LOKI_INCLUDED_SAFE_BIT_FIELDS_H diff --git a/shared/loki/SafeFormat.h b/shared/loki/SafeFormat.h new file mode 100644 index 00000000..9d948581 --- /dev/null +++ b/shared/loki/SafeFormat.h @@ -0,0 +1,590 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2005 by Andrei Alexandrescu +// Copyright (c) 2006 Peter Kümmel +// Permission to use, copy, modify, distribute, and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author makes no representations about the suitability of this software +// for any purpose. It is provided "as is" without express or implied +// warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_SAFEFORMAT_INC_ +#define LOKI_SAFEFORMAT_INC_ + +// $Id: SafeFormat.h 911 2008-12-15 20:55:24Z syntheticpp $ + + +//////////////////////////////////////////////////////////////////////////////// +// This file contains definitions for SafePrintf. SafeScanf coming soon (the +// design is similar). +// See Alexandrescu, Andrei: Type-safe Formatting, C/C++ Users Journal, Aug 2005 +//////////////////////////////////////////////////////////////////////////////// + +#include <cstdio> +#include <climits> +#include <string> +#include <cstring> +#include <stdexcept> +#include <utility> +#include <cassert> +#include <locale> +#include <iostream> + +#include <loki/LokiExport.h> + + +// long is 32 bit on 64-bit Windows! +// intptr_t used to get 64 bit on Win64 +#if defined(_WIN32) || defined(_WIN64) +# define LOKI_SAFEFORMAT_SIGNED_LONG intptr_t +# define LOKI_SAFEFORMAT_UNSIGNED_LONG uintptr_t +#else +# define LOKI_SAFEFORMAT_SIGNED_LONG signed long +# define LOKI_SAFEFORMAT_UNSIGNED_LONG unsigned long +#endif + +// Windows headers could have min/max defined +#ifdef max +# undef max +#endif +#ifdef min +# undef min +#endif + +namespace Loki +{ + + // Crude writing method: writes straight to the file, unbuffered + // Must be combined with a buffer to work properly (and efficiently) + LOKI_EXPORT + void write(std::FILE* f, const char* from, const char* to); + + // Write to an ostream + LOKI_EXPORT + void write(std::ostream& f, const char* from, const char* to); + + // Write to a string + LOKI_EXPORT + void write(std::string& s, const char* from, const char* to); + + // Write to a fixed-size buffer + template <class Char> + void write(std::pair<Char*, std::size_t>& s, const Char* from, const Char* to) { + assert(from <= to); + if(from + s.second < to) + throw std::overflow_error(""); + // s.first: position one past the final copied element + s.first = std::copy(from, to, s.first); + // remaining buffer size + s.second -= to - from; + } + + //////////////////////////////////////////////////////////////////////////////// + // PrintfState class template + // Holds the formatting state, and implements operator() to format stuff + // Todo: make sure errors are handled properly + //////////////////////////////////////////////////////////////////////////////// + + template <class Device, class Char> + struct PrintfState { + PrintfState(Device dev, const Char * format) + : device_(dev) + , format_(format) + , width_(0) + , prec_(0) + , flags_(0) + , result_(0) { + Advance(); + } + + ~PrintfState() { + } + + #define LOKI_PRINTF_STATE_FORWARD(type) \ + PrintfState& operator()(type par) {\ + return (*this)(static_cast< LOKI_SAFEFORMAT_UNSIGNED_LONG >(par)); \ + } + + LOKI_PRINTF_STATE_FORWARD(bool) + LOKI_PRINTF_STATE_FORWARD(char) + LOKI_PRINTF_STATE_FORWARD(signed char) + LOKI_PRINTF_STATE_FORWARD(unsigned char) + LOKI_PRINTF_STATE_FORWARD(signed short) + LOKI_PRINTF_STATE_FORWARD(unsigned short) + LOKI_PRINTF_STATE_FORWARD(signed int) + LOKI_PRINTF_STATE_FORWARD(signed long) +#if (defined(_WIN32) || defined(_WIN64)) + LOKI_PRINTF_STATE_FORWARD(unsigned long) +#else + // on Windows already defined by uintptr_t + LOKI_PRINTF_STATE_FORWARD(unsigned int) +#endif + + // Print (or gobble in case of the "*" specifier) an int + PrintfState& operator()(LOKI_SAFEFORMAT_UNSIGNED_LONG i) { + if (result_ == -1) return *this; // don't even bother + // % [flags] [width] [.prec] [modifier] type_char + // Fetch the flags + ReadFlags(); + if (*format_ == '*') { + // read the width and get out + SetWidth(static_cast<size_t>(i)); + ++format_; + return *this; + } + ReadWidth(); + // precision + if (*format_ == '.') { + // deal with precision + if (format_[1] == '*') { + // read the precision and get out + SetPrec(static_cast<size_t>(i)); + format_ += 2; + return *this; + } + ReadPrecision(); + } + ReadModifiers(); + // input size modifier + if (ForceShort()) { + // short int + const Char c = *format_; + if (c == 'x' || c == 'X' || c == 'u' || c == 'o') { + i = static_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(static_cast<unsigned short>(i)); + } + } + FormatWithCurrentFlags(i); + return *this; + } + + PrintfState& operator()(void* n) { + if (result_ == -1) return *this; // don't even bother + PrintUsing_snprintf(n,"p"); + return *this; + } + + PrintfState& operator()(double n) { + if (result_ == -1) return *this; // don't even bother + PrintUsing_snprintf(n,"eEfgG"); + return *this; + } + + PrintfState& operator()(long double n) { + if (result_ == -1) return *this; // don't even bother + PrintUsing_snprintf(n,"eEfgG"); + return *this; + } + + // Store the number of characters printed so far + PrintfState& operator()(int * pi) { + return StoreCountHelper(pi); + } + + // Store the number of characters printed so far + PrintfState& operator()(short * pi) { + return StoreCountHelper(pi); + } + + // Store the number of characters printed so far + PrintfState& operator()(long * pi) { + return StoreCountHelper(pi); + } + + PrintfState& operator()(const std::string& stdstr) { + return operator()(stdstr.c_str()); + } + + PrintfState& operator()(const char *const s) { + if (result_ == -1) return *this; + ReadLeaders(); + const char fmt = *format_; + if (fmt == 'p') { + FormatWithCurrentFlags(reinterpret_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(s)); + return *this; + } + if (fmt != 's') { + result_ = -1; + return *this; + } + const size_t len = std::min(std::strlen(s), prec_); + if (width_ > len) { + if (LeftJustify()) { + Write(s, s + len); + Fill(' ', width_ - len); + } else { + Fill(' ', width_ - len); + Write(s, s + len); + } + } else { + Write(s, s + len); + } + Next(); + return *this; + } + + PrintfState& operator()(const void *const p) { + return (*this)(reinterpret_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(p)); + } + + // read the result + operator int() const { + return static_cast<int>(result_); + } + + private: + PrintfState& operator=(const PrintfState&); + template <typename T> + PrintfState& StoreCountHelper(T *const pi) { + if (result_ == -1) return *this; // don't even bother + ReadLeaders(); + const char fmt = *format_; + if (fmt == 'p') { // pointer + FormatWithCurrentFlags(reinterpret_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(pi)); + return *this; + } + if (fmt != 'n') { + result_ = -1; + return *this; + } + assert(pi != 0); + *pi = result_; + Next(); + return *this; + } + + void FormatWithCurrentFlags(const LOKI_SAFEFORMAT_UNSIGNED_LONG i) { + // look at the format character + Char formatChar = *format_; + bool isSigned = formatChar == 'd' || formatChar == 'i'; + if (formatChar == 'p') { + formatChar = 'x'; // pointers go to hex + SetAlternateForm(); // printed with '0x' in front + isSigned = true; // that's what gcc does + } + if (!strchr("cdiuoxX", formatChar)) { + result_ = -1; + return; + } + Char buf[ + sizeof(LOKI_SAFEFORMAT_UNSIGNED_LONG) * 3 // digits + + 1 // sign or ' ' + + 2 // 0x or 0X + + 1]; // terminating zero + const Char *const bufEnd = buf + (sizeof(buf) / sizeof(Char)); + Char * bufLast = buf + (sizeof(buf) / sizeof(Char) - 1); + Char signChar = 0; + unsigned int base = 10; + + if (formatChar == 'c') { + // Format only one character + // The 'fill with zeros' flag is ignored + ResetFillZeros(); + *bufLast = static_cast<char>(i); + } else { + // TODO: inefficient code, refactor + const bool negative = isSigned && static_cast<LOKI_SAFEFORMAT_SIGNED_LONG>(i) < 0; + if (formatChar == 'o') base = 8; + else if (formatChar == 'x' || formatChar == 'X') base = 16; + bufLast = isSigned + ? RenderWithoutSign(static_cast<LOKI_SAFEFORMAT_SIGNED_LONG>(i), bufLast, base, + formatChar == 'X') + : RenderWithoutSign(i, bufLast, base, + formatChar == 'X'); + // Add the sign + if (isSigned) { + negative ? signChar = '-' + : ShowSignAlways() ? signChar = '+' + : Blank() ? signChar = ' ' + : 0; + } + } + // precision + size_t + countDigits = bufEnd - bufLast, + countZeros = prec_ != size_t(-1) && countDigits < prec_ && + formatChar != 'c' + ? prec_ - countDigits + : 0, + countBase = base != 10 && AlternateForm() && i != 0 + ? (base == 16 ? 2 : countZeros > 0 ? 0 : 1) + : 0, + countSign = (signChar != 0), + totalPrintable = countDigits + countZeros + countBase + countSign; + size_t countPadLeft = 0, countPadRight = 0; + if (width_ > totalPrintable) { + if (LeftJustify()) { + countPadRight = width_ - totalPrintable; + countPadLeft = 0; + } else { + countPadLeft = width_ - totalPrintable; + countPadRight = 0; + } + } + if (FillZeros() && prec_ == size_t(-1)) { + // pad with zeros and no precision - transfer padding to precision + countZeros = countPadLeft; + countPadLeft = 0; + } + // ok, all computed, ready to print to device + Fill(' ', countPadLeft); + if (signChar != 0) Write(&signChar, &signChar + 1); + if (countBase > 0) Fill('0', 1); + if (countBase == 2) Fill(formatChar, 1); + Fill('0', countZeros); + Write(bufLast, bufEnd); + Fill(' ', countPadRight); + // done, advance + Next(); + } + + void Write(const Char* b, const Char* e) { + if (result_ < 0) return; + const LOKI_SAFEFORMAT_SIGNED_LONG x = e - b; + write(device_, b, e); + result_ += x; + } + + template <class Value> + void PrintUsing_snprintf(Value n, const char* check_fmt_char) { + const Char *const fmt = format_ - 1; + assert(*fmt == '%'); + // enforce format string validity + ReadLeaders(); + // enforce format spec + if (!strchr(check_fmt_char, *format_)) { + result_ = -1; + return; + } + // format char validated, copy it to a temp and use legacy sprintf + ++format_; + Char fmtBuf[128], resultBuf[1024]; + if (format_ >= fmt + sizeof(fmtBuf) / sizeof(Char)) { + result_ = -1; + return; + } + memcpy(fmtBuf, fmt, (format_ - fmt) * sizeof(Char)); + fmtBuf[format_ - fmt] = 0; + + const int stored = +#ifdef _MSC_VER +#if _MSC_VER < 1400 + _snprintf +#else + _snprintf_s +#endif +#else + snprintf +#endif + (resultBuf, sizeof(resultBuf) / sizeof(Char), fmtBuf, n); + + if (stored < 0) { + result_ = -1; + return; + } + Write(resultBuf, resultBuf + strlen(resultBuf)); + Advance(); // output stuff to the next format directive + } + + void Fill(const Char c, size_t n) { + for (; n > 0; --n) { + Write(&c, &c + 1); + } + } + + Char* RenderWithoutSign(LOKI_SAFEFORMAT_UNSIGNED_LONG n, char* bufLast, + unsigned int base, bool uppercase) { + const Char hex1st = uppercase ? 'A' : 'a'; + for (;;) { + const LOKI_SAFEFORMAT_UNSIGNED_LONG next = n / base; + Char c = static_cast<Char>(n - next * base); + c = static_cast<Char>(c + (c <= 9 ? '0' : static_cast<Char>(hex1st - 10))); + *bufLast = c; + n = next; + if (n == 0) break; + --bufLast; + } + return bufLast; + } + + char* RenderWithoutSign(LOKI_SAFEFORMAT_SIGNED_LONG n, char* bufLast, unsigned int base, + bool uppercase) { + if (n != LONG_MIN) { + return RenderWithoutSign(static_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(n < 0 ? -n : n), + bufLast, base, uppercase); + } + // annoying corner case + char* save = bufLast; + ++n; + bufLast = RenderWithoutSign(static_cast<LOKI_SAFEFORMAT_UNSIGNED_LONG>(n), + bufLast, base, uppercase); + --(*save); + return bufLast; + } + + void Next() { + ++format_; + Advance(); + } + + void Advance() { + ResetAll(); + const Char* begin = format_; + for (;;) { + if (*format_ == '%') { + if (format_[1] != '%') { // It's a format specifier + Write(begin, format_); + ++format_; + break; + } + // It's a "%%" + Write(begin, ++format_); + begin = ++format_; + continue; + } + if (*format_ == 0) { + Write(begin, format_); + break; + } + ++format_; + } + } + + void ReadFlags() { + for (;; ++format_) { + switch (*format_) { + case '-': SetLeftJustify(); break; + case '+': SetShowSignAlways(); break; + case ' ': SetBlank(); break; + case '#': SetAlternateForm(); break; + case '0': SetFillZeros(); break; + default: return; + } + } + } + + void ParseDecimalSizeT(size_t& dest) { + if (!std::isdigit(*format_, std::locale())) return; + size_t r = 0; + do { + // TODO: inefficient - rewrite + r *= 10; + r += *format_ - '0'; + ++format_; + } while (std::isdigit(*format_, std::locale())); + dest = r; + } + + void ReadWidth() { + ParseDecimalSizeT(width_); + } + + void ReadPrecision() { + assert(*format_ == '.'); + ++format_; + ParseDecimalSizeT(prec_); + } + + void ReadModifiers() { + switch (*format_) { + case 'h': SetForceShort(); ++format_; break; + case 'l': ++format_; break; + // more (C99 and platform-specific modifiers) to come + } + } + + void ReadLeaders() { + ReadFlags(); + ReadWidth(); + if (*format_ == '.') ReadPrecision(); + ReadModifiers(); + } + + enum { + leftJustify = 1, + showSignAlways = 2, + blank = 4, + alternateForm = 8, + fillZeros = 16, + forceShort = 32 + }; + + bool LeftJustify() const { return (flags_ & leftJustify) != 0; } + bool ShowSignAlways() const { return (flags_ & showSignAlways) != 0; } + void SetWidth(size_t w) { width_ = w; } + void SetLeftJustify() { flags_ |= leftJustify; } + void SetShowSignAlways() { flags_ |= showSignAlways; } + bool Blank() const { return (flags_ & blank) != 0; } + bool AlternateForm() const { return (flags_ & alternateForm) != 0; } + bool FillZeros() const { return (flags_ & fillZeros) != 0; } + bool ForceShort() const { return (flags_ & forceShort) != 0; } + + void SetPrec(size_t p) { prec_ = p; } + void SetBlank() { flags_ |= blank; } + void SetAlternateForm() { flags_ |= alternateForm; } + void SetFillZeros() { flags_ |= fillZeros; } + void ResetFillZeros() { flags_ &= ~fillZeros; } + void SetForceShort() { flags_ |= forceShort; } + + void ResetAll() { + assert(result_ != EOF); + width_ = 0; + prec_ = size_t(-1); + flags_ = 0; + } + + // state + Device device_; + const Char* format_; + size_t width_; + size_t prec_; + unsigned int flags_; + LOKI_SAFEFORMAT_SIGNED_LONG result_; + }; + + LOKI_EXPORT + PrintfState<std::FILE*, char> Printf(const char* format); + + LOKI_EXPORT + PrintfState<std::FILE*, char> Printf(const std::string& format); + + LOKI_EXPORT + PrintfState<std::FILE*, char> FPrintf(std::FILE* f, const char* format); + + LOKI_EXPORT + PrintfState<std::FILE*, char> FPrintf(std::FILE* f, const std::string& format); + + LOKI_EXPORT + PrintfState<std::ostream&, char> FPrintf(std::ostream& f, const char* format); + + LOKI_EXPORT + PrintfState<std::ostream&, char> FPrintf(std::ostream& f, const std::string& format); + + LOKI_EXPORT + PrintfState<std::string&, char> SPrintf(std::string& s, const char* format); + + LOKI_EXPORT + PrintfState<std::string&, char> SPrintf(std::string& s, const std::string& format); + + template <class T, class Char> + PrintfState<T&, Char> XPrintf(T& device, const Char* format) { + return PrintfState<T&, Char>(device, format); + } + + template <class T> + PrintfState<T&, char> XPrintf(T& device, const std::string& format) { + return PrintfState<T&, char>(device, format.c_str()); + } + + template <class Char, std::size_t N> + PrintfState<std::pair<Char*, std::size_t>, Char> + BufPrintf(Char (&buf)[N], const Char* format) { + std::pair<Char*, std::size_t> temp(buf, N); + return PrintfState<std::pair<Char*, std::size_t>, Char>(temp, format); + } + +}// namespace Loki + + +#endif // end file guardian + diff --git a/shared/loki/ScopeGuard.h b/shared/loki/ScopeGuard.h new file mode 100644 index 00000000..a7e61ddd --- /dev/null +++ b/shared/loki/ScopeGuard.h @@ -0,0 +1,666 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2000 Andrei Alexandrescu +// Copyright (c) 2000 Petru Marginean +// Copyright (c) 2005 Joshua Lehrer +// +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_SCOPEGUARD_INC_ +#define LOKI_SCOPEGUARD_INC_ + +// $Id: ScopeGuard.h 799 2006-12-20 00:37:13Z rich_sposato $ + + +#include <loki/RefToValue.h> + +/// \defgroup ExceptionGroup Exception-safe code + +namespace Loki +{ + + //////////////////////////////////////////////////////////////// + /// + /// \class ScopeGuardImplBase + /// \ingroup ExceptionGroup + /// + /// Base class used by all ScopeGuard implementations. All commonly used + /// functions are in this class (e.g. - Dismiss and SafeExecute). + /// + /// See Andrei's and Petru Marginean's CUJ article + /// http://www.cuj.com/documents/s=8000/cujcexp1812alexandr/alexandr.htm + /// + /// Changes to the original code by Joshua Lehrer: + /// http://www.lehrerfamily.com/scopeguard.html + //////////////////////////////////////////////////////////////// + + class ScopeGuardImplBase + { + /// Copy-assignment operator is not implemented and private. + ScopeGuardImplBase& operator =(const ScopeGuardImplBase&); + + protected: + + ~ScopeGuardImplBase() + {} + + /// Copy-constructor takes over responsibility from other ScopeGuard. + ScopeGuardImplBase(const ScopeGuardImplBase& other) throw() + : dismissed_(other.dismissed_) + { + other.Dismiss(); + } + + template <typename J> + static void SafeExecute(J& j) throw() + { + if (!j.dismissed_) + try + { + j.Execute(); + } + catch(...) + {} + } + + mutable bool dismissed_; + + public: + ScopeGuardImplBase() throw() : dismissed_(false) + {} + + void Dismiss() const throw() + { + dismissed_ = true; + } + }; + + //////////////////////////////////////////////////////////////// + /// + /// \typedef typedef const ScopeGuardImplBase& ScopeGuard + /// \ingroup ExceptionGroup + /// + //////////////////////////////////////////////////////////////// + + typedef const ScopeGuardImplBase& ScopeGuard; + + //////////////////////////////////////////////////////////////// + /// + /// \class ScopeGuardImpl0 + /// \ingroup ExceptionGroup + /// + /// Implementation class for a standalone function or class static function + /// with no parameters. ScopeGuard ignores any value returned from the + /// call within the Execute function. + /// + /// This class has a single standalone helper function, MakeGuard which + /// creates and returns a ScopeGuard. + /// + //////////////////////////////////////////////////////////////// + + template <typename F> + class ScopeGuardImpl0 : public ScopeGuardImplBase + { + public: + static ScopeGuardImpl0<F> MakeGuard(F fun) + { + return ScopeGuardImpl0<F>(fun); + } + + ~ScopeGuardImpl0() throw() + { + SafeExecute(*this); + } + + void Execute() + { + fun_(); + } + + protected: + ScopeGuardImpl0(F fun) : fun_(fun) + {} + + F fun_; + }; + + template <typename F> + inline ScopeGuardImpl0<F> MakeGuard(F fun) + { + return ScopeGuardImpl0<F>::MakeGuard(fun); + } + + //////////////////////////////////////////////////////////////// + /// + /// \class ScopeGuardImpl1 + /// \ingroup ExceptionGroup + /// + /// Implementation class for a standalone function or class static function + /// with one parameter. Each parameter is copied by value - use + /// ::Loki::ByRef if you must use a reference instead. ScopeGuard ignores + /// any value returned from the call within the Execute function. + /// + /// This class has a single standalone helper function, MakeGuard which + /// creates and returns a ScopeGuard. + /// + //////////////////////////////////////////////////////////////// + + template <typename F, typename P1> + class ScopeGuardImpl1 : public ScopeGuardImplBase + { + public: + static ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1) + { + return ScopeGuardImpl1<F, P1>(fun, p1); + } + + ~ScopeGuardImpl1() throw() + { + SafeExecute(*this); + } + + void Execute() + { + fun_(p1_); + } + + protected: + ScopeGuardImpl1(F fun, P1 p1) : fun_(fun), p1_(p1) + {} + + F fun_; + const P1 p1_; + }; + + template <typename F, typename P1> + inline ScopeGuardImpl1<F, P1> MakeGuard(F fun, P1 p1) + { + return ScopeGuardImpl1<F, P1>::MakeGuard(fun, p1); + } + + //////////////////////////////////////////////////////////////// + /// + /// \class ScopeGuardImpl2 + /// \ingroup ExceptionGroup + /// + /// Implementation class for a standalone function or class static function + /// with two parameters. Each parameter is copied by value - use + /// ::Loki::ByRef if you must use a reference instead. ScopeGuard ignores + /// any value returned from the call within the Execute function. + /// + /// This class has a single standalone helper function, MakeGuard which + /// creates and returns a ScopeGuard. + /// + //////////////////////////////////////////////////////////////// + + template <typename F, typename P1, typename P2> + class ScopeGuardImpl2: public ScopeGuardImplBase + { + public: + static ScopeGuardImpl2<F, P1, P2> MakeGuard(F fun, P1 p1, P2 p2) + { + return ScopeGuardImpl2<F, P1, P2>(fun, p1, p2); + } + + ~ScopeGuardImpl2() throw() + { + SafeExecute(*this); + } + + void Execute() + { + fun_(p1_, p2_); + } + + protected: + ScopeGuardImpl2(F fun, P1 p1, P2 p2) : fun_(fun), p1_(p1), p2_(p2) + {} + + F fun_; + const P1 p1_; + const P2 p2_; + }; + + template <typename F, typename P1, typename P2> + inline ScopeGuardImpl2<F, P1, P2> MakeGuard(F fun, P1 p1, P2 p2) + { + return ScopeGuardImpl2<F, P1, P2>::MakeGuard(fun, p1, p2); + } + + //////////////////////////////////////////////////////////////// + /// + /// \class ScopeGuardImpl3 + /// \ingroup ExceptionGroup + /// + /// Implementation class for a standalone function or class static function + /// with three parameters. Each parameter is copied by value - use + /// ::Loki::ByRef if you must use a reference instead. ScopeGuard ignores + /// any value returned from the call within the Execute function. + /// + /// This class has a single standalone helper function, MakeGuard which + /// creates and returns a ScopeGuard. + /// + //////////////////////////////////////////////////////////////// + + template <typename F, typename P1, typename P2, typename P3> + class ScopeGuardImpl3 : public ScopeGuardImplBase + { + public: + static ScopeGuardImpl3<F, P1, P2, P3> MakeGuard(F fun, P1 p1, P2 p2, P3 p3) + { + return ScopeGuardImpl3<F, P1, P2, P3>(fun, p1, p2, p3); + } + + ~ScopeGuardImpl3() throw() + { + SafeExecute(*this); + } + + void Execute() + { + fun_(p1_, p2_, p3_); + } + + protected: + ScopeGuardImpl3(F fun, P1 p1, P2 p2, P3 p3) : fun_(fun), p1_(p1), p2_(p2), p3_(p3) + {} + + F fun_; + const P1 p1_; + const P2 p2_; + const P3 p3_; + }; + + template <typename F, typename P1, typename P2, typename P3> + inline ScopeGuardImpl3<F, P1, P2, P3> MakeGuard(F fun, P1 p1, P2 p2, P3 p3) + { + return ScopeGuardImpl3<F, P1, P2, P3>::MakeGuard(fun, p1, p2, p3); + } + + //////////////////////////////////////////////////////////////// + /// + /// \class ScopeGuardImpl4 + /// \ingroup ExceptionGroup + /// + /// Implementation class for a standalone function or class static function + /// with four parameters. Each parameter is copied by value - use + /// ::Loki::ByRef if you must use a reference instead. ScopeGuard ignores + /// any value returned from the call within the Execute function. + /// + /// This class has a single standalone helper function, MakeGuard which + /// creates and returns a ScopeGuard. + /// + //////////////////////////////////////////////////////////////// + + template < typename F, typename P1, typename P2, typename P3, typename P4 > + class ScopeGuardImpl4 : public ScopeGuardImplBase + { + public: + static ScopeGuardImpl4< F, P1, P2, P3, P4 > MakeGuard( + F fun, P1 p1, P2 p2, P3 p3, P4 p4 ) + { + return ScopeGuardImpl4< F, P1, P2, P3, P4 >( fun, p1, p2, p3, p4 ); + } + + ~ScopeGuardImpl4() throw() + { + SafeExecute( *this ); + } + + void Execute() + { + fun_( p1_, p2_, p3_, p4_ ); + } + + protected: + ScopeGuardImpl4( F fun, P1 p1, P2 p2, P3 p3, P4 p4 ) : + fun_( fun ), p1_( p1 ), p2_( p2 ), p3_( p3 ), p4_( p4 ) + {} + + F fun_; + const P1 p1_; + const P2 p2_; + const P3 p3_; + const P4 p4_; + }; + + template < typename F, typename P1, typename P2, typename P3, typename P4 > + inline ScopeGuardImpl4< F, P1, P2, P3, P4 > MakeGuard( F fun, P1 p1, P2 p2, P3 p3, P4 p4 ) + { + return ScopeGuardImpl4< F, P1, P2, P3, P4 >::MakeGuard( fun, p1, p2, p3, p4 ); + } + + //////////////////////////////////////////////////////////////// + /// + /// \class ScopeGuardImpl5 + /// \ingroup ExceptionGroup + /// + /// Implementation class for a standalone function or class static function + /// with five parameters. Each parameter is copied by value - use + /// ::Loki::ByRef if you must use a reference instead. ScopeGuard ignores + /// any value returned from the call within the Execute function. + /// + /// This class has a single standalone helper function, MakeGuard which + /// creates and returns a ScopeGuard. + /// + //////////////////////////////////////////////////////////////// + + template < typename F, typename P1, typename P2, typename P3, typename P4, typename P5 > + class ScopeGuardImpl5 : public ScopeGuardImplBase + { + public: + static ScopeGuardImpl5< F, P1, P2, P3, P4, P5 > MakeGuard( + F fun, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5 ) + { + return ScopeGuardImpl5< F, P1, P2, P3, P4, P5 >( fun, p1, p2, p3, p4, p5 ); + } + + ~ScopeGuardImpl5() throw() + { + SafeExecute( *this ); + } + + void Execute() + { + fun_( p1_, p2_, p3_, p4_, p5_ ); + } + + protected: + ScopeGuardImpl5( F fun, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5 ) : + fun_( fun ), p1_( p1 ), p2_( p2 ), p3_( p3 ), p4_( p4 ), p5_( p5 ) + {} + + F fun_; + const P1 p1_; + const P2 p2_; + const P3 p3_; + const P4 p4_; + const P5 p5_; + }; + + template < typename F, typename P1, typename P2, typename P3, typename P4, typename P5 > + inline ScopeGuardImpl5< F, P1, P2, P3, P4, P5 > MakeGuard( F fun, P1 p1, P2 p2, P3 p3, P4 p4, P5 p5 ) + { + return ScopeGuardImpl5< F, P1, P2, P3, P4, P5 >::MakeGuard( fun, p1, p2, p3, p4, p5 ); + } + + //////////////////////////////////////////////////////////////// + /// + /// \class ObjScopeGuardImpl0 + /// \ingroup ExceptionGroup + /// + /// Implementation class for a class per-instance member function with no + /// parameters. ScopeGuard ignores any value returned from the call within + /// the Execute function. + /// + /// This class has 3 standalone helper functions which create a ScopeGuard. + /// One is MakeObjGuard, which is deprecated but provided for older code. + /// The other two are MakeGuard overloads, one which takes a pointer to an + /// object, and the other which takes a reference. + /// + //////////////////////////////////////////////////////////////// + + template <class Obj, typename MemFun> + class ObjScopeGuardImpl0 : public ScopeGuardImplBase + { + public: + static ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun) + { + return ObjScopeGuardImpl0<Obj, MemFun>(obj, memFun); + } + + ~ObjScopeGuardImpl0() throw() + { + SafeExecute(*this); + } + + void Execute() + { + (obj_.*memFun_)(); + } + + protected: + ObjScopeGuardImpl0(Obj& obj, MemFun memFun) : obj_(obj), memFun_(memFun) + {} + + Obj& obj_; + MemFun memFun_; + }; + + template <class Obj, typename MemFun> + inline ObjScopeGuardImpl0<Obj, MemFun> MakeObjGuard(Obj& obj, MemFun memFun) + { + return ObjScopeGuardImpl0<Obj, MemFun>::MakeObjGuard(obj, memFun); + } + + template <typename Ret, class Obj1, class Obj2> + inline ObjScopeGuardImpl0<Obj1,Ret(Obj2::*)()> MakeGuard(Ret(Obj2::*memFun)(), Obj1 &obj) + { + return ObjScopeGuardImpl0<Obj1,Ret(Obj2::*)()>::MakeObjGuard(obj,memFun); + } + + template <typename Ret, class Obj1, class Obj2> + inline ObjScopeGuardImpl0<Obj1,Ret(Obj2::*)()> MakeGuard(Ret(Obj2::*memFun)(), Obj1 *obj) + { + return ObjScopeGuardImpl0<Obj1,Ret(Obj2::*)()>::MakeObjGuard(*obj,memFun); + } + + //////////////////////////////////////////////////////////////// + /// + /// \class ObjScopeGuardImpl1 + /// \ingroup ExceptionGroup + /// + /// Implementation class for a class per-instance member function with one + /// parameter. The parameter is copied by value - use ::Loki::ByRef if you + /// must use a reference instead. ScopeGuard ignores any value returned + /// from the call within the Execute function. + /// + /// This class has 3 standalone helper functions which create a ScopeGuard. + /// One is MakeObjGuard, which is deprecated but provided for older code. + /// The other two are MakeGuard overloads, one which takes a pointer to an + /// object, and the other which takes a reference. + /// + //////////////////////////////////////////////////////////////// + + template <class Obj, typename MemFun, typename P1> + class ObjScopeGuardImpl1 : public ScopeGuardImplBase + { + public: + static ObjScopeGuardImpl1<Obj, MemFun, P1> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1) + { + return ObjScopeGuardImpl1<Obj, MemFun, P1>(obj, memFun, p1); + } + + ~ObjScopeGuardImpl1() throw() + { + SafeExecute(*this); + } + + void Execute() + { + (obj_.*memFun_)(p1_); + } + + protected: + ObjScopeGuardImpl1(Obj& obj, MemFun memFun, P1 p1) : obj_(obj), memFun_(memFun), p1_(p1) + {} + + Obj& obj_; + MemFun memFun_; + const P1 p1_; + }; + + template <class Obj, typename MemFun, typename P1> + inline ObjScopeGuardImpl1<Obj, MemFun, P1> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1) + { + return ObjScopeGuardImpl1<Obj, MemFun, P1>::MakeObjGuard(obj, memFun, p1); + } + + template <typename Ret, class Obj1, class Obj2, typename P1a, typename P1b> + inline ObjScopeGuardImpl1<Obj1,Ret(Obj2::*)(P1a),P1b> MakeGuard(Ret(Obj2::*memFun)(P1a), Obj1 &obj, P1b p1) + { + return ObjScopeGuardImpl1<Obj1,Ret(Obj2::*)(P1a),P1b>::MakeObjGuard(obj,memFun,p1); + } + + template <typename Ret, class Obj1, class Obj2, typename P1a, typename P1b> + inline ObjScopeGuardImpl1<Obj1,Ret(Obj2::*)(P1a),P1b> MakeGuard(Ret(Obj2::*memFun)(P1a), Obj1 *obj, P1b p1) + { + return ObjScopeGuardImpl1<Obj1,Ret(Obj2::*)(P1a),P1b>::MakeObjGuard(*obj,memFun,p1); + } + + //////////////////////////////////////////////////////////////// + /// + /// \class ObjScopeGuardImpl2 + /// \ingroup ExceptionGroup + /// + /// Implementation class for a class per-instance member function with two + /// parameters. Each parameter is copied by value - use ::Loki::ByRef if you + /// must use a reference instead. ScopeGuard ignores any value returned + /// from the call within the Execute function. + /// + /// This class has 3 standalone helper functions which create a ScopeGuard. + /// One is MakeObjGuard, which is deprecated but provided for older code. + /// The other two are MakeGuard overloads, one which takes a pointer to an + /// object, and the other which takes a reference. + /// + //////////////////////////////////////////////////////////////// + + template <class Obj, typename MemFun, typename P1, typename P2> + class ObjScopeGuardImpl2 : public ScopeGuardImplBase + { + public: + static ObjScopeGuardImpl2<Obj, MemFun, P1, P2> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2) + { + return ObjScopeGuardImpl2<Obj, MemFun, P1, P2>(obj, memFun, p1, p2); + } + + ~ObjScopeGuardImpl2() throw() + { + SafeExecute(*this); + } + + void Execute() + { + (obj_.*memFun_)(p1_, p2_); + } + + protected: + ObjScopeGuardImpl2(Obj& obj, MemFun memFun, P1 p1, P2 p2) : obj_(obj), memFun_(memFun), p1_(p1), p2_(p2) + {} + + Obj& obj_; + MemFun memFun_; + const P1 p1_; + const P2 p2_; + }; + + template <class Obj, typename MemFun, typename P1, typename P2> + inline ObjScopeGuardImpl2<Obj, MemFun, P1, P2> MakeObjGuard(Obj& obj, MemFun memFun, P1 p1, P2 p2) + { + return ObjScopeGuardImpl2<Obj, MemFun, P1, P2>::MakeObjGuard(obj, memFun, p1, p2); + } + + template <typename Ret, class Obj1, class Obj2, typename P1a, typename P1b, typename P2a, typename P2b> + inline ObjScopeGuardImpl2<Obj1,Ret(Obj2::*)(P1a,P2a),P1b,P2b> MakeGuard(Ret(Obj2::*memFun)(P1a,P2a), Obj1 &obj, P1b p1, P2b p2) + { + return ObjScopeGuardImpl2<Obj1,Ret(Obj2::*)(P1a,P2a),P1b,P2b>::MakeObjGuard(obj,memFun,p1,p2); + } + + template <typename Ret, class Obj1, class Obj2, typename P1a, typename P1b, typename P2a, typename P2b> + inline ObjScopeGuardImpl2<Obj1,Ret(Obj2::*)(P1a,P2a),P1b,P2b> MakeGuard(Ret(Obj2::*memFun)(P1a,P2a), Obj1 *obj, P1b p1, P2b p2) + { + return ObjScopeGuardImpl2<Obj1,Ret(Obj2::*)(P1a,P2a),P1b,P2b>::MakeObjGuard(*obj,memFun,p1,p2); + } + + //////////////////////////////////////////////////////////////// + /// + /// \class ObjScopeGuardImpl3 + /// \ingroup ExceptionGroup + /// + /// Implementation class for a class per-instance member function with three + /// parameters. Each parameter is copied by value - use ::Loki::ByRef if you + /// must use a reference instead. ScopeGuard ignores any value returned + /// from the call within the Execute function. + /// + /// This class has 3 standalone helper functions which create a ScopeGuard. + /// One is MakeObjGuard, which is deprecated but provided for older code. + /// The other two are MakeGuard overloads, one which takes a pointer to an + /// object, and the other which takes a reference. + /// + //////////////////////////////////////////////////////////////// + + template < class Obj, typename MemFun, typename P1, typename P2, typename P3 > + class ObjScopeGuardImpl3 : public ScopeGuardImplBase + { + public: + static ObjScopeGuardImpl3< Obj, MemFun, P1, P2, P3 > MakeObjGuard( + Obj & obj, MemFun memFun, P1 p1, P2 p2, P3 p3 ) + { + return ObjScopeGuardImpl3< Obj, MemFun, P1, P2, P3 >( obj, memFun, p1, p2, p3 ); + } + + ~ObjScopeGuardImpl3() throw() + { + SafeExecute( *this ); + } + + void Execute() + { + ( obj_.*memFun_ )( p1_, p2_, p3_ ); + } + + protected: + ObjScopeGuardImpl3( Obj & obj, MemFun memFun, P1 p1, P2 p2, P3 p3 ) : + obj_( obj ), memFun_( memFun ), p1_( p1 ), p2_( p2 ), p3_( p3 ) + {} + + Obj& obj_; + MemFun memFun_; + const P1 p1_; + const P2 p2_; + const P3 p3_; + }; + + template < class Obj, typename MemFun, typename P1, typename P2, typename P3 > + inline ObjScopeGuardImpl3< Obj, MemFun, P1, P2, P3 > MakeObjGuard( + Obj & obj, MemFun memFun, P1 p1, P2 p2, P3 p3 ) + { + return ObjScopeGuardImpl3< Obj, MemFun, P1, P2, P3 >::MakeObjGuard( + obj, memFun, p1, p2, p3 ); + } + + template < typename Ret, class Obj1, class Obj2, typename P1a, typename P1b, + typename P2a, typename P2b, typename P3a, typename P3b > + inline ObjScopeGuardImpl3< Obj1, Ret( Obj2::* )( P1a, P2a, P3a ), P1b, P2b, P3b > + MakeGuard( Ret( Obj2::*memFun )( P1a, P2a, P3a ), Obj1 & obj, P1b p1, P2b p2, P3b p3 ) + { + return ObjScopeGuardImpl3< Obj1, Ret( Obj2::* )( P1a, P2a, P3a ), P1b, P2b, P3b > + ::MakeObjGuard( obj, memFun, p1, p2, p3 ); + } + + template < typename Ret, class Obj1, class Obj2, typename P1a, typename P1b, + typename P2a, typename P2b, typename P3a, typename P3b > + inline ObjScopeGuardImpl3< Obj1, Ret( Obj2::* )( P1a, P2a, P3a ), P1b, P2b, P3b > + MakeGuard( Ret( Obj2::*memFun )( P1a, P2a, P3a ), Obj1 * obj, P1b p1, P2b p2, P3b p3 ) + { + return ObjScopeGuardImpl3< Obj1, Ret( Obj2::* )( P1a, P2a, P3a ), P1b, P2b, P3b > + ::MakeObjGuard( *obj, memFun, p1, p2, p3 ); + } + +} // namespace Loki + +#define LOKI_CONCATENATE_DIRECT(s1, s2) s1##s2 +#define LOKI_CONCATENATE(s1, s2) LOKI_CONCATENATE_DIRECT(s1, s2) +#define LOKI_ANONYMOUS_VARIABLE(str) LOKI_CONCATENATE(str, __LINE__) + +#define LOKI_ON_BLOCK_EXIT ::Loki::ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = ::Loki::MakeGuard +#define LOKI_ON_BLOCK_EXIT_OBJ ::Loki::ScopeGuard LOKI_ANONYMOUS_VARIABLE(scopeGuard) = ::Loki::MakeObjGuard + +#endif // end file guardian + diff --git a/shared/loki/Sequence.h b/shared/loki/Sequence.h new file mode 100644 index 00000000..4e5bd235 --- /dev/null +++ b/shared/loki/Sequence.h @@ -0,0 +1,49 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2005 by Peter Kümmel +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_SEQUENCE_INC_ +#define LOKI_SEQUENCE_INC_ + +// $Id: Sequence.h 768 2006-10-25 20:40:40Z syntheticpp $ + + +#include "Typelist.h" + +namespace Loki +{ + + template + < + class T01=NullType,class T02=NullType,class T03=NullType,class T04=NullType,class T05=NullType, + class T06=NullType,class T07=NullType,class T08=NullType,class T09=NullType,class T10=NullType, + class T11=NullType,class T12=NullType,class T13=NullType,class T14=NullType,class T15=NullType, + class T16=NullType,class T17=NullType,class T18=NullType,class T19=NullType,class T20=NullType + > + struct Seq + { + private: + typedef typename Seq< T02, T03, T04, T05, T06, T07, T08, T09, T10, + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20>::Type + TailResult; + public: + typedef Typelist<T01, TailResult> Type; + }; + + template<> + struct Seq<> + { + typedef NullType Type; + }; + +} // namespace Loki + +#endif // end file guardian + diff --git a/shared/loki/Singleton.h b/shared/loki/Singleton.h new file mode 100644 index 00000000..42d6eb0d --- /dev/null +++ b/shared/loki/Singleton.h @@ -0,0 +1,889 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_SINGLETON_INC_ +#define LOKI_SINGLETON_INC_ + +// $Id: Singleton.h 834 2007-08-02 19:36:10Z syntheticpp $ + + +#include "LokiExport.h" +#include "Threads.h" +#include <algorithm> +#include <stdexcept> +#include <cassert> +#include <cstdlib> +#include <new> +#include <vector> +#include <list> +#include <memory> + +#ifdef _MSC_VER +#define LOKI_C_CALLING_CONVENTION_QUALIFIER __cdecl +#else +#define LOKI_C_CALLING_CONVENTION_QUALIFIER +#endif + +/// \defgroup SingletonGroup Singleton +/// \defgroup CreationGroup Creation policies +/// \ingroup SingletonGroup +/// \defgroup LifetimeGroup Lifetime policies +/// \ingroup SingletonGroup +/// The lifetimes of the singleton. +/// \par Special lifetime for SmallObjects +/// When the holded object is a Small(Value)Object or the holded object +/// uses objects which are or inherit from Small(Value)Object +/// then you can't use the default lifetime: you must use the lifetime +/// \code Loki::LongevityLifetime::DieAsSmallObjectChild \endcode +/// Be aware of this when you use Loki::Factory, Loki::Functor, or Loki::Function. + + + +namespace Loki +{ + typedef void (LOKI_C_CALLING_CONVENTION_QUALIFIER *atexit_pfn_t)(); + + namespace Private + { + +#ifndef LOKI_MAKE_DLL + void LOKI_C_CALLING_CONVENTION_QUALIFIER AtExitFn(); // declaration needed below +#else + void LOKI_EXPORT AtExitFn(); +#endif + + class LifetimeTracker; + +#define LOKI_ENABLE_NEW_SETLONGLIVITY_HELPER_DATA_IMPL +#ifdef LOKI_ENABLE_NEW_SETLONGLIVITY_HELPER_DATA_IMPL + + // Helper data + // std::list because of the inserts + typedef std::list<LifetimeTracker*> TrackerArray; + extern LOKI_EXPORT TrackerArray* pTrackerArray; +#else + // Helper data + typedef LifetimeTracker** TrackerArray; + extern TrackerArray pTrackerArray; + extern unsigned int elements; +#endif + + //////////////////////////////////////////////////////////////////////////////// + // class LifetimeTracker + // Helper class for SetLongevity + //////////////////////////////////////////////////////////////////////////////// + + class LifetimeTracker + { + public: + LifetimeTracker(unsigned int x) : longevity_(x) + {} + + virtual ~LifetimeTracker() = 0; + + static bool Compare(const LifetimeTracker* lhs, + const LifetimeTracker* rhs) + { + return lhs->longevity_ > rhs->longevity_; + } + + private: + unsigned int longevity_; + }; + + // Definition required + inline LifetimeTracker::~LifetimeTracker() {} + + // Helper destroyer function + template <typename T> + struct Deleter + { + typedef void (*Type)(T*); + static void Delete(T* pObj) + { delete pObj; } + }; + + // Concrete lifetime tracker for objects of type T + template <typename T, typename Destroyer> + class ConcreteLifetimeTracker : public LifetimeTracker + { + public: + ConcreteLifetimeTracker(T* p,unsigned int longevity, Destroyer d) + : LifetimeTracker(longevity) + , pTracked_(p) + , destroyer_(d) + {} + + ~ConcreteLifetimeTracker() + { destroyer_(pTracked_); } + + private: + T* pTracked_; + Destroyer destroyer_; + }; + + } // namespace Private + + //////////////////////////////////////////////////////////////////////////////// + /// \ingroup LifetimeGroup + /// + /// Assigns an object a longevity; ensures ordered destructions of objects + /// registered thusly during the exit sequence of the application + //////////////////////////////////////////////////////////////////////////////// + +#ifdef LOKI_ENABLE_NEW_SETLONGLIVITY_HELPER_DATA_IMPL + + template <typename T, typename Destroyer> + void SetLongevity(T* pDynObject, unsigned int longevity, + Destroyer d) + { + using namespace Private; + + // manage lifetime of stack manually + if(pTrackerArray==0) + pTrackerArray = new TrackerArray; + + // automatically delete the ConcreteLifetimeTracker object when a exception is thrown + std::auto_ptr<LifetimeTracker> + p( new ConcreteLifetimeTracker<T, Destroyer>(pDynObject, longevity, d) ); + + // Find correct position + TrackerArray::iterator pos = std::upper_bound( + pTrackerArray->begin(), + pTrackerArray->end(), + p.get(), + LifetimeTracker::Compare); + + // Insert the pointer to the ConcreteLifetimeTracker object into the queue + pTrackerArray->insert(pos, p.get()); + + // nothing has thrown: don't delete the ConcreteLifetimeTracker object + p.release(); + + // Register a call to AtExitFn + std::atexit(Private::AtExitFn); + } + +#else + + template <typename T, typename Destroyer> + void SetLongevity(T* pDynObject, unsigned int longevity, + Destroyer d) + { + using namespace Private; + + TrackerArray pNewArray = static_cast<TrackerArray>( + std::realloc(pTrackerArray, + sizeof(*pTrackerArray) * (elements + 1))); + if (!pNewArray) throw std::bad_alloc(); + + // Delayed assignment for exception safety + pTrackerArray = pNewArray; + + LifetimeTracker* p = new ConcreteLifetimeTracker<T, Destroyer>( + pDynObject, longevity, d); + + // Insert a pointer to the object into the queue + TrackerArray pos = std::upper_bound( + pTrackerArray, + pTrackerArray + elements, + p, + LifetimeTracker::Compare); + std::copy_backward( + pos, + pTrackerArray + elements, + pTrackerArray + elements + 1); + *pos = p; + ++elements; + + // Register a call to AtExitFn + std::atexit(Private::AtExitFn); + } + +#endif + + template <typename T> + void SetLongevity(T* pDynObject, unsigned int longevity, + typename Private::Deleter<T>::Type d = Private::Deleter<T>::Delete) + { + SetLongevity<T, typename Private::Deleter<T>::Type>(pDynObject, longevity, d); + } + + //////////////////////////////////////////////////////////////////////////////// + /// \struct CreateUsingNew + /// + /// \ingroup CreationGroup + /// Implementation of the CreationPolicy used by SingletonHolder + /// Creates objects using a straight call to the new operator + //////////////////////////////////////////////////////////////////////////////// + template <class T> struct CreateUsingNew + { + static T* Create() + { return new T; } + + static void Destroy(T* p) + { delete p; } + }; + + //////////////////////////////////////////////////////////////////////////////// + /// \struct CreateUsing + /// + /// \ingroup CreationGroup + /// Implementation of the CreationPolicy used by SingletonHolder + /// Creates objects using a custom allocater. + /// Usage: e.g. CreateUsing<std::allocator>::Allocator + //////////////////////////////////////////////////////////////////////////////// + template<template<class> class Alloc> + struct CreateUsing + { + template <class T> + struct Allocator + { + static Alloc<T> allocator; + + static T* Create() + { + return new (allocator.allocate(1)) T; + } + + static void Destroy(T* p) + { + //allocator.destroy(p); + p->~T(); + allocator.deallocate(p,1); + } + }; + }; + + //////////////////////////////////////////////////////////////////////////////// + /// \struct CreateUsingMalloc + /// + /// \ingroup CreationGroup + /// Implementation of the CreationPolicy used by SingletonHolder + /// Creates objects using a call to std::malloc, followed by a call to the + /// placement new operator + //////////////////////////////////////////////////////////////////////////////// + template <class T> struct CreateUsingMalloc + { + static T* Create() + { + void* p = std::malloc(sizeof(T)); + if (!p) return 0; + return new(p) T; + } + + static void Destroy(T* p) + { + p->~T(); + std::free(p); + } + }; + + + //////////////////////////////////////////////////////////////////////////////// + /// \struct CreateStatic + /// + /// \ingroup CreationGroup + /// Implementation of the CreationPolicy used by SingletonHolder + /// Creates an object in static memory + /// Implementation is slightly nonportable because it uses the MaxAlign trick + /// (an union of all types to ensure proper memory alignment). This trick is + /// nonportable in theory but highly portable in practice. + //////////////////////////////////////////////////////////////////////////////// + template <class T> struct CreateStatic + { + +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable : 4121 ) +// alignment of a member was sensitive to packing +#endif // _MSC_VER + + union MaxAlign + { + char t_[sizeof(T)]; + short int shortInt_; + int int_; + long int longInt_; + float float_; + double double_; + long double longDouble_; + struct Test; + int Test::* pMember_; + int (Test::*pMemberFn_)(int); + }; + +#ifdef _MSC_VER +#pragma warning( pop ) +#endif // _MSC_VER + + static T* Create() + { + static MaxAlign staticMemory_; + return new(&staticMemory_) T; + } + + static void Destroy(T* p) + { + p->~T(); + } + }; + + //////////////////////////////////////////////////////////////////////////////// + /// \struct DefaultLifetime + /// + /// \ingroup LifetimeGroup + /// Implementation of the LifetimePolicy used by SingletonHolder + /// Schedules an object's destruction as per C++ rules + /// Forwards to std::atexit + //////////////////////////////////////////////////////////////////////////////// + template <class T> + struct DefaultLifetime + { + static void ScheduleDestruction(T*, atexit_pfn_t pFun) + { std::atexit(pFun); } + + static void OnDeadReference() + { throw std::logic_error("Dead Reference Detected"); } + }; + + //////////////////////////////////////////////////////////////////////////////// + /// \struct PhoenixSingleton + /// + /// \ingroup LifetimeGroup + /// Implementation of the LifetimePolicy used by SingletonHolder + /// Schedules an object's destruction as per C++ rules, and it allows object + /// recreation by not throwing an exception from OnDeadReference + //////////////////////////////////////////////////////////////////////////////// + template <class T> + class PhoenixSingleton + { + public: + static void ScheduleDestruction(T*, atexit_pfn_t pFun) + { +#ifndef ATEXIT_FIXED + if (!destroyedOnce_) +#endif + std::atexit(pFun); + } + + static void OnDeadReference() + { +#ifndef ATEXIT_FIXED + destroyedOnce_ = true; +#endif + } + + private: +#ifndef ATEXIT_FIXED + static bool destroyedOnce_; +#endif + }; + +#ifndef ATEXIT_FIXED + template <class T> bool PhoenixSingleton<T>::destroyedOnce_ = false; +#endif + + //////////////////////////////////////////////////////////////////////////////// + // Copyright (c) 2004 by Curtis Krauskopf - curtis@decompile.com + /// + /// \struct DeletableSingleton + /// + /// \ingroup LifetimeGroup + /// + /// A DeletableSingleton allows the instantiated singleton to be + /// destroyed at any time. The singleton can be reinstantiated at + /// any time, even during program termination. + /// If the singleton exists when the program terminates, it will + /// be automatically deleted. + /// + /// \par Usage: + /// The singleton can be deleted manually: + /// + /// DeletableSingleton<MyClass>::GracefulDelete(); + //////////////////////////////////////////////////////////////////////////////// + template <class T> + class DeletableSingleton + { + public: + + static void ScheduleDestruction(T*, atexit_pfn_t pFun) + { + static bool firstPass = true; + isDead = false; + deleter = pFun; + if (firstPass || needCallback) + { + std::atexit(atexitCallback); + firstPass = false; + needCallback = false; + } + } + + static void OnDeadReference() + { + } + /// delete singleton object manually + static void GracefulDelete() + { + if (isDead) + return; + isDead = true; + deleter(); + } + + protected: + static atexit_pfn_t deleter; + static bool isDead; + static bool needCallback; + + static void atexitCallback() + { +#ifdef ATEXIT_FIXED + needCallback = true; +#else + needCallback = false; +#endif + GracefulDelete(); + } + }; + + template <class T> + atexit_pfn_t DeletableSingleton<T>::deleter = 0; + + template <class T> + bool DeletableSingleton<T>::isDead = true; + + template <class T> + bool DeletableSingleton<T>::needCallback = true; + + //////////////////////////////////////////////////////////////////////////////// + // class template Adapter + // Helper for SingletonWithLongevity below + //////////////////////////////////////////////////////////////////////////////// + + namespace Private + { + template <class T> + struct Adapter + { + void operator()(T*) { return pFun_(); } + atexit_pfn_t pFun_; + }; + } + + //////////////////////////////////////////////////////////////////////////////// + /// \struct SingletonWithLongevity + /// + /// \ingroup LifetimeGroup + /// Implementation of the LifetimePolicy used by SingletonHolder + /// Schedules an object's destruction in order of their longevities + /// Assumes a visible function GetLongevity(T*) that returns the longevity of the + /// object. + //////////////////////////////////////////////////////////////////////////////// + template <class T> + class SingletonWithLongevity + { + public: + static void ScheduleDestruction(T* pObj, atexit_pfn_t pFun) + { + Private::Adapter<T> adapter = { pFun }; + SetLongevity(pObj, GetLongevity(pObj), adapter); + } + + static void OnDeadReference() + { throw std::logic_error("Dead Reference Detected"); } + }; + + //////////////////////////////////////////////////////////////////////////////// + /// \struct NoDestroy + /// + /// \ingroup LifetimeGroup + /// Implementation of the LifetimePolicy used by SingletonHolder + /// Never destroys the object + //////////////////////////////////////////////////////////////////////////////// + template <class T> + struct NoDestroy + { + static void ScheduleDestruction(T*, atexit_pfn_t) + {} + + static void OnDeadReference() + {} + }; + + + //////////////////////////////////////////////////////////////////////////////// + /// \defgroup LongevityLifetimeGroup LongevityLifetime + /// \ingroup LifetimeGroup + /// + /// \namespace LongevityLifetime + /// + /// \ingroup LongevityLifetimeGroup + /// \brief In this namespace are special lifetime policies to manage lifetime + /// dependencies. + //////////////////////////////////////////////////////////////////////////////// + namespace LongevityLifetime + { + //////////////////////////////////////////////////////////////////////////////// + /// \struct SingletonFixedLongevity + /// + /// \ingroup LongevityLifetimeGroup + /// Add your own lifetimes into the namespace 'LongevityLifetime' + /// with your prefered lifetime by adding a struct like this: + /// + /// template<class T> + /// struct MyLifetime : SingletonFixedLongevity< MyLifetimeNumber ,T> {} + //////////////////////////////////////////////////////////////////////////////// + template <unsigned int Longevity, class T> + class SingletonFixedLongevity + { + public: + virtual ~SingletonFixedLongevity() {} + + static void ScheduleDestruction(T* pObj, atexit_pfn_t pFun) + { + Private::Adapter<T> adapter = { pFun }; + SetLongevity(pObj, Longevity , adapter); + } + + static void OnDeadReference() + { throw std::logic_error("Dead Reference Detected"); } + }; + + /// \struct DieLast + /// \ingroup LongevityLifetimeGroup + /// \brief Longest possible SingletonWithLongevity lifetime: 0xFFFFFFFF + template <class T> + struct DieLast : SingletonFixedLongevity<0xFFFFFFFF ,T> + {}; + + /// \struct DieDirectlyBeforeLast + /// \ingroup LongevityLifetimeGroup + /// \brief Lifetime is a one less than DieLast: 0xFFFFFFFF-1 + template <class T> + struct DieDirectlyBeforeLast : SingletonFixedLongevity<0xFFFFFFFF-1 ,T> + {}; + + /// \struct DieFirst + /// \ingroup LongevityLifetimeGroup + /// \brief Shortest possible SingletonWithLongevity lifetime: 0 + template <class T> + struct DieFirst : SingletonFixedLongevity<0,T> + {}; + + }//namespace LongevityLifetime + + //////////////////////////////////////////////////////////////////////////////// + /// \class FollowIntoDeath + /// + /// \ingroup LifetimeGroup + /// + /// Lifetime policyfor the SingletonHolder tempalte. + /// Followers will die after the master dies Followers will not die, if + /// - master never dies (NoDestroy policy) + /// - master never created + /// - master dies not in the function registered with atexit + /// - master dies not by a call of a the atexit registerd function (DeletableSingleton::GracefulDelete) + /// + /// \par Usage: + /// + /// Lifetimes of the master and the follower singletons, e.g. with a M and a F class: + /// \code SingletonHolder< M , FollowIntoDeath::With<DefaultLifetime>::AsMasterLifetime > MasterSingleton; \endcode + /// \code SingletonHolder< F , CreateUsingNew, FollowIntoDeath::AfterMaster< MasterSingleton >::IsDestroyed > FollowerSingleton \endcode + //////////////////////////////////////////////////////////////////////////////// + class FollowIntoDeath + { + template<class T> + class Followers + { + typedef std::vector<atexit_pfn_t> Container; + typedef typename Container::iterator iterator; + static Container* followers_; + + public: + static void Init() + { + static bool done = false; + if(!done) + { + followers_ = new Container; + done = true; + } + } + + static void AddFollower(atexit_pfn_t ae) + { + Init(); + followers_->push_back(ae); + } + + static void DestroyFollowers() + { + Init(); + for(iterator it = followers_->begin();it != followers_->end();++it) + (*it)(); + delete followers_; + } + }; + + public: + + /// \struct With + /// Template for the master + /// \param Lifetime Lifetime policy for the master + template<template <class> class Lifetime> + struct With + { + /// \struct AsMasterLifetime + /// Policy for master + template<class Master> + struct AsMasterLifetime + { + static void ScheduleDestruction(Master* pObj, atexit_pfn_t pFun) + { + Followers<Master>::Init(); + Lifetime<Master>::ScheduleDestruction(pObj, pFun); + + // use same policy for the followers and force a new + // template instantiation, this adds a additional atexit entry + // does not work with SetLonlevity, but there you can control + // the lifetime with the GetLongevity function. + Lifetime<Followers<Master> >::ScheduleDestruction(0,Followers<Master>::DestroyFollowers); + } + + static void OnDeadReference() + { + throw std::logic_error("Dead Reference Detected"); + } + }; + }; + + /// \struct AfterMaster + /// Template for the follower + /// \param Master Master to follow into death + template<class Master> + struct AfterMaster + { + /// \struct IsDestroyed + /// Policy for followers + template<class F> + struct IsDestroyed + { + static void ScheduleDestruction(F*, atexit_pfn_t pFun) + { + Followers<Master>::AddFollower(pFun); + } + + static void OnDeadReference() + { + throw std::logic_error("Dead Reference Detected"); + } + }; + }; + }; + + template<class T> + typename FollowIntoDeath::Followers<T>::Container* + FollowIntoDeath::Followers<T>::followers_ = 0; + + + + //////////////////////////////////////////////////////////////////////////////// + /// \class SingletonHolder + /// + /// \ingroup SingletonGroup + /// + /// Provides Singleton amenities for a type T + /// To protect that type from spurious instantiations, + /// you have to protect it yourself. + /// + /// \param CreationPolicy Creation policy, default: CreateUsingNew + /// \param LifetimePolicy Lifetime policy, default: DefaultLifetime, + /// \param ThreadingModel Threading policy, + /// default: LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL + //////////////////////////////////////////////////////////////////////////////// + template + < + typename T, + template <class> class CreationPolicy = CreateUsingNew, + template <class> class LifetimePolicy = DefaultLifetime, + template <class, class> class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL, + class MutexPolicy = LOKI_DEFAULT_MUTEX + > + class SingletonHolder + { + public: + + /// Type of the singleton object + typedef T ObjectType; + + /// Returns a reference to singleton object + static T& Instance(); + + private: + // Helpers + static void MakeInstance(); + static void LOKI_C_CALLING_CONVENTION_QUALIFIER DestroySingleton(); + + // Protection + SingletonHolder(); + + // Data + typedef typename ThreadingModel<T*,MutexPolicy>::VolatileType PtrInstanceType; + static PtrInstanceType pInstance_; + static bool destroyed_; + }; + + //////////////////////////////////////////////////////////////////////////////// + // SingletonHolder's data + //////////////////////////////////////////////////////////////////////////////// + + template + < + class T, + template <class> class C, + template <class> class L, + template <class, class> class M, + class X + > + typename SingletonHolder<T, C, L, M, X>::PtrInstanceType + SingletonHolder<T, C, L, M, X>::pInstance_ = 0; + + template + < + class T, + template <class> class C, + template <class> class L, + template <class, class> class M, + class X + > + bool SingletonHolder<T, C, L, M, X>::destroyed_ = false; + + //////////////////////////////////////////////////////////////////////////////// + // SingletonHolder::Instance + //////////////////////////////////////////////////////////////////////////////// + + template + < + class T, + template <class> class CreationPolicy, + template <class> class LifetimePolicy, + template <class, class> class ThreadingModel, + class MutexPolicy + > + inline T& SingletonHolder<T, CreationPolicy, + LifetimePolicy, ThreadingModel, MutexPolicy>::Instance() + { + if (!pInstance_) + { + MakeInstance(); + } + return *pInstance_; + } + + //////////////////////////////////////////////////////////////////////////////// + // SingletonHolder::MakeInstance (helper for Instance) + //////////////////////////////////////////////////////////////////////////////// + + template + < + class T, + template <class> class CreationPolicy, + template <class> class LifetimePolicy, + template <class, class> class ThreadingModel, + class MutexPolicy + > + void SingletonHolder<T, CreationPolicy, + LifetimePolicy, ThreadingModel, MutexPolicy>::MakeInstance() + { + typename ThreadingModel<SingletonHolder,MutexPolicy>::Lock guard; + (void)guard; + + if (!pInstance_) + { + if (destroyed_) + { + destroyed_ = false; + LifetimePolicy<T>::OnDeadReference(); + } + pInstance_ = CreationPolicy<T>::Create(); + LifetimePolicy<T>::ScheduleDestruction(pInstance_, + &DestroySingleton); + } + } + + template + < + class T, + template <class> class CreationPolicy, + template <class> class L, + template <class, class> class M, + class X + > + void LOKI_C_CALLING_CONVENTION_QUALIFIER + SingletonHolder<T, CreationPolicy, L, M, X>::DestroySingleton() + { + assert(!destroyed_); + CreationPolicy<T>::Destroy(pInstance_); + pInstance_ = 0; + destroyed_ = true; + } + + + //////////////////////////////////////////////////////////////////////////////// + /// \class Singleton + /// + /// \ingroup SingletonGroup + /// + /// Convenience template to implement a getter function for a singleton object. + /// Often needed in a shared library which hosts singletons. + /// + /// \par Usage + /// + /// see test/SingletonDll + /// + //////////////////////////////////////////////////////////////////////////////// + +#ifndef LOKI_SINGLETON_EXPORT +#define LOKI_SINGLETON_EXPORT +#endif + + template<class T> + class LOKI_SINGLETON_EXPORT Singleton + { + public: + static T& Instance(); + }; + +} // namespace Loki + + +/// \def LOKI_SINGLETON_INSTANCE_DEFINITION(SHOLDER) +/// Convenience macro for the definition of the static Instance member function +/// Put this macro called with a SingletonHolder typedef into your cpp file. + +#define LOKI_SINGLETON_INSTANCE_DEFINITION(SHOLDER) \ +namespace Loki \ +{ \ + template<> \ + SHOLDER::ObjectType& Singleton<SHOLDER::ObjectType>::Instance() \ + { \ + return SHOLDER::Instance(); \ + } \ +} + + +#endif // end file guardian + diff --git a/shared/loki/SmallObj.cpp b/shared/loki/SmallObj.cpp new file mode 100644 index 00000000..a2911bb1 --- /dev/null +++ b/shared/loki/SmallObj.cpp @@ -0,0 +1,1226 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// + +// $Id: SmallObj.cpp 823 2007-05-08 10:48:40Z lfittl $ + + +#include <loki/SmallObj.h> + +#include <cassert> +#include <climits> +#include <vector> +#include <bitset> + +//#define DO_EXTRA_LOKI_TESTS +//#define USE_NEW_TO_ALLOCATE +//#define LOKI_CHECK_FOR_CORRUPTION + +#ifdef DO_EXTRA_LOKI_TESTS + #include <iostream> +#endif + +namespace Loki +{ + + /** @struct Chunk + @ingroup SmallObjectGroupInternal + Contains info about each allocated Chunk - which is a collection of + contiguous blocks. Each block is the same size, as specified by the + FixedAllocator. The number of blocks in a Chunk depends upon page size. + This is a POD-style struct with value-semantics. All functions and data + are private so that they can not be changed by anything other than the + FixedAllocator which owns the Chunk. + + @par Minimal Interface + For the sake of runtime efficiency, no constructor, destructor, or + copy-assignment operator is defined. The inline functions made by the + compiler should be sufficient, and perhaps faster than hand-crafted + functions. The lack of these functions allows vector to create and copy + Chunks as needed without overhead. The Init and Release functions do + what the default constructor and destructor would do. A Chunk is not in + a usable state after it is constructed and before calling Init. Nor is + a Chunk usable after Release is called, but before the destructor. + + @par Efficiency + Down near the lowest level of the allocator, runtime efficiencies trump + almost all other considerations. Each function does the minimum required + of it. All functions should execute in constant time to prevent higher- + level code from unwittingly using a version of Shlemiel the Painter's + Algorithm. + + @par Stealth Indexes + The first char of each empty block contains the index of the next empty + block. These stealth indexes form a singly-linked list within the blocks. + A Chunk is corrupt if this singly-linked list has a loop or is shorter + than blocksAvailable_. Much of the allocator's time and space efficiency + comes from how these stealth indexes are implemented. + */ + class Chunk + { + private: + friend class FixedAllocator; + + /** Initializes a just-constructed Chunk. + @param blockSize Number of bytes per block. + @param blocks Number of blocks per Chunk. + @return True for success, false for failure. + */ + bool Init( std::size_t blockSize, unsigned char blocks ); + + /** Allocate a block within the Chunk. Complexity is always O(1), and + this will never throw. Does not actually "allocate" by calling + malloc, new, or any other function, but merely adjusts some internal + indexes to indicate an already allocated block is no longer available. + @return Pointer to block within Chunk. + */ + void * Allocate( std::size_t blockSize ); + + /** Deallocate a block within the Chunk. Complexity is always O(1), and + this will never throw. For efficiency, this assumes the address is + within the block and aligned along the correct byte boundary. An + assertion checks the alignment, and a call to HasBlock is done from + within VicinityFind. Does not actually "deallocate" by calling free, + delete, or other function, but merely adjusts some internal indexes to + indicate a block is now available. + */ + void Deallocate( void * p, std::size_t blockSize ); + + /** Resets the Chunk back to pristine values. The available count is + set back to zero, and the first available index is set to the zeroth + block. The stealth indexes inside each block are set to point to the + next block. This assumes the Chunk's data was already using Init. + */ + void Reset( std::size_t blockSize, unsigned char blocks ); + + /// Releases the allocated block of memory. + void Release(); + + /** Determines if the Chunk has been corrupted. + @param numBlocks Total # of blocks in the Chunk. + @param blockSize # of bytes in each block. + @param checkIndexes True if caller wants to check indexes of available + blocks for corruption. If false, then caller wants to skip some + tests tests just to run faster. (Debug version does more checks, but + release version runs faster.) + @return True if Chunk is corrupt. + */ + bool IsCorrupt( unsigned char numBlocks, std::size_t blockSize, + bool checkIndexes ) const; + + /** Determines if block is available. + @param p Address of block managed by Chunk. + @param numBlocks Total # of blocks in the Chunk. + @param blockSize # of bytes in each block. + @return True if block is available, else false if allocated. + */ + bool IsBlockAvailable( void * p, unsigned char numBlocks, + std::size_t blockSize ) const; + + /// Returns true if block at address P is inside this Chunk. + inline bool HasBlock( void * p, std::size_t chunkLength ) const + { + unsigned char * pc = static_cast< unsigned char * >( p ); + return ( pData_ <= pc ) && ( pc < pData_ + chunkLength ); + } + + inline bool HasAvailable( unsigned char numBlocks ) const + { return ( blocksAvailable_ == numBlocks ); } + + inline bool IsFilled( void ) const + { return ( 0 == blocksAvailable_ ); } + + /// Pointer to array of allocated blocks. + unsigned char * pData_; + /// Index of first empty block. + unsigned char firstAvailableBlock_; + /// Count of empty blocks. + unsigned char blocksAvailable_; + }; + + /** @class FixedAllocator + @ingroup SmallObjectGroupInternal + Offers services for allocating fixed-sized objects. It has a container + of "containers" of fixed-size blocks. The outer container has all the + Chunks. The inner container is a Chunk which owns some blocks. + + @par Class Level Invariants + - There is always either zero or one Chunk which is empty. + - If this has no empty Chunk, then emptyChunk_ is NULL. + - If this has an empty Chunk, then emptyChunk_ points to it. + - If the Chunk container is empty, then deallocChunk_ and allocChunk_ + are NULL. + - If the Chunk container is not-empty, then deallocChunk_ and allocChunk_ + are either NULL or point to Chunks within the container. + - allocChunk_ will often point to the last Chunk in the container since + it was likely allocated most recently, and therefore likely to have an + available block. + */ + class FixedAllocator + { + private: + + /** Deallocates the block at address p, and then handles the internal + bookkeeping needed to maintain class invariants. This assumes that + deallocChunk_ points to the correct chunk. + */ + void DoDeallocate( void * p ); + + /** Creates an empty Chunk and adds it to the end of the ChunkList. + All calls to the lower-level memory allocation functions occur inside + this function, and so the only try-catch block is inside here. + @return true for success, false for failure. + */ + bool MakeNewChunk( void ); + + /** Finds the Chunk which owns the block at address p. It starts at + deallocChunk_ and searches in both forwards and backwards directions + from there until it finds the Chunk which owns p. This algorithm + should find the Chunk quickly if it is deallocChunk_ or is close to it + in the Chunks container. This goes both forwards and backwards since + that works well for both same-order and opposite-order deallocations. + (Same-order = objects are deallocated in the same order in which they + were allocated. Opposite order = objects are deallocated in a last to + first order. Complexity is O(C) where C is count of all Chunks. This + never throws. + @return Pointer to Chunk that owns p, or NULL if no owner found. + */ + Chunk * VicinityFind( void * p ) const; + + /// Not implemented. + FixedAllocator(const FixedAllocator&); + /// Not implemented. + FixedAllocator& operator=(const FixedAllocator&); + + /// Type of container used to hold Chunks. + typedef std::vector< Chunk > Chunks; + /// Iterator through container of Chunks. + typedef Chunks::iterator ChunkIter; + /// Iterator through const container of Chunks. + typedef Chunks::const_iterator ChunkCIter; + + /// Fewest # of objects managed by a Chunk. + static unsigned char MinObjectsPerChunk_; + + /// Most # of objects managed by a Chunk - never exceeds UCHAR_MAX. + static unsigned char MaxObjectsPerChunk_; + + /// Number of bytes in a single block within a Chunk. + std::size_t blockSize_; + /// Number of blocks managed by each Chunk. + unsigned char numBlocks_; + + /// Container of Chunks. + Chunks chunks_; + /// Pointer to Chunk used for last or next allocation. + Chunk * allocChunk_; + /// Pointer to Chunk used for last or next deallocation. + Chunk * deallocChunk_; + /// Pointer to the only empty Chunk if there is one, else NULL. + Chunk * emptyChunk_; + + public: + /// Create a FixedAllocator which manages blocks of 'blockSize' size. + FixedAllocator(); + + /// Destroy the FixedAllocator and release all its Chunks. + ~FixedAllocator(); + + /// Initializes a FixedAllocator by calculating # of blocks per Chunk. + void Initialize( std::size_t blockSize, std::size_t pageSize ); + + /** Returns pointer to allocated memory block of fixed size - or NULL + if it failed to allocate. + */ + void * Allocate( void ); + + /** Deallocate a memory block previously allocated with Allocate. If + the block is not owned by this FixedAllocator, it returns false so + that SmallObjAllocator can call the default deallocator. If the + block was found, this returns true. + */ + bool Deallocate( void * p, Chunk * hint ); + + /// Returns block size with which the FixedAllocator was initialized. + inline std::size_t BlockSize() const { return blockSize_; } + + /** Releases the memory used by the empty Chunk. This will take + constant time under any situation. + @return True if empty chunk found and released, false if none empty. + */ + bool TrimEmptyChunk( void ); + + /** Releases unused spots from ChunkList. This takes constant time + with respect to # of Chunks, but actual time depends on underlying + memory allocator. + @return False if no unused spots, true if some found and released. + */ + bool TrimChunkList( void ); + + /** Returns count of empty Chunks held by this allocator. Complexity + is O(C) where C is the total number of Chunks - empty or used. + */ + std::size_t CountEmptyChunks( void ) const; + + /** Determines if FixedAllocator is corrupt. Checks data members to + see if any have erroneous values, or violate class invariants. It + also checks if any Chunk is corrupt. Complexity is O(C) where C is + the number of Chunks. If any data is corrupt, this will return true + in release mode, or assert in debug mode. + */ + bool IsCorrupt( void ) const; + + /** Returns true if the block at address p is within a Chunk owned by + this FixedAllocator. Complexity is O(C) where C is the total number + of Chunks - empty or used. + */ + const Chunk * HasBlock( void * p ) const; + inline Chunk * HasBlock( void * p ) + { + return const_cast< Chunk * >( + const_cast< const FixedAllocator * >( this )->HasBlock( p ) ); + } + + }; + + unsigned char FixedAllocator::MinObjectsPerChunk_ = 8; + unsigned char FixedAllocator::MaxObjectsPerChunk_ = UCHAR_MAX; + +// Chunk::Init ---------------------------------------------------------------- + +bool Chunk::Init( std::size_t blockSize, unsigned char blocks ) +{ + assert(blockSize > 0); + assert(blocks > 0); + // Overflow check + const std::size_t allocSize = blockSize * blocks; + assert( allocSize / blockSize == blocks); + +#ifdef USE_NEW_TO_ALLOCATE + // If this new operator fails, it will throw, and the exception will get + // caught one layer up. + pData_ = static_cast< unsigned char * >( ::operator new ( allocSize ) ); +#else + // malloc can't throw, so its only way to indicate an error is to return + // a NULL pointer, so we have to check for that. + pData_ = static_cast< unsigned char * >( ::std::malloc( allocSize ) ); + if ( NULL == pData_ ) return false; +#endif + + Reset( blockSize, blocks ); + return true; +} + +// Chunk::Reset --------------------------------------------------------------- + +void Chunk::Reset(std::size_t blockSize, unsigned char blocks) +{ + assert(blockSize > 0); + assert(blocks > 0); + // Overflow check + assert((blockSize * blocks) / blockSize == blocks); + + firstAvailableBlock_ = 0; + blocksAvailable_ = blocks; + + unsigned char i = 0; + for ( unsigned char * p = pData_; i != blocks; p += blockSize ) + { + *p = ++i; + } +} + +// Chunk::Release ------------------------------------------------------------- + +void Chunk::Release() +{ + assert( NULL != pData_ ); +#ifdef USE_NEW_TO_ALLOCATE + ::operator delete ( pData_ ); +#else + ::std::free( static_cast< void * >( pData_ ) ); +#endif +} + +// Chunk::Allocate ------------------------------------------------------------ + +void* Chunk::Allocate(std::size_t blockSize) +{ + if ( IsFilled() ) return NULL; + + assert((firstAvailableBlock_ * blockSize) / blockSize == + firstAvailableBlock_); + unsigned char * pResult = pData_ + (firstAvailableBlock_ * blockSize); + firstAvailableBlock_ = *pResult; + --blocksAvailable_; + + return pResult; +} + +// Chunk::Deallocate ---------------------------------------------------------- + +void Chunk::Deallocate(void* p, std::size_t blockSize) +{ + assert(p >= pData_); + + unsigned char* toRelease = static_cast<unsigned char*>(p); + // Alignment check + assert((toRelease - pData_) % blockSize == 0); + unsigned char index = static_cast< unsigned char >( + ( toRelease - pData_ ) / blockSize); + +#if defined(DEBUG) || defined(_DEBUG) + // Check if block was already deleted. Attempting to delete the same + // block more than once causes Chunk's linked-list of stealth indexes to + // become corrupt. And causes count of blocksAvailable_ to be wrong. + if ( 0 < blocksAvailable_ ) + assert( firstAvailableBlock_ != index ); +#endif + + *toRelease = firstAvailableBlock_; + firstAvailableBlock_ = index; + // Truncation check + assert(firstAvailableBlock_ == (toRelease - pData_) / blockSize); + + ++blocksAvailable_; +} + +// Chunk::IsCorrupt ----------------------------------------------------------- + +bool Chunk::IsCorrupt( unsigned char numBlocks, std::size_t blockSize, + bool checkIndexes ) const +{ + + if ( numBlocks < blocksAvailable_ ) + { + // Contents at this Chunk corrupted. This might mean something has + // overwritten memory owned by the Chunks container. + assert( false ); + return true; + } + if ( IsFilled() ) + // Useless to do further corruption checks if all blocks allocated. + return false; + unsigned char index = firstAvailableBlock_; + if ( numBlocks <= index ) + { + // Contents at this Chunk corrupted. This might mean something has + // overwritten memory owned by the Chunks container. + assert( false ); + return true; + } + if ( !checkIndexes ) + // Caller chose to skip more complex corruption tests. + return false; + + /* If the bit at index was set in foundBlocks, then the stealth index was + found on the linked-list. + */ + std::bitset< UCHAR_MAX > foundBlocks; + unsigned char * nextBlock = NULL; + + /* The loop goes along singly linked-list of stealth indexes and makes sure + that each index is within bounds (0 <= index < numBlocks) and that the + index was not already found while traversing the linked-list. The linked- + list should have exactly blocksAvailable_ nodes, so the for loop will not + check more than blocksAvailable_. This loop can't check inside allocated + blocks for corruption since such blocks are not within the linked-list. + Contents of allocated blocks are not changed by Chunk. + + Here are the types of corrupted link-lists which can be verified. The + corrupt index is shown with asterisks in each example. + + Type 1: Index is too big. + numBlocks == 64 + blocksAvailable_ == 7 + firstAvailableBlock_ -> 17 -> 29 -> *101* + There should be no indexes which are equal to or larger than the total + number of blocks. Such an index would refer to a block beyond the + Chunk's allocated domain. + + Type 2: Index is repeated. + numBlocks == 64 + blocksAvailable_ == 5 + firstAvailableBlock_ -> 17 -> 29 -> 53 -> *17* -> 29 -> 53 ... + No index should be repeated within the linked-list since that would + indicate the presence of a loop in the linked-list. + */ + for ( unsigned char cc = 0; ; ) + { + nextBlock = pData_ + ( index * blockSize ); + foundBlocks.set( index, true ); + ++cc; + if ( cc >= blocksAvailable_ ) + // Successfully counted off number of nodes in linked-list. + break; + index = *nextBlock; + if ( numBlocks <= index ) + { + /* This catches Type 1 corruptions as shown in above comments. + This implies that a block was corrupted due to a stray pointer + or an operation on a nearby block overran the size of the block. + */ + assert( false ); + return true; + } + if ( foundBlocks.test( index ) ) + { + /* This catches Type 2 corruptions as shown in above comments. + This implies that a block was corrupted due to a stray pointer + or an operation on a nearby block overran the size of the block. + Or perhaps the program tried to delete a block more than once. + */ + assert( false ); + return true; + } + } + if ( foundBlocks.count() != blocksAvailable_ ) + { + /* This implies that the singly-linked-list of stealth indexes was + corrupted. Ideally, this should have been detected within the loop. + */ + assert( false ); + return true; + } + + return false; +} + +// Chunk::IsBlockAvailable ---------------------------------------------------- + +bool Chunk::IsBlockAvailable( void * p, unsigned char numBlocks, + std::size_t blockSize ) const +{ + (void) numBlocks; + + if ( IsFilled() ) + return false; + + unsigned char * place = static_cast< unsigned char * >( p ); + // Alignment check + assert( ( place - pData_ ) % blockSize == 0 ); + unsigned char blockIndex = static_cast< unsigned char >( + ( place - pData_ ) / blockSize ); + + unsigned char index = firstAvailableBlock_; + assert( numBlocks > index ); + if ( index == blockIndex ) + return true; + + /* If the bit at index was set in foundBlocks, then the stealth index was + found on the linked-list. + */ + std::bitset< UCHAR_MAX > foundBlocks; + unsigned char * nextBlock = NULL; + for ( unsigned char cc = 0; ; ) + { + nextBlock = pData_ + ( index * blockSize ); + foundBlocks.set( index, true ); + ++cc; + if ( cc >= blocksAvailable_ ) + // Successfully counted off number of nodes in linked-list. + break; + index = *nextBlock; + if ( index == blockIndex ) + return true; + assert( numBlocks > index ); + assert( !foundBlocks.test( index ) ); + } + + return false; +} + +// FixedAllocator::FixedAllocator --------------------------------------------- + +FixedAllocator::FixedAllocator() + : blockSize_( 0 ) + , numBlocks_( 0 ) + , chunks_( 0 ) + , allocChunk_( NULL ) + , deallocChunk_( NULL ) + , emptyChunk_( NULL ) +{ +} + +// FixedAllocator::~FixedAllocator -------------------------------------------- + +FixedAllocator::~FixedAllocator() +{ +#ifdef DO_EXTRA_LOKI_TESTS + TrimEmptyChunk(); + assert( chunks_.empty() && "Memory leak detected!" ); +#endif + for ( ChunkIter i( chunks_.begin() ); i != chunks_.end(); ++i ) + i->Release(); +} + +// FixedAllocator::Initialize ------------------------------------------------- + +void FixedAllocator::Initialize( std::size_t blockSize, std::size_t pageSize ) +{ + assert( blockSize > 0 ); + assert( pageSize >= blockSize ); + blockSize_ = blockSize; + + std::size_t numBlocks = pageSize / blockSize; + if ( numBlocks > MaxObjectsPerChunk_ ) numBlocks = MaxObjectsPerChunk_; + else if ( numBlocks < MinObjectsPerChunk_ ) numBlocks = MinObjectsPerChunk_; + + numBlocks_ = static_cast<unsigned char>(numBlocks); + assert(numBlocks_ == numBlocks); +} + +// FixedAllocator::CountEmptyChunks ------------------------------------------- + +std::size_t FixedAllocator::CountEmptyChunks( void ) const +{ +#ifdef DO_EXTRA_LOKI_TESTS + // This code is only used for specialized tests of the allocator. + // It is #ifdef-ed so that its O(C) complexity does not overwhelm the + // functions which call it. + std::size_t count = 0; + for ( ChunkCIter it( chunks_.begin() ); it != chunks_.end(); ++it ) + { + const Chunk & chunk = *it; + if ( chunk.HasAvailable( numBlocks_ ) ) + ++count; + } + return count; +#else + return ( NULL == emptyChunk_ ) ? 0 : 1; +#endif +} + +// FixedAllocator::IsCorrupt -------------------------------------------------- + +bool FixedAllocator::IsCorrupt( void ) const +{ + const bool isEmpty = chunks_.empty(); + ChunkCIter start( chunks_.begin() ); + ChunkCIter last( chunks_.end() ); + const size_t emptyChunkCount = CountEmptyChunks(); + + if ( isEmpty ) + { + if ( start != last ) + { + assert( false ); + return true; + } + if ( 0 < emptyChunkCount ) + { + assert( false ); + return true; + } + if ( NULL != deallocChunk_ ) + { + assert( false ); + return true; + } + if ( NULL != allocChunk_ ) + { + assert( false ); + return true; + } + if ( NULL != emptyChunk_ ) + { + assert( false ); + return true; + } + } + + else + { + const Chunk * front = &chunks_.front(); + const Chunk * back = &chunks_.back(); + if ( start >= last ) + { + assert( false ); + return true; + } + if ( back < deallocChunk_ ) + { + assert( false ); + return true; + } + if ( back < allocChunk_ ) + { + assert( false ); + return true; + } + if ( front > deallocChunk_ ) + { + assert( false ); + return true; + } + if ( front > allocChunk_ ) + { + assert( false ); + return true; + } + + switch ( emptyChunkCount ) + { + case 0: + if ( emptyChunk_ != NULL ) + { + assert( false ); + return true; + } + break; + case 1: + if ( emptyChunk_ == NULL ) + { + assert( false ); + return true; + } + if ( back < emptyChunk_ ) + { + assert( false ); + return true; + } + if ( front > emptyChunk_ ) + { + assert( false ); + return true; + } + if ( !emptyChunk_->HasAvailable( numBlocks_ ) ) + { + // This may imply somebody tried to delete a block twice. + assert( false ); + return true; + } + break; + default: + assert( false ); + return true; + } + for ( ChunkCIter it( start ); it != last; ++it ) + { + const Chunk & chunk = *it; + if ( chunk.IsCorrupt( numBlocks_, blockSize_, true ) ) + return true; + } + } + + return false; +} + +// FixedAllocator::HasBlock --------------------------------------------------- + +const Chunk * FixedAllocator::HasBlock( void * p ) const +{ + const std::size_t chunkLength = numBlocks_ * blockSize_; + for ( ChunkCIter it( chunks_.begin() ); it != chunks_.end(); ++it ) + { + const Chunk & chunk = *it; + if ( chunk.HasBlock( p, chunkLength ) ) + return &chunk; + } + return NULL; +} + +// FixedAllocator::TrimEmptyChunk --------------------------------------------- + +bool FixedAllocator::TrimEmptyChunk( void ) +{ + // prove either emptyChunk_ points nowhere, or points to a truly empty Chunk. + assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) ); + if ( NULL == emptyChunk_ ) return false; + + // If emptyChunk_ points to valid Chunk, then chunk list is not empty. + assert( !chunks_.empty() ); + // And there should be exactly 1 empty Chunk. + assert( 1 == CountEmptyChunks() ); + + Chunk * lastChunk = &chunks_.back(); + if ( lastChunk != emptyChunk_ ) + std::swap( *emptyChunk_, *lastChunk ); + assert( lastChunk->HasAvailable( numBlocks_ ) ); + lastChunk->Release(); + chunks_.pop_back(); + + if ( chunks_.empty() ) + { + allocChunk_ = NULL; + deallocChunk_ = NULL; + } + else + { + if ( deallocChunk_ == emptyChunk_ ) + { + deallocChunk_ = &chunks_.front(); + assert( deallocChunk_->blocksAvailable_ < numBlocks_ ); + } + if ( allocChunk_ == emptyChunk_ ) + { + allocChunk_ = &chunks_.back(); + assert( allocChunk_->blocksAvailable_ < numBlocks_ ); + } + } + + emptyChunk_ = NULL; + assert( 0 == CountEmptyChunks() ); + + return true; +} + +// FixedAllocator::TrimChunkList ---------------------------------------------- + +bool FixedAllocator::TrimChunkList( void ) +{ + if ( chunks_.empty() ) + { + assert( NULL == allocChunk_ ); + assert( NULL == deallocChunk_ ); + } + + if ( chunks_.size() == chunks_.capacity() ) + return false; + // Use the "make-a-temp-and-swap" trick to remove excess capacity. + Chunks( chunks_ ).swap( chunks_ ); + + return true; +} + +// FixedAllocator::MakeNewChunk ----------------------------------------------- + +bool FixedAllocator::MakeNewChunk( void ) +{ + bool allocated = false; + try + { + std::size_t size = chunks_.size(); + // Calling chunks_.reserve *before* creating and initializing the new + // Chunk means that nothing is leaked by this function in case an + // exception is thrown from reserve. + if ( chunks_.capacity() == size ) + { + if ( 0 == size ) size = 4; + chunks_.reserve( size * 2 ); + } + Chunk newChunk; + allocated = newChunk.Init( blockSize_, numBlocks_ ); + if ( allocated ) + chunks_.push_back( newChunk ); + } + catch ( ... ) + { + allocated = false; + } + if ( !allocated ) return false; + + allocChunk_ = &chunks_.back(); + deallocChunk_ = &chunks_.front(); + return true; +} + +// FixedAllocator::Allocate --------------------------------------------------- + +void * FixedAllocator::Allocate( void ) +{ + // prove either emptyChunk_ points nowhere, or points to a truly empty Chunk. + assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) ); + assert( CountEmptyChunks() < 2 ); + + if ( ( NULL == allocChunk_ ) || allocChunk_->IsFilled() ) + { + if ( NULL != emptyChunk_ ) + { + allocChunk_ = emptyChunk_; + emptyChunk_ = NULL; + } + else + { + for ( ChunkIter i( chunks_.begin() ); ; ++i ) + { + if ( chunks_.end() == i ) + { + if ( !MakeNewChunk() ) + return NULL; + break; + } + if ( !i->IsFilled() ) + { + allocChunk_ = &*i; + break; + } + } + } + } + else if ( allocChunk_ == emptyChunk_) + // detach emptyChunk_ from allocChunk_, because after + // calling allocChunk_->Allocate(blockSize_); the chunk + // is no longer empty. + emptyChunk_ = NULL; + + assert( allocChunk_ != NULL ); + assert( !allocChunk_->IsFilled() ); + void * place = allocChunk_->Allocate( blockSize_ ); + + // prove either emptyChunk_ points nowhere, or points to a truly empty Chunk. + assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) ); + assert( CountEmptyChunks() < 2 ); +#ifdef LOKI_CHECK_FOR_CORRUPTION + if ( allocChunk_->IsCorrupt( numBlocks_, blockSize_, true ) ) + { + assert( false ); + return NULL; + } +#endif + + return place; +} + +// FixedAllocator::Deallocate ------------------------------------------------- + +bool FixedAllocator::Deallocate( void * p, Chunk * hint ) +{ + assert(!chunks_.empty()); + assert(&chunks_.front() <= deallocChunk_); + assert(&chunks_.back() >= deallocChunk_); + assert( &chunks_.front() <= allocChunk_ ); + assert( &chunks_.back() >= allocChunk_ ); + assert( CountEmptyChunks() < 2 ); + + Chunk * foundChunk = ( NULL == hint ) ? VicinityFind( p ) : hint; + if ( NULL == foundChunk ) + return false; + + assert( foundChunk->HasBlock( p, numBlocks_ * blockSize_ ) ); +#ifdef LOKI_CHECK_FOR_CORRUPTION + if ( foundChunk->IsCorrupt( numBlocks_, blockSize_, true ) ) + { + assert( false ); + return false; + } + if ( foundChunk->IsBlockAvailable( p, numBlocks_, blockSize_ ) ) + { + assert( false ); + return false; + } +#endif + deallocChunk_ = foundChunk; + DoDeallocate(p); + assert( CountEmptyChunks() < 2 ); + + return true; +} + +// FixedAllocator::VicinityFind ----------------------------------------------- + +Chunk * FixedAllocator::VicinityFind( void * p ) const +{ + if ( chunks_.empty() ) return NULL; + assert(deallocChunk_); + + const std::size_t chunkLength = numBlocks_ * blockSize_; + Chunk * lo = deallocChunk_; + Chunk * hi = deallocChunk_ + 1; + const Chunk * loBound = &chunks_.front(); + const Chunk * hiBound = &chunks_.back() + 1; + + // Special case: deallocChunk_ is the last in the array + if (hi == hiBound) hi = NULL; + + for (;;) + { + if (lo) + { + if ( lo->HasBlock( p, chunkLength ) ) return lo; + if ( lo == loBound ) + { + lo = NULL; + if ( NULL == hi ) break; + } + else --lo; + } + + if (hi) + { + if ( hi->HasBlock( p, chunkLength ) ) return hi; + if ( ++hi == hiBound ) + { + hi = NULL; + if ( NULL == lo ) break; + } + } + } + + return NULL; +} + +// FixedAllocator::DoDeallocate ----------------------------------------------- + +void FixedAllocator::DoDeallocate(void* p) +{ + // Show that deallocChunk_ really owns the block at address p. + assert( deallocChunk_->HasBlock( p, numBlocks_ * blockSize_ ) ); + // Either of the next two assertions may fail if somebody tries to + // delete the same block twice. + assert( emptyChunk_ != deallocChunk_ ); + assert( !deallocChunk_->HasAvailable( numBlocks_ ) ); + // prove either emptyChunk_ points nowhere, or points to a truly empty Chunk. + assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) ); + + // call into the chunk, will adjust the inner list but won't release memory + deallocChunk_->Deallocate(p, blockSize_); + + if ( deallocChunk_->HasAvailable( numBlocks_ ) ) + { + assert( emptyChunk_ != deallocChunk_ ); + // deallocChunk_ is empty, but a Chunk is only released if there are 2 + // empty chunks. Since emptyChunk_ may only point to a previously + // cleared Chunk, if it points to something else besides deallocChunk_, + // then FixedAllocator currently has 2 empty Chunks. + if ( NULL != emptyChunk_ ) + { + // If last Chunk is empty, just change what deallocChunk_ + // points to, and release the last. Otherwise, swap an empty + // Chunk with the last, and then release it. + Chunk * lastChunk = &chunks_.back(); + if ( lastChunk == deallocChunk_ ) + deallocChunk_ = emptyChunk_; + else if ( lastChunk != emptyChunk_ ) + std::swap( *emptyChunk_, *lastChunk ); + assert( lastChunk->HasAvailable( numBlocks_ ) ); + lastChunk->Release(); + chunks_.pop_back(); + if ( ( allocChunk_ == lastChunk ) || allocChunk_->IsFilled() ) + allocChunk_ = deallocChunk_; + } + emptyChunk_ = deallocChunk_; + } + + // prove either emptyChunk_ points nowhere, or points to a truly empty Chunk. + assert( ( NULL == emptyChunk_ ) || ( emptyChunk_->HasAvailable( numBlocks_ ) ) ); +} + +// GetOffset ------------------------------------------------------------------ +/// @ingroup SmallObjectGroupInternal +/// Calculates index into array where a FixedAllocator of numBytes is located. +inline std::size_t GetOffset( std::size_t numBytes, std::size_t alignment ) +{ + const std::size_t alignExtra = alignment-1; + return ( numBytes + alignExtra ) / alignment; +} + +// DefaultAllocator ----------------------------------------------------------- +/** @ingroup SmallObjectGroupInternal + Calls the default allocator when SmallObjAllocator decides not to handle a + request. SmallObjAllocator calls this if the number of bytes is bigger than + the size which can be handled by any FixedAllocator. + @param numBytes number of bytes + @param doThrow True if this function should throw an exception, or false if it + should indicate failure by returning a NULL pointer. +*/ +void * DefaultAllocator( std::size_t numBytes, bool doThrow ) +{ +#ifdef USE_NEW_TO_ALLOCATE + return doThrow ? ::operator new( numBytes ) : + ::operator new( numBytes, std::nothrow_t() ); +#else + void * p = ::std::malloc( numBytes ); + if ( doThrow && ( NULL == p ) ) + throw std::bad_alloc(); + return p; +#endif +} + +// DefaultDeallocator --------------------------------------------------------- +/** @ingroup SmallObjectGroupInternal + Calls default deallocator when SmallObjAllocator decides not to handle a + request. The default deallocator could be the global delete operator or the + free function. The free function is the preferred default deallocator since + it matches malloc which is the preferred default allocator. SmallObjAllocator + will call this if an address was not found among any of its own blocks. + */ +void DefaultDeallocator( void * p ) +{ +#ifdef USE_NEW_TO_ALLOCATE + ::operator delete( p ); +#else + ::std::free( p ); +#endif +} + +// SmallObjAllocator::SmallObjAllocator --------------------------------------- + +SmallObjAllocator::SmallObjAllocator( std::size_t pageSize, + std::size_t maxObjectSize, std::size_t objectAlignSize ) : + pool_( NULL ), + maxSmallObjectSize_( maxObjectSize ), + objectAlignSize_( objectAlignSize ) +{ +#ifdef DO_EXTRA_LOKI_TESTS + std::cout << "SmallObjAllocator " << this << std::endl; +#endif + assert( 0 != objectAlignSize ); + const std::size_t allocCount = GetOffset( maxObjectSize, objectAlignSize ); + pool_ = new FixedAllocator[ allocCount ]; + for ( std::size_t i = 0; i < allocCount; ++i ) + pool_[ i ].Initialize( ( i+1 ) * objectAlignSize, pageSize ); +} + +// SmallObjAllocator::~SmallObjAllocator -------------------------------------- + +SmallObjAllocator::~SmallObjAllocator( void ) +{ +#ifdef DO_EXTRA_LOKI_TESTS + std::cout << "~SmallObjAllocator " << this << std::endl; +#endif + delete [] pool_; +} + +// SmallObjAllocator::TrimExcessMemory ---------------------------------------- + +bool SmallObjAllocator::TrimExcessMemory( void ) +{ + bool found = false; + const std::size_t allocCount = GetOffset( GetMaxObjectSize(), GetAlignment() ); + std::size_t i = 0; + for ( ; i < allocCount; ++i ) + { + if ( pool_[ i ].TrimEmptyChunk() ) + found = true; + } + for ( i = 0; i < allocCount; ++i ) + { + if ( pool_[ i ].TrimChunkList() ) + found = true; + } + + return found; +} + +// SmallObjAllocator::Allocate ------------------------------------------------ + +void * SmallObjAllocator::Allocate( std::size_t numBytes, bool doThrow ) +{ + if ( numBytes > GetMaxObjectSize() ) + return DefaultAllocator( numBytes, doThrow ); + + assert( NULL != pool_ ); + if ( 0 == numBytes ) numBytes = 1; + const std::size_t index = GetOffset( numBytes, GetAlignment() ) - 1; + const std::size_t allocCount = GetOffset( GetMaxObjectSize(), GetAlignment() ); + (void) allocCount; + assert( index < allocCount ); + + FixedAllocator & allocator = pool_[ index ]; + assert( allocator.BlockSize() >= numBytes ); + assert( allocator.BlockSize() < numBytes + GetAlignment() ); + void * place = allocator.Allocate(); + + if ( ( NULL == place ) && TrimExcessMemory() ) + place = allocator.Allocate(); + + if ( ( NULL == place ) && doThrow ) + { +#ifdef _MSC_VER + throw std::bad_alloc( "could not allocate small object" ); +#else + // GCC did not like a literal string passed to std::bad_alloc. + // so just throw the default-constructed exception. + throw std::bad_alloc(); +#endif + } + return place; +} + +// SmallObjAllocator::Deallocate ---------------------------------------------- + +void SmallObjAllocator::Deallocate( void * p, std::size_t numBytes ) +{ + if ( NULL == p ) return; + if ( numBytes > GetMaxObjectSize() ) + { + DefaultDeallocator( p ); + return; + } + assert( NULL != pool_ ); + if ( 0 == numBytes ) numBytes = 1; + const std::size_t index = GetOffset( numBytes, GetAlignment() ) - 1; + const std::size_t allocCount = GetOffset( GetMaxObjectSize(), GetAlignment() ); + (void) allocCount; + assert( index < allocCount ); + FixedAllocator & allocator = pool_[ index ]; + assert( allocator.BlockSize() >= numBytes ); + assert( allocator.BlockSize() < numBytes + GetAlignment() ); + const bool found = allocator.Deallocate( p, NULL ); + (void) found; + assert( found ); +} + +// SmallObjAllocator::Deallocate ---------------------------------------------- + +void SmallObjAllocator::Deallocate( void * p ) +{ + if ( NULL == p ) return; + assert( NULL != pool_ ); + FixedAllocator * pAllocator = NULL; + const std::size_t allocCount = GetOffset( GetMaxObjectSize(), GetAlignment() ); + Chunk * chunk = NULL; + + for ( std::size_t ii = 0; ii < allocCount; ++ii ) + { + chunk = pool_[ ii ].HasBlock( p ); + if ( NULL != chunk ) + { + pAllocator = &pool_[ ii ]; + break; + } + } + if ( NULL == pAllocator ) + { + DefaultDeallocator( p ); + return; + } + + assert( NULL != chunk ); + const bool found = pAllocator->Deallocate( p, chunk ); + (void) found; + assert( found ); +} + +// SmallObjAllocator::IsCorrupt ----------------------------------------------- + +bool SmallObjAllocator::IsCorrupt( void ) const +{ + if ( NULL == pool_ ) + { + assert( false ); + return true; + } + if ( 0 == GetAlignment() ) + { + assert( false ); + return true; + } + if ( 0 == GetMaxObjectSize() ) + { + assert( false ); + return true; + } + const std::size_t allocCount = GetOffset( GetMaxObjectSize(), GetAlignment() ); + for ( std::size_t ii = 0; ii < allocCount; ++ii ) + { + if ( pool_[ ii ].IsCorrupt() ) + return true; + } + return false; +} + +} // end namespace Loki + diff --git a/shared/loki/SmallObj.h b/shared/loki/SmallObj.h new file mode 100644 index 00000000..65828bf2 --- /dev/null +++ b/shared/loki/SmallObj.h @@ -0,0 +1,644 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_SMALLOBJ_INC_ +#define LOKI_SMALLOBJ_INC_ + +// $Id: SmallObj.h 806 2007-02-03 00:01:52Z rich_sposato $ + + +#include "LokiExport.h" +#include "Threads.h" +#include "Singleton.h" +#include <cstddef> +#include <new> // needed for std::nothrow_t parameter. + +#ifndef LOKI_DEFAULT_CHUNK_SIZE +#define LOKI_DEFAULT_CHUNK_SIZE 4096 +#endif + +#ifndef LOKI_MAX_SMALL_OBJECT_SIZE +#define LOKI_MAX_SMALL_OBJECT_SIZE 256 +#endif + +#ifndef LOKI_DEFAULT_OBJECT_ALIGNMENT +#define LOKI_DEFAULT_OBJECT_ALIGNMENT 4 +#endif + +#ifndef LOKI_DEFAULT_SMALLOBJ_LIFETIME +#define LOKI_DEFAULT_SMALLOBJ_LIFETIME ::Loki::LongevityLifetime::DieAsSmallObjectParent +#endif + +#if defined(LOKI_SMALL_OBJECT_USE_NEW_ARRAY) && defined(_MSC_VER) +#pragma message("Don't define LOKI_SMALL_OBJECT_USE_NEW_ARRAY when using a Microsoft compiler to prevent memory leaks.") +#pragma message("now calling '#undef LOKI_SMALL_OBJECT_USE_NEW_ARRAY'") +#undef LOKI_SMALL_OBJECT_USE_NEW_ARRAY +#endif + +/// \defgroup SmallObjectGroup Small objects +/// +/// \defgroup SmallObjectGroupInternal Internals +/// \ingroup SmallObjectGroup + +namespace Loki +{ + namespace LongevityLifetime + { + /** @struct DieAsSmallObjectParent + @ingroup SmallObjectGroup + Lifetime policy to manage lifetime dependencies of + SmallObject base and child classes. + The Base class should have this lifetime + */ + template <class T> + struct DieAsSmallObjectParent : DieLast<T> {}; + + /** @struct DieAsSmallObjectChild + @ingroup SmallObjectGroup + Lifetime policy to manage lifetime dependencies of + SmallObject base and child classes. + The Child class should have this lifetime + */ + template <class T> + struct DieAsSmallObjectChild : DieDirectlyBeforeLast<T> {}; + + } + + class FixedAllocator; + + /** @class SmallObjAllocator + @ingroup SmallObjectGroupInternal + Manages pool of fixed-size allocators. + Designed to be a non-templated base class of AllocatorSingleton so that + implementation details can be safely hidden in the source code file. + */ + class LOKI_EXPORT SmallObjAllocator + { + protected: + /** The only available constructor needs certain parameters in order to + initialize all the FixedAllocator's. This throws only if + @param pageSize # of bytes in a page of memory. + @param maxObjectSize Max # of bytes which this may allocate. + @param objectAlignSize # of bytes between alignment boundaries. + */ + SmallObjAllocator( std::size_t pageSize, std::size_t maxObjectSize, + std::size_t objectAlignSize ); + + /** Destructor releases all blocks, all Chunks, and FixedAllocator's. + Any outstanding blocks are unavailable, and should not be used after + this destructor is called. The destructor is deliberately non-virtual + because it is protected, not public. + */ + ~SmallObjAllocator( void ); + + public: + /** Allocates a block of memory of requested size. Complexity is often + constant-time, but might be O(C) where C is the number of Chunks in a + FixedAllocator. + + @par Exception Safety Level + Provides either strong-exception safety, or no-throw exception-safety + level depending upon doThrow parameter. The reason it provides two + levels of exception safety is because it is used by both the nothrow + and throwing new operators. The underlying implementation will never + throw of its own accord, but this can decide to throw if it does not + allocate. The only exception it should emit is std::bad_alloc. + + @par Allocation Failure + If it does not allocate, it will call TrimExcessMemory and attempt to + allocate again, before it decides to throw or return NULL. Many + allocators loop through several new_handler functions, and terminate + if they can not allocate, but not this one. It only makes one attempt + using its own implementation of the new_handler, and then returns NULL + or throws so that the program can decide what to do at a higher level. + (Side note: Even though the C++ Standard allows allocators and + new_handlers to terminate if they fail, the Loki allocator does not do + that since that policy is not polite to a host program.) + + @param size # of bytes needed for allocation. + @param doThrow True if this should throw if unable to allocate, false + if it should provide no-throw exception safety level. + @return NULL if nothing allocated and doThrow is false. Else the + pointer to an available block of memory. + */ + void * Allocate( std::size_t size, bool doThrow ); + + /** Deallocates a block of memory at a given place and of a specific + size. Complexity is almost always constant-time, and is O(C) only if + it has to search for which Chunk deallocates. This never throws. + */ + void Deallocate( void * p, std::size_t size ); + + /** Deallocates a block of memory at a given place but of unknown size + size. Complexity is O(F + C) where F is the count of FixedAllocator's + in the pool, and C is the number of Chunks in all FixedAllocator's. This + does not throw exceptions. This overloaded version of Deallocate is + called by the nothow delete operator - which is called when the nothrow + new operator is used, but a constructor throws an exception. + */ + void Deallocate( void * p ); + + /// Returns max # of bytes which this can allocate. + inline std::size_t GetMaxObjectSize() const + { return maxSmallObjectSize_; } + + /// Returns # of bytes between allocation boundaries. + inline std::size_t GetAlignment() const { return objectAlignSize_; } + + /** Releases empty Chunks from memory. Complexity is O(F + C) where F + is the count of FixedAllocator's in the pool, and C is the number of + Chunks in all FixedAllocator's. This will never throw. This is called + by AllocatorSingleto::ClearExtraMemory, the new_handler function for + Loki's allocator, and is called internally when an allocation fails. + @return True if any memory released, or false if none released. + */ + bool TrimExcessMemory( void ); + + /** Returns true if anything in implementation is corrupt. Complexity + is O(F + C + B) where F is the count of FixedAllocator's in the pool, + C is the number of Chunks in all FixedAllocator's, and B is the number + of blocks in all Chunks. If it determines any data is corrupted, this + will return true in release version, but assert in debug version at + the line where it detects the corrupted data. If it does not detect + any corrupted data, it returns false. + */ + bool IsCorrupt( void ) const; + + private: + /// Default-constructor is not implemented. + SmallObjAllocator( void ); + /// Copy-constructor is not implemented. + SmallObjAllocator( const SmallObjAllocator & ); + /// Copy-assignment operator is not implemented. + SmallObjAllocator & operator = ( const SmallObjAllocator & ); + + /// Pointer to array of fixed-size allocators. + Loki::FixedAllocator * pool_; + + /// Largest object size supported by allocators. + const std::size_t maxSmallObjectSize_; + + /// Size of alignment boundaries. + const std::size_t objectAlignSize_; + }; + + + /** @class AllocatorSingleton + @ingroup SmallObjectGroupInternal + This template class is derived from + SmallObjAllocator in order to pass template arguments into it, and still + have a default constructor for the singleton. Each instance is a unique + combination of all the template parameters, and hence is singleton only + with respect to those parameters. The template parameters have default + values and the class has typedefs identical to both SmallObject and + SmallValueObject so that this class can be used directly instead of going + through SmallObject or SmallValueObject. That design feature allows + clients to use the new_handler without having the name of the new_handler + function show up in classes derived from SmallObject or SmallValueObject. + Thus, the only functions in the allocator which show up in SmallObject or + SmallValueObject inheritance hierarchies are the new and delete + operators. + */ + template + < + template <class, class> class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL, + std::size_t chunkSize = LOKI_DEFAULT_CHUNK_SIZE, + std::size_t maxSmallObjectSize = LOKI_MAX_SMALL_OBJECT_SIZE, + std::size_t objectAlignSize = LOKI_DEFAULT_OBJECT_ALIGNMENT, + template <class> class LifetimePolicy = LOKI_DEFAULT_SMALLOBJ_LIFETIME, + class MutexPolicy = LOKI_DEFAULT_MUTEX + > + class AllocatorSingleton : public SmallObjAllocator + { + public: + + /// Defines type of allocator. + typedef AllocatorSingleton< ThreadingModel, chunkSize, + maxSmallObjectSize, objectAlignSize, LifetimePolicy > MyAllocator; + + /// Defines type for thread-safety locking mechanism. + typedef ThreadingModel< MyAllocator, MutexPolicy > MyThreadingModel; + + /// Defines singleton made from allocator. + typedef Loki::SingletonHolder< MyAllocator, Loki::CreateStatic, + LifetimePolicy, ThreadingModel > MyAllocatorSingleton; + + /// Returns reference to the singleton. + inline static AllocatorSingleton & Instance( void ) + { + return MyAllocatorSingleton::Instance(); + } + + /// The default constructor is not meant to be called directly. + inline AllocatorSingleton() : + SmallObjAllocator( chunkSize, maxSmallObjectSize, objectAlignSize ) + {} + + /// The destructor is not meant to be called directly. + inline ~AllocatorSingleton( void ) {} + + /** Clears any excess memory used by the allocator. Complexity is + O(F + C) where F is the count of FixedAllocator's in the pool, and C + is the number of Chunks in all FixedAllocator's. This never throws. + @note This function can be used as a new_handler when Loki and other + memory allocators can no longer allocate. Although the C++ Standard + allows new_handler functions to terminate the program when they can + not release any memory, this will not do so. + */ + static void ClearExtraMemory( void ); + + /** Returns true if anything in implementation is corrupt. Complexity + is O(F + C + B) where F is the count of FixedAllocator's in the pool, + C is the number of Chunks in all FixedAllocator's, and B is the number + of blocks in all Chunks. If it determines any data is corrupted, this + will return true in release version, but assert in debug version at + the line where it detects the corrupted data. If it does not detect + any corrupted data, it returns false. + */ + static bool IsCorrupted( void ); + + private: + /// Copy-constructor is not implemented. + AllocatorSingleton( const AllocatorSingleton & ); + /// Copy-assignment operator is not implemented. + AllocatorSingleton & operator = ( const AllocatorSingleton & ); + }; + + template + < + template <class, class> class T, + std::size_t C, + std::size_t M, + std::size_t O, + template <class> class L, + class X + > + void AllocatorSingleton< T, C, M, O, L, X >::ClearExtraMemory( void ) + { + typename MyThreadingModel::Lock lock; + (void)lock; // get rid of warning + Instance().TrimExcessMemory(); + } + + template + < + template <class, class> class T, + std::size_t C, + std::size_t M, + std::size_t O, + template <class> class L, + class X + > + bool AllocatorSingleton< T, C, M, O, L, X >::IsCorrupted( void ) + { + typename MyThreadingModel::Lock lock; + (void)lock; // get rid of warning + return Instance().IsCorrupt(); + } + + /** This standalone function provides the longevity level for Small-Object + Allocators which use the Loki::SingletonWithLongevity policy. The + SingletonWithLongevity class can find this function through argument- + dependent lookup. + + @par Longevity Levels + No Small-Object Allocator depends on any other Small-Object allocator, so + this does not need to calculate dependency levels among allocators, and + it returns just a constant. All allocators must live longer than the + objects which use the allocators, it must return a longevity level higher + than any such object. + */ + template + < + template <class, class> class T, + std::size_t C, + std::size_t M, + std::size_t O, + template <class> class L, + class X + > + inline unsigned int GetLongevity( + AllocatorSingleton< T, C, M, O, L, X > * ) + { + // Returns highest possible value. + return 0xFFFFFFFF; + } + + + /** @class SmallObjectBase + @ingroup SmallObjectGroup + Base class for small object allocation classes. + The shared implementation of the new and delete operators are here instead + of being duplicated in both SmallObject or SmallValueObject, later just + called Small-Objects. This class is not meant to be used directly by clients, + or derived from by clients. Class has no data members so compilers can + use Empty-Base-Optimization. + + @par ThreadingModel + This class doesn't support ObjectLevelLockable policy for ThreadingModel. + The allocator is a singleton, so a per-instance mutex is not necessary. + Nor is using ObjectLevelLockable recommended with SingletonHolder since + the SingletonHolder::MakeInstance function requires a mutex that exists + prior to when the object is created - which is not possible if the mutex + is inside the object, such as required for ObjectLevelLockable. If you + attempt to use ObjectLevelLockable, the compiler will emit errors because + it can't use the default constructor in ObjectLevelLockable. If you need + a thread-safe allocator, use the ClassLevelLockable policy. + + @par Lifetime Policy + + The SmallObjectBase template needs a lifetime policy because it owns + a singleton of SmallObjAllocator which does all the low level functions. + When using a Small-Object in combination with the SingletonHolder template + you have to choose two lifetimes, that of the Small-Object and that of + the singleton. The rule is: The Small-Object lifetime must be greater than + the lifetime of the singleton hosting the Small-Object. Violating this rule + results in a crash on exit, because the hosting singleton tries to delete + the Small-Object which is then already destroyed. + + The lifetime policies recommended for use with Small-Objects hosted + by a SingletonHolder template are + - LongevityLifetime::DieAsSmallObjectParent / LongevityLifetime::DieAsSmallObjectChild + - SingletonWithLongevity + - FollowIntoDeath (not supported by MSVC 7.1) + - NoDestroy + + The default lifetime of Small-Objects is + LongevityLifetime::DieAsSmallObjectParent to + insure that memory is not released before a object with the lifetime + LongevityLifetime::DieAsSmallObjectChild using that + memory is destroyed. The LongevityLifetime::DieAsSmallObjectParent + lifetime has the highest possible value of a SetLongevity lifetime, so + you can use it in combination with your own lifetime not having also + the highest possible value. + + The DefaultLifetime and PhoenixSingleton policies are *not* recommended + since they can cause the allocator to be destroyed and release memory + for singletons hosting a object which inherit from either SmallObject + or SmallValueObject. + + @par Lifetime usage + + - LongevityLifetime: The Small-Object has + LongevityLifetime::DieAsSmallObjectParent policy and the Singleton + hosting the Small-Object has LongevityLifetime::DieAsSmallObjectChild. + The child lifetime has a hard coded SetLongevity lifetime which is + shorter than the lifetime of the parent, thus the child dies + before the parent. + + - Both Small-Object and Singleton use SingletonWithLongevity policy. + The longevity level for the singleton must be lower than that for the + Small-Object. This is why the AllocatorSingleton's GetLongevity function + returns the highest value. + + - FollowIntoDeath lifetime: The Small-Object has + FollowIntoDeath::With<LIFETIME>::AsMasterLiftime + policy and the Singleton has + FollowIntoDeath::AfterMaster<MASTERSINGLETON>::IsDestroyed policy, + where you could choose the LIFETIME. + + - Both Small-Object and Singleton use NoDestroy policy. + Since neither is ever destroyed, the destruction order does not matter. + Note: you will get memory leaks! + + - The Small-Object has NoDestroy policy but the Singleton has + SingletonWithLongevity policy. Note: you will get memory leaks! + + + You should *not* use NoDestroy for the singleton, and then use + SingletonWithLongevity for the Small-Object. + + @par Examples: + + - test/SmallObj/SmallSingleton.cpp + - test/Singleton/Dependencies.cpp + */ + template + < + template <class, class> class ThreadingModel, + std::size_t chunkSize, + std::size_t maxSmallObjectSize, + std::size_t objectAlignSize, + template <class> class LifetimePolicy, + class MutexPolicy + > + class SmallObjectBase + { + +#if (LOKI_MAX_SMALL_OBJECT_SIZE != 0) && (LOKI_DEFAULT_CHUNK_SIZE != 0) && (LOKI_DEFAULT_OBJECT_ALIGNMENT != 0) + + public: + /// Defines type of allocator singleton, must be public + /// to handle singleton lifetime dependencies. + typedef AllocatorSingleton< ThreadingModel, chunkSize, + maxSmallObjectSize, objectAlignSize, LifetimePolicy > ObjAllocatorSingleton; + + private: + + /// Defines type for thread-safety locking mechanism. + typedef ThreadingModel< ObjAllocatorSingleton, MutexPolicy > MyThreadingModel; + + /// Use singleton defined in AllocatorSingleton. + typedef typename ObjAllocatorSingleton::MyAllocatorSingleton MyAllocatorSingleton; + + public: + + /// Throwing single-object new throws bad_alloc when allocation fails. +#ifdef _MSC_VER + /// @note MSVC complains about non-empty exception specification lists. + static void * operator new ( std::size_t size ) +#else + static void * operator new ( std::size_t size ) throw ( std::bad_alloc ) +#endif + { + typename MyThreadingModel::Lock lock; + (void)lock; // get rid of warning + return MyAllocatorSingleton::Instance().Allocate( size, true ); + } + + /// Non-throwing single-object new returns NULL if allocation fails. + static void * operator new ( std::size_t size, const std::nothrow_t & ) throw () + { + typename MyThreadingModel::Lock lock; + (void)lock; // get rid of warning + return MyAllocatorSingleton::Instance().Allocate( size, false ); + } + + /// Placement single-object new merely calls global placement new. + inline static void * operator new ( std::size_t size, void * place ) + { + return ::operator new( size, place ); + } + + /// Single-object delete. + static void operator delete ( void * p, std::size_t size ) throw () + { + typename MyThreadingModel::Lock lock; + (void)lock; // get rid of warning + MyAllocatorSingleton::Instance().Deallocate( p, size ); + } + + /** Non-throwing single-object delete is only called when nothrow + new operator is used, and the constructor throws an exception. + */ + static void operator delete ( void * p, const std::nothrow_t & ) throw() + { + typename MyThreadingModel::Lock lock; + (void)lock; // get rid of warning + MyAllocatorSingleton::Instance().Deallocate( p ); + } + + /// Placement single-object delete merely calls global placement delete. + inline static void operator delete ( void * p, void * place ) + { + ::operator delete ( p, place ); + } + +#ifdef LOKI_SMALL_OBJECT_USE_NEW_ARRAY + + /// Throwing array-object new throws bad_alloc when allocation fails. +#ifdef _MSC_VER + /// @note MSVC complains about non-empty exception specification lists. + static void * operator new [] ( std::size_t size ) +#else + static void * operator new [] ( std::size_t size ) + throw ( std::bad_alloc ) +#endif + { + typename MyThreadingModel::Lock lock; + (void)lock; // get rid of warning + return MyAllocatorSingleton::Instance().Allocate( size, true ); + } + + /// Non-throwing array-object new returns NULL if allocation fails. + static void * operator new [] ( std::size_t size, + const std::nothrow_t & ) throw () + { + typename MyThreadingModel::Lock lock; + (void)lock; // get rid of warning + return MyAllocatorSingleton::Instance().Allocate( size, false ); + } + + /// Placement array-object new merely calls global placement new. + inline static void * operator new [] ( std::size_t size, void * place ) + { + return ::operator new( size, place ); + } + + /// Array-object delete. + static void operator delete [] ( void * p, std::size_t size ) throw () + { + typename MyThreadingModel::Lock lock; + (void)lock; // get rid of warning + MyAllocatorSingleton::Instance().Deallocate( p, size ); + } + + /** Non-throwing array-object delete is only called when nothrow + new operator is used, and the constructor throws an exception. + */ + static void operator delete [] ( void * p, + const std::nothrow_t & ) throw() + { + typename MyThreadingModel::Lock lock; + (void)lock; // get rid of warning + MyAllocatorSingleton::Instance().Deallocate( p ); + } + + /// Placement array-object delete merely calls global placement delete. + inline static void operator delete [] ( void * p, void * place ) + { + ::operator delete ( p, place ); + } +#endif // #if use new array functions. + +#endif // #if default template parameters are not zero + + protected: + inline SmallObjectBase( void ) {} + inline SmallObjectBase( const SmallObjectBase & ) {} + inline SmallObjectBase & operator = ( const SmallObjectBase & ) + { return *this; } + inline ~SmallObjectBase() {} + }; // end class SmallObjectBase + + + /** @class SmallObject + @ingroup SmallObjectGroup + SmallObject Base class for polymorphic small objects, offers fast + allocations & deallocations. Destructor is virtual and public. Default + constructor is trivial. Copy-constructor and copy-assignment operator are + not implemented since polymorphic classes almost always disable those + operations. Class has no data members so compilers can use + Empty-Base-Optimization. + */ + template + < + template <class, class> class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL, + std::size_t chunkSize = LOKI_DEFAULT_CHUNK_SIZE, + std::size_t maxSmallObjectSize = LOKI_MAX_SMALL_OBJECT_SIZE, + std::size_t objectAlignSize = LOKI_DEFAULT_OBJECT_ALIGNMENT, + template <class> class LifetimePolicy = LOKI_DEFAULT_SMALLOBJ_LIFETIME, + class MutexPolicy = LOKI_DEFAULT_MUTEX + > + class SmallObject : public SmallObjectBase< ThreadingModel, chunkSize, + maxSmallObjectSize, objectAlignSize, LifetimePolicy, MutexPolicy > + { + + public: + virtual ~SmallObject() {} + protected: + inline SmallObject( void ) {} + + private: + /// Copy-constructor is not implemented. + SmallObject( const SmallObject & ); + /// Copy-assignment operator is not implemented. + SmallObject & operator = ( const SmallObject & ); + }; // end class SmallObject + + + /** @class SmallValueObject + @ingroup SmallObjectGroup + SmallValueObject Base class for small objects with value-type + semantics - offers fast allocations & deallocations. Destructor is + non-virtual, inline, and protected to prevent unintentional destruction + through base class. Default constructor is trivial. Copy-constructor + and copy-assignment operator are trivial since value-types almost always + need those operations. Class has no data members so compilers can use + Empty-Base-Optimization. + */ + template + < + template <class, class> class ThreadingModel = LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL, + std::size_t chunkSize = LOKI_DEFAULT_CHUNK_SIZE, + std::size_t maxSmallObjectSize = LOKI_MAX_SMALL_OBJECT_SIZE, + std::size_t objectAlignSize = LOKI_DEFAULT_OBJECT_ALIGNMENT, + template <class> class LifetimePolicy = LOKI_DEFAULT_SMALLOBJ_LIFETIME, + class MutexPolicy = LOKI_DEFAULT_MUTEX + > + class SmallValueObject : public SmallObjectBase< ThreadingModel, chunkSize, + maxSmallObjectSize, objectAlignSize, LifetimePolicy, MutexPolicy > + { + protected: + inline SmallValueObject( void ) {} + inline SmallValueObject( const SmallValueObject & ) {} + inline SmallValueObject & operator = ( const SmallValueObject & ) + { return *this; } + inline ~SmallValueObject() {} + }; // end class SmallValueObject + +} // namespace Loki + +#endif // end file guardian + diff --git a/shared/loki/SmartPtr.h b/shared/loki/SmartPtr.h new file mode 100644 index 00000000..df548553 --- /dev/null +++ b/shared/loki/SmartPtr.h @@ -0,0 +1,1778 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_SMARTPTR_INC_ +#define LOKI_SMARTPTR_INC_ + +// $Id: SmartPtr.h 903 2008-11-10 05:55:12Z rich_sposato $ + + +/// \defgroup SmartPointerGroup Smart pointers +/// Policy based implementation of a smart pointer +/// \defgroup SmartPointerOwnershipGroup Ownership policies +/// \ingroup SmartPointerGroup +/// \defgroup SmartPointerStorageGroup Storage policies +/// \ingroup SmartPointerGroup +/// \defgroup SmartPointerConversionGroup Conversion policies +/// \ingroup SmartPointerGroup +/// \defgroup SmartPointerCheckingGroup Checking policies +/// \ingroup SmartPointerGroup + +#include "LokiExport.h" +#include "SmallObj.h" +#include "TypeManip.h" +#include "static_check.h" +#include "RefToValue.h" +#include "ConstPolicy.h" + +#include <functional> +#include <stdexcept> +#include <cassert> +#include <string> + +#if !defined(_MSC_VER) +# if defined(__sparc__) +# include <inttypes.h> +# else +# include <stdint.h> +# endif +#endif + +#if defined(_MSC_VER) || defined(__GNUC__) +// GCC>=4.1 must use -ffriend-injection due to a bug in GCC +#define LOKI_ENABLE_FRIEND_TEMPLATE_TEMPLATE_PARAMETER_WORKAROUND +#endif + + +namespace Loki +{ + +//////////////////////////////////////////////////////////////////////////////// +/// \class HeapStorage +/// +/// \ingroup SmartPointerStorageGroup +/// Implementation of the StoragePolicy used by SmartPtr. Uses explicit call +/// to T's destructor followed by call to free. +//////////////////////////////////////////////////////////////////////////////// + + + template <class T> + class HeapStorage + { + public: + typedef T* StoredType; /// the type of the pointee_ object + typedef T* InitPointerType; /// type used to declare OwnershipPolicy type. + typedef T* PointerType; /// type returned by operator-> + typedef T& ReferenceType; /// type returned by operator* + + HeapStorage() : pointee_(Default()) + {} + + // The storage policy doesn't initialize the stored pointer + // which will be initialized by the OwnershipPolicy's Clone fn + HeapStorage(const HeapStorage&) : pointee_(0) + {} + + template <class U> + HeapStorage(const HeapStorage<U>&) : pointee_(0) + {} + + HeapStorage(const StoredType& p) : pointee_(p) {} + + PointerType operator->() const { return pointee_; } + + ReferenceType operator*() const { return *pointee_; } + + void Swap(HeapStorage& rhs) + { std::swap(pointee_, rhs.pointee_); } + + // Accessors + template <class F> + friend typename HeapStorage<F>::PointerType GetImpl(const HeapStorage<F>& sp); + + template <class F> + friend const typename HeapStorage<F>::StoredType& GetImplRef(const HeapStorage<F>& sp); + + template <class F> + friend typename HeapStorage<F>::StoredType& GetImplRef(HeapStorage<F>& sp); + + protected: + // Destroys the data stored + // (Destruction might be taken over by the OwnershipPolicy) + void Destroy() + { + if ( 0 != pointee_ ) + { + pointee_->~T(); + ::free( pointee_ ); + } + } + + // Default value to initialize the pointer + static StoredType Default() + { return 0; } + + private: + // Data + StoredType pointee_; + }; + + template <class T> + inline typename HeapStorage<T>::PointerType GetImpl(const HeapStorage<T>& sp) + { return sp.pointee_; } + + template <class T> + inline const typename HeapStorage<T>::StoredType& GetImplRef(const HeapStorage<T>& sp) + { return sp.pointee_; } + + template <class T> + inline typename HeapStorage<T>::StoredType& GetImplRef(HeapStorage<T>& sp) + { return sp.pointee_; } + + +//////////////////////////////////////////////////////////////////////////////// +/// \class DefaultSPStorage +/// +/// \ingroup SmartPointerStorageGroup +/// Implementation of the StoragePolicy used by SmartPtr +//////////////////////////////////////////////////////////////////////////////// + + + template <class T> + class DefaultSPStorage + { + public: + typedef T* StoredType; // the type of the pointee_ object + typedef T* InitPointerType; /// type used to declare OwnershipPolicy type. + typedef T* PointerType; // type returned by operator-> + typedef T& ReferenceType; // type returned by operator* + + DefaultSPStorage() : pointee_(Default()) + {} + + // The storage policy doesn't initialize the stored pointer + // which will be initialized by the OwnershipPolicy's Clone fn + DefaultSPStorage(const DefaultSPStorage&) : pointee_(0) + {} + + template <class U> + DefaultSPStorage(const DefaultSPStorage<U>&) : pointee_(0) + {} + + DefaultSPStorage(const StoredType& p) : pointee_(p) {} + + PointerType operator->() const { return pointee_; } + + ReferenceType operator*() const { return *pointee_; } + + void Swap(DefaultSPStorage& rhs) + { std::swap(pointee_, rhs.pointee_); } + + // Accessors + template <class F> + friend typename DefaultSPStorage<F>::PointerType GetImpl(const DefaultSPStorage<F>& sp); + + template <class F> + friend const typename DefaultSPStorage<F>::StoredType& GetImplRef(const DefaultSPStorage<F>& sp); + + template <class F> + friend typename DefaultSPStorage<F>::StoredType& GetImplRef(DefaultSPStorage<F>& sp); + + protected: + // Destroys the data stored + // (Destruction might be taken over by the OwnershipPolicy) + // + // If your compiler gives you a warning in this area while + // compiling the tests, it is on purpose, please ignore it. + void Destroy() + { + delete pointee_; + } + + // Default value to initialize the pointer + static StoredType Default() + { return 0; } + + private: + // Data + StoredType pointee_; + }; + + template <class T> + inline typename DefaultSPStorage<T>::PointerType GetImpl(const DefaultSPStorage<T>& sp) + { return sp.pointee_; } + + template <class T> + inline const typename DefaultSPStorage<T>::StoredType& GetImplRef(const DefaultSPStorage<T>& sp) + { return sp.pointee_; } + + template <class T> + inline typename DefaultSPStorage<T>::StoredType& GetImplRef(DefaultSPStorage<T>& sp) + { return sp.pointee_; } + + +//////////////////////////////////////////////////////////////////////////////// +/// \class LockedStorage +/// +/// \ingroup SmartPointerStorageGroup +/// Implementation of the StoragePolicy used by SmartPtr. +/// +/// Each call to operator-> locks the object for the duration of a call to a +/// member function of T. +/// +/// \par How It Works +/// LockedStorage has a helper class called Locker, which acts as a smart +/// pointer with limited abilities. LockedStorage::operator-> returns an +/// unnamed temporary of type Locker<T> that exists for the duration of the +/// call to a member function of T. The unnamed temporary locks the object +/// when it is constructed by operator-> and unlocks the object when it is +/// destructed. +/// +/// \note This storage policy requires class T to have member functions Lock +/// and Unlock. If your class does not have Lock or Unlock functions, you may +/// either make a child class which does, or make a policy class similar to +/// LockedStorage which calls other functions to lock the object. +//////////////////////////////////////////////////////////////////////////////// + + template <class T> + class Locker + { + public: + Locker( const T * p ) : pointee_( const_cast< T * >( p ) ) + { + if ( pointee_ != 0 ) + pointee_->Lock(); + } + + ~Locker( void ) + { + if ( pointee_ != 0 ) + pointee_->Unlock(); + } + + operator T * () + { + return pointee_; + } + + T * operator->() + { + return pointee_; + } + + private: + Locker( void ); + Locker & operator = ( const Locker & ); + T * pointee_; + }; + + template <class T> + class LockedStorage + { + public: + + typedef T* StoredType; /// the type of the pointee_ object + typedef T* InitPointerType; /// type used to declare OwnershipPolicy type. + typedef Locker< T > PointerType; /// type returned by operator-> + typedef T& ReferenceType; /// type returned by operator* + + LockedStorage() : pointee_( Default() ) {} + + ~LockedStorage( void ) {} + + LockedStorage( const LockedStorage&) : pointee_( 0 ) {} + + LockedStorage( const StoredType & p ) : pointee_( p ) {} + + PointerType operator->() + { + return Locker< T >( pointee_ ); + } + + void Swap(LockedStorage& rhs) + { + std::swap( pointee_, rhs.pointee_ ); + } + + // Accessors + template <class F> + friend typename LockedStorage<F>::InitPointerType GetImpl(const LockedStorage<F>& sp); + + template <class F> + friend const typename LockedStorage<F>::StoredType& GetImplRef(const LockedStorage<F>& sp); + + template <class F> + friend typename LockedStorage<F>::StoredType& GetImplRef(LockedStorage<F>& sp); + + protected: + // Destroys the data stored + // (Destruction might be taken over by the OwnershipPolicy) + void Destroy() + { + delete pointee_; + } + + // Default value to initialize the pointer + static StoredType Default() + { return 0; } + + private: + /// Dereference operator is not implemented. + ReferenceType operator*(); + + // Data + StoredType pointee_; + }; + + template <class T> + inline typename LockedStorage<T>::InitPointerType GetImpl(const LockedStorage<T>& sp) + { return sp.pointee_; } + + template <class T> + inline const typename LockedStorage<T>::StoredType& GetImplRef(const LockedStorage<T>& sp) + { return sp.pointee_; } + + template <class T> + inline typename LockedStorage<T>::StoredType& GetImplRef(LockedStorage<T>& sp) + { return sp.pointee_; } + + +//////////////////////////////////////////////////////////////////////////////// +/// \class ArrayStorage +/// +/// \ingroup SmartPointerStorageGroup +/// Implementation of the ArrayStorage used by SmartPtr +//////////////////////////////////////////////////////////////////////////////// + + + template <class T> + class ArrayStorage + { + public: + typedef T* StoredType; // the type of the pointee_ object + typedef T* InitPointerType; /// type used to declare OwnershipPolicy type. + typedef T* PointerType; // type returned by operator-> + typedef T& ReferenceType; // type returned by operator* + + ArrayStorage() : pointee_(Default()) + {} + + // The storage policy doesn't initialize the stored pointer + // which will be initialized by the OwnershipPolicy's Clone fn + ArrayStorage(const ArrayStorage&) : pointee_(0) + {} + + template <class U> + ArrayStorage(const ArrayStorage<U>&) : pointee_(0) + {} + + ArrayStorage(const StoredType& p) : pointee_(p) {} + + PointerType operator->() const { return pointee_; } + + ReferenceType operator*() const { return *pointee_; } + + void Swap(ArrayStorage& rhs) + { std::swap(pointee_, rhs.pointee_); } + + // Accessors + template <class F> + friend typename ArrayStorage<F>::PointerType GetImpl(const ArrayStorage<F>& sp); + + template <class F> + friend const typename ArrayStorage<F>::StoredType& GetImplRef(const ArrayStorage<F>& sp); + + template <class F> + friend typename ArrayStorage<F>::StoredType& GetImplRef(ArrayStorage<F>& sp); + + protected: + // Destroys the data stored + // (Destruction might be taken over by the OwnershipPolicy) + void Destroy() + { delete [] pointee_; } + + // Default value to initialize the pointer + static StoredType Default() + { return 0; } + + private: + // Data + StoredType pointee_; + }; + + template <class T> + inline typename ArrayStorage<T>::PointerType GetImpl(const ArrayStorage<T>& sp) + { return sp.pointee_; } + + template <class T> + inline const typename ArrayStorage<T>::StoredType& GetImplRef(const ArrayStorage<T>& sp) + { return sp.pointee_; } + + template <class T> + inline typename ArrayStorage<T>::StoredType& GetImplRef(ArrayStorage<T>& sp) + { return sp.pointee_; } + + +//////////////////////////////////////////////////////////////////////////////// +/// \class RefCounted +/// +/// \ingroup SmartPointerOwnershipGroup +/// Implementation of the OwnershipPolicy used by SmartPtr +/// Provides a classic external reference counting implementation +//////////////////////////////////////////////////////////////////////////////// + + template <class P> + class RefCounted + { + public: + RefCounted() + : pCount_(static_cast<uintptr_t*>( + SmallObject<>::operator new(sizeof(uintptr_t)))) + { + assert(pCount_!=0); + *pCount_ = 1; + } + + RefCounted(const RefCounted& rhs) + : pCount_(rhs.pCount_) + {} + + // MWCW lacks template friends, hence the following kludge + template <typename P1> + RefCounted(const RefCounted<P1>& rhs) + : pCount_(reinterpret_cast<const RefCounted&>(rhs).pCount_) + {} + + P Clone(const P& val) + { + ++*pCount_; + return val; + } + + bool Release(const P&) + { + if (!--*pCount_) + { + SmallObject<>::operator delete(pCount_, sizeof(uintptr_t)); + pCount_ = NULL; + return true; + } + return false; + } + + void Swap(RefCounted& rhs) + { std::swap(pCount_, rhs.pCount_); } + + enum { destructiveCopy = false }; + + private: + // Data + uintptr_t* pCount_; + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \struct RefCountedMT +/// +/// \ingroup SmartPointerOwnershipGroup +/// Implementation of the OwnershipPolicy used by SmartPtr +/// Implements external reference counting for multithreaded programs +/// Policy Usage: RefCountedMTAdj<ThreadingModel>::RefCountedMT +/// +/// \par Warning +/// There could be a race condition, see bug "Race condition in RefCountedMTAdj::Release" +/// http://sourceforge.net/tracker/index.php?func=detail&aid=1408845&group_id=29557&atid=396644 +/// As stated in bug 1408845, the Release function is not thread safe if a +/// SmartPtr copy-constructor tries to copy the last pointer to an object in +/// one thread, while the destructor is acting on the last pointer in another +/// thread. The existence of a race between a copy-constructor and destructor +/// implies a design flaw at a higher level. That race condition must be +/// fixed at a higher design level, and no change to this class could fix it. +//////////////////////////////////////////////////////////////////////////////// + + template <template <class, class> class ThreadingModel, + class MX = LOKI_DEFAULT_MUTEX > + struct RefCountedMTAdj + { + template <class P> + class RefCountedMT : public ThreadingModel< RefCountedMT<P>, MX > + { + typedef ThreadingModel< RefCountedMT<P>, MX > base_type; + typedef typename base_type::IntType CountType; + typedef volatile CountType *CountPtrType; + + public: + RefCountedMT() + { + pCount_ = static_cast<CountPtrType>( + SmallObject<LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL>::operator new( + sizeof(*pCount_))); + assert(pCount_); + //*pCount_ = 1; + ThreadingModel<RefCountedMT, MX>::AtomicAssign(*pCount_, 1); + } + + RefCountedMT(const RefCountedMT& rhs) + : pCount_(rhs.pCount_) + {} + + //MWCW lacks template friends, hence the following kludge + template <typename P1> + RefCountedMT(const RefCountedMT<P1>& rhs) + : pCount_(reinterpret_cast<const RefCountedMT<P>&>(rhs).pCount_) + {} + + P Clone(const P& val) + { + ThreadingModel<RefCountedMT, MX>::AtomicIncrement(*pCount_); + return val; + } + + bool Release(const P&) + { + bool isZero = false; + ThreadingModel< RefCountedMT, MX >::AtomicDecrement( *pCount_, 0, isZero ); + if ( isZero ) + { + SmallObject<LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL>::operator delete( + const_cast<CountType *>(pCount_), + sizeof(*pCount_)); + return true; + } + return false; + } + + void Swap(RefCountedMT& rhs) + { std::swap(pCount_, rhs.pCount_); } + + enum { destructiveCopy = false }; + + private: + // Data + CountPtrType pCount_; + }; + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \class COMRefCounted +/// +/// \ingroup SmartPointerOwnershipGroup +/// Implementation of the OwnershipPolicy used by SmartPtr +/// Adapts COM intrusive reference counting to OwnershipPolicy-specific syntax +//////////////////////////////////////////////////////////////////////////////// + + template <class P> + class COMRefCounted + { + public: + COMRefCounted() + {} + + template <class U> + COMRefCounted(const COMRefCounted<U>&) + {} + + static P Clone(const P& val) + { + if(val!=0) + val->AddRef(); + return val; + } + + static bool Release(const P& val) + { + if(val!=0) + val->Release(); + return false; + } + + enum { destructiveCopy = false }; + + static void Swap(COMRefCounted&) + {} + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \struct DeepCopy +/// +/// \ingroup SmartPointerOwnershipGroup +/// Implementation of the OwnershipPolicy used by SmartPtr +/// Implements deep copy semantics, assumes existence of a Clone() member +/// function of the pointee type +//////////////////////////////////////////////////////////////////////////////// + + template <class P> + struct DeepCopy + { + DeepCopy() + {} + + template <class P1> + DeepCopy(const DeepCopy<P1>&) + {} + + static P Clone(const P& val) + { return val->Clone(); } + + static bool Release(const P&) + { return true; } + + static void Swap(DeepCopy&) + {} + + enum { destructiveCopy = false }; + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \class RefLinked +/// +/// \ingroup SmartPointerOwnershipGroup +/// Implementation of the OwnershipPolicy used by SmartPtr +/// Implements reference linking +//////////////////////////////////////////////////////////////////////////////// + + namespace Private + { + class LOKI_EXPORT RefLinkedBase + { + public: + RefLinkedBase() + { prev_ = next_ = this; } + + RefLinkedBase(const RefLinkedBase& rhs); + + bool Release(); + + void Swap(RefLinkedBase& rhs); + + bool Merge( RefLinkedBase & rhs ); + + enum { destructiveCopy = false }; + + private: + static unsigned int CountPrevCycle( const RefLinkedBase * pThis ); + static unsigned int CountNextCycle( const RefLinkedBase * pThis ); + bool HasPrevNode( const RefLinkedBase * p ) const; + bool HasNextNode( const RefLinkedBase * p ) const; + + mutable const RefLinkedBase* prev_; + mutable const RefLinkedBase* next_; + }; + } + + template <class P> + class RefLinked : public Private::RefLinkedBase + { + public: + RefLinked() + {} + + template <class P1> + RefLinked(const RefLinked<P1>& rhs) + : Private::RefLinkedBase(rhs) + {} + + static P Clone(const P& val) + { return val; } + + bool Release(const P&) + { return Private::RefLinkedBase::Release(); } + + template < class P1 > + bool Merge( RefLinked< P1 > & rhs ) + { + return Private::RefLinkedBase::Merge( rhs ); + } + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \class DestructiveCopy +/// +/// \ingroup SmartPointerOwnershipGroup +/// Implementation of the OwnershipPolicy used by SmartPtr +/// Implements destructive copy semantics (a la std::auto_ptr) +//////////////////////////////////////////////////////////////////////////////// + + template <class P> + class DestructiveCopy + { + public: + DestructiveCopy() + {} + + template <class P1> + DestructiveCopy(const DestructiveCopy<P1>&) + {} + + template <class P1> + static P Clone(P1& val) + { + P result(val); + val = P1(); + return result; + } + + static bool Release(const P&) + { return true; } + + static void Swap(DestructiveCopy&) + {} + + enum { destructiveCopy = true }; + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \class NoCopy +/// +/// \ingroup SmartPointerOwnershipGroup +/// Implementation of the OwnershipPolicy used by SmartPtr +/// Implements a policy that doesn't allow copying objects +//////////////////////////////////////////////////////////////////////////////// + + template <class P> + class NoCopy + { + public: + NoCopy() + {} + + template <class P1> + NoCopy(const NoCopy<P1>&) + {} + + static P Clone(const P&) + { + // Make it depended on template parameter + static const bool DependedFalse = sizeof(P*) == 0; + + LOKI_STATIC_CHECK(DependedFalse, This_Policy_Disallows_Value_Copying); + } + + static bool Release(const P&) + { return true; } + + static void Swap(NoCopy&) + {} + + enum { destructiveCopy = false }; + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \struct AllowConversion +/// +/// \ingroup SmartPointerConversionGroup +/// Implementation of the ConversionPolicy used by SmartPtr +/// Allows implicit conversion from SmartPtr to the pointee type +//////////////////////////////////////////////////////////////////////////////// + + struct AllowConversion + { + enum { allow = true }; + + void Swap(AllowConversion&) + {} + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \struct DisallowConversion +/// +/// \ingroup SmartPointerConversionGroup +/// Implementation of the ConversionPolicy used by SmartPtr +/// Does not allow implicit conversion from SmartPtr to the pointee type +/// You can initialize a DisallowConversion with an AllowConversion +//////////////////////////////////////////////////////////////////////////////// + + struct DisallowConversion + { + DisallowConversion() + {} + + DisallowConversion(const AllowConversion&) + {} + + enum { allow = false }; + + void Swap(DisallowConversion&) + {} + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \struct NoCheck +/// +/// \ingroup SmartPointerCheckingGroup +/// Implementation of the CheckingPolicy used by SmartPtr +/// Well, it's clear what it does :o) +//////////////////////////////////////////////////////////////////////////////// + + template <class P> + struct NoCheck + { + NoCheck() + {} + + template <class P1> + NoCheck(const NoCheck<P1>&) + {} + + static void OnDefault(const P&) + {} + + static void OnInit(const P&) + {} + + static void OnDereference(const P&) + {} + + static void Swap(NoCheck&) + {} + }; + + +//////////////////////////////////////////////////////////////////////////////// +/// \struct AssertCheck +/// +/// \ingroup SmartPointerCheckingGroup +/// Implementation of the CheckingPolicy used by SmartPtr +/// Checks the pointer before dereference +//////////////////////////////////////////////////////////////////////////////// + + template <class P> + struct AssertCheck + { + AssertCheck() + {} + + template <class P1> + AssertCheck(const AssertCheck<P1>&) + {} + + template <class P1> + AssertCheck(const NoCheck<P1>&) + {} + + static void OnDefault(const P&) + {} + + static void OnInit(const P&) + {} + + static void OnDereference(P val) + { assert(val); (void)val; } + + static void Swap(AssertCheck&) + {} + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \struct AssertCheckStrict +/// +/// \ingroup SmartPointerCheckingGroup +/// Implementation of the CheckingPolicy used by SmartPtr +/// Checks the pointer against zero upon initialization and before dereference +/// You can initialize an AssertCheckStrict with an AssertCheck +//////////////////////////////////////////////////////////////////////////////// + + template <class P> + struct AssertCheckStrict + { + AssertCheckStrict() + {} + + template <class U> + AssertCheckStrict(const AssertCheckStrict<U>&) + {} + + template <class U> + AssertCheckStrict(const AssertCheck<U>&) + {} + + template <class P1> + AssertCheckStrict(const NoCheck<P1>&) + {} + + static void OnDefault(P val) + { assert(val); } + + static void OnInit(P val) + { assert(val); } + + static void OnDereference(P val) + { assert(val); } + + static void Swap(AssertCheckStrict&) + {} + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \struct NullPointerException +/// +/// \ingroup SmartPointerGroup +/// Used by some implementations of the CheckingPolicy used by SmartPtr +//////////////////////////////////////////////////////////////////////////////// + + struct NullPointerException : public std::runtime_error + { + NullPointerException() : std::runtime_error(std::string("")) + { } + const char* what() const throw() + { return "Null Pointer Exception"; } + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \struct RejectNullStatic +/// +/// \ingroup SmartPointerCheckingGroup +/// Implementation of the CheckingPolicy used by SmartPtr +/// Checks the pointer upon initialization and before dereference +//////////////////////////////////////////////////////////////////////////////// + + template <class P> + struct RejectNullStatic + { + RejectNullStatic() + {} + + template <class P1> + RejectNullStatic(const RejectNullStatic<P1>&) + {} + + template <class P1> + RejectNullStatic(const NoCheck<P1>&) + {} + + template <class P1> + RejectNullStatic(const AssertCheck<P1>&) + {} + + template <class P1> + RejectNullStatic(const AssertCheckStrict<P1>&) + {} + + static void OnDefault(const P&) + { + // Make it depended on template parameter + static const bool DependedFalse = sizeof(P*) == 0; + + LOKI_STATIC_CHECK(DependedFalse, ERROR_This_Policy_Does_Not_Allow_Default_Initialization); + } + + static void OnInit(const P& val) + { if (!val) throw NullPointerException(); } + + static void OnDereference(const P& val) + { if (!val) throw NullPointerException(); } + + static void Swap(RejectNullStatic&) + {} + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \struct RejectNull +/// +/// \ingroup SmartPointerCheckingGroup +/// Implementation of the CheckingPolicy used by SmartPtr +/// Checks the pointer before dereference +//////////////////////////////////////////////////////////////////////////////// + + template <class P> + struct RejectNull + { + RejectNull() + {} + + template <class P1> + RejectNull(const RejectNull<P1>&) + {} + + static void OnInit(P) + {} + + static void OnDefault(P) + {} + + void OnDereference(P val) + { if (!val) throw NullPointerException(); } + + void OnDereference(P val) const + { if (!val) throw NullPointerException(); } + + void Swap(RejectNull&) + {} + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \struct RejectNullStrict +/// +/// \ingroup SmartPointerCheckingGroup +/// Implementation of the CheckingPolicy used by SmartPtr +/// Checks the pointer upon initialization and before dereference +//////////////////////////////////////////////////////////////////////////////// + + template <class P> + struct RejectNullStrict + { + RejectNullStrict() + {} + + template <class P1> + RejectNullStrict(const RejectNullStrict<P1>&) + {} + + template <class P1> + RejectNullStrict(const RejectNull<P1>&) + {} + + static void OnInit(P val) + { if (!val) throw NullPointerException(); } + + void OnDereference(P val) + { OnInit(val); } + + void OnDereference(P val) const + { OnInit(val); } + + void Swap(RejectNullStrict&) + {} + }; + + +//////////////////////////////////////////////////////////////////////////////// +// class template SmartPtr (declaration) +// The reason for all the fuss above +//////////////////////////////////////////////////////////////////////////////// + + template + < + typename T, + template <class> class OwnershipPolicy = RefCounted, + class ConversionPolicy = DisallowConversion, + template <class> class CheckingPolicy = AssertCheck, + template <class> class StoragePolicy = DefaultSPStorage, + template<class> class ConstnessPolicy = LOKI_DEFAULT_CONSTNESS + > + class SmartPtr; + +//////////////////////////////////////////////////////////////////////////////// +// class template SmartPtrDef (definition) +// this class added to unify the usage of SmartPtr +// instead of writing SmartPtr<T,OP,CP,KP,SP> write SmartPtrDef<T,OP,CP,KP,SP>::type +//////////////////////////////////////////////////////////////////////////////// + + template + < + typename T, + template <class> class OwnershipPolicy = RefCounted, + class ConversionPolicy = DisallowConversion, + template <class> class CheckingPolicy = AssertCheck, + template <class> class StoragePolicy = DefaultSPStorage, + template<class> class ConstnessPolicy = LOKI_DEFAULT_CONSTNESS + > + struct SmartPtrDef + { + typedef SmartPtr + < + T, + OwnershipPolicy, + ConversionPolicy, + CheckingPolicy, + StoragePolicy, + ConstnessPolicy + > + type; + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \class SmartPtr +/// +/// \ingroup SmartPointerGroup +/// +/// \param OwnershipPolicy default = RefCounted, +/// \param ConversionPolicy default = DisallowConversion, +/// \param CheckingPolicy default = AssertCheck, +/// \param StoragePolicy default = DefaultSPStorage +/// \param ConstnessPolicy default = LOKI_DEFAULT_CONSTNESS +/// +/// \par IMPORTANT NOTE +/// Due to threading issues, the OwnershipPolicy has been changed as follows: +/// +/// - Release() returns a boolean saying if that was the last release +/// so the pointer can be deleted by the StoragePolicy +/// - IsUnique() was removed +//////////////////////////////////////////////////////////////////////////////// + + template + < + typename T, + template <class> class OwnershipPolicy, + class ConversionPolicy, + template <class> class CheckingPolicy, + template <class> class StoragePolicy, + template <class> class ConstnessPolicy + > + class SmartPtr + : public StoragePolicy<T> + , public OwnershipPolicy<typename StoragePolicy<T>::InitPointerType> + , public CheckingPolicy<typename StoragePolicy<T>::StoredType> + , public ConversionPolicy + { + typedef StoragePolicy<T> SP; + typedef OwnershipPolicy<typename StoragePolicy<T>::InitPointerType> OP; + typedef CheckingPolicy<typename StoragePolicy<T>::StoredType> KP; + typedef ConversionPolicy CP; + + public: + typedef typename ConstnessPolicy<T>::Type* ConstPointerType; + typedef typename ConstnessPolicy<T>::Type& ConstReferenceType; + + typedef typename SP::PointerType PointerType; + typedef typename SP::StoredType StoredType; + typedef typename SP::ReferenceType ReferenceType; + + typedef typename Select<OP::destructiveCopy,SmartPtr, const SmartPtr>::Result + CopyArg; + + private: + struct NeverMatched {}; + +#ifdef LOKI_SMARTPTR_CONVERSION_CONSTRUCTOR_POLICY + typedef typename Select< CP::allow, const StoredType&, NeverMatched>::Result ImplicitArg; + typedef typename Select<!CP::allow, const StoredType&, NeverMatched>::Result ExplicitArg; +#else + typedef const StoredType& ImplicitArg; + typedef typename Select<false, const StoredType&, NeverMatched>::Result ExplicitArg; +#endif + + public: + + SmartPtr() + { + KP::OnDefault(GetImpl(*this)); + } + + explicit + SmartPtr(ExplicitArg p) : SP(p) + { + KP::OnInit(GetImpl(*this)); + } + + SmartPtr(ImplicitArg p) : SP(p) + { + KP::OnInit(GetImpl(*this)); + } + + SmartPtr(CopyArg& rhs) : SP(rhs), OP(rhs), KP(rhs), CP(rhs) + { + GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); + } + + template + < + typename T1, + template <class> class OP1, + class CP1, + template <class> class KP1, + template <class> class SP1, + template <class> class CNP1 + > + SmartPtr(const SmartPtr<T1, OP1, CP1, KP1, SP1, CNP1 >& rhs) + : SP(rhs), OP(rhs), KP(rhs), CP(rhs) + { GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); } + + template + < + typename T1, + template <class> class OP1, + class CP1, + template <class> class KP1, + template <class> class SP1, + template <class> class CNP1 + > + SmartPtr(SmartPtr<T1, OP1, CP1, KP1, SP1, CNP1 >& rhs) + : SP(rhs), OP(rhs), KP(rhs), CP(rhs) + { + GetImplRef(*this) = OP::Clone(GetImplRef(rhs)); + } + + SmartPtr(RefToValue<SmartPtr> rhs) + : SP(rhs), OP(rhs), KP(rhs), CP(rhs) + {} + + operator RefToValue<SmartPtr>() + { return RefToValue<SmartPtr>(*this); } + + SmartPtr& operator=(CopyArg& rhs) + { + SmartPtr temp(rhs); + temp.Swap(*this); + return *this; + } + + template + < + typename T1, + template <class> class OP1, + class CP1, + template <class> class KP1, + template <class> class SP1, + template <class> class CNP1 + > + SmartPtr& operator=(const SmartPtr<T1, OP1, CP1, KP1, SP1, CNP1 >& rhs) + { + SmartPtr temp(rhs); + temp.Swap(*this); + return *this; + } + + template + < + typename T1, + template <class> class OP1, + class CP1, + template <class> class KP1, + template <class> class SP1, + template <class> class CNP1 + > + SmartPtr& operator=(SmartPtr<T1, OP1, CP1, KP1, SP1, CNP1 >& rhs) + { + SmartPtr temp(rhs); + temp.Swap(*this); + return *this; + } + + void Swap(SmartPtr& rhs) + { + OP::Swap(rhs); + CP::Swap(rhs); + KP::Swap(rhs); + SP::Swap(rhs); + } + + ~SmartPtr() + { + if (OP::Release(GetImpl(*static_cast<SP*>(this)))) + { + SP::Destroy(); + } + } + +#ifdef LOKI_ENABLE_FRIEND_TEMPLATE_TEMPLATE_PARAMETER_WORKAROUND + + // old non standard in class definition of friends + friend inline void Release(SmartPtr& sp, typename SP::StoredType& p) + { + p = GetImplRef(sp); + GetImplRef(sp) = SP::Default(); + } + + friend inline void Reset(SmartPtr& sp, typename SP::StoredType p) + { SmartPtr(p).Swap(sp); } + +#else + + template + < + typename T1, + template <class> class OP1, + class CP1, + template <class> class KP1, + template <class> class SP1, + template <class> class CNP1 + > + friend void Release(SmartPtr<T1, OP1, CP1, KP1, SP1, CNP1>& sp, + typename SP1<T1>::StoredType& p); + + template + < + typename T1, + template <class> class OP1, + class CP1, + template <class> class KP1, + template <class> class SP1, + template <class> class CNP1 + > + friend void Reset(SmartPtr<T1, OP1, CP1, KP1, SP1, CNP1>& sp, + typename SP1<T1>::StoredType p); +#endif + + + template + < + typename T1, + template <class> class OP1, + class CP1, + template <class> class KP1, + template <class> class SP1, + template <class> class CNP1 + > + bool Merge( SmartPtr< T1, OP1, CP1, KP1, SP1, CNP1 > & rhs ) + { + if ( GetImpl( *this ) != GetImpl( rhs ) ) + { + return false; + } + return OP::template Merge( rhs ); + } + + PointerType operator->() + { + KP::OnDereference(GetImplRef(*this)); + return SP::operator->(); + } + + ConstPointerType operator->() const + { + KP::OnDereference(GetImplRef(*this)); + return SP::operator->(); + } + + ReferenceType operator*() + { + KP::OnDereference(GetImplRef(*this)); + return SP::operator*(); + } + + ConstReferenceType operator*() const + { + KP::OnDereference(GetImplRef(*this)); + return SP::operator*(); + } + + bool operator!() const // Enables "if (!sp) ..." + { return GetImpl(*this) == 0; } + + static inline T * GetPointer( const SmartPtr & sp ) + { return GetImpl( sp ); } + + // Ambiguity buster + template + < + typename T1, + template <class> class OP1, + class CP1, + template <class> class KP1, + template <class> class SP1, + template <class> class CNP1 + > + bool operator==(const SmartPtr<T1, OP1, CP1, KP1, SP1, CNP1 >& rhs) const + { return GetImpl(*this) == GetImpl(rhs); } + + // Ambiguity buster + template + < + typename T1, + template <class> class OP1, + class CP1, + template <class> class KP1, + template <class> class SP1, + template <class> class CNP1 + > + bool operator!=(const SmartPtr<T1, OP1, CP1, KP1, SP1, CNP1 >& rhs) const + { return !(*this == rhs); } + + // Ambiguity buster + template + < + typename T1, + template <class> class OP1, + class CP1, + template <class> class KP1, + template <class> class SP1, + template <class> class CNP1 + > + bool operator<(const SmartPtr<T1, OP1, CP1, KP1, SP1, CNP1 >& rhs) const + { return GetImpl(*this) < GetImpl(rhs); } + + // Ambiguity buster + template + < + typename T1, + template <class> class OP1, + class CP1, + template <class> class KP1, + template <class> class SP1, + template <class> class CNP1 + > + inline bool operator > ( const SmartPtr< T1, OP1, CP1, KP1, SP1, CNP1 > & rhs ) + { + return ( GetImpl( rhs ) < GetImpl( *this ) ); + } + + // Ambiguity buster + template + < + typename T1, + template <class> class OP1, + class CP1, + template <class> class KP1, + template <class> class SP1, + template <class> class CNP1 + > + inline bool operator <= ( const SmartPtr< T1, OP1, CP1, KP1, SP1, CNP1 > & rhs ) + { + return !( GetImpl( rhs ) < GetImpl( *this ) ); + } + + // Ambiguity buster + template + < + typename T1, + template <class> class OP1, + class CP1, + template <class> class KP1, + template <class> class SP1, + template <class> class CNP1 + > + inline bool operator >= ( const SmartPtr< T1, OP1, CP1, KP1, SP1, CNP1 > & rhs ) + { + return !( GetImpl( *this ) < GetImpl( rhs ) ); + } + + private: + // Helper for enabling 'if (sp)' + struct Tester + { + Tester(int) {} + void dummy() {} + }; + + typedef void (Tester::*unspecified_boolean_type_)(); + + typedef typename Select<CP::allow, Tester, unspecified_boolean_type_>::Result + unspecified_boolean_type; + + public: + // enable 'if (sp)' + operator unspecified_boolean_type() const + { + return !*this ? 0 : &Tester::dummy; + } + + private: + // Helper for disallowing automatic conversion + struct Insipid + { + Insipid(PointerType) {} + }; + + typedef typename Select<CP::allow, PointerType, Insipid>::Result + AutomaticConversionResult; + + public: + operator AutomaticConversionResult() const + { return GetImpl(*this); } + }; + + +//////////////////////////////////////////////////////////////////////////////// +// friends +//////////////////////////////////////////////////////////////////////////////// + +#ifndef LOKI_ENABLE_FRIEND_TEMPLATE_TEMPLATE_PARAMETER_WORKAROUND + + template + < + typename T, + template <class> class OP, + class CP, + template <class> class KP, + template <class> class SP, + template <class> class CNP + > + inline void Release(SmartPtr<T, OP, CP, KP, SP, CNP>& sp, + typename SP<T>::StoredType& p) + { + p = GetImplRef(sp); + GetImplRef(sp) = SP<T>::Default(); + } + + template + < + typename T, + template <class> class OP, + class CP, + template <class> class KP, + template <class> class SP, + template <class> class CNP + > + inline void Reset(SmartPtr<T, OP, CP, KP, SP, CNP>& sp, + typename SP<T>::StoredType p) + { SmartPtr<T, OP, CP, KP, SP, CNP>(p).Swap(sp); } + +#endif + +//////////////////////////////////////////////////////////////////////////////// +// free comparison operators for class template SmartPtr +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// operator== for lhs = SmartPtr, rhs = raw pointer +/// \ingroup SmartPointerGroup +//////////////////////////////////////////////////////////////////////////////// + + template + < + typename T, + template <class> class OP, + class CP, + template <class> class KP, + template <class> class SP, + template <class> class CNP1, + typename U + > + inline bool operator==(const SmartPtr<T, OP, CP, KP, SP, CNP1 >& lhs, + U* rhs) + { return GetImpl(lhs) == rhs; } + +//////////////////////////////////////////////////////////////////////////////// +/// operator== for lhs = raw pointer, rhs = SmartPtr +/// \ingroup SmartPointerGroup +//////////////////////////////////////////////////////////////////////////////// + + template + < + typename T, + template <class> class OP, + class CP, + template <class> class KP, + template <class> class SP, + template <class> class CNP1, + typename U + > + inline bool operator==(U* lhs, + const SmartPtr<T, OP, CP, KP, SP, CNP1 >& rhs) + { return rhs == lhs; } + +//////////////////////////////////////////////////////////////////////////////// +/// operator!= for lhs = SmartPtr, rhs = raw pointer +/// \ingroup SmartPointerGroup +//////////////////////////////////////////////////////////////////////////////// + + template + < + typename T, + template <class> class OP, + class CP, + template <class> class KP, + template <class> class SP, + template <class> class CNP, + typename U + > + inline bool operator!=(const SmartPtr<T, OP, CP, KP, SP, CNP >& lhs, + U* rhs) + { return !(lhs == rhs); } + +//////////////////////////////////////////////////////////////////////////////// +/// operator!= for lhs = raw pointer, rhs = SmartPtr +/// \ingroup SmartPointerGroup +//////////////////////////////////////////////////////////////////////////////// + + template + < + typename T, + template <class> class OP, + class CP, + template <class> class KP, + template <class> class SP, + template <class> class CNP, + typename U + > + inline bool operator!=(U* lhs, + const SmartPtr<T, OP, CP, KP, SP, CNP >& rhs) + { return rhs != lhs; } + +//////////////////////////////////////////////////////////////////////////////// +/// operator< for lhs = SmartPtr, rhs = raw pointer +/// \ingroup SmartPointerGroup +//////////////////////////////////////////////////////////////////////////////// + + template + < + typename T, + template <class> class OP, + class CP, + template <class> class KP, + template <class> class SP, + template <class> class CNP, + typename U + > + inline bool operator<(const SmartPtr<T, OP, CP, KP, SP, CNP >& lhs, + U* rhs) + { + return ( GetImpl( lhs ) < rhs ); + } + +//////////////////////////////////////////////////////////////////////////////// +/// operator< for lhs = raw pointer, rhs = SmartPtr +/// \ingroup SmartPointerGroup +//////////////////////////////////////////////////////////////////////////////// + + template + < + typename T, + template <class> class OP, + class CP, + template <class> class KP, + template <class> class SP, + template <class> class CNP, + typename U + > + inline bool operator<(U* lhs, + const SmartPtr<T, OP, CP, KP, SP, CNP >& rhs) + { + return ( GetImpl( rhs ) < lhs ); + } + +//////////////////////////////////////////////////////////////////////////////// +// operator> for lhs = SmartPtr, rhs = raw pointer +/// \ingroup SmartPointerGroup +//////////////////////////////////////////////////////////////////////////////// + + template + < + typename T, + template <class> class OP, + class CP, + template <class> class KP, + template <class> class SP, + template <class> class CNP, + typename U + > + inline bool operator>(const SmartPtr<T, OP, CP, KP, SP, CNP >& lhs, + U* rhs) + { return rhs < lhs; } + +//////////////////////////////////////////////////////////////////////////////// +/// operator> for lhs = raw pointer, rhs = SmartPtr +/// \ingroup SmartPointerGroup +//////////////////////////////////////////////////////////////////////////////// + + template + < + typename T, + template <class> class OP, + class CP, + template <class> class KP, + template <class> class SP, + template <class> class CNP, + typename U + > + inline bool operator>(U* lhs, + const SmartPtr<T, OP, CP, KP, SP, CNP >& rhs) + { return rhs < lhs; } + +//////////////////////////////////////////////////////////////////////////////// +/// operator<= for lhs = SmartPtr, rhs = raw pointer +/// \ingroup SmartPointerGroup +//////////////////////////////////////////////////////////////////////////////// + + template + < + typename T, + template <class> class OP, + class CP, + template <class> class KP, + template <class> class SP, + template <class> class CNP, + typename U + > + inline bool operator<=(const SmartPtr<T, OP, CP, KP, SP, CNP >& lhs, + U* rhs) + { return !(rhs < lhs); } + +//////////////////////////////////////////////////////////////////////////////// +/// operator<= for lhs = raw pointer, rhs = SmartPtr +/// \ingroup SmartPointerGroup +//////////////////////////////////////////////////////////////////////////////// + + template + < + typename T, + template <class> class OP, + class CP, + template <class> class KP, + template <class> class SP, + template <class> class CNP, + typename U + > + inline bool operator<=(U* lhs, + const SmartPtr<T, OP, CP, KP, SP, CNP >& rhs) + { return !(rhs < lhs); } + +//////////////////////////////////////////////////////////////////////////////// +/// operator>= for lhs = SmartPtr, rhs = raw pointer +/// \ingroup SmartPointerGroup +//////////////////////////////////////////////////////////////////////////////// + + template + < + typename T, + template <class> class OP, + class CP, + template <class> class KP, + template <class> class SP, + template <class> class CNP, + typename U + > + inline bool operator>=(const SmartPtr<T, OP, CP, KP, SP, CNP >& lhs, + U* rhs) + { return !(lhs < rhs); } + +//////////////////////////////////////////////////////////////////////////////// +/// operator>= for lhs = raw pointer, rhs = SmartPtr +/// \ingroup SmartPointerGroup +//////////////////////////////////////////////////////////////////////////////// + + template + < + typename T, + template <class> class OP, + class CP, + template <class> class KP, + template <class> class SP, + template <class> class CNP, + typename U + > + inline bool operator>=(U* lhs, + const SmartPtr<T, OP, CP, KP, SP, CNP >& rhs) + { return !(lhs < rhs); } + +} // namespace Loki + +//////////////////////////////////////////////////////////////////////////////// +/// specialization of std::less for SmartPtr +/// \ingroup SmartPointerGroup +//////////////////////////////////////////////////////////////////////////////// + +namespace std +{ + template + < + typename T, + template <class> class OP, + class CP, + template <class> class KP, + template <class> class SP, + template <class> class CNP + > + struct less< Loki::SmartPtr<T, OP, CP, KP, SP, CNP > > + : public binary_function<Loki::SmartPtr<T, OP, CP, KP, SP, CNP >, + Loki::SmartPtr<T, OP, CP, KP, SP, CNP >, bool> + { + bool operator()(const Loki::SmartPtr<T, OP, CP, KP, SP, CNP >& lhs, + const Loki::SmartPtr<T, OP, CP, KP, SP, CNP >& rhs) const + { return less<T*>()(GetImpl(lhs), GetImpl(rhs)); } + }; +} + +#endif // end file guardian + diff --git a/shared/loki/StrongPtr.h b/shared/loki/StrongPtr.h new file mode 100644 index 00000000..7ec9766f --- /dev/null +++ b/shared/loki/StrongPtr.h @@ -0,0 +1,1697 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2006 Rich Sposato +// The copyright on this file is protected under the terms of the MIT license. +// +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author makes no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_STRONG_PTR_INC_ +#define LOKI_STRONG_PTR_INC_ + +// $Id: StrongPtr.h 914 2008-12-19 00:39:29Z rich_sposato $ + + +#include <loki/SmartPtr.h> +#if defined (LOKI_OBJECT_LEVEL_THREADING) || defined (LOKI_CLASS_LEVEL_THREADING) + #include <loki/Threads.h> +#endif + + +//////////////////////////////////////////////////////////////////////////////// +/// +/// \par Terminology +/// These terms are used within this file's comments. +/// -# StrongPtr : Class used to implement both strong and weak pointers. The +/// second template parameter determines if a StrongPtr is weak or strong. +/// -# Strong pointer : A pointer that claims ownership of a shared object. +/// When the last strong copointer dies, the object is destroyed even if +/// there are weak copointers. +/// -# Weak pointer : A pointer that does not own the shared object it points +/// to. It only destroys the shared object if there no strong copointers +/// exist when it dies. +/// -# Copointers : All the pointers that refer to the same shared object. +/// The copointers must have the same ownership policy, but the other +/// policies may be different. +/// -# Pointee : The shared object. +/// +/// \par OwnershipPolicy +/// The ownership policy has the pointer to the actual object, and it also +/// keeps track of the strong and weak copointers so that it can know if any +/// strong copointers remain. The plain pointer it maintains is stored as a +/// void pointer, which allows the ownership policy classes to be monolithic +/// classes instead of template classes. As monolithic classes, they reduce +/// amount of code-bloat. +/// +/// \par Writing Your Own OwnershipPolicy +/// If you write your own policy, you must implement these 12 functions: +/// -# explicit YourPolicy( bool strong ) +/// -# YourPolicy( void * p, bool strong ) +/// -# YourPolicy( const YourPolicy & rhs, bool strong ) +/// -# bool Release( bool strong ) +/// -# void Increment( bool strong ) +/// -# bool Decrement( bool strong ) +/// -# bool HasStrongPointer( void ) const +/// -# void Swap( YourPolicy & rhs ) +/// -# void SetPointer( void * p ) +/// -# void ZapPointer( void ) +/// -# void * GetPointer( void ) const +/// -# void * & GetPointerRef( void ) const +/// It is strongly recommended that all 12 of these functions be protected +/// instead of public. These two functions are optional for single-threaded +/// policies, but required for multi-threaded policies: +/// -# void Lock( void ) const +/// -# void Unlock( void ) const +/// This function is entirely optional: +/// -# bool Merge( TwoRefLinks & rhs ) +/// +/// \par DeletePolicy +/// The delete policy provides a mechanism to destroy an object and a default +/// value for an uninitialized pointer. You can override this policy with +/// your own when using the Singleton, NullObject, or Prototype design +/// patterns. +/// +/// \par Writing Your Own DeletePolicy +/// If you write your own policy, you must implement these 3 functions: +/// -# void static Delete( const P * p ) +/// -# static P * Default( void ) +/// -# void Swap( YourResetPolicy & ) +/// +/// \par ResetPolicy +/// A reset policy tells the ReleaseAll and ResetAll functions whether they +/// should release or reset the StrongPtr copointers. These functions do +/// not affect just one StrongPtr, but all copointers. That is unlike +/// SmartPtr where the Release and Reset functions only affect 1 SmartPtr, +/// and leave all copointers untouched. A useful trick you can do with the +/// ResetPolicy is to not allow reset when a strong pointer exists, and then +/// use the NoCheck policy for all strong pointers. The reset policy +/// guarantees the strong pointers always have a valid pointee, so checking +/// is not required; but weak pointers may still require checking. +/// +/// \par Writing Your Own ResetPolicy +/// If you write your own policy, you must implement these 2 functions: +/// -# bool OnReleaseAll( bool ) const +/// -# bool OnResetAll( bool ) const +/// The bool parameter means that this was called with a strong pointer or +/// one of its copointers is strong. The return value means the pointer +/// can be reset or released. +/// +/// \defgroup StrongPointerOwnershipGroup StrongPtr Ownership policies +/// \ingroup SmartPointerGroup +/// \defgroup StrongPointerDeleteGroup Delete policies +/// \ingroup SmartPointerGroup +/// \defgroup StrongPointerResetGroup Reset policies +/// \ingroup SmartPointerGroup +//////////////////////////////////////////////////////////////////////////////// + + +namespace Loki +{ + + +//////////////////////////////////////////////////////////////////////////////// +/// \class DeleteUsingFree +/// +/// \ingroup StrongPointerDeleteGroup +/// Implementation of the DeletePolicy used by StrongPtr. Uses explicit call +/// to T's destructor followed by call to free. This policy is useful for +/// managing the lifetime of pointers to structs returned by C functions. +//////////////////////////////////////////////////////////////////////////////// + +template < class P > +class DeleteUsingFree +{ +public: + inline void static Delete( const P * p ) + { + if ( 0 != p ) + { + p->~P(); + ::free( p ); + } + } + + /// Provides default value to initialize the pointer + inline static P * Default( void ) + { + return 0; + } + + inline void Swap( DeleteUsingFree & ) {} +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \class DeleteNothing +/// +/// \ingroup StrongPointerDeleteGroup +/// Implementation of the DeletePolicy used by StrongPtr. This will never +/// delete anything. You can use this policy with pointers to an undefined +/// type or a pure interface class with a protected destructor. +//////////////////////////////////////////////////////////////////////////////// + +template < class P > +class DeleteNothing +{ +public: + inline static void Delete( const P * ) + { + // Do nothing at all! + } + + inline static P * Default( void ) + { + return 0; + } + + inline void Swap( DeleteNothing & ) {} +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \class DeleteSingle +/// +/// \ingroup StrongPointerDeleteGroup +/// Implementation of the DeletePolicy used by StrongPtr. This deletes just +/// one shared object. This is the default class for the DeletePolicy. +//////////////////////////////////////////////////////////////////////////////// + +template < class P > +class DeleteSingle +{ +public: + inline static void Delete( const P * p ) + { + /** @note If you see an error message about a negative subscript, that + means your are attempting to use Loki to delete an incomplete type. + Please don't use this policy with incomplete types; you may want to + use DeleteNothing instead. + */ + typedef char Type_Must_Be_Defined[ sizeof(P) ? 1 : -1 ]; + delete p; + } + + inline static P * Default( void ) + { + return 0; + } + + inline void Swap( DeleteSingle & ) {} +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \class DeleteArray +/// +/// \ingroup StrongPointerDeleteGroup +/// Implementation of the DeletePolicy used by StrongPtr. This deletes an +/// array of shared objects. +//////////////////////////////////////////////////////////////////////////////// + +template < class P > +class DeleteArray +{ +public: + inline static void Delete( const P * p ) + { + /** @note If you see an error message about a negative subscript, that + means your are attempting to use Loki to delete an incomplete type. + Please don't use this policy with incomplete types; you may want to + use DeleteNothing instead. + */ + typedef char Type_Must_Be_Defined[ sizeof(P) ? 1 : -1 ]; + delete [] p; + } + + inline static P * Default( void ) + { + return 0; + } + + inline void Swap( DeleteArray & ) {} +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \class CantResetWithStrong +/// +/// \ingroup StrongPointerResetGroup +/// Implementation of the ResetPolicy used by StrongPtr. This is the default +/// ResetPolicy for StrongPtr. It forbids reset and release only if a strong +/// copointer exists. +//////////////////////////////////////////////////////////////////////////////// + +template < class P > +struct CantResetWithStrong +{ + inline bool OnReleaseAll( bool hasStrongPtr ) const + { + return ! hasStrongPtr; + } + + inline bool OnResetAll( bool hasStrongPtr ) const + { + return ! hasStrongPtr; + } +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \class AllowReset +/// +/// \ingroup StrongPointerResetGroup +/// Implementation of the ResetPolicy used by StrongPtr. It allows reset and +/// release under any circumstance. +//////////////////////////////////////////////////////////////////////////////// + +template < class P > +struct AllowReset +{ + inline bool OnReleaseAll( bool ) const + { + return true; + } + inline bool OnResetAll( bool ) const + { + return true; + } +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \class NeverReset +/// +/// \ingroup StrongPointerResetGroup +/// Implementation of the ResetPolicy used by StrongPtr. It forbids reset and +/// release under any circumstance. +//////////////////////////////////////////////////////////////////////////////// + +template < class P > +struct NeverReset +{ + inline bool OnReleaseAll( bool ) const + { + return false; + } + inline bool OnResetAll( bool ) const + { + return false; + } +}; + +// ---------------------------------------------------------------------------- + +namespace Private +{ + +//////////////////////////////////////////////////////////////////////////////// +/// \class TwoRefCountInfo +/// +/// \ingroup StrongPointerOwnershipGroup +/// Implementation detail for reference counting strong and weak pointers. +/// It maintains a void pointer and 2 reference counts. Since it is just a +/// class for managing implementation details, it is not intended to be used +/// directly - which is why it is in a private namespace. Each instance is a +/// shared resource for all copointers, and there should be only one of these +/// for each set of copointers. This class is small, trivial, and inline. +//////////////////////////////////////////////////////////////////////////////// + +class LOKI_EXPORT TwoRefCountInfo +{ +public: + + inline explicit TwoRefCountInfo( bool strong ) + : m_pointer( 0 ) + , m_strongCount( strong ? 1 : 0 ) + , m_weakCount( strong ? 0 : 1 ) + { + } + + inline TwoRefCountInfo( void * p, bool strong ) + : m_pointer( p ) + , m_strongCount( strong ? 1 : 0 ) + , m_weakCount( strong ? 0 : 1 ) + { + } + + inline ~TwoRefCountInfo( void ) + { + assert( 0 == m_strongCount ); + assert( 0 == m_weakCount ); + } + + inline bool HasStrongPointer( void ) const + { + return ( 0 < m_strongCount ); + } + + inline bool HasWeakPointer( void ) const + { + return ( 0 < m_weakCount ); + } + + inline void IncStrongCount( void ) + { + ++m_strongCount; + } + + inline void IncWeakCount( void ) + { + ++m_weakCount; + } + + inline bool DecStrongCount( void ) + { + assert( 0 < m_strongCount ); + --m_strongCount; + const bool isZero = ( 0 == m_strongCount ); + return isZero; + } + + inline void DecWeakCount( void ) + { + assert( 0 < m_weakCount ); + --m_weakCount; + } + + inline void ZapPointer( void ) + { + m_pointer = 0; + } + + void SetPointer( void * p ) + { + m_pointer = p; + } + + inline void * GetPointer( void ) const + { + return m_pointer; + } + + inline void * & GetPointerRef( void ) const + { + return const_cast< void * & >( m_pointer ); + } + +private: + /// Copy-constructor not implemented. + TwoRefCountInfo( const TwoRefCountInfo & ); + /// Copy-assignment operator not implemented. + TwoRefCountInfo & operator = ( const TwoRefCountInfo & ); + + void * m_pointer; + unsigned int m_strongCount; + unsigned int m_weakCount; +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \class LockableTwoRefCountInfo +/// +/// \ingroup StrongPointerOwnershipGroup +/// Implementation detail for thread-safe reference counting for strong and +/// weak pointers. It uses TwoRefCountInfo to manage the pointer and counts. +/// All this does is provide a thread safety mechanism. Since it is just a +/// class for managing implementation details, it is not intended to be used +/// directly - which is why it is in a private namespace. Each instance is a +/// shared resource for all copointers, and there should be only one of these +/// for each set of copointers. This class is small, trivial, and inline. +/// +/// \note This class is not designed for use with a single-threaded model. +/// Tests using a single-threaded model will not run properly, but tests in a +/// multi-threaded model with either class-level-locking or object-level-locking +/// do run properly. +//////////////////////////////////////////////////////////////////////////////// + +#if defined (LOKI_OBJECT_LEVEL_THREADING) || defined (LOKI_CLASS_LEVEL_THREADING) + +class LOKI_EXPORT LockableTwoRefCountInfo + : private Loki::Private::TwoRefCountInfo +{ +public: + + inline explicit LockableTwoRefCountInfo( bool strong ) + : TwoRefCountInfo( strong ) + , m_Mutex() + { + } + + LockableTwoRefCountInfo( void * p, bool strong ) + : TwoRefCountInfo( p, strong ) + , m_Mutex() + { + } + + inline ~LockableTwoRefCountInfo( void ) + { + } + + inline void Lock( void ) const + { + m_Mutex.Lock(); + } + + inline void Unlock( void ) const + { + m_Mutex.Unlock(); + } + + inline bool HasStrongPointer( void ) const + { + m_Mutex.Lock(); + const bool has = TwoRefCountInfo::HasStrongPointer(); + m_Mutex.Unlock(); + return has; + } + + inline bool HasWeakPointer( void ) const + { + m_Mutex.Lock(); + const bool has = TwoRefCountInfo::HasWeakPointer(); + m_Mutex.Unlock(); + return has; + } + + inline void IncStrongCount( void ) + { + m_Mutex.Lock(); + TwoRefCountInfo::IncStrongCount(); + m_Mutex.Unlock(); + } + + inline void IncWeakCount( void ) + { + m_Mutex.Lock(); + TwoRefCountInfo::IncWeakCount(); + m_Mutex.Unlock(); + } + + inline bool DecStrongCount( void ) + { + m_Mutex.Lock(); + const bool isZero = TwoRefCountInfo::DecStrongCount(); + m_Mutex.Unlock(); + return isZero; + } + + inline void DecWeakCount( void ) + { + m_Mutex.Lock(); + TwoRefCountInfo::DecWeakCount(); + m_Mutex.Unlock(); + } + + inline void ZapPointer( void ) + { + m_Mutex.Lock(); + TwoRefCountInfo::ZapPointer(); + m_Mutex.Unlock(); + } + + void SetPointer( void * p ) + { + m_Mutex.Lock(); + TwoRefCountInfo::SetPointer( p ); + m_Mutex.Unlock(); + } + + inline void * GetPointer( void ) const + { + return TwoRefCountInfo::GetPointer(); + } + + inline void * & GetPointerRef( void ) const + { + return TwoRefCountInfo::GetPointerRef(); + } + +private: + /// Default constructor is not available. + LockableTwoRefCountInfo( void ); + /// Copy constructor is not available. + LockableTwoRefCountInfo( const LockableTwoRefCountInfo & ); + /// Copy-assignment operator is not available. + LockableTwoRefCountInfo & operator = ( const LockableTwoRefCountInfo & ); + + mutable LOKI_DEFAULT_MUTEX m_Mutex; +}; + +#endif // if object-level-locking or class-level-locking + +} // end namespace Private + +//////////////////////////////////////////////////////////////////////////////// +/// \class TwoRefCounts +/// +/// \ingroup StrongPointerOwnershipGroup +/// This implementation of StrongPtr's OwnershipPolicy uses a pointer to a +/// shared instance of TwoRefCountInfo. This is the default policy for +/// OwnershipPolicy. Some functions are trivial enough to be inline, while +/// others are implemented elsewhere. It is not thread safe, and is intended +/// for single-threaded environments. +//////////////////////////////////////////////////////////////////////////////// + +class LOKI_EXPORT TwoRefCounts +{ +protected: + + explicit TwoRefCounts( bool strong ); + + TwoRefCounts( const void * p, bool strong ); + + TwoRefCounts( const TwoRefCounts & rhs, bool strong ) : + m_counts( rhs.m_counts ) + { + Increment( strong ); + } + + /** The destructor does not need to do anything since the call to + ZapPointer inside StrongPtr::~StrongPtr will do the cleanup which + this dtor would have done. + */ + inline ~TwoRefCounts( void ) {} + + inline bool Release( bool strong ) + { + return Decrement( strong ); + } + + bool HasStrongPointer( void ) const + { + return m_counts->HasStrongPointer(); + } + + void Swap( TwoRefCounts & rhs ); + + void SetPointer( void * p ) + { + m_counts->SetPointer( p ); + } + + void ZapPointer( void ); + + inline void * & GetPointerRef( void ) const + { + return m_counts->GetPointerRef(); + } + + inline void * GetPointer( void ) const + { + return m_counts->GetPointer(); + } + +private: + TwoRefCounts( void ); + TwoRefCounts & operator = ( const TwoRefCounts & ); + + void Increment( bool strong ); + + bool Decrement( bool strong ); + + /// Pointer to all shared data. + Loki::Private::TwoRefCountInfo * m_counts; +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \class LockableTwoRefCounts +/// +/// \ingroup StrongPointerOwnershipGroup +/// This implementation of StrongPtr's OwnershipPolicy uses a pointer to a +/// shared instance of LockableTwoRefCountInfo. It behaves very similarly to +/// TwoRefCounts, except that it provides thread-safety. Some functions are +/// trivial enough to be inline, while others are implemented elsewhere. +/// +/// \note This class is not designed for use with a single-threaded model. +/// Tests using a single-threaded model will not run properly, but tests in a +/// multi-threaded model with either class-level-locking or object-level-locking +/// do run properly. +//////////////////////////////////////////////////////////////////////////////// + +#if defined (LOKI_OBJECT_LEVEL_THREADING) || defined (LOKI_CLASS_LEVEL_THREADING) + +class LOKI_EXPORT LockableTwoRefCounts +{ + typedef SmallValueObject< ::Loki::ClassLevelLockable > ThreadSafePointerAllocator; + +protected: + + explicit LockableTwoRefCounts( bool strong ) + : m_counts( NULL ) + { + void * temp = ThreadSafePointerAllocator::operator new( + sizeof(Loki::Private::LockableTwoRefCountInfo) ); +#ifdef DO_EXTRA_LOKI_TESTS + assert( temp != 0 ); +#endif + m_counts = new ( temp ) Loki::Private::LockableTwoRefCountInfo( strong ); + } + + LockableTwoRefCounts( const void * p, bool strong ) + : m_counts( NULL ) + { + void * temp = ThreadSafePointerAllocator::operator new( + sizeof(Loki::Private::LockableTwoRefCountInfo) ); +#ifdef DO_EXTRA_LOKI_TESTS + assert( temp != 0 ); +#endif + void * p2 = const_cast< void * >( p ); + m_counts = new ( temp ) + Loki::Private::LockableTwoRefCountInfo( p2, strong ); + } + + LockableTwoRefCounts( const LockableTwoRefCounts & rhs, bool strong ) : + m_counts( rhs.m_counts ) + { + Increment( strong ); + } + + /** The destructor does not need to do anything since the call to + ZapPointer inside StrongPtr::~StrongPtr will do the cleanup which + this dtor would have done. + */ + inline ~LockableTwoRefCounts( void ) {} + + inline void Lock( void ) const + { + m_counts->Lock(); + } + + inline void Unlock( void ) const + { + m_counts->Unlock(); + } + + inline bool Release( bool strong ) + { + return Decrement( strong ); + } + + void Increment( bool strong ) + { + if ( strong ) + { + m_counts->IncStrongCount(); + } + else + { + m_counts->IncWeakCount(); + } + } + + bool Decrement( bool strong ) + { + bool noStrongPointers = false; + if ( strong ) + { + noStrongPointers = m_counts->DecStrongCount(); + } + else + { + m_counts->DecWeakCount(); + noStrongPointers = !m_counts->HasStrongPointer(); + } + return noStrongPointers; + } + + bool HasStrongPointer( void ) const + { + return m_counts->HasStrongPointer(); + } + + void Swap( LockableTwoRefCounts & rhs ) + { + std::swap( m_counts, rhs.m_counts ); + } + + void SetPointer( void * p ) + { + m_counts->SetPointer( p ); + } + + void ZapPointer( void ) + { +#ifdef DO_EXTRA_LOKI_TESTS + assert( !m_counts->HasStrongPointer() ); +#endif + if ( m_counts->HasWeakPointer() ) + { + m_counts->ZapPointer(); + } + else + { + ThreadSafePointerAllocator::operator delete ( m_counts, + sizeof(Loki::Private::LockableTwoRefCountInfo) ); + m_counts = NULL; + } + } + + inline void * GetPointer( void ) const + { + return m_counts->GetPointer(); + } + + inline void * & GetPointerRef( void ) const + { + return m_counts->GetPointerRef(); + } + +private: + LockableTwoRefCounts( void ); + LockableTwoRefCounts & operator = ( const LockableTwoRefCounts & ); + + /// Pointer to all shared data. + Loki::Private::LockableTwoRefCountInfo * m_counts; +}; + +#endif // if object-level-locking or class-level-locking + +//////////////////////////////////////////////////////////////////////////////// +/// \class TwoRefLinks +/// +/// \ingroup StrongPointerOwnershipGroup +/// This implementation of StrongPtr's OwnershipPolicy uses a doubly-linked +/// cycle of copointers to a shared object. Some functions are trivial enough +/// to be inline, while others are implemented in elsewhere. It is not thread +/// safe, and is intended for single-threaded environments. +//////////////////////////////////////////////////////////////////////////////// + +class LOKI_EXPORT TwoRefLinks +{ +protected: + + inline explicit TwoRefLinks( bool strong ) + : m_pointer( 0 ) + , m_strong( strong ) + { + m_prev = m_next = this; + } + + TwoRefLinks( const void * p, bool strong ); + + TwoRefLinks( const TwoRefLinks & rhs, bool strong ); + + bool Release( bool strong ); + + void Swap( TwoRefLinks & rhs ); + + bool Merge( TwoRefLinks & rhs ); + + bool HasStrongPointer( void ) const; + + inline void ZapPointer( void ) + { + ZapAllNodes(); + } + + void SetPointer( void * p ); + + inline void * GetPointer( void ) const + { + return m_pointer; + } + + inline void * & GetPointerRef( void ) const + { + return const_cast< void * & >( m_pointer ); + } + +private: + static unsigned int CountPrevCycle( const TwoRefLinks * pThis ); + static unsigned int CountNextCycle( const TwoRefLinks * pThis ); + + /// Not implemented. + TwoRefLinks( void ); + /// Not implemented. + TwoRefLinks & operator = ( const TwoRefLinks & ); + + bool HasPrevNode( const TwoRefLinks * p ) const; + bool HasNextNode( const TwoRefLinks * p ) const; + bool AllNodesHaveSamePointer( void ) const; + void ZapAllNodes( void ); + + void * m_pointer; + mutable TwoRefLinks * m_prev; + mutable TwoRefLinks * m_next; + const bool m_strong; +}; + +//////////////////////////////////////////////////////////////////////////////// +/// \class StrongPtr +/// +/// \ingroup SmartPointerGroup +/// +/// \param Strong default = true, +/// \param OwnershipPolicy default = TwoRefCounts, +/// \param ConversionPolicy default = DisallowConversion, +/// \param CheckingPolicy default = AssertCheck, +/// \param ResetPolicy default = CantResetWithStrong, +/// \param DeletePolicy default = DeleteSingle +/// \param ConstnessPolicy default = LOKI_DEFAULT_CONSTNESS +//////////////////////////////////////////////////////////////////////////////// + +template +< + typename T, + bool Strong = true, + class OwnershipPolicy = Loki::TwoRefCounts, + class ConversionPolicy = Loki::DisallowConversion, + template < class > class CheckingPolicy = Loki::AssertCheck, + template < class > class ResetPolicy = Loki::CantResetWithStrong, + template < class > class DeletePolicy = Loki::DeleteSingle, + template < class > class ConstnessPolicy = LOKI_DEFAULT_CONSTNESS +> +class StrongPtr + : public OwnershipPolicy + , public ConversionPolicy + , public CheckingPolicy< T * > + , public ResetPolicy< T > + , public DeletePolicy< T > +{ + typedef ConversionPolicy CP; + typedef CheckingPolicy< T * > KP; + typedef ResetPolicy< T > RP; + typedef DeletePolicy< T > DP; + +public: + + typedef OwnershipPolicy OP; + + typedef T * StoredType; // the type of the pointer + typedef T * PointerType; // type returned by operator-> + typedef T & ReferenceType; // type returned by operator* + + typedef typename ConstnessPolicy< T >::Type * ConstPointerType; + typedef typename ConstnessPolicy< T >::Type & ConstReferenceType; + +private: + struct NeverMatched {}; + +#ifdef LOKI_SMARTPTR_CONVERSION_CONSTRUCTOR_POLICY + typedef typename Select< CP::allow, const StoredType&, NeverMatched>::Result ImplicitArg; + typedef typename Select<!CP::allow, const StoredType&, NeverMatched>::Result ExplicitArg; +#else + typedef const StoredType& ImplicitArg; + typedef typename Select<false, const StoredType&, NeverMatched>::Result ExplicitArg; +#endif + +public: + + StrongPtr( void ) : OP( Strong ) + { + KP::OnDefault( GetPointer() ); + } + + explicit StrongPtr( ExplicitArg p ) : OP( p, Strong ) + { + KP::OnInit( GetPointer() ); + } + + StrongPtr( ImplicitArg p ) : OP( p, Strong ) + { + KP::OnInit( GetPointer() ); + } + + StrongPtr( const StrongPtr & rhs ) + : OP( rhs, Strong ), CP( rhs ), KP( rhs ), DP( rhs ) + { + } + + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + StrongPtr( + const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) + : OP( rhs, Strong ) + { + } + + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + StrongPtr( + StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) + : OP( rhs, Strong ) + { + } + + StrongPtr( RefToValue< StrongPtr > rhs ) + : OP( rhs, Strong ), KP( rhs ), CP( rhs ), DP( rhs ) + { + } + + operator RefToValue< StrongPtr >( void ) + { + return RefToValue< StrongPtr >( *this ); + } + + StrongPtr & operator = ( const StrongPtr & rhs ) + { + if ( GetPointer() != rhs.GetPointer() ) + { + StrongPtr temp( rhs ); + temp.Swap( *this ); + } + return *this; + } + + StrongPtr & operator = ( T * p ) + { + if ( GetPointer() != p ) + { + StrongPtr temp( p ); + Swap( temp ); + } + return *this; + } + + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + StrongPtr & operator = ( + const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) + { + if ( !rhs.Equals( GetPointer() ) ) + { + StrongPtr temp( rhs ); + temp.Swap( *this ); + } + return *this; + } + + bool IsStrong( void ) const + { + return Strong; + } + + void Swap( StrongPtr & rhs ) + { + OP::Swap( rhs ); + CP::Swap( rhs ); + KP::Swap( rhs ); + DP::Swap( rhs ); + } + + ~StrongPtr() + { + if ( OP::Release( Strong ) ) + { + // Must zap the pointer before deleteing the object. Otherwise a + // cycle of weak pointers will lead to recursion, which leads to + // to deleting the shared object multiple times, which leads to + // undefined behavior. Therefore, this must get pointer before + // zapping it, and then delete the temp pointer. + T * p = GetPointer(); + OP::ZapPointer(); + if ( p != 0 ) + { + DP::Delete( p ); + } + } + } + +#ifdef LOKI_ENABLE_FRIEND_TEMPLATE_TEMPLATE_PARAMETER_WORKAROUND + + // old non standard in class definition of friends + friend bool ReleaseAll( StrongPtr & sp, + typename StrongPtr::StoredType & p ) + { + if ( !sp.RP::OnReleaseAll( sp.IsStrong() || sp.OP::HasStrongPointer() ) ) + { + return false; + } + p = sp.GetPointer(); + sp.OP::SetPointer( sp.DP::Default() ); + return true; + } + + friend bool ResetAll( StrongPtr & sp, + typename StrongPtr::StoredType p ) + { + if ( sp.OP::GetPointer() == p ) + { + return true; + } + if ( !sp.RP::OnResetAll( sp.IsStrong() || sp.OP::HasStrongPointer() ) ) + { + return false; + } + sp.DP::Delete( sp.GetPointer() ); + sp.OP::SetPointer( p ); + return true; + } + +#else + + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + friend bool ReleaseAll( StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & sp, + typename StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 >::StoredType & p ); + + + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + friend bool ResetAll( StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & sp, + typename StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 >::StoredType p ); + +#endif + + + /** Merges ownership of two StrongPtr's that point to same shared object + but are not copointers. Requires Merge function in OwnershipPolicy. + \return True for success, false if not pointer to same object. + */ + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + bool Merge( StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) + { + if ( OP::GetPointer() != rhs.OP::GetPointer() ) + { + return false; + } + return OP::Merge( rhs ); + } + + /** Locks StrongPtr so other threads can't affect pointer. Requires the + OwnershipPolicy to have Lock function. + */ + void Lock( void ) + { + OP::Lock(); + } + + /** Unlocks StrongPtr so other threads can affect pointer. Requires the + OwnershipPolicy to have Unlock function. + */ + void Unlock( void ) + { + OP::Unlock(); + } + + PointerType operator -> () + { + KP::OnDereference( GetPointer() ); + return GetPointer(); + } + + ConstPointerType operator -> () const + { + KP::OnDereference( GetPointer() ); + return GetPointer(); + } + + ReferenceType operator * () + { + KP::OnDereference( GetPointer() ); + return * GetPointer(); + } + + ConstReferenceType operator * () const + { + KP::OnDereference( GetPointer() ); + return * GetPointer(); + } + + /// Helper function which can be called to avoid exposing GetPointer function. + template < class T1 > + bool Equals( const T1 * p ) const + { + return ( GetPointer() == p ); + } + + /// Helper function which can be called to avoid exposing GetPointer function. + template < class T1 > + bool LessThan( const T1 * p ) const + { + return ( GetPointer() < p ); + } + + /// Helper function which can be called to avoid exposing GetPointer function. + template < class T1 > + bool GreaterThan( const T1 * p ) const + { + return ( GetPointer() > p ); + } + + /// Equality comparison operator is templated to handle ambiguity. + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + bool operator == ( + const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) const + { + return ( rhs.Equals( GetPointer() ) ); + } + + /// Inequality comparison operator is templated to handle ambiguity. + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + bool operator != ( + const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) const + { + return !( rhs.Equals( GetPointer() ) ); + } + + /// Less-than comparison operator is templated to handle ambiguity. + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + bool operator < ( + const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) const + { + return ( rhs.GreaterThan( GetPointer() ) ); + } + + /// Greater-than comparison operator is templated to handle ambiguity. + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + inline bool operator > ( + const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) const + { + return ( rhs.LessThan( GetPointer() ) ); + } + + /// Less-than-or-equal-to operator is templated to handle ambiguity. + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + inline bool operator <= ( + const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) const + { + return !( rhs.LessThan( GetPointer() ) ); + } + + /// Greater-than-or-equal-to operator is templated to handle ambiguity. + template + < + typename T1, + bool S1, + class OP1, + class CP1, + template < class > class KP1, + template < class > class RP1, + template < class > class DP1, + template < class > class CNP1 + > + inline bool operator >= ( + const StrongPtr< T1, S1, OP1, CP1, KP1, RP1, DP1, CNP1 > & rhs ) const + { + return !( rhs.GreaterThan( GetPointer() ) ); + } + + inline bool operator ! () const // Enables "if ( !sp ) ..." + { + return ( 0 == OP::GetPointer() ); + } + +protected: + + inline PointerType GetPointer( void ) + { + return reinterpret_cast< PointerType >( OP::GetPointer() ); + } + + inline ConstPointerType GetPointer( void ) const + { + return reinterpret_cast< ConstPointerType >( OP::GetPointer() ); + } + +private: + + inline ReferenceType GetPointerRef( void ) + { + return reinterpret_cast< ReferenceType >( OP::GetPointerRef() ); + } + + inline ConstReferenceType GetPointerRef( void ) const + { + return reinterpret_cast< ConstReferenceType >( OP::GetPointerRef() ); + } + + // Helper for enabling 'if (sp)' + struct Tester + { + Tester(int) {} + void dummy() {} + }; + + typedef void (Tester::*unspecified_boolean_type_)(); + + typedef typename Select< CP::allow, Tester, unspecified_boolean_type_ >::Result + unspecified_boolean_type; + +public: + // enable 'if (sp)' + operator unspecified_boolean_type() const + { + return !*this ? 0 : &Tester::dummy; + } + +private: + // Helper for disallowing automatic conversion + struct Insipid + { + Insipid(PointerType) {} + }; + + typedef typename Select< CP::allow, PointerType, Insipid >::Result + AutomaticConversionResult; + +public: + operator AutomaticConversionResult() const + { + return GetPointer(); + } + +}; + +// ---------------------------------------------------------------------------- + +// friend functions + +#ifndef LOKI_ENABLE_FRIEND_TEMPLATE_TEMPLATE_PARAMETER_WORKAROUND + +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +bool ReleaseAll( StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & sp, + typename StrongPtr< T, S, OP, CP, KP, RP, DP, CNP >::StoredType & p ) +{ + if ( !sp.RP<T>::OnReleaseAll( sp.IsStrong() || sp.OP::HasStrongPointer() ) ) + { + return false; + } + p = sp.GetPointer(); + sp.OP::SetPointer( sp.DP<T>::Default() ); + return true; +} + +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +bool ResetAll( StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & sp, + typename StrongPtr< T, S, OP, CP, KP, RP, DP, CNP >::StoredType p ) +{ + if ( sp.OP::GetPointer() == p ) + { + return true; + } + if ( !sp.RP<T>::OnResetAll( sp.IsStrong() || sp.OP::HasStrongPointer() ) ) + { + return false; + } + sp.DP<T>::Delete( sp.GetPointer() ); + sp.OP::SetPointer( p ); + return true; +} +#endif + + +// free comparison operators for class template StrongPtr + +/// operator== for lhs = StrongPtr, rhs = raw pointer +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator == ( + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, U * rhs ) +{ + return ( lhs.Equals( rhs ) ); +} + +/// operator== for lhs = raw pointer, rhs = StrongPtr +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator == ( U * lhs, + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs ) +{ + return ( rhs.Equals( lhs ) ); +} + +/// operator!= for lhs = StrongPtr, rhs = raw pointer +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator != ( + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, U * rhs ) +{ + return !( lhs.Equals( rhs ) ); +} + +/// operator!= for lhs = raw pointer, rhs = StrongPtr +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator != ( U * lhs, + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs ) +{ + return !( rhs.Equals( lhs ) ); +} + +/// operator< for lhs = StrongPtr, rhs = raw pointer +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator < ( + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, U * rhs ) +{ + return ( lhs.LessThan( rhs ) ); +} + +/// operator< for lhs = raw pointer, rhs = StrongPtr +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator < ( U * lhs, + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs ) +{ + return ( rhs.GreaterThan( lhs ) ); +} + +// operator> for lhs = StrongPtr, rhs = raw pointer +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator > ( + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, U * rhs ) +{ + return ( lhs.GreaterThan( rhs ) ); +} + +/// operator> for lhs = raw pointer, rhs = StrongPtr +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator > ( U * lhs, + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs ) +{ + return ( rhs.LessThan( lhs ) ); +} + +/// operator<= for lhs = StrongPtr, rhs = raw pointer +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator <= ( + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, U * rhs ) +{ + return !( lhs.GreaterThan( rhs ) ); +} + +/// operator<= for lhs = raw pointer, rhs = StrongPtr +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator <= ( U * lhs, + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs ) +{ + return !( rhs.LessThan( lhs ) ); +} + +/// operator>= for lhs = StrongPtr, rhs = raw pointer +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator >= ( + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, U * rhs ) +{ + return !( lhs.LessThan( rhs ) ); +} + +/// operator>= for lhs = raw pointer, rhs = StrongPtr +/// \ingroup SmartPointerGroup +template +< + typename U, + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP +> +inline bool operator >= ( U * lhs, + const StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs ) +{ + return !( rhs.GreaterThan( lhs ) ); +} + +} // namespace Loki + +namespace std +{ + //////////////////////////////////////////////////////////////////////////////// + /// specialization of std::less for StrongPtr + /// \ingroup SmartPointerGroup + //////////////////////////////////////////////////////////////////////////////// + template + < + typename T, + bool S, + class OP, + class CP, + template < class > class KP, + template < class > class RP, + template < class > class DP, + template < class > class CNP + > + struct less< Loki::StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > > + : public binary_function< + Loki::StrongPtr< T, S, OP, CP, KP, RP, DP, CNP >, + Loki::StrongPtr< T, S, OP, CP, KP, RP, DP, CNP >, bool > + { + bool operator () ( + const Loki::StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & lhs, + const Loki::StrongPtr< T, S, OP, CP, KP, RP, DP, CNP > & rhs ) const + { + return ( lhs < rhs ); + } + }; +} + +//////////////////////////////////////////////////////////////////////////////// + +#endif // end file guardian + diff --git a/shared/loki/Threads.h b/shared/loki/Threads.h new file mode 100644 index 00000000..cb44f094 --- /dev/null +++ b/shared/loki/Threads.h @@ -0,0 +1,609 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_THREADS_INC_ +#define LOKI_THREADS_INC_ + +// $Id: Threads.h 902 2008-11-10 05:47:06Z rich_sposato $ + + +/// @defgroup ThreadingGroup Threading +/// Policies to for the threading model: +/// +/// - SingleThreaded +/// - ObjectLevelLockable +/// - ClassLevelLockable +/// +/// All classes in Loki have configurable threading model. +/// +/// The macro LOKI_DEFAULT_THREADING selects the default +/// threading model for certain components of Loki +/// (it affects only default template arguments) +/// +/// \par Usage: +/// +/// To use a specific threading model define +/// +/// - nothing, single-theading is default +/// - LOKI_OBJECT_LEVEL_THREADING for object-level-threading +/// - LOKI_CLASS_LEVEL_THREADING for class-level-threading +/// +/// \par Supported platfroms: +/// +/// - Windows (windows.h) +/// - POSIX (pthread.h): +/// No recursive mutex support with pthread. +/// This means: calling Lock() on a Loki::Mutex twice from the +/// same thread before unlocking the mutex deadlocks the system. +/// To avoid this redesign your synchronization. See also: +/// http://sourceforge.net/tracker/index.php?func=detail&aid=1516182&group_id=29557&atid=396647 + + +#include <cassert> + +#if defined(LOKI_CLASS_LEVEL_THREADING) || defined(LOKI_OBJECT_LEVEL_THREADING) + + #define LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL ::Loki::ClassLevelLockable + + #if defined(LOKI_CLASS_LEVEL_THREADING) && !defined(LOKI_OBJECT_LEVEL_THREADING) + #define LOKI_DEFAULT_THREADING ::Loki::ClassLevelLockable + #else + #define LOKI_DEFAULT_THREADING ::Loki::ObjectLevelLockable + #endif + + #if defined(_WIN32) || defined(_WIN64) + #include <windows.h> + #define LOKI_WINDOWS_H + #else + #include <pthread.h> + #define LOKI_PTHREAD_H + #endif + +#else + + #define LOKI_DEFAULT_THREADING ::Loki::SingleThreaded + #define LOKI_DEFAULT_THREADING_NO_OBJ_LEVEL ::Loki::SingleThreaded + +#endif + +#ifndef LOKI_DEFAULT_MUTEX +#define LOKI_DEFAULT_MUTEX ::Loki::Mutex +#endif + +#ifdef LOKI_WINDOWS_H + +#define LOKI_THREADS_MUTEX(x) CRITICAL_SECTION (x); +#define LOKI_THREADS_MUTEX_INIT(x) ::InitializeCriticalSection (x) +#define LOKI_THREADS_MUTEX_DELETE(x) ::DeleteCriticalSection (x) +#define LOKI_THREADS_MUTEX_LOCK(x) ::EnterCriticalSection (x) +#define LOKI_THREADS_MUTEX_UNLOCK(x) ::LeaveCriticalSection (x) +#define LOKI_THREADS_LONG LONG +#define LOKI_THREADS_MUTEX_CTOR(x) + +#define LOKI_THREADS_ATOMIC_FUNCTIONS \ + static IntType AtomicMultiply(volatile IntType& lval, const IntType val) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + lval *= val; \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicDivide(volatile IntType& lval, const IntType val) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + lval /= val; \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicIncrement(volatile IntType& lval) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + ++lval; \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicDecrement(volatile IntType& lval) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + --lval; \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static void AtomicAssign(volatile IntType& lval, const IntType val) \ + { InterlockedExchange(&const_cast<IntType&>(lval), val); } \ + \ + static void AtomicAssign(IntType& lval, volatile const IntType& val) \ + { InterlockedExchange(&lval, val); } \ + \ + static IntType AtomicIncrement(volatile IntType& lval, const IntType compare, bool & matches ) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + ++lval; \ + matches = ( lval == compare ); \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicDecrement(volatile IntType& lval, const IntType compare, bool & matches ) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + --lval; \ + matches = ( lval == compare ); \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicAdd(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + lval += val; \ + matches = ( lval == compare ); \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicSubtract(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + lval -= val; \ + matches = ( lval == compare ); \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicMultiply(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + lval *= val; \ + matches = ( lval == compare ); \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicDivide(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \ + { \ + ::EnterCriticalSection( &atomic_mutex_ ); \ + lval /= val; \ + matches = ( lval == compare ); \ + ::LeaveCriticalSection( &atomic_mutex_ ); \ + return lval; \ + } + +#elif defined(LOKI_PTHREAD_H) + + +#define LOKI_THREADS_MUTEX(x) pthread_mutex_t (x); + +#define LOKI_THREADS_MUTEX_INIT(x) ::pthread_mutex_init(x, 0) + +// define to 1 to enable recursive mutex support +#if 0 +// experimental recursive mutex support +#define LOKI_THREADS_MUTEX_CTOR(x) : x(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) +#else +// no recursive mutex support +#define LOKI_THREADS_MUTEX_CTOR(x) +#endif + +#define LOKI_THREADS_MUTEX_DELETE(x) ::pthread_mutex_destroy (x) +#define LOKI_THREADS_MUTEX_LOCK(x) ::pthread_mutex_lock (x) +#define LOKI_THREADS_MUTEX_UNLOCK(x) ::pthread_mutex_unlock (x) +#define LOKI_THREADS_LONG long + +#define LOKI_THREADS_ATOMIC(x) \ + pthread_mutex_lock(&atomic_mutex_); \ + x; \ + pthread_mutex_unlock(&atomic_mutex_) + +#define LOKI_THREADS_ATOMIC_FUNCTIONS \ + private: \ + static pthread_mutex_t atomic_mutex_; \ + public: \ + static IntType AtomicMultiply(volatile IntType& lval, const IntType val) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + lval *= val; \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicDivide(volatile IntType& lval, const IntType val) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + lval /= val; \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicIncrement(volatile IntType& lval) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + ++lval; \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicDecrement(volatile IntType& lval) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + --lval; \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static void AtomicAssign(volatile IntType& lval, const IntType val) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + lval = val; \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static void AtomicAssign(IntType& lval, volatile const IntType& val) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + lval = val; \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicIncrement(volatile IntType& lval, const IntType compare, bool & matches ) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + ++lval; \ + matches = ( compare == lval ); \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicDecrement(volatile IntType& lval, const IntType compare, bool & matches ) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + --lval; \ + matches = ( compare == lval ); \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } \ + static IntType AtomicMultiply(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + lval *= val; \ + matches = ( lval == compare ); \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } \ + \ + static IntType AtomicDivide(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) \ + { \ + ::pthread_mutex_lock( &atomic_mutex_ ); \ + lval /= val; \ + matches = ( lval == compare ); \ + ::pthread_mutex_unlock( &atomic_mutex_ ); \ + return lval; \ + } + +#else // single threaded + +#define LOKI_THREADS_MUTEX(x) +#define LOKI_THREADS_MUTEX_INIT(x) +#define LOKI_THREADS_MUTEX_DELETE(x) +#define LOKI_THREADS_MUTEX_LOCK(x) +#define LOKI_THREADS_MUTEX_UNLOCK(x) +#define LOKI_THREADS_LONG +#define LOKI_THREADS_MUTEX_CTOR(x) + +#endif + + + +namespace Loki +{ + + //////////////////////////////////////////////////////////////////////////////// + /// \class Mutex + // + /// \ingroup ThreadingGroup + /// A simple and portable Mutex. A default policy class for locking objects. + //////////////////////////////////////////////////////////////////////////////// + + class Mutex + { + public: + Mutex() LOKI_THREADS_MUTEX_CTOR(mtx_) + { + LOKI_THREADS_MUTEX_INIT(&mtx_); + } + ~Mutex() + { + LOKI_THREADS_MUTEX_DELETE(&mtx_); + } + void Lock() + { + LOKI_THREADS_MUTEX_LOCK(&mtx_); + } + void Unlock() + { + LOKI_THREADS_MUTEX_UNLOCK(&mtx_); + } + private: + /// Copy-constructor not implemented. + Mutex(const Mutex &); + /// Copy-assignement operator not implemented. + Mutex & operator = (const Mutex &); + LOKI_THREADS_MUTEX(mtx_) + }; + + + //////////////////////////////////////////////////////////////////////////////// + /// \class SingleThreaded + /// + /// \ingroup ThreadingGroup + /// Implementation of the ThreadingModel policy used by various classes + /// Implements a single-threaded model; no synchronization + //////////////////////////////////////////////////////////////////////////////// + template <class Host, class MutexPolicy = LOKI_DEFAULT_MUTEX> + class SingleThreaded + { + public: + /// \struct Lock + /// Dummy Lock class + struct Lock + { + Lock() {} + explicit Lock(const SingleThreaded&) {} + explicit Lock(const SingleThreaded*) {} + }; + + typedef Host VolatileType; + + typedef int IntType; + + static IntType AtomicAdd(volatile IntType& lval, const IntType val) + { return lval += val; } + + static IntType AtomicSubtract(volatile IntType& lval, const IntType val) + { return lval -= val; } + + static IntType AtomicMultiply(volatile IntType& lval, const IntType val) + { return lval *= val; } + + static IntType AtomicDivide(volatile IntType& lval, const IntType val) + { return lval /= val; } + + static IntType AtomicIncrement(volatile IntType& lval) + { return ++lval; } + + static IntType AtomicDecrement(volatile IntType& lval) + { return --lval; } + + static void AtomicAssign(volatile IntType & lval, const IntType val) + { lval = val; } + + static void AtomicAssign(IntType & lval, volatile IntType & val) + { lval = val; } + + static IntType AtomicAdd(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) + { + lval += val; + matches = ( lval == compare ); + return lval; + } + + static IntType AtomicSubtract(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) + { + lval -= val; + matches = ( lval == compare ); + return lval; + } + + static IntType AtomicMultiply(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) + { + lval *= val; + matches = ( lval == compare ); + return lval; + } + + static IntType AtomicDivide(volatile IntType& lval, const IntType val, const IntType compare, bool & matches ) + { + lval /= val; + matches = ( lval == compare ); + return lval; + } + + static IntType AtomicIncrement(volatile IntType& lval, const IntType compare, bool & matches ) + { + ++lval; + matches = ( lval == compare ); + return lval; + } + + static IntType AtomicDecrement(volatile IntType& lval, const IntType compare, bool & matches ) + { + --lval; + matches = ( lval == compare ); + return lval; + } + + }; + + +#if defined(LOKI_WINDOWS_H) || defined(LOKI_PTHREAD_H) + + //////////////////////////////////////////////////////////////////////////////// + /// \class ObjectLevelLockable + /// + /// \ingroup ThreadingGroup + /// Implementation of the ThreadingModel policy used by various classes + /// Implements a object-level locking scheme + //////////////////////////////////////////////////////////////////////////////// + template < class Host, class MutexPolicy = LOKI_DEFAULT_MUTEX > + class ObjectLevelLockable + { + mutable MutexPolicy mtx_; + + public: + ObjectLevelLockable() : mtx_() {} + + ObjectLevelLockable(const ObjectLevelLockable&) : mtx_() {} + + ~ObjectLevelLockable() {} + + class Lock; + friend class Lock; + + /// \struct Lock + /// Lock class to lock on object level + class Lock + { + public: + + /// Lock object + explicit Lock(const ObjectLevelLockable& host) : host_(host) + { + host_.mtx_.Lock(); + } + + /// Lock object + explicit Lock(const ObjectLevelLockable* host) : host_(*host) + { + host_.mtx_.Lock(); + } + + /// Unlock object + ~Lock() + { + host_.mtx_.Unlock(); + } + + private: + /// private by design of the object level threading + Lock(); + Lock(const Lock&); + Lock& operator=(const Lock&); + const ObjectLevelLockable& host_; + }; + + typedef volatile Host VolatileType; + + typedef LOKI_THREADS_LONG IntType; + + LOKI_THREADS_ATOMIC_FUNCTIONS + + }; + +#ifdef LOKI_PTHREAD_H + template <class Host, class MutexPolicy> + pthread_mutex_t ObjectLevelLockable<Host, MutexPolicy>::atomic_mutex_ = PTHREAD_MUTEX_INITIALIZER; +#endif + + //////////////////////////////////////////////////////////////////////////////// + /// \class ClassLevelLockable + /// + /// \ingroup ThreadingGroup + /// Implementation of the ThreadingModel policy used by various classes + /// Implements a class-level locking scheme + //////////////////////////////////////////////////////////////////////////////// + template <class Host, class MutexPolicy = LOKI_DEFAULT_MUTEX > + class ClassLevelLockable + { + struct Initializer + { + bool init_; + MutexPolicy mtx_; + + Initializer() : init_(false), mtx_() + { + init_ = true; + } + + ~Initializer() + { + assert(init_); + } + }; + + static Initializer initializer_; + + public: + + class Lock; + friend class Lock; + + /// \struct Lock + /// Lock class to lock on class level + class Lock + { + public: + + /// Lock class + Lock() + { + assert(initializer_.init_); + initializer_.mtx_.Lock(); + } + + /// Lock class + explicit Lock(const ClassLevelLockable&) + { + assert(initializer_.init_); + initializer_.mtx_.Lock(); + } + + /// Lock class + explicit Lock(const ClassLevelLockable*) + { + assert(initializer_.init_); + initializer_.mtx_.Lock(); + } + + /// Unlock class + ~Lock() + { + assert(initializer_.init_); + initializer_.mtx_.Unlock(); + } + + private: + Lock(const Lock&); + Lock& operator=(const Lock&); + }; + + typedef volatile Host VolatileType; + + typedef LOKI_THREADS_LONG IntType; + + LOKI_THREADS_ATOMIC_FUNCTIONS + + }; + +#ifdef LOKI_PTHREAD_H + template <class Host, class MutexPolicy> + pthread_mutex_t ClassLevelLockable<Host, MutexPolicy>::atomic_mutex_ = PTHREAD_MUTEX_INITIALIZER; +#endif + + template < class Host, class MutexPolicy > + typename ClassLevelLockable< Host, MutexPolicy >::Initializer + ClassLevelLockable< Host, MutexPolicy >::initializer_; + +#endif // #if defined(LOKI_WINDOWS_H) || defined(LOKI_PTHREAD_H) + +} // namespace Loki + + +#endif // end file guardian + diff --git a/shared/loki/Tuple.h b/shared/loki/Tuple.h new file mode 100644 index 00000000..47fc19e2 --- /dev/null +++ b/shared/loki/Tuple.h @@ -0,0 +1,22 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// + +// Last update: June 20, 2001 + +//////////////////////////////////////////////////////////////////////////////// +// This file is intentionally left empty +// Due to compiler limitations, its contents has been moved to +// HierarchyGenerators.h +//////////////////////////////////////////////////////////////////////////////// diff --git a/shared/loki/TypeManip.h b/shared/loki/TypeManip.h new file mode 100644 index 00000000..e08b4e03 --- /dev/null +++ b/shared/loki/TypeManip.h @@ -0,0 +1,284 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Welsey Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_TYPEMANIP_INC_ +#define LOKI_TYPEMANIP_INC_ + +// $Id: TypeManip.h 749 2006-10-17 19:49:26Z syntheticpp $ + + +namespace Loki +{ +//////////////////////////////////////////////////////////////////////////////// +// class template Int2Type +// Converts each integral constant into a unique type +// Invocation: Int2Type<v> where v is a compile-time constant integral +// Defines 'value', an enum that evaluates to v +//////////////////////////////////////////////////////////////////////////////// + + template <int v> + struct Int2Type + { + enum { value = v }; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template Type2Type +// Converts each type into a unique, insipid type +// Invocation Type2Type<T> where T is a type +// Defines the type OriginalType which maps back to T +//////////////////////////////////////////////////////////////////////////////// + + template <typename T> + struct Type2Type + { + typedef T OriginalType; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template Select +// Selects one of two types based upon a boolean constant +// Invocation: Select<flag, T, U>::Result +// where: +// flag is a compile-time boolean constant +// T and U are types +// Result evaluates to T if flag is true, and to U otherwise. +//////////////////////////////////////////////////////////////////////////////// + + template <bool flag, typename T, typename U> + struct Select + { + typedef T Result; + }; + template <typename T, typename U> + struct Select<false, T, U> + { + typedef U Result; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template IsSameType +// Return true iff two given types are the same +// Invocation: SameType<T, U>::value +// where: +// T and U are types +// Result evaluates to true iff U == T (types equal) +//////////////////////////////////////////////////////////////////////////////// + + template <typename T, typename U> + struct IsSameType + { + enum { value = false }; + }; + + template <typename T> + struct IsSameType<T,T> + { + enum { value = true }; + }; + +//////////////////////////////////////////////////////////////////////////////// +// Helper types Small and Big - guarantee that sizeof(Small) < sizeof(Big) +//////////////////////////////////////////////////////////////////////////////// + + namespace Private + { + template <class T, class U> + struct ConversionHelper + { + typedef char Small; + struct Big { char dummy[2]; }; + static Big Test(...); + static Small Test(U); + static T MakeT(); + }; + } + +//////////////////////////////////////////////////////////////////////////////// +// class template Conversion +// Figures out the conversion relationships between two types +// Invocations (T and U are types): +// a) Conversion<T, U>::exists +// returns (at compile time) true if there is an implicit conversion from T +// to U (example: Derived to Base) +// b) Conversion<T, U>::exists2Way +// returns (at compile time) true if there are both conversions from T +// to U and from U to T (example: int to char and back) +// c) Conversion<T, U>::sameType +// returns (at compile time) true if T and U represent the same type +// +// Caveat: might not work if T and U are in a private inheritance hierarchy. +//////////////////////////////////////////////////////////////////////////////// + + template <class T, class U> + struct Conversion + { + typedef Private::ConversionHelper<T, U> H; +#ifndef __MWERKS__ + enum { exists = sizeof(typename H::Small) == sizeof((H::Test(H::MakeT()))) }; +#else + enum { exists = false }; +#endif + enum { exists2Way = exists && Conversion<U, T>::exists }; + enum { sameType = false }; + }; + + template <class T> + struct Conversion<T, T> + { + enum { exists = 1, exists2Way = 1, sameType = 1 }; + }; + + template <class T> + struct Conversion<void, T> + { + enum { exists = 0, exists2Way = 0, sameType = 0 }; + }; + + template <class T> + struct Conversion<T, void> + { + enum { exists = 0, exists2Way = 0, sameType = 0 }; + }; + + template <> + struct Conversion<void, void> + { + public: + enum { exists = 1, exists2Way = 1, sameType = 1 }; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template SuperSubclass +// Invocation: SuperSubclass<B, D>::value where B and D are types. +// Returns true if B is a public base of D, or if B and D are aliases of the +// same type. +// +// Caveat: might not work if T and U are in a private inheritance hierarchy. +//////////////////////////////////////////////////////////////////////////////// + +template <class T, class U> +struct SuperSubclass +{ + enum { value = (::Loki::Conversion<const volatile U*, const volatile T*>::exists && + !::Loki::Conversion<const volatile T*, const volatile void*>::sameType) }; + + // Dummy enum to make sure that both classes are fully defined. + enum{ dontUseWithIncompleteTypes = ( sizeof (T) == sizeof (U) ) }; +}; + +template <> +struct SuperSubclass<void, void> +{ + enum { value = false }; +}; + +template <class U> +struct SuperSubclass<void, U> +{ + enum { value = (::Loki::Conversion<const volatile U*, const volatile void*>::exists && + !::Loki::Conversion<const volatile void*, const volatile void*>::sameType) }; + + // Dummy enum to make sure that both classes are fully defined. + enum{ dontUseWithIncompleteTypes = ( 0 == sizeof (U) ) }; +}; + +template <class T> +struct SuperSubclass<T, void> +{ + enum { value = (::Loki::Conversion<const volatile void*, const volatile T*>::exists && + !::Loki::Conversion<const volatile T*, const volatile void*>::sameType) }; + + // Dummy enum to make sure that both classes are fully defined. + enum{ dontUseWithIncompleteTypes = ( sizeof (T) == 0 ) }; +}; + +//////////////////////////////////////////////////////////////////////////////// +// class template SuperSubclassStrict +// Invocation: SuperSubclassStrict<B, D>::value where B and D are types. +// Returns true if B is a public base of D. +// +// Caveat: might not work if T and U are in a private inheritance hierarchy. +//////////////////////////////////////////////////////////////////////////////// + +template<class T,class U> +struct SuperSubclassStrict +{ + enum { value = (::Loki::Conversion<const volatile U*, const volatile T*>::exists && + !::Loki::Conversion<const volatile T*, const volatile void*>::sameType && + !::Loki::Conversion<const volatile T*, const volatile U*>::sameType) }; + + // Dummy enum to make sure that both classes are fully defined. + enum{ dontUseWithIncompleteTypes = ( sizeof (T) == sizeof (U) ) }; +}; + +template<> +struct SuperSubclassStrict<void, void> +{ + enum { value = false }; +}; + +template<class U> +struct SuperSubclassStrict<void, U> +{ + enum { value = (::Loki::Conversion<const volatile U*, const volatile void*>::exists && + !::Loki::Conversion<const volatile void*, const volatile void*>::sameType && + !::Loki::Conversion<const volatile void*, const volatile U*>::sameType) }; + + // Dummy enum to make sure that both classes are fully defined. + enum{ dontUseWithIncompleteTypes = ( 0 == sizeof (U) ) }; +}; + +template<class T> +struct SuperSubclassStrict<T, void> +{ + enum { value = (::Loki::Conversion<const volatile void*, const volatile T*>::exists && + !::Loki::Conversion<const volatile T*, const volatile void*>::sameType && + !::Loki::Conversion<const volatile T*, const volatile void*>::sameType) }; + + // Dummy enum to make sure that both classes are fully defined. + enum{ dontUseWithIncompleteTypes = ( sizeof (T) == 0 ) }; +}; + + +} // namespace Loki + +//////////////////////////////////////////////////////////////////////////////// +// macro SUPERSUBCLASS +// Invocation: SUPERSUBCLASS(B, D) where B and D are types. +// Returns true if B is a public base of D, or if B and D are aliases of the +// same type. +// +// Caveat: might not work if T and U are in a private inheritance hierarchy. +// Deprecated: Use SuperSubclass class template instead. +//////////////////////////////////////////////////////////////////////////////// + +#define LOKI_SUPERSUBCLASS(T, U) \ + ::Loki::SuperSubclass<T,U>::value + +//////////////////////////////////////////////////////////////////////////////// +// macro SUPERSUBCLASS_STRICT +// Invocation: SUPERSUBCLASS(B, D) where B and D are types. +// Returns true if B is a public base of D. +// +// Caveat: might not work if T and U are in a private inheritance hierarchy. +// Deprecated: Use SuperSubclassStrict class template instead. +//////////////////////////////////////////////////////////////////////////////// + +#define LOKI_SUPERSUBCLASS_STRICT(T, U) \ + ::Loki::SuperSubclassStrict<T,U>::value + + +#endif // end file guardian + diff --git a/shared/loki/TypeTraits.h b/shared/loki/TypeTraits.h new file mode 100644 index 00000000..a592cab9 --- /dev/null +++ b/shared/loki/TypeTraits.h @@ -0,0 +1,2228 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_TYPETRAITS_INC_ +#define LOKI_TYPETRAITS_INC_ + +// $Id: TypeTraits.h 835 2007-08-02 19:39:02Z syntheticpp $ + + +#include "Typelist.h" +#include "Sequence.h" + +#if (defined _MSC_VER) && (_MSC_VER < 1400) +#include <string> +#endif + + +#ifdef _MSC_VER +#pragma warning( push ) +#pragma warning( disable : 4180 ) //qualifier applied to function type has no meaning; ignored +#endif + +namespace Loki +{ +//////////////////////////////////////////////////////////////////////////////// +// class template IsCustomUnsignedInt +// Offers a means to integrate nonstandard built-in unsigned integral types +// (such as unsigned __int64 or unsigned long long int) with the TypeTraits +// class template defined below. +// Invocation: IsCustomUnsignedInt<T> where T is any type +// Defines 'value', an enum that is 1 iff T is a custom built-in unsigned +// integral type +// Specialize this class template for nonstandard unsigned integral types +// and define value = 1 in those specializations +//////////////////////////////////////////////////////////////////////////////// + + template <typename T> + struct IsCustomUnsignedInt + { + enum { value = 0 }; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template IsCustomSignedInt +// Offers a means to integrate nonstandard built-in unsigned integral types +// (such as unsigned __int64 or unsigned long long int) with the TypeTraits +// class template defined below. +// Invocation: IsCustomSignedInt<T> where T is any type +// Defines 'value', an enum that is 1 iff T is a custom built-in signed +// integral type +// Specialize this class template for nonstandard unsigned integral types +// and define value = 1 in those specializations +//////////////////////////////////////////////////////////////////////////////// + + template <typename T> + struct IsCustomSignedInt + { + enum { value = 0 }; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template IsCustomFloat +// Offers a means to integrate nonstandard floating point types with the +// TypeTraits class template defined below. +// Invocation: IsCustomFloat<T> where T is any type +// Defines 'value', an enum that is 1 iff T is a custom built-in +// floating point type +// Specialize this class template for nonstandard unsigned integral types +// and define value = 1 in those specializations +//////////////////////////////////////////////////////////////////////////////// + + template <typename T> + struct IsCustomFloat + { + enum { value = 0 }; + }; + +//////////////////////////////////////////////////////////////////////////////// +// Helper types for class template TypeTraits defined below +//////////////////////////////////////////////////////////////////////////////// + + namespace Private + { +#ifndef LOKI_DISABLE_TYPELIST_MACROS + typedef LOKI_TYPELIST_4(unsigned char, unsigned short int,unsigned int, unsigned long int) + StdUnsignedInts; + typedef LOKI_TYPELIST_4(signed char, short int,int, long int) + StdSignedInts; + typedef LOKI_TYPELIST_3(bool, char, wchar_t) + StdOtherInts; + typedef LOKI_TYPELIST_3(float, double, long double) + StdFloats; +#else + typedef Loki::Seq<unsigned char, unsigned short int,unsigned int, unsigned long int>::Type + StdUnsignedInts; + typedef Loki::Seq<signed char, short int,int, long int>::Type + StdSignedInts; + typedef Loki::Seq<bool, char, wchar_t>::Type + StdOtherInts; + typedef Loki::Seq<float, double, long double>::Type + StdFloats; + +#endif + template <typename U> struct AddPointer + { + typedef U* Result; + }; + + template <typename U> struct AddPointer<U&> + { + typedef U* Result; + }; + + template <class U> struct AddReference + { + typedef U & Result; + }; + + template <class U> struct AddReference<U &> + { + typedef U & Result; + }; + + template <> struct AddReference<void> + { + typedef NullType Result; + }; + + template <class U> struct AddParameterType + { + typedef const U & Result; + }; + + template <class U> struct AddParameterType<U &> + { + typedef U & Result; + }; + + template <> struct AddParameterType<void> + { + typedef NullType Result; + }; + + template <typename T> + struct IsFunctionPointerRaw + {enum{result = 0};}; + + template <typename T> + struct IsFunctionPointerRaw<T(*)()> + {enum {result = 1};}; + + template <typename T, + typename P01> + struct IsFunctionPointerRaw<T(*)(P01)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02> + struct IsFunctionPointerRaw<T(*)( + P01, P02)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19, typename P20> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19, P20)> + {enum {result = 1};}; + + template <typename T> + struct IsFunctionPointerRaw<T(*)( + ...)> + {enum {result = 1};}; + + template <typename T, + typename P01> + struct IsFunctionPointerRaw<T(*)( + P01, ...)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02> + struct IsFunctionPointerRaw<T(*)( + P01, P02, ...)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, ...)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, ...)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + ...)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, ...)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, ...)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, ...)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, ...)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + ...)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, ...)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, ...)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, ...)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, ...)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + ...)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, ...)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, ...)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, ...)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19, ...)> + {enum {result = 1};}; + + template <typename T, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19, typename P20> + struct IsFunctionPointerRaw<T(*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19, P20, + ...)> + {enum {result = 1};}; + + + template <typename T> + struct IsMemberFunctionPointerRaw + {enum{result = 0};}; + + template <typename T, typename S> + struct IsMemberFunctionPointerRaw<T (S::*)()> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01> + struct IsMemberFunctionPointerRaw<T (S::*)(P01)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19, typename P20> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19, P20)> + {enum {result = 1};}; + + template <typename T, typename S> + struct IsMemberFunctionPointerRaw<T (S::*)( + ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19, ...)> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19, typename P20> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19, P20, + ...)> + {enum {result = 1};}; + + // Const versions + + template <typename T, typename S> + struct IsMemberFunctionPointerRaw<T (S::*)() const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01> + struct IsMemberFunctionPointerRaw<T (S::*)(P01) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19, typename P20> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19, P20) const> + {enum {result = 1};}; + + template <typename T, typename S> + struct IsMemberFunctionPointerRaw<T (S::*)( + ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19, ...) const> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19, typename P20> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19, P20, + ...) const> + {enum {result = 1};}; + + // Volatile versions + + template <typename T, typename S> + struct IsMemberFunctionPointerRaw<T (S::*)() volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01> + struct IsMemberFunctionPointerRaw<T (S::*)(P01) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19, typename P20> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19, P20) volatile> + {enum {result = 1};}; + + template <typename T, typename S> + struct IsMemberFunctionPointerRaw<T (S::*)( + ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19, ...) volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19, typename P20> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19, P20, + ...) volatile> + {enum {result = 1};}; + + // Const volatile versions + + template <typename T, typename S> + struct IsMemberFunctionPointerRaw<T (S::*)() const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01> + struct IsMemberFunctionPointerRaw<T (S::*)(P01) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19, typename P20> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19, P20) const volatile> + {enum {result = 1};}; + + template <typename T, typename S> + struct IsMemberFunctionPointerRaw<T (S::*)( + ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19, ...) const volatile> + {enum {result = 1};}; + + template <typename T, typename S, + typename P01, typename P02, typename P03, typename P04, typename P05, + typename P06, typename P07, typename P08, typename P09, typename P10, + typename P11, typename P12, typename P13, typename P14, typename P15, + typename P16, typename P17, typename P18, typename P19, typename P20> + struct IsMemberFunctionPointerRaw<T (S::*)( + P01, P02, P03, P04, P05, + P06, P07, P08, P09, P10, + P11, P12, P13, P14, P15, + P16, P17, P18, P19, P20, + ...) const volatile> + {enum {result = 1};}; + + }// namespace Private + +//////////////////////////////////////////////////////////////////////////////// +// class template TypeTraits +// +// Figures out at compile time various properties of any given type +// Invocations (T is a type, TypeTraits<T>::Property): +// +// - isPointer : returns true if T is a pointer type +// - PointeeType : returns the type to which T points if T is a pointer +// type, NullType otherwise +// - isReference : returns true if T is a reference type +// - ReferredType : returns the type to which T refers if T is a reference +// type, NullType otherwise +// - isMemberPointer : returns true if T is a pointer to member type +// - isStdUnsignedInt: returns true if T is a standard unsigned integral type +// - isStdSignedInt : returns true if T is a standard signed integral type +// - isStdIntegral : returns true if T is a standard integral type +// - isStdFloat : returns true if T is a standard floating-point type +// - isStdArith : returns true if T is a standard arithmetic type +// - isStdFundamental: returns true if T is a standard fundamental type +// - isUnsignedInt : returns true if T is a unsigned integral type +// - isSignedInt : returns true if T is a signed integral type +// - isIntegral : returns true if T is a integral type +// - isFloat : returns true if T is a floating-point type +// - isArith : returns true if T is a arithmetic type +// - isFundamental : returns true if T is a fundamental type +// - ParameterType : returns the optimal type to be used as a parameter for +// functions that take Ts +// - isConst : returns true if T is a const-qualified type +// - NonConstType : Type with removed 'const' qualifier from T, if any +// - isVolatile : returns true if T is a volatile-qualified type +// - NonVolatileType : Type with removed 'volatile' qualifier from T, if any +// - UnqualifiedType : Type with removed 'const' and 'volatile' qualifiers from +// T, if any +// - ParameterType : returns the optimal type to be used as a parameter +// for functions that take 'const T's +// +//////////////////////////////////////////////////////////////////////////////// + + template <typename T> + class TypeTraits + { + private: + + template <class U> struct ReferenceTraits + { + enum { result = false }; + typedef U ReferredType; + }; + + template <class U> struct ReferenceTraits<U&> + { + enum { result = true }; + typedef U ReferredType; + }; + + template <class U> struct PointerTraits + { + enum { result = false }; + typedef NullType PointeeType; + }; + + template <class U> struct PointerTraits<U*> + { + enum { result = true }; + typedef U PointeeType; + }; + + template <class U> struct PointerTraits<U*&> + { + enum { result = true }; + typedef U PointeeType; + }; + + template <class U> struct PToMTraits + { + enum { result = false }; + }; + + template <class U, class V> struct PToMTraits<U V::*> + { + enum { result = true }; + }; + + template <class U, class V> struct PToMTraits<U V::*&> + { + enum { result = true }; + }; + + template <class U> struct FunctionPointerTraits + { + enum{ result = Private::IsFunctionPointerRaw<U>::result }; + }; + + template <typename U> struct PToMFunctionTraits + { + enum{ result = Private::IsMemberFunctionPointerRaw<U>::result }; + }; + + template <class U> struct UnConst + { + typedef U Result; + enum { isConst = 0 }; + }; + + template <class U> struct UnConst<const U> + { + typedef U Result; + enum { isConst = 1 }; + }; + + template <class U> struct UnConst<const U&> + { + typedef U& Result; + enum { isConst = 1 }; + }; + + template <class U> struct UnVolatile + { + typedef U Result; + enum { isVolatile = 0 }; + }; + + template <class U> struct UnVolatile<volatile U> + { + typedef U Result; + enum { isVolatile = 1 }; + }; + + template <class U> struct UnVolatile<volatile U&> + { + typedef U& Result; + enum { isVolatile = 1 }; + }; + + public: + typedef typename UnConst<T>::Result + NonConstType; + typedef typename UnVolatile<T>::Result + NonVolatileType; + typedef typename UnVolatile<typename UnConst<T>::Result>::Result + UnqualifiedType; + typedef typename PointerTraits<UnqualifiedType>::PointeeType + PointeeType; + typedef typename ReferenceTraits<T>::ReferredType + ReferredType; + + enum { isConst = UnConst<T>::isConst }; + enum { isVolatile = UnVolatile<T>::isVolatile }; + enum { isReference = ReferenceTraits<UnqualifiedType>::result }; + enum { isFunction = FunctionPointerTraits<typename Private::AddPointer<T>::Result >::result }; + enum { isFunctionPointer= FunctionPointerTraits< + typename ReferenceTraits<UnqualifiedType>::ReferredType >::result }; + enum { isMemberFunctionPointer= PToMFunctionTraits< + typename ReferenceTraits<UnqualifiedType>::ReferredType >::result }; + enum { isMemberPointer = PToMTraits< + typename ReferenceTraits<UnqualifiedType>::ReferredType >::result || + isMemberFunctionPointer }; + enum { isPointer = PointerTraits< + typename ReferenceTraits<UnqualifiedType>::ReferredType >::result || + isFunctionPointer }; + + enum { isStdUnsignedInt = TL::IndexOf<Private::StdUnsignedInts, UnqualifiedType>::value >= 0 || + TL::IndexOf<Private::StdUnsignedInts, + typename ReferenceTraits<UnqualifiedType>::ReferredType>::value >= 0}; + enum { isStdSignedInt = TL::IndexOf<Private::StdSignedInts, UnqualifiedType>::value >= 0 || + TL::IndexOf<Private::StdSignedInts, + typename ReferenceTraits<UnqualifiedType>::ReferredType>::value >= 0}; + enum { isStdIntegral = isStdUnsignedInt || isStdSignedInt || + TL::IndexOf<Private::StdOtherInts, UnqualifiedType>::value >= 0 || + TL::IndexOf<Private::StdOtherInts, + typename ReferenceTraits<UnqualifiedType>::ReferredType>::value >= 0}; + enum { isStdFloat = TL::IndexOf<Private::StdFloats, UnqualifiedType>::value >= 0 || + TL::IndexOf<Private::StdFloats, + typename ReferenceTraits<UnqualifiedType>::ReferredType>::value >= 0}; + enum { isStdArith = isStdIntegral || isStdFloat }; + enum { isStdFundamental = isStdArith || isStdFloat || Conversion<T, void>::sameType }; + + enum { isUnsignedInt = isStdUnsignedInt || IsCustomUnsignedInt<UnqualifiedType>::value }; + enum { isSignedInt = isStdSignedInt || IsCustomSignedInt<UnqualifiedType>::value }; + enum { isIntegral = isStdIntegral || isUnsignedInt || isSignedInt }; + enum { isFloat = isStdFloat || IsCustomFloat<UnqualifiedType>::value }; + enum { isArith = isIntegral || isFloat }; + enum { isFundamental = isStdFundamental || isArith }; + + typedef typename Select<isStdArith || isPointer || isMemberPointer, T, + typename Private::AddParameterType<T>::Result>::Result + ParameterType; + }; +} + +#ifdef _MSC_VER +#pragma warning( pop ) +#endif // _MSC_VER + + +#endif // end file guardian + diff --git a/shared/loki/Typelist.h b/shared/loki/Typelist.h new file mode 100644 index 00000000..6a885927 --- /dev/null +++ b/shared/loki/Typelist.h @@ -0,0 +1,459 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Welsey Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_TYPELIST_INC_ +#define LOKI_TYPELIST_INC_ + +// $Id: Typelist.h 749 2006-10-17 19:49:26Z syntheticpp $ + + +#include "NullType.h" +#include "TypeManip.h" +#include "TypelistMacros.h" + + +namespace Loki +{ +//////////////////////////////////////////////////////////////////////////////// +// class template Typelist +// The building block of typelists of any length +// Use it through the LOKI_TYPELIST_NN macros +// Defines nested types: +// Head (first element, a non-typelist type by convention) +// Tail (second element, can be another typelist) +//////////////////////////////////////////////////////////////////////////////// + + template <class T, class U> + struct Typelist + { + typedef T Head; + typedef U Tail; + }; + +// Typelist utility algorithms + + namespace TL + { + +//////////////////////////////////////////////////////////////////////////////// +// class template MakeTypelist +// Takes a number of arguments equal to its numeric suffix +// The arguments are type names. +// MakeTypelist<T1, T2, ...>::Result +// returns a typelist that is of T1, T2, ... +//////////////////////////////////////////////////////////////////////////////// + + template + < + typename T1 = NullType, typename T2 = NullType, typename T3 = NullType, + typename T4 = NullType, typename T5 = NullType, typename T6 = NullType, + typename T7 = NullType, typename T8 = NullType, typename T9 = NullType, + typename T10 = NullType, typename T11 = NullType, typename T12 = NullType, + typename T13 = NullType, typename T14 = NullType, typename T15 = NullType, + typename T16 = NullType, typename T17 = NullType, typename T18 = NullType + > + struct MakeTypelist + { + private: + typedef typename MakeTypelist + < + T2 , T3 , T4 , + T5 , T6 , T7 , + T8 , T9 , T10, + T11, T12, T13, + T14, T15, T16, + T17, T18 + > + ::Result TailResult; + + public: + typedef Typelist<T1, TailResult> Result; + }; + + template<> + struct MakeTypelist<> + { + typedef NullType Result; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template Length +// Computes the length of a typelist +// Invocation (TList is a typelist): +// Length<TList>::value +// returns a compile-time constant containing the length of TList, not counting +// the end terminator (which by convention is NullType) +//////////////////////////////////////////////////////////////////////////////// + + template <class TList> struct Length; + template <> struct Length<NullType> + { + enum { value = 0 }; + }; + + template <class T, class U> + struct Length< Typelist<T, U> > + { + enum { value = 1 + Length<U>::value }; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template TypeAt +// Finds the type at a given index in a typelist +// Invocation (TList is a typelist and index is a compile-time integral +// constant): +// TypeAt<TList, index>::Result +// returns the type in position 'index' in TList +// If you pass an out-of-bounds index, the result is a compile-time error +//////////////////////////////////////////////////////////////////////////////// + + template <class TList, unsigned int index> struct TypeAt; + + template <class Head, class Tail> + struct TypeAt<Typelist<Head, Tail>, 0> + { + typedef Head Result; + }; + + template <class Head, class Tail, unsigned int i> + struct TypeAt<Typelist<Head, Tail>, i> + { + typedef typename TypeAt<Tail, i - 1>::Result Result; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template TypeAtNonStrict +// Finds the type at a given index in a typelist +// Invocations (TList is a typelist and index is a compile-time integral +// constant): +// a) TypeAt<TList, index>::Result +// returns the type in position 'index' in TList, or NullType if index is +// out-of-bounds +// b) TypeAt<TList, index, D>::Result +// returns the type in position 'index' in TList, or D if index is out-of-bounds +//////////////////////////////////////////////////////////////////////////////// + + template <class TList, unsigned int index, + typename DefaultType = NullType> + struct TypeAtNonStrict + { + typedef DefaultType Result; + }; + + template <class Head, class Tail, typename DefaultType> + struct TypeAtNonStrict<Typelist<Head, Tail>, 0, DefaultType> + { + typedef Head Result; + }; + + template <class Head, class Tail, unsigned int i, typename DefaultType> + struct TypeAtNonStrict<Typelist<Head, Tail>, i, DefaultType> + { + typedef typename + TypeAtNonStrict<Tail, i - 1, DefaultType>::Result Result; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template IndexOf +// Finds the index of a type in a typelist +// Invocation (TList is a typelist and T is a type): +// IndexOf<TList, T>::value +// returns the position of T in TList, or NullType if T is not found in TList +//////////////////////////////////////////////////////////////////////////////// + + template <class TList, class T> struct IndexOf; + + template <class T> + struct IndexOf<NullType, T> + { + enum { value = -1 }; + }; + + template <class T, class Tail> + struct IndexOf<Typelist<T, Tail>, T> + { + enum { value = 0 }; + }; + + template <class Head, class Tail, class T> + struct IndexOf<Typelist<Head, Tail>, T> + { + private: + enum { temp = IndexOf<Tail, T>::value }; + public: + enum { value = (temp == -1 ? -1 : 1 + temp) }; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template Append +// Appends a type or a typelist to another +// Invocation (TList is a typelist and T is either a type or a typelist): +// Append<TList, T>::Result +// returns a typelist that is TList followed by T and NullType-terminated +//////////////////////////////////////////////////////////////////////////////// + + template <class TList, class T> struct Append; + + template <> struct Append<NullType, NullType> + { + typedef NullType Result; + }; + + template <class T> struct Append<NullType, T> + { + typedef Typelist<T,NullType> Result; + }; + + template <class Head, class Tail> + struct Append<NullType, Typelist<Head, Tail> > + { + typedef Typelist<Head, Tail> Result; + }; + + template <class Head, class Tail, class T> + struct Append<Typelist<Head, Tail>, T> + { + typedef Typelist<Head, + typename Append<Tail, T>::Result> + Result; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template Erase +// Erases the first occurence, if any, of a type in a typelist +// Invocation (TList is a typelist and T is a type): +// Erase<TList, T>::Result +// returns a typelist that is TList without the first occurence of T +//////////////////////////////////////////////////////////////////////////////// + + template <class TList, class T> struct Erase; + + template <class T> // Specialization 1 + struct Erase<NullType, T> + { + typedef NullType Result; + }; + + template <class T, class Tail> // Specialization 2 + struct Erase<Typelist<T, Tail>, T> + { + typedef Tail Result; + }; + + template <class Head, class Tail, class T> // Specialization 3 + struct Erase<Typelist<Head, Tail>, T> + { + typedef Typelist<Head, + typename Erase<Tail, T>::Result> + Result; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template EraseAll +// Erases all first occurences, if any, of a type in a typelist +// Invocation (TList is a typelist and T is a type): +// EraseAll<TList, T>::Result +// returns a typelist that is TList without any occurence of T +//////////////////////////////////////////////////////////////////////////////// + + template <class TList, class T> struct EraseAll; + template <class T> + struct EraseAll<NullType, T> + { + typedef NullType Result; + }; + template <class T, class Tail> + struct EraseAll<Typelist<T, Tail>, T> + { + // Go all the way down the list removing the type + typedef typename EraseAll<Tail, T>::Result Result; + }; + template <class Head, class Tail, class T> + struct EraseAll<Typelist<Head, Tail>, T> + { + // Go all the way down the list removing the type + typedef Typelist<Head, + typename EraseAll<Tail, T>::Result> + Result; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template NoDuplicates +// Removes all duplicate types in a typelist +// Invocation (TList is a typelist): +// NoDuplicates<TList, T>::Result +//////////////////////////////////////////////////////////////////////////////// + + template <class TList> struct NoDuplicates; + + template <> struct NoDuplicates<NullType> + { + typedef NullType Result; + }; + + template <class Head, class Tail> + struct NoDuplicates< Typelist<Head, Tail> > + { + private: + typedef typename NoDuplicates<Tail>::Result L1; + typedef typename Erase<L1, Head>::Result L2; + public: + typedef Typelist<Head, L2> Result; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template Replace +// Replaces the first occurence of a type in a typelist, with another type +// Invocation (TList is a typelist, T, U are types): +// Replace<TList, T, U>::Result +// returns a typelist in which the first occurence of T is replaced with U +//////////////////////////////////////////////////////////////////////////////// + + template <class TList, class T, class U> struct Replace; + + template <class T, class U> + struct Replace<NullType, T, U> + { + typedef NullType Result; + }; + + template <class T, class Tail, class U> + struct Replace<Typelist<T, Tail>, T, U> + { + typedef Typelist<U, Tail> Result; + }; + + template <class Head, class Tail, class T, class U> + struct Replace<Typelist<Head, Tail>, T, U> + { + typedef Typelist<Head, + typename Replace<Tail, T, U>::Result> + Result; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template ReplaceAll +// Replaces all occurences of a type in a typelist, with another type +// Invocation (TList is a typelist, T, U are types): +// Replace<TList, T, U>::Result +// returns a typelist in which all occurences of T is replaced with U +//////////////////////////////////////////////////////////////////////////////// + + template <class TList, class T, class U> struct ReplaceAll; + + template <class T, class U> + struct ReplaceAll<NullType, T, U> + { + typedef NullType Result; + }; + + template <class T, class Tail, class U> + struct ReplaceAll<Typelist<T, Tail>, T, U> + { + typedef Typelist<U, typename ReplaceAll<Tail, T, U>::Result> Result; + }; + + template <class Head, class Tail, class T, class U> + struct ReplaceAll<Typelist<Head, Tail>, T, U> + { + typedef Typelist<Head, + typename ReplaceAll<Tail, T, U>::Result> + Result; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template Reverse +// Reverses a typelist +// Invocation (TList is a typelist): +// Reverse<TList>::Result +// returns a typelist that is TList reversed +//////////////////////////////////////////////////////////////////////////////// + + template <class TList> struct Reverse; + + template <> + struct Reverse<NullType> + { + typedef NullType Result; + }; + + template <class Head, class Tail> + struct Reverse< Typelist<Head, Tail> > + { + typedef typename Append< + typename Reverse<Tail>::Result, Head>::Result Result; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template MostDerived +// Finds the type in a typelist that is the most derived from a given type +// Invocation (TList is a typelist, T is a type): +// MostDerived<TList, T>::Result +// returns the type in TList that's the most derived from T +//////////////////////////////////////////////////////////////////////////////// + + template <class TList, class T> struct MostDerived; + + template <class T> + struct MostDerived<NullType, T> + { + typedef T Result; + }; + + template <class Head, class Tail, class T> + struct MostDerived<Typelist<Head, Tail>, T> + { + private: + typedef typename MostDerived<Tail, T>::Result Candidate; + public: + typedef typename Select< + SuperSubclass<Candidate,Head>::value, + Head, Candidate>::Result Result; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template DerivedToFront +// Arranges the types in a typelist so that the most derived types appear first +// Invocation (TList is a typelist): +// DerivedToFront<TList>::Result +// returns the reordered TList +//////////////////////////////////////////////////////////////////////////////// + + template <class TList> struct DerivedToFront; + + template <> + struct DerivedToFront<NullType> + { + typedef NullType Result; + }; + + template <class Head, class Tail> + struct DerivedToFront< Typelist<Head, Tail> > + { + private: + typedef typename MostDerived<Tail, Head>::Result + TheMostDerived; + typedef typename Replace<Tail, + TheMostDerived, Head>::Result Temp; + typedef typename DerivedToFront<Temp>::Result L; + public: + typedef Typelist<TheMostDerived, L> Result; + }; + + } // namespace TL +} // namespace Loki + + +#endif // end file guardian + diff --git a/shared/loki/TypelistMacros.h b/shared/loki/TypelistMacros.h new file mode 100644 index 00000000..6c14b348 --- /dev/null +++ b/shared/loki/TypelistMacros.h @@ -0,0 +1,353 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Welsey Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_TYPELISTMACROS_INC_ +#define LOKI_TYPELISTMACROS_INC_ + +// $Id: TypelistMacros.h 749 2006-10-17 19:49:26Z syntheticpp $ + + +//#define LOKI_DISABLE_TYPELIST_MACROS +#ifndef LOKI_DISABLE_TYPELIST_MACROS + +//////////////////////////////////////////////////////////////////////////////// +// macros LOKI_TYPELIST_1, LOKI_TYPELIST_2, ... LOKI_TYPELIST_50 +// Each takes a number of arguments equal to its numeric suffix +// The arguments are type names. LOKI_TYPELIST_NN generates a typelist containing +// all types passed as arguments, in that order. +// Example: LOKI_TYPELIST_2(char, int) generates a type containing char and int. +//////////////////////////////////////////////////////////////////////////////// + +#define LOKI_TYPELIST_1(T1) ::Loki::Typelist<T1, ::Loki::NullType> + +#define LOKI_TYPELIST_2(T1, T2) ::Loki::Typelist<T1, LOKI_TYPELIST_1(T2) > + +#define LOKI_TYPELIST_3(T1, T2, T3) ::Loki::Typelist<T1, LOKI_TYPELIST_2(T2, T3) > + +#define LOKI_TYPELIST_4(T1, T2, T3, T4) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_3(T2, T3, T4) > + +#define LOKI_TYPELIST_5(T1, T2, T3, T4, T5) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_4(T2, T3, T4, T5) > + +#define LOKI_TYPELIST_6(T1, T2, T3, T4, T5, T6) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_5(T2, T3, T4, T5, T6) > + +#define LOKI_TYPELIST_7(T1, T2, T3, T4, T5, T6, T7) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_6(T2, T3, T4, T5, T6, T7) > + +#define LOKI_TYPELIST_8(T1, T2, T3, T4, T5, T6, T7, T8) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_7(T2, T3, T4, T5, T6, T7, T8) > + +#define LOKI_TYPELIST_9(T1, T2, T3, T4, T5, T6, T7, T8, T9) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_8(T2, T3, T4, T5, T6, T7, T8, T9) > + +#define LOKI_TYPELIST_10(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_9(T2, T3, T4, T5, T6, T7, T8, T9, T10) > + +#define LOKI_TYPELIST_11(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_10(T2, T3, T4, T5, T6, T7, T8, T9, T10, T11) > + +#define LOKI_TYPELIST_12(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_11(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12) > + +#define LOKI_TYPELIST_13(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_12(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13) > + +#define LOKI_TYPELIST_14(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_13(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14) > + +#define LOKI_TYPELIST_15(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_14(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15) > + +#define LOKI_TYPELIST_16(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_15(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16) > + +#define LOKI_TYPELIST_17(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_16(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17) > + +#define LOKI_TYPELIST_18(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_17(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18) > + +#define LOKI_TYPELIST_19(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_18(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19) > + +#define LOKI_TYPELIST_20(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_19(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20) > + +#define LOKI_TYPELIST_21(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_20(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21) > + +#define LOKI_TYPELIST_22(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_21(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22) > + +#define LOKI_TYPELIST_23(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_22(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23) > + +#define LOKI_TYPELIST_24(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_23(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24) > + +#define LOKI_TYPELIST_25(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, T21, T22, T23, T24, T25) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_24(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25) > + +#define LOKI_TYPELIST_26(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_25(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26) > + +#define LOKI_TYPELIST_27(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_26(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27) > + +#define LOKI_TYPELIST_28(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_27(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28) > + +#define LOKI_TYPELIST_29(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_28(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29) > + +#define LOKI_TYPELIST_30(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_29(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30) > + +#define LOKI_TYPELIST_31(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_30(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31) > + +#define LOKI_TYPELIST_32(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_31(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32) > + +#define LOKI_TYPELIST_33(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_32(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33) > + +#define LOKI_TYPELIST_34(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_33(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, T31, T32, T33, T34) > + +#define LOKI_TYPELIST_35(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_34(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35) > + +#define LOKI_TYPELIST_36(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_35(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36) > + +#define LOKI_TYPELIST_37(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_36(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37) > + +#define LOKI_TYPELIST_38(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_37(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38) > + +#define LOKI_TYPELIST_39(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_38(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39) > + +#define LOKI_TYPELIST_40(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_39(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40) > + +#define LOKI_TYPELIST_41(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_40(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41) > + +#define LOKI_TYPELIST_42(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_41(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42) > + +#define LOKI_TYPELIST_43(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_42(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43) > + +#define LOKI_TYPELIST_44(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_43(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, T41, T42, T43, T44) > + +#define LOKI_TYPELIST_45(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \ + T41, T42, T43, T44, T45) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_44(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \ + T41, T42, T43, T44, T45) > + +#define LOKI_TYPELIST_46(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \ + T41, T42, T43, T44, T45, T46) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_45(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \ + T41, T42, T43, T44, T45, T46) > + +#define LOKI_TYPELIST_47(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \ + T41, T42, T43, T44, T45, T46, T47) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_46(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \ + T41, T42, T43, T44, T45, T46, T47) > + +#define LOKI_TYPELIST_48(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \ + T41, T42, T43, T44, T45, T46, T47, T48) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_47(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \ + T41, T42, T43, T44, T45, T46, T47, T48) > + +#define LOKI_TYPELIST_49(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \ + T41, T42, T43, T44, T45, T46, T47, T48, T49) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_48(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \ + T41, T42, T43, T44, T45, T46, T47, T48, T49) > + +#define LOKI_TYPELIST_50(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \ + T41, T42, T43, T44, T45, T46, T47, T48, T49, T50) \ + ::Loki::Typelist<T1, LOKI_TYPELIST_49(T2, T3, T4, T5, T6, T7, T8, T9, T10, \ + T11, T12, T13, T14, T15, T16, T17, T18, T19, T20, \ + T21, T22, T23, T24, T25, T26, T27, T28, T29, T30, \ + T31, T32, T33, T34, T35, T36, T37, T38, T39, T40, \ + T41, T42, T43, T44, T45, T46, T47, T48, T49, T50) > + +#endif //LOKI_DISABLE_TYPELIST_MACROS + +#endif // end file guardian + diff --git a/shared/loki/Visitor.h b/shared/loki/Visitor.h new file mode 100644 index 00000000..4425a9fa --- /dev/null +++ b/shared/loki/Visitor.h @@ -0,0 +1,355 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_VISITOR_INC_ +#define LOKI_VISITOR_INC_ + +// $Id: Visitor.h 751 2006-10-17 19:50:37Z syntheticpp $ + + +/// \defgroup VisitorGroup Visitor + +#include "Typelist.h" +#include "HierarchyGenerators.h" + +namespace Loki +{ + +//////////////////////////////////////////////////////////////////////////////// +/// \class BaseVisitor +/// +/// \ingroup VisitorGroup +/// The base class of any Acyclic Visitor +//////////////////////////////////////////////////////////////////////////////// + + class BaseVisitor + { + public: + virtual ~BaseVisitor() {} + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \class Visitor +/// +/// \ingroup VisitorGroup +/// The building block of Acyclic Visitor +/// +/// \par Usage +/// +/// Defining the visitable class: +/// +/// \code +/// class RasterBitmap : public BaseVisitable<> +/// { +/// public: +/// LOKI_DEFINE_VISITABLE() +/// }; +/// \endcode +/// +/// Way 1 to define a visitor: +/// \code +/// class SomeVisitor : +/// public BaseVisitor // required +/// public Visitor<RasterBitmap>, +/// public Visitor<Paragraph> +/// { +/// public: +/// void Visit(RasterBitmap&); // visit a RasterBitmap +/// void Visit(Paragraph &); // visit a Paragraph +/// }; +/// \endcode +/// +/// Way 2 to define the visitor: +/// \code +/// class SomeVisitor : +/// public BaseVisitor // required +/// public Visitor<LOKI_TYPELIST_2(RasterBitmap, Paragraph)> +/// { +/// public: +/// void Visit(RasterBitmap&); // visit a RasterBitmap +/// void Visit(Paragraph &); // visit a Paragraph +/// }; +/// \endcode +/// +/// Way 3 to define the visitor: +/// \code +/// class SomeVisitor : +/// public BaseVisitor // required +/// public Visitor<Seq<RasterBitmap, Paragraph>::Type> +/// { +/// public: +/// void Visit(RasterBitmap&); // visit a RasterBitmap +/// void Visit(Paragraph &); // visit a Paragraph +/// }; +/// \endcode +/// +/// \par Using const visit functions: +/// +/// Defining the visitable class (true for const): +/// +/// \code +/// class RasterBitmap : public BaseVisitable<void, DefaultCatchAll, true> +/// { +/// public: +/// LOKI_DEFINE_CONST_VISITABLE() +/// }; +/// \endcode +/// +/// Defining the visitor which only calls const member functions: +/// \code +/// class SomeVisitor : +/// public BaseVisitor // required +/// public Visitor<RasterBitmap, void, true>, +/// { +/// public: +/// void Visit(const RasterBitmap&); // visit a RasterBitmap by a const member function +/// }; +/// \endcode +/// +/// \par Example: +/// +/// test/Visitor/main.cpp +//////////////////////////////////////////////////////////////////////////////// + + template <class T, typename R = void, bool ConstVisit = false> + class Visitor; + + template <class T, typename R> + class Visitor<T, R, false> + { + public: + typedef R ReturnType; + typedef T ParamType; + virtual ~Visitor() {} + virtual ReturnType Visit(ParamType&) = 0; + }; + + template <class T, typename R> + class Visitor<T, R, true> + { + public: + typedef R ReturnType; + typedef const T ParamType; + virtual ~Visitor() {} + virtual ReturnType Visit(ParamType&) = 0; + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template Visitor (specialization) +// This specialization is not present in the book. It makes it easier to define +// Visitors for multiple types in a shot by using a typelist. Example: +// +// class SomeVisitor : +// public BaseVisitor // required +// public Visitor<LOKI_TYPELIST_2(RasterBitmap, Paragraph)> +// { +// public: +// void Visit(RasterBitmap&); // visit a RasterBitmap +// void Visit(Paragraph &); // visit a Paragraph +// }; +//////////////////////////////////////////////////////////////////////////////// + + template <class Head, class Tail, typename R> + class Visitor<Typelist<Head, Tail>, R, false> + : public Visitor<Head, R, false>, public Visitor<Tail, R, false> + { + public: + typedef R ReturnType; + // using Visitor<Head, R>::Visit; + // using Visitor<Tail, R>::Visit; + }; + + template <class Head, typename R> + class Visitor<Typelist<Head, NullType>, R, false> : public Visitor<Head, R, false> + { + public: + typedef R ReturnType; + using Visitor<Head, R, false>::Visit; + }; + + template <class Head, class Tail, typename R> + class Visitor<Typelist<Head, Tail>, R, true> + : public Visitor<Head, R, true>, public Visitor<Tail, R, true> + { + public: + typedef R ReturnType; + // using Visitor<Head, R>::Visit; + // using Visitor<Tail, R>::Visit; + }; + + template <class Head, typename R> + class Visitor<Typelist<Head, NullType>, R, true> : public Visitor<Head, R, true> + { + public: + typedef R ReturnType; + using Visitor<Head, R, true>::Visit; + }; + + +//////////////////////////////////////////////////////////////////////////////// +// class template BaseVisitorImpl +// Implements non-strict visitation (you can implement only part of the Visit +// functions) +//////////////////////////////////////////////////////////////////////////////// + + template <class TList, typename R = void> class BaseVisitorImpl; + + template <class Head, class Tail, typename R> + class BaseVisitorImpl<Typelist<Head, Tail>, R> + : public Visitor<Head, R> + , public BaseVisitorImpl<Tail, R> + { + public: + // using BaseVisitorImpl<Tail, R>::Visit; + + virtual R Visit(Head&) + { return R(); } + }; + + template <class Head, typename R> + class BaseVisitorImpl<Typelist<Head, NullType>, R> + : public Visitor<Head, R> + { + public: + virtual R Visit(Head&) + { return R(); } + }; + +//////////////////////////////////////////////////////////////////////////////// +// class template BaseVisitable +//////////////////////////////////////////////////////////////////////////////// + +template <typename R, typename Visited> +struct DefaultCatchAll +{ + static R OnUnknownVisitor(Visited&, BaseVisitor&) + { return R(); } +}; + +//////////////////////////////////////////////////////////////////////////////// +// class template BaseVisitable +//////////////////////////////////////////////////////////////////////////////// + + template + < + typename R = void, + template <typename, class> class CatchAll = DefaultCatchAll, + bool ConstVisitable = false + > + class BaseVisitable; + + template<typename R,template <typename, class> class CatchAll> + class BaseVisitable<R, CatchAll, false> + { + public: + typedef R ReturnType; + virtual ~BaseVisitable() {} + virtual ReturnType Accept(BaseVisitor&) = 0; + + protected: // give access only to the hierarchy + template <class T> + static ReturnType AcceptImpl(T& visited, BaseVisitor& guest) + { + // Apply the Acyclic Visitor + if (Visitor<T,R>* p = dynamic_cast<Visitor<T,R>*>(&guest)) + { + return p->Visit(visited); + } + return CatchAll<R, T>::OnUnknownVisitor(visited, guest); + } + }; + + template<typename R,template <typename, class> class CatchAll> + class BaseVisitable<R, CatchAll, true> + { + public: + typedef R ReturnType; + virtual ~BaseVisitable() {} + virtual ReturnType Accept(BaseVisitor&) const = 0; + + protected: // give access only to the hierarchy + template <class T> + static ReturnType AcceptImpl(const T& visited, BaseVisitor& guest) + { + // Apply the Acyclic Visitor + if (Visitor<T,R,true>* p = dynamic_cast<Visitor<T,R,true>*>(&guest)) + { + return p->Visit(visited); + } + return CatchAll<R, T>::OnUnknownVisitor(const_cast<T&>(visited), guest); + } + }; + + +//////////////////////////////////////////////////////////////////////////////// +/// \def LOKI_DEFINE_VISITABLE() +/// \ingroup VisitorGroup +/// Put it in every class that you want to make visitable +/// (in addition to deriving it from BaseVisitable<R>) +//////////////////////////////////////////////////////////////////////////////// + +#define LOKI_DEFINE_VISITABLE() \ + virtual ReturnType Accept(::Loki::BaseVisitor& guest) \ + { return AcceptImpl(*this, guest); } + +//////////////////////////////////////////////////////////////////////////////// +/// \def LOKI_DEFINE_CONST_VISITABLE() +/// \ingroup VisitorGroup +/// Put it in every class that you want to make visitable by const member +/// functions (in addition to deriving it from BaseVisitable<R>) +//////////////////////////////////////////////////////////////////////////////// + +#define LOKI_DEFINE_CONST_VISITABLE() \ + virtual ReturnType Accept(::Loki::BaseVisitor& guest) const \ + { return AcceptImpl(*this, guest); } + +//////////////////////////////////////////////////////////////////////////////// +/// \class CyclicVisitor +/// +/// \ingroup VisitorGroup +/// Put it in every class that you want to make visitable (in addition to +/// deriving it from BaseVisitable<R> +//////////////////////////////////////////////////////////////////////////////// + + template <typename R, class TList> + class CyclicVisitor : public Visitor<TList, R> + { + public: + typedef R ReturnType; + // using Visitor<TList, R>::Visit; + + template <class Visited> + ReturnType GenericVisit(Visited& host) + { + Visitor<Visited, ReturnType>& subObj = *this; + return subObj.Visit(host); + } + }; + +//////////////////////////////////////////////////////////////////////////////// +/// \def LOKI_DEFINE_CYCLIC_VISITABLE(SomeVisitor) +/// \ingroup VisitorGroup +/// Put it in every class that you want to make visitable by a cyclic visitor +//////////////////////////////////////////////////////////////////////////////// + +#define LOKI_DEFINE_CYCLIC_VISITABLE(SomeVisitor) \ + virtual SomeVisitor::ReturnType Accept(SomeVisitor& guest) \ + { return guest.GenericVisit(*this); } + +} // namespace Loki + + + +#endif // end file guardian + diff --git a/shared/loki/readme.txt b/shared/loki/readme.txt new file mode 100644 index 00000000..a35cf387 --- /dev/null +++ b/shared/loki/readme.txt @@ -0,0 +1,12 @@ +// $Id: readme.txt 753 2006-10-17 19:54:22Z syntheticpp $ + +The Golden Code +KEEPEN DER DAMDDEN FUGGERMUTTENS OTTEN DIS CODDEN FIL + +A compliant C++ compiler will compile all of this code as is. +See the respective vendor directories for code that actually compiles & runs. + +Note: Right now, this code contains CodeWarrior & gcc modifications, +which may be removed at a future point in time +(by moving them to a vendor specific implementation). +MKH
\ No newline at end of file diff --git a/shared/loki/static_check.h b/shared/loki/static_check.h new file mode 100644 index 00000000..51ce389e --- /dev/null +++ b/shared/loki/static_check.h @@ -0,0 +1,45 @@ +//////////////////////////////////////////////////////////////////////////////// +// The Loki Library +// Copyright (c) 2001 by Andrei Alexandrescu +// This code accompanies the book: +// Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design +// Patterns Applied". Copyright (c) 2001. Addison-Wesley. +// Permission to use, copy, modify, distribute and sell this software for any +// purpose is hereby granted without fee, provided that the above copyright +// notice appear in all copies and that both that copyright notice and this +// permission notice appear in supporting documentation. +// The author or Addison-Wesley Longman make no representations about the +// suitability of this software for any purpose. It is provided "as is" +// without express or implied warranty. +//////////////////////////////////////////////////////////////////////////////// +#ifndef LOKI_STATIC_CHECK_INC_ +#define LOKI_STATIC_CHECK_INC_ + +// $Id: static_check.h 752 2006-10-17 19:52:18Z syntheticpp $ + + +namespace Loki +{ +//////////////////////////////////////////////////////////////////////////////// +// Helper structure for the STATIC_CHECK macro +//////////////////////////////////////////////////////////////////////////////// + + template<int> struct CompileTimeError; + template<> struct CompileTimeError<true> {}; +} + +//////////////////////////////////////////////////////////////////////////////// +// macro STATIC_CHECK +// Invocation: STATIC_CHECK(expr, id) +// where: +// expr is a compile-time integral or pointer expression +// id is a C++ identifier that does not need to be defined +// If expr is zero, id will appear in a compile-time error message. +//////////////////////////////////////////////////////////////////////////////// + +#define LOKI_STATIC_CHECK(expr, msg) \ + { Loki::CompileTimeError<((expr) != 0)> ERROR_##msg; (void)ERROR_##msg; } + + +#endif // end file guardian + diff --git a/shared/shadow.cpp b/shared/shadow.cpp index 02a6a522..da7cfd99 100644 --- a/shared/shadow.cpp +++ b/shared/shadow.cpp @@ -30,9 +30,9 @@ public: private: ShadowlDllHandler() : - createShadowCopy(NULL), - releaseShadowCopy(NULL), - hShadow(NULL) + createShadowCopy(NULL), + releaseShadowCopy(NULL), + hShadow(NULL) { //get a handle to the DLL module containing the required functionality hShadow = ::LoadLibrary(L"Shadow.dll"); @@ -53,7 +53,7 @@ private: ShadowCopy::ShadowCopy() : - backupHandle(NULL) {} + backupHandle(NULL) {} ShadowCopy::~ShadowCopy() diff --git a/shared/shadow.h b/shared/shadow.h index 15fd4d9d..8affdebf 100644 --- a/shared/shadow.h +++ b/shared/shadow.h @@ -11,21 +11,21 @@ header should be used in the windows build only! namespace FreeFileSync { - class ShadowCopy //buffer access to Windows Volume Shadow Copy Service - { - public: - ShadowCopy(); - ~ShadowCopy(); +class ShadowCopy //buffer access to Windows Volume Shadow Copy Service +{ +public: + ShadowCopy(); + ~ShadowCopy(); - Zstring makeShadowCopy(const Zstring& inputFile); //throw(FileError); returns filename on shadow copy + Zstring makeShadowCopy(const Zstring& inputFile); //throw(FileError); returns filename on shadow copy - private: - bool isOkay(); +private: + bool isOkay(); - Zstring realVolumeLast; //buffer last volume name - Zstring shadowVolumeLast; //buffer last created shadow volume - void* backupHandle; - }; + Zstring realVolumeLast; //buffer last volume name + Zstring shadowVolumeLast; //buffer last created shadow volume + void* backupHandle; +}; } #endif // SHADOW_H_INCLUDED diff --git a/shared/standardPaths.cpp b/shared/standardPaths.cpp index 54774673..3d5cfdb5 100644 --- a/shared/standardPaths.cpp +++ b/shared/standardPaths.cpp @@ -2,20 +2,23 @@ #include <wx/stdpaths.h> #include <wx/filename.h> #include "systemConstants.h" +#include "stringConv.h" + +using namespace FreeFileSync; wxString assembleFileForUserData(const wxString fileName) { - static const bool isPortableVersion = !wxFileExists(FreeFileSync::getInstallationDir() + globalFunctions::FILE_NAME_SEPARATOR + wxT("uninstall.exe")); //this check is a bit lame... + static const bool isPortableVersion = !wxFileExists(FreeFileSync::getInstallationDir() + zToWx(globalFunctions::FILE_NAME_SEPARATOR) + wxT("uninstall.exe")); //this check is a bit lame... if (isPortableVersion) //use current working directory - return wxString(wxT(".")) + globalFunctions::FILE_NAME_SEPARATOR + fileName; + return wxString(wxT(".")) + zToWx(globalFunctions::FILE_NAME_SEPARATOR) + fileName; else //usen OS' standard paths { wxString userDirectory = wxStandardPathsBase::Get().GetUserDataDir(); - if (!userDirectory.EndsWith(wxString(globalFunctions::FILE_NAME_SEPARATOR))) - userDirectory += globalFunctions::FILE_NAME_SEPARATOR; + if (!userDirectory.EndsWith(zToWx(globalFunctions::FILE_NAME_SEPARATOR))) + userDirectory += zToWx(globalFunctions::FILE_NAME_SEPARATOR); if (!wxDirExists(userDirectory)) ::wxMkdir(userDirectory); //only top directory needs to be created: no recursion necessary diff --git a/shared/standardPaths.h b/shared/standardPaths.h index 64811246..34f6ab48 100644 --- a/shared/standardPaths.h +++ b/shared/standardPaths.h @@ -9,11 +9,11 @@ namespace FreeFileSync //------------------------------------------------------------------------------ //global functions //------------------------------------------------------------------------------ - const wxString& getGlobalConfigFile(); - const wxString& getDefaultLogDirectory(); - const wxString& getLastErrorTxtFile(); - const wxString& getInstallationDir(); //FreeFileSync installation directory without path separator - const wxString& getConfigDir(); +const wxString& getGlobalConfigFile(); +const wxString& getDefaultLogDirectory(); +const wxString& getLastErrorTxtFile(); +const wxString& getInstallationDir(); //FreeFileSync installation directory without path separator +const wxString& getConfigDir(); //------------------------------------------------------------------------------ } diff --git a/shared/stringConv.h b/shared/stringConv.h new file mode 100644 index 00000000..f4048aab --- /dev/null +++ b/shared/stringConv.h @@ -0,0 +1,104 @@ +#ifndef STRINGCONV_H_INCLUDED +#define STRINGCONV_H_INCLUDED + +#include <wx/string.h> +#include "zstring.h" + +namespace FreeFileSync +{ +//conversion from Zstring to wxString +wxString zToWx(const Zstring& str); +wxString zToWx(const DefaultChar* str); +wxString zToWx(DefaultChar ch); +//conversion from wxString to Zstring +Zstring wxToZ(const wxString& str); +Zstring wxToZ(const wxChar* str); +Zstring wxToZ(wxChar ch); + + + + + + + + + + + + + + + + + + + + + + + + + + + + +//---------------Inline Implementation--------------------------------------------------- +inline +wxString zToWx(const Zstring& str) +{ +#ifdef ZSTRING_CHAR + return wxString::FromUTF8(str.c_str(), str.length()); +#elif defined ZSTRING_WIDE_CHAR + return wxString(str.c_str(), str.length()); +#endif +} + + +inline +wxString zToWx(const DefaultChar* str) +{ +#ifdef ZSTRING_CHAR + return wxString::FromUTF8(str); +#elif defined ZSTRING_WIDE_CHAR + return str; +#endif +} + + +inline +wxString zToWx(DefaultChar ch) +{ + return zToWx(Zstring() + ch); +} + +//----------------------------------------------------------------- +inline +Zstring wxToZ(const wxString& str) +{ +#ifdef ZSTRING_CHAR + return Zstring(str.ToUTF8()); +#elif defined ZSTRING_WIDE_CHAR + return Zstring(str.c_str(), str.length()); +#endif +} + + +inline +Zstring wxToZ(const wxChar* str) +{ +#ifdef ZSTRING_CHAR + return Zstring(wxString(str).ToUTF8()); +#elif defined ZSTRING_WIDE_CHAR + return str; +#endif +} + + +inline +Zstring wxToZ(wxChar ch) +{ + return wxToZ(wxString(ch)); +} +} + +#endif // STRINGCONV_H_INCLUDED diff --git a/shared/systemConstants.h b/shared/systemConstants.h index 84c1ae85..bae23d5a 100644 --- a/shared/systemConstants.h +++ b/shared/systemConstants.h @@ -2,7 +2,7 @@ #define SYSTEMCONSTANTS_H_INCLUDED #include "zstring.h" - +#include <wx/string.h> namespace globalFunctions { @@ -10,11 +10,11 @@ namespace globalFunctions // GLOBALS //------------------------------------------------ #ifdef FFS_WIN - const DefaultChar FILE_NAME_SEPARATOR = '\\'; - static const DefaultChar* const LINE_BREAK = L"\r\n"; //internal linkage +const DefaultChar FILE_NAME_SEPARATOR = '\\'; +static const wxChar* const LINE_BREAK = wxT("\r\n"); //internal linkage #elif defined FFS_LINUX - const DefaultChar FILE_NAME_SEPARATOR = '/'; - static const DefaultChar* const LINE_BREAK = "\n"; +const DefaultChar FILE_NAME_SEPARATOR = '/'; +static const wxChar* const LINE_BREAK = wxT("\n"); #endif } diff --git a/shared/systemFunctions.cpp b/shared/systemFunctions.cpp index 4fd17fc1..3d6915cd 100644 --- a/shared/systemFunctions.cpp +++ b/shared/systemFunctions.cpp @@ -11,27 +11,29 @@ #ifdef FFS_WIN -wxString FreeFileSync::getLastErrorFormatted(const unsigned long lastError) //try to get additional Windows error information +wxString FreeFileSync::getLastErrorFormatted(unsigned long lastError) //try to get additional Windows error information { //determine error code if none was specified - const unsigned long lastErrorCode = lastError == 0 ? ::GetLastError() : lastError; + if (lastError == 0) + lastError = ::GetLastError(); - wxString output = wxString(wxT("Windows Error Code ")) + wxString::Format(wxT("%u"), lastErrorCode); + wxString output = wxString(wxT("Windows Error Code ")) + wxString::Format(wxT("%u"), lastError); WCHAR buffer[1001]; - if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_MAX_WIDTH_MASK, 0, lastErrorCode, 0, buffer, 1001, NULL) != 0) + if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_MAX_WIDTH_MASK, 0, lastError, 0, buffer, 1001, NULL) != 0) output += wxString(wxT(": ")) + buffer; return output; } #elif defined FFS_LINUX -wxString FreeFileSync::getLastErrorFormatted(const int lastError) //try to get additional Linux error information +wxString FreeFileSync::getLastErrorFormatted(int lastError) //try to get additional Linux error information { //determine error code if none was specified - const int lastErrorCode = lastError == 0 ? errno : lastError; + if (lastError == 0) + lastError = errno; //don't use :: errno is a macro! - wxString output = wxString(wxT("Linux Error Code ")) + wxString::Format(wxT("%i"), lastErrorCode); - output += wxString(wxT(": ")) + ::strerror(lastErrorCode); + wxString output = wxString(wxT("Linux Error Code ")) + wxString::Format(wxT("%i"), lastError); + output += wxString(wxT(": ")) + wxString::FromUTF8(::strerror(lastError)); return output; } #endif diff --git a/shared/systemFunctions.h b/shared/systemFunctions.h index b449d8d2..bfeacdd4 100644 --- a/shared/systemFunctions.h +++ b/shared/systemFunctions.h @@ -8,9 +8,9 @@ namespace FreeFileSync { #ifdef FFS_WIN - wxString getLastErrorFormatted(const unsigned long lastError = 0); //try to get additional Windows error information +wxString getLastErrorFormatted(unsigned long lastError = 0); //try to get additional Windows error information #elif defined FFS_LINUX - wxString getLastErrorFormatted(const int lastError = 0); //try to get additional Linux error information +wxString getLastErrorFormatted(int lastError = 0); //try to get additional Linux error information #endif } diff --git a/shared/tinyxml/tinyxml.cpp b/shared/tinyxml/tinyxml.cpp index aa13deec..033d13be 100644 --- a/shared/tinyxml/tinyxml.cpp +++ b/shared/tinyxml/tinyxml.cpp @@ -504,7 +504,7 @@ const TiXmlDocument* TiXmlNode::GetDocument() const TiXmlElement::TiXmlElement (const char * _value) - : TiXmlNode( TiXmlNode::ELEMENT ) + : TiXmlNode( TiXmlNode::ELEMENT ) { firstChild = lastChild = 0; value = _value; @@ -513,7 +513,7 @@ TiXmlElement::TiXmlElement (const char * _value) #ifdef TIXML_USE_STL TiXmlElement::TiXmlElement( const std::string& _value ) - : TiXmlNode( TiXmlNode::ELEMENT ) + : TiXmlNode( TiXmlNode::ELEMENT ) { firstChild = lastChild = 0; value = _value; @@ -522,7 +522,7 @@ TiXmlElement::TiXmlElement( const std::string& _value ) TiXmlElement::TiXmlElement( const TiXmlElement& copy) - : TiXmlNode( TiXmlNode::ELEMENT ) + : TiXmlNode( TiXmlNode::ELEMENT ) { firstChild = lastChild = 0; copy.CopyTo( this ); @@ -1418,7 +1418,7 @@ TiXmlNode* TiXmlText::Clone() const TiXmlDeclaration::TiXmlDeclaration( const char * _version, const char * _encoding, const char * _standalone ) - : TiXmlNode( TiXmlNode::DECLARATION ) + : TiXmlNode( TiXmlNode::DECLARATION ) { version = _version; encoding = _encoding; @@ -1430,7 +1430,7 @@ TiXmlDeclaration::TiXmlDeclaration( const char * _version, TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, const std::string& _encoding, const std::string& _standalone ) - : TiXmlNode( TiXmlNode::DECLARATION ) + : TiXmlNode( TiXmlNode::DECLARATION ) { version = _version; encoding = _encoding; @@ -1440,7 +1440,7 @@ TiXmlDeclaration::TiXmlDeclaration( const std::string& _version, TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy ) - : TiXmlNode( TiXmlNode::DECLARATION ) + : TiXmlNode( TiXmlNode::DECLARATION ) { copy.CopyTo( this ); } diff --git a/shared/tinyxml/tinyxmlparser.cpp b/shared/tinyxml/tinyxmlparser.cpp index a601016a..503becde 100644 --- a/shared/tinyxml/tinyxmlparser.cpp +++ b/shared/tinyxml/tinyxmlparser.cpp @@ -433,11 +433,11 @@ const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncodi { const char* start = p; while ( p && *p - && ( IsAlphaNum( (unsigned char ) *p, encoding ) - || *p == '_' - || *p == '-' - || *p == '.' - || *p == ':' ) ) + && ( IsAlphaNum( (unsigned char ) *p, encoding ) + || *p == '_' + || *p == '-' + || *p == '.' + || *p == ':' ) ) { //(*name) += *p; // expensive ++p; @@ -588,11 +588,11 @@ bool TiXmlBase::StringEqual( const char* p, } const char* TiXmlBase::ReadText( const char* p, - TIXML_STRING * text, - bool trimWhiteSpace, - const char* endTag, - bool caseInsensitive, - TiXmlEncoding encoding ) + TIXML_STRING * text, + bool trimWhiteSpace, + const char* endTag, + bool caseInsensitive, + TiXmlEncoding encoding ) { *text = ""; if ( !trimWhiteSpace // certain tags always keep whitespace diff --git a/shared/toggleButton.h b/shared/toggleButton.h index b7475e0c..1110ad5d 100644 --- a/shared/toggleButton.h +++ b/shared/toggleButton.h @@ -14,8 +14,8 @@ public: long style = 0, const wxValidator& validator = wxDefaultValidator, const wxString& name = wxButtonNameStr) : - wxBitmapButton(parent, id, bitmap, pos, size, style, validator, name), - active(false) {} + wxBitmapButton(parent, id, bitmap, pos, size, style, validator, name), + active(false) {} void init(const wxBitmap& activeBmp, const wxString& activeTooltip, diff --git a/shared/xmlBase.cpp b/shared/xmlBase.cpp index ba96b663..c098f94a 100644 --- a/shared/xmlBase.cpp +++ b/shared/xmlBase.cpp @@ -43,7 +43,8 @@ xmlAccess::XmlType xmlAccess::getXmlType(const wxString& filename) return XML_OTHER; } catch (const std::exception&) - { //unfortunately TiXml isn't very smart and tries to allocate space for the complete file: length_error exception is thrown for large files! + { + //unfortunately TiXml isn't very smart and tries to allocate space for the complete file: length_error exception is thrown for large files! return XML_OTHER; } diff --git a/shared/xmlBase.h b/shared/xmlBase.h index ed838843..3a01c515 100644 --- a/shared/xmlBase.h +++ b/shared/xmlBase.h @@ -10,108 +10,108 @@ namespace xmlAccess { - enum XmlType - { - XML_GUI_CONFIG, - XML_BATCH_CONFIG, - XML_GLOBAL_SETTINGS, - XML_REAL_CONFIG, - XML_OTHER - }; +enum XmlType +{ + XML_GUI_CONFIG, + XML_BATCH_CONFIG, + XML_GLOBAL_SETTINGS, + XML_REAL_CONFIG, + XML_OTHER +}; - XmlType getXmlType(const wxString& filename); +XmlType getXmlType(const wxString& filename); - bool loadXmlDocument(const wxString& fileName, const XmlType type, TiXmlDocument& document); - void getDefaultXmlDocument(const XmlType type, TiXmlDocument& document); - bool saveXmlDocument(const wxString& fileName, const TiXmlDocument& document); +bool loadXmlDocument(const wxString& fileName, const XmlType type, TiXmlDocument& document); +void getDefaultXmlDocument(const XmlType type, TiXmlDocument& document); +bool saveXmlDocument(const wxString& fileName, const TiXmlDocument& document); //------------------------------------------------------------------------------------------ - //small helper functions - bool readXmlElement(const std::string& name, const TiXmlElement* parent, std::string& output); - bool readXmlElement(const std::string& name, const TiXmlElement* parent, wxString& output); - bool readXmlElement(const std::string& name, const TiXmlElement* parent, int& output); - bool readXmlElement(const std::string& name, const TiXmlElement* parent, unsigned int& output); - bool readXmlElement(const std::string& name, const TiXmlElement* parent, long& output); - bool readXmlElement(const std::string& name, const TiXmlElement* parent, bool& output); - bool readXmlElement(const std::string& name, const TiXmlElement* parent, std::vector<wxString>& output); - - bool readXmlAttribute(const std::string& name, const TiXmlElement* node, std::string& output); - bool readXmlAttribute(const std::string& name, const TiXmlElement* node, wxString& output); - bool readXmlAttribute(const std::string& name, const TiXmlElement* node, int& output); - bool readXmlAttribute(const std::string& name, const TiXmlElement* node, unsigned int& output); - bool readXmlAttribute(const std::string& name, const TiXmlElement* node, bool& output); - - void addXmlElement(const std::string& name, const std::string& value, TiXmlElement* parent); - void addXmlElement(const std::string& name, const wxString& value, TiXmlElement* parent); - void addXmlElement(const std::string& name, const int value, TiXmlElement* parent); - void addXmlElement(const std::string& name, const unsigned int value, TiXmlElement* parent); - void addXmlElement(const std::string& name, const long value, TiXmlElement* parent); - void addXmlElement(const std::string& name, const bool value, TiXmlElement* parent); - void addXmlElement(const std::string& name, const std::vector<wxString>& value, TiXmlElement* parent); - - void addXmlAttribute(const std::string& name, const std::string& value, TiXmlElement* node); - void addXmlAttribute(const std::string& name, const wxString& value, TiXmlElement* node); - void addXmlAttribute(const std::string& name, const int value, TiXmlElement* node); - void addXmlAttribute(const std::string& name, const unsigned int value, TiXmlElement* node); - void addXmlAttribute(const std::string& name, const bool value, TiXmlElement* node); - - - - class XmlParser +//small helper functions +bool readXmlElement(const std::string& name, const TiXmlElement* parent, std::string& output); +bool readXmlElement(const std::string& name, const TiXmlElement* parent, wxString& output); +bool readXmlElement(const std::string& name, const TiXmlElement* parent, int& output); +bool readXmlElement(const std::string& name, const TiXmlElement* parent, unsigned int& output); +bool readXmlElement(const std::string& name, const TiXmlElement* parent, long& output); +bool readXmlElement(const std::string& name, const TiXmlElement* parent, bool& output); +bool readXmlElement(const std::string& name, const TiXmlElement* parent, std::vector<wxString>& output); + +bool readXmlAttribute(const std::string& name, const TiXmlElement* node, std::string& output); +bool readXmlAttribute(const std::string& name, const TiXmlElement* node, wxString& output); +bool readXmlAttribute(const std::string& name, const TiXmlElement* node, int& output); +bool readXmlAttribute(const std::string& name, const TiXmlElement* node, unsigned int& output); +bool readXmlAttribute(const std::string& name, const TiXmlElement* node, bool& output); + +void addXmlElement(const std::string& name, const std::string& value, TiXmlElement* parent); +void addXmlElement(const std::string& name, const wxString& value, TiXmlElement* parent); +void addXmlElement(const std::string& name, const int value, TiXmlElement* parent); +void addXmlElement(const std::string& name, const unsigned int value, TiXmlElement* parent); +void addXmlElement(const std::string& name, const long value, TiXmlElement* parent); +void addXmlElement(const std::string& name, const bool value, TiXmlElement* parent); +void addXmlElement(const std::string& name, const std::vector<wxString>& value, TiXmlElement* parent); + +void addXmlAttribute(const std::string& name, const std::string& value, TiXmlElement* node); +void addXmlAttribute(const std::string& name, const wxString& value, TiXmlElement* node); +void addXmlAttribute(const std::string& name, const int value, TiXmlElement* node); +void addXmlAttribute(const std::string& name, const unsigned int value, TiXmlElement* node); +void addXmlAttribute(const std::string& name, const bool value, TiXmlElement* node); + + + +class XmlParser +{ +public: + XmlParser(const TiXmlElement* rootElement) : root(rootElement) {} + + void logError(const std::string& nodeName); + bool errorsOccured() const; + const wxString getErrorMessageFormatted() const; + +protected: + //another level of indirection: if errors occur during xml parsing they are logged + template <class T> + void readXmlElementLogging(const std::string& name, const TiXmlElement* parent, T& output) { - public: - XmlParser(const TiXmlElement* rootElement) : root(rootElement) {} - - void logError(const std::string& nodeName); - bool errorsOccured() const; - const wxString getErrorMessageFormatted() const; - - protected: - //another level of indirection: if errors occur during xml parsing they are logged - template <class T> - void readXmlElementLogging(const std::string& name, const TiXmlElement* parent, T& output) - { - if (!readXmlElement(name, parent, output)) - logError(name); - } - - template <class T> - void readXmlAttributeLogging(const std::string& name, const TiXmlElement* node, T& output) - { - if (!readXmlAttribute(name, node, output)) - logError(name); - } - - const TiXmlElement* const root; - std::vector<wxString> failedNodes; - }; + if (!readXmlElement(name, parent, output)) + logError(name); + } + template <class T> + void readXmlAttributeLogging(const std::string& name, const TiXmlElement* node, T& output) + { + if (!readXmlAttribute(name, node, output)) + logError(name); + } - class XmlError //Exception class + const TiXmlElement* const root; + std::vector<wxString> failedNodes; +}; + + +class XmlError //Exception class +{ +public: + enum Severity { - public: - enum Severity - { - WARNING = 77, - FATAL - }; - - XmlError(const wxString& message, Severity sev = FATAL) : errorMessage(message), m_severity(sev) {} - - const wxString& show() const - { - return errorMessage; - } - Severity getSeverity() const - { - return m_severity; - } - private: - const wxString errorMessage; - const Severity m_severity; + WARNING = 77, + FATAL }; + + XmlError(const wxString& message, Severity sev = FATAL) : errorMessage(message), m_severity(sev) {} + + const wxString& show() const + { + return errorMessage; + } + Severity getSeverity() const + { + return m_severity; + } +private: + const wxString errorMessage; + const Severity m_severity; +}; } diff --git a/shared/zstring.cpp b/shared/zstring.cpp index 6b2b68c6..9909abb9 100644 --- a/shared/zstring.cpp +++ b/shared/zstring.cpp @@ -1,8 +1,8 @@ #include "zstring.h" +#include <stdexcept> #ifdef FFS_WIN #include <wx/msw/wrapwin.h> //includes "windows.h" -#include <stdexcept> #endif //FFS_WIN #ifdef __WXDEBUG__ @@ -27,12 +27,12 @@ AllocationCount::~AllocationCount() leakingStrings += wxT("\"\n"); } - MessageBox(NULL, wxString(wxT("Memory leak detected! (No problem if it occurs while Unit testing only!)")) + wxT("\n\n") + MessageBox(NULL, wxString(wxT("Memory leak detected!")) + wxT("\n\n") + wxT("Candidates:\n") + leakingStrings, wxString::Format(wxT("%i"), activeStrings.size()), 0); } #else - std::abort(); + throw std::logic_error("Memory leak!"); #endif } @@ -198,7 +198,8 @@ Zstring& Zstring::Trim(bool fromRight) if (descr->refCount > 1) //allocate new string *this = Zstring(cursor, thisLen - diff); else - { //overwrite this string + { + //overwrite this string ::memmove(strBegin, cursor, (thisLen - diff + 1) * sizeof(DefaultChar)); //note: do not simply let data point to different location: this corrupts reserve()! descr->length -= diff; } @@ -307,7 +308,8 @@ Zstring& Zstring::replace(size_t pos1, size_t n1, const DefaultChar* str, size_t const size_t newLen = oldLen - n1 + n2; if (newLen > oldLen || descr->refCount > 1) - { //allocate a new string + { + //allocate a new string StringDescriptor* newDescr = allocate(newLen); //assemble new string with replacement @@ -342,7 +344,8 @@ Zstring& Zstring::operator=(const DefaultChar* source) if (descr->refCount > 1 || descr->capacity < sourceLen) //allocate new string *this = Zstring(source, sourceLen); else - { //overwrite this string + { + //overwrite this string ::memcpy(data(), source, (sourceLen + 1) * sizeof(DefaultChar)); //include null-termination descr->length = sourceLen; } @@ -355,7 +358,8 @@ Zstring& Zstring::assign(const DefaultChar* source, size_t len) if (descr->refCount > 1 || descr->capacity < len) //allocate new string *this = Zstring(source, len); else - { //overwrite this string + { + //overwrite this string ::memcpy(data(), source, len * sizeof(DefaultChar)); //don't know if source is null-terminated data()[len] = 0; //include null-termination descr->length = len; @@ -412,7 +416,8 @@ void Zstring::reserve(size_t capacityNeeded) //make unshared and check capacity assert(capacityNeeded != 0); if (descr->refCount > 1) - { //allocate a new string + { + //allocate a new string const size_t oldLength = length(); assert(oldLength <= getCapacityToAllocate(capacityNeeded)); @@ -425,7 +430,8 @@ void Zstring::reserve(size_t capacityNeeded) //make unshared and check capacity descr = newDescr; } else if (descr->capacity < capacityNeeded) - { //try to resize the current string (allocate anew if necessary) + { + //try to resize the current string (allocate anew if necessary) const size_t newCapacity = getCapacityToAllocate(capacityNeeded); #ifdef __WXDEBUG__ diff --git a/shared/zstring.h b/shared/zstring.h index 018ca42e..9c7c2245 100644 --- a/shared/zstring.h +++ b/shared/zstring.h @@ -13,6 +13,7 @@ #include <new> #include <stdlib.h> #include <vector> +#include <sstream> #ifdef __WXDEBUG__ #include <set> @@ -22,8 +23,10 @@ #ifdef ZSTRING_CHAR typedef char DefaultChar; //use char strings +#define DefaultStr(x) x // #elif defined ZSTRING_WIDE_CHAR typedef wchar_t DefaultChar; //use wide character strings +#define DefaultStr(x) L ## x // #endif @@ -123,6 +126,10 @@ private: }; +template <class T> +Zstring numberToZstring(const T& number); //convert number to Zstring + + //####################################################################################### //begin of implementation @@ -146,13 +153,13 @@ int defaultCompare(const char* str1, const char* str2, const size_t count) } inline -char* defaultStrFind(const char* str1, const char* str2) +const char* defaultStrFind(const char* str1, const char* str2) { return strstr(str1, str2); } inline -char* defaultStrFind(const char* str1, int ch) +const char* defaultStrFind(const char* str1, int ch) { return strchr(str1, ch); } @@ -236,6 +243,7 @@ public: private: AllocationCount() {} + AllocationCount(const AllocationCount&); ~AllocationCount(); wxCriticalSection lockActStrings; @@ -253,11 +261,12 @@ size_t getCapacityToAllocate(const size_t length) inline Zstring::StringDescriptor* Zstring::allocate(const size_t newLength) -{ //allocate and set data for new string +{ + //allocate and set data for new string const size_t newCapacity = getCapacityToAllocate(newLength); assert(newCapacity); - StringDescriptor* newDescr = static_cast<StringDescriptor*>(::malloc(sizeof(StringDescriptor) + (newCapacity + 1) * sizeof(DefaultChar))); //use C-memory functions because of realloc() + StringDescriptor* const newDescr = static_cast<StringDescriptor*>(::malloc(sizeof(StringDescriptor) + (newCapacity + 1) * sizeof(DefaultChar))); //use C-memory functions because of realloc() if (newDescr == NULL) throw std::bad_alloc(); @@ -288,6 +297,7 @@ Zstring::Zstring() inline + Zstring::Zstring(const DefaultChar* source) { initAndCopy(source, defaultLength(source)); @@ -671,4 +681,17 @@ const Zstring Zstring::operator+(const DefaultChar ch) const } +template <class T> +inline +Zstring numberToZstring(const T& number) //convert number to string the C++ way +{ +#ifdef ZSTRING_CHAR + std::stringstream ss; +#elif defined ZSTRING_WIDE_CHAR + std::wstringstream ss; +#endif + ss << number; + return Zstring(ss.str().c_str(), ss.str().length()); +} + #endif // ZSTRING_H_INCLUDED |