diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..47476c9
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,223 @@
+#################
+## Eclipse
+#################
+
+*.pydevproject
+.project
+.metadata
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.classpath
+.settings/
+.loadpath
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# CDT-specific
+.cproject
+
+# PDT-specific
+.buildpath
+
+
+#################
+## Visual Studio
+#################
+
+## Ignore Visual Studio temporary files, build results, and
+## files generated by popular Visual Studio add-ons.
+
+# User-specific files
+*.suo
+*.user
+*.sln.docstates
+
+# Build results
+
+[Dd]ebug/
+[Rr]elease/
+x64/
+Win32/
+build/
+[Bb]in/
+[Oo]bj/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+*_i.c
+*_p.c
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.log
+*.scc
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opensdf
+*.sdf
+*.cachefile
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# NCrunch
+*.ncrunch*
+.*crunch*.local.xml
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.Publish.xml
+*.pubxml
+*.publishproj
+
+# NuGet Packages Directory
+## TODO: If you have NuGet Package Restore enabled, uncomment the next line
+#packages/
+
+# Windows Azure Build Output
+csx
+*.build.csdef
+
+# Windows Store app package directory
+AppPackages/
+
+# Others
+sql/
+*.Cache
+ClientBin/
+[Ss]tyle[Cc]op.*
+~$*
+*~
+*.dbmdl
+*.[Pp]ublish.xml
+*.pfx
+*.publishsettings
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file to a newer
+# Visual Studio version. Backup files are not needed, because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+App_Data/*.mdf
+App_Data/*.ldf
+
+# TFS
+$tf/
+..svnbridge/
+
+#############
+## Windows detritus
+#############
+
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Mac crap
+.DS_Store
+
+
+#############
+## Python
+#############
+
+*.py[cod]
+
+# Packages
+*.egg
+*.egg-info
+dist/
+build/
+eggs/
+parts/
+var/
+sdist/
+develop-eggs/
+.installed.cfg
+
+# Installer logs
+pip-log.txt
+
+# Unit test / coverage reports
+.coverage
+.tox
+
+#Translations
+*.mo
+
+#Mr Developer
+.mr.developer.cfg
+NEXT COMMIT MESSAGE.txt
+.tfignore
diff --git a/3FD.WinRT/3FD.WinRT.Shared/3FD.WinRT.Shared.vcxitems b/3FD.WinRT/3FD.WinRT.Shared/3FD.WinRT.Shared.vcxitems
new file mode 100644
index 0000000..a03ba9f
--- /dev/null
+++ b/3FD.WinRT/3FD.WinRT.Shared/3FD.WinRT.Shared.vcxitems
@@ -0,0 +1,79 @@
+
+
+
+ $(MSBuildAllProjects);$(MSBuildThisFileFullPath)
+ true
+ {857dc1c8-d5d4-471c-bcbe-c29e5f7dd49c}
+ _3FD_WinRT
+ 3FD.WinRT.Shared
+ 248F659F-DAC5-46E8-AC09-60EC9FC95053
+
+
+
+ %(AdditionalIncludeDirectories);$(MSBuildThisFileDirectory)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NotUsing
+ false
+
+
+
+
+
+
+ Create
+
+
+
+
+
+
+ %(AdditionalIncludeDirectories)
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/3FD.WinRT/3FD.WinRT.Shared/3FD.WinRT.Shared.vcxitems.filters b/3FD.WinRT/3FD.WinRT.Shared/3FD.WinRT.Shared.vcxitems.filters
new file mode 100644
index 0000000..8e60da0
--- /dev/null
+++ b/3FD.WinRT/3FD.WinRT.Shared/3FD.WinRT.Shared.vcxitems.filters
@@ -0,0 +1,172 @@
+
+
+
+
+ core
+
+
+ core
+
+
+ core
+
+
+ core
+
+
+ core
+
+
+ core
+
+
+ core
+
+
+ core
+
+
+
+ VS
+
+
+ VS
+
+
+ SQLite\SQLite3
+
+
+ SQLite
+
+
+ Utils
+
+
+ Utils
+
+
+ GC
+
+
+ GC
+
+
+ GC
+
+
+ GC
+
+
+ GC
+
+
+ GC
+
+
+ GC
+
+
+ GC
+
+
+ GC
+
+
+
+
+ core
+
+
+ core
+
+
+ core
+
+
+ core
+
+
+ core
+
+
+ core
+
+
+ VS
+
+
+ SQLite\SQLite3
+
+
+ core
+
+
+ SQLite
+
+
+ SQLite
+
+
+ SQLite
+
+
+ SQLite
+
+
+ Utils
+
+
+ Utils
+
+
+ Utils
+
+
+ Utils
+
+
+ Utils
+
+
+ GC
+
+
+ GC
+
+
+ GC
+
+
+ GC
+
+
+ GC
+
+
+ GC
+
+
+ GC
+
+
+
+
+ {cb4543ca-3686-4f43-af80-4deaa88f416d}
+
+
+ {0f1f3f48-c08f-4417-84fa-201f33b43f1f}
+
+
+ {1315d311-f876-447e-bc69-6e1df5fc46b5}
+
+
+ {94de4c02-75f7-44e1-9044-dbc76e30785d}
+
+
+ {8f047188-10f4-423f-915b-5cfffa8e3dda}
+
+
+ {856acd8a-ade3-4325-b172-1fa27b608c83}
+
+
+
\ No newline at end of file
diff --git a/3FD.WinRT/3FD.WinRT.Shared/logger_winrt.cpp b/3FD.WinRT/3FD.WinRT.Shared/logger_winrt.cpp
new file mode 100644
index 0000000..5868c29
--- /dev/null
+++ b/3FD.WinRT/3FD.WinRT.Shared/logger_winrt.cpp
@@ -0,0 +1,355 @@
+#include "stdafx.h"
+#include "logger.h"
+#include "configuration.h"
+#include "callstacktracer.h"
+#include "utils_winrt.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace _3fd
+{
+ namespace core
+ {
+ ///
+ /// Gets the unique instance of the singleton class.
+ ///
+ /// A pointer to the singleton.
+ Logger * Logger::GetInstance()
+ {
+ if (uniqueObjectPtr != nullptr)
+ return uniqueObjectPtr;
+ else
+ {
+ try
+ {
+ CreateInstance(AppConfig::GetApplicationId(), false);
+ }
+ catch (IAppException &)
+ {/* DO NOTHING: SWALLOW EXCEPTION
+ Even when the set-up of the logger fails, the application must continue
+ to execute, because the logger is merely an auxiliary service. Here an
+ exception cannot be forwarded up in the stack because the current call
+ chain might have been originated in a destructor. */
+ }
+
+ return uniqueObjectPtr;
+ }
+ }
+
+ ///
+ /// Prepares the log event string.
+ ///
+ /// The file stream output.
+ /// The event timestamp.
+ /// The event priority.
+ /// A reference to the string stream output.
+ static std::ofstream &PrepareEventString(std::ofstream &ofs, time_t timestamp, Logger::Priority prio)
+ {
+ static const auto pid = GetCurrentProcessId();
+ std::array buffer;
+ strftime(buffer.data(), buffer.size(), "%Y-%b-%d %H:%M:%S", localtime(×tamp));
+ ofs << buffer.data() << " [process " << pid;
+
+ switch (prio)
+ {
+ case Logger::PRIO_FATAL:
+ ofs << "] - FATAL - ";
+ break;
+
+ case Logger::PRIO_CRITICAL:
+ ofs << "] - CRITICAL - ";
+ break;
+
+ case Logger::PRIO_ERROR:
+ ofs << "] - ERROR - ";
+ break;
+
+ case Logger::PRIO_WARNING:
+ ofs << "] - WARNING - ";
+ break;
+
+ case Logger::PRIO_NOTICE:
+ ofs << "] - NOTICE - ";
+ break;
+
+ case Logger::PRIO_INFORMATION:
+ ofs << "] - INFORMATION - ";
+ break;
+
+ case Logger::PRIO_DEBUG:
+ ofs << "] - DEBUG - ";
+ break;
+
+ case Logger::PRIO_TRACE:
+ ofs << "] - TRACE - ";
+ break;
+
+ default:
+ break;
+ }
+
+ return ofs;
+ }
+
+ ///
+ /// Opens the text log file stream for writing (append).
+ ///
+ /// The path for the text log file.
+ /// The file stream output.
+ static void OpenTextLogStream(Platform::String ^txtLogFilePath, std::ofstream &ofs)
+ {
+ std::wstring_convert> transcoder;
+ ofs.open(transcoder.to_bytes(txtLogFilePath->Data()), std::ios::app | std::ios::out);
+ if (ofs.is_open() == false)
+ throw AppException("Could not open text log file");
+ }
+
+ ///
+ /// Shifts the log to a new file, compress the content of the old, and moves it to the app temporary data store.
+ ///
+ static void ShiftToNewLogFile(Windows::Storage::StorageFile^ &txtLogFile, std::ofstream &ofs)
+ {
+ using namespace std::chrono;
+ using namespace Windows::Storage;
+ using namespace Windows::Foundation;
+
+ ofs.close(); // first close the stream to the current log file
+
+ // Rename the current log file:
+ std::wostringstream woss;
+ woss << txtLogFile->Path->Data() << L".old";
+ auto currLogFileName = txtLogFile->Name;
+ auto tempLogFileName = ref new Platform::String(woss.str().c_str());
+ utils::WinRTExt::WaitForAsync(txtLogFile->RenameAsync(tempLogFileName));
+
+ // Start reading log file to buffer:
+ auto asyncOperReadLogToBuffer = FileIO::ReadBufferAsync(txtLogFile);
+
+ // Create a new log file:
+ txtLogFile = utils::WinRTExt::WaitForAsync(ApplicationData::Current->LocalFolder->CreateFileAsync(currLogFileName));
+ OpenTextLogStream(txtLogFile->Path, ofs);
+
+ // Await for completion of reading operation:
+ auto readBuffer = utils::WinRTExt::WaitForAsync(asyncOperReadLogToBuffer);
+
+ // Create the file which will contain the previous log compressed:
+ std::wstring_convert> transcoder;
+ auto now = system_clock::to_time_t(system_clock::now());
+ woss << txtLogFile->DisplayName->Data() << L'[' << transcoder.from_bytes(ctime(&now)) << L"].log.dat";
+
+ auto compressedLogFile = utils::WinRTExt::WaitForAsync(
+ ApplicationData::Current->TemporaryFolder->CreateFileAsync(
+ ref new Platform::String(woss.str().c_str()),
+ CreationCollisionOption::ReplaceExisting
+ )
+ );
+
+ // Create a writable stream for such file:
+ auto outputStream = utils::WinRTExt::WaitForAsync(
+ compressedLogFile->OpenAsync(FileAccessMode::ReadWrite)
+ );
+
+ // Compress the text content of the previous log file:
+ auto compressor = ref new Compression::Compressor(outputStream);
+ utils::WinRTExt::WaitForAsync(compressor->WriteAsync(readBuffer));
+ utils::WinRTExt::WaitForAsync(compressor->FinishAsync());
+ utils::WinRTExt::WaitForAsync(compressor->FlushAsync());
+
+ // Write log shift event in the new log:
+ now = system_clock::to_time_t(system_clock::now());
+ PrepareEventString(ofs, now, Logger::PRIO_NOTICE)
+ << L"The log text file has been shifted. The previous file has been compressed from "
+ << readBuffer->Length / 1024 << L" to " << outputStream->Size / 1024
+ << L" KB and moved to the app temporary data store."
+ << std::endl << std::flush;
+ }
+
+ ///
+ /// Estimates the room left in the log file for more events.
+ ///
+ /// The text log file.
+ /// The estimate, which is positive when there is room left, otherwise, negative.
+ static long EstimateRoomForLogEvents(Windows::Storage::StorageFile ^txtLogFile)
+ {
+ // Get the file size:
+ auto fileSize = utils::WinRTExt::WaitForAsync(
+ txtLogFile->GetBasicPropertiesAsync()
+ )->Size;
+
+# if defined ENABLE_3FD_CST && defined ENABLE_3FD_ERR_IMPL_DETAILS
+ const uint32_t avgLineSize(300);
+# elif defined ENABLE_3FD_CST
+ const uint32_t avgLineSize(250);
+# elif defined ENABLE_3FD_ERR_IMPL_DETAILS
+ const uint32_t avgLineSize(150);
+# else
+ const uint32_t avgLineSize(100);
+# endif
+ // Estimate the amount of events for which there is still room left in the log file:
+ return static_cast (
+ (AppConfig::GetSettings().common.log.sizeLimit * 1024 - fileSize) / avgLineSize
+ );
+ }
+
+ ///
+ /// The procedure executed by the log writer thread.
+ ///
+ void Logger::LogWriterThreadProc()
+ {
+ try
+ {
+ std::ofstream ofs;
+ OpenTextLogStream(m_txtLogFile->Path, ofs);
+ long estimateRoomForLogEvents = EstimateRoomForLogEvents(m_txtLogFile);
+ bool terminate(false);
+
+ do
+ {
+ // Wait for queued messages:
+ terminate = m_terminationEvent.WaitFor(250);
+
+ // Write the queued messages in the text log file:
+ Event *ev;
+ while (m_eventsQueue.pop(ev))
+ {
+ PrepareEventString(ofs, ev->time, ev->prio) << ev->what; // add the main details and message
+#ifdef ENABLE_3FD_ERR_IMPL_DETAILS
+ if (ev->details.empty() == false) // add the details
+ ofs << " - " << ev->details;
+#endif
+#ifdef ENABLE_3FD_CST
+ if (ev->cst.empty() == false) // add the call stack trace
+ ofs << " - Call Stack: { " << ev->cst << " }";
+#endif
+ delete ev;
+
+ ofs << std::endl << std::flush; // flush the content to the file
+
+ if (ofs.bad())
+ throw AppException("Failed to write in the text log output file stream");
+
+ --estimateRoomForLogEvents;
+ }
+
+ // If the log file was supposed to reach its size limit now:
+ if (estimateRoomForLogEvents <= 0)
+ {
+ // Recalculate estimate for current log file and, if there is no room left, shift to a new one:
+ estimateRoomForLogEvents = EstimateRoomForLogEvents(m_txtLogFile);
+ if (estimateRoomForLogEvents < 0)
+ {
+ ShiftToNewLogFile(m_txtLogFile, ofs);
+ estimateRoomForLogEvents = EstimateRoomForLogEvents(m_txtLogFile); // recalculate estimate for new log file
+ }
+ }
+ }
+ while (!terminate);
+ }
+ catch (...)
+ {/* DO NOTHING: SWALLOW EXCEPTION
+ An eventual failure in this thread will be kept silent because logging is
+ an auxiliary service, hence it should not further affect the application
+ execution. Here an exception cannot be forwarded up in the stack because
+ this procedure is running asynchronous.*/
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The application ID.
+ /// Whether log output should be redirected to the console. Because a store app does not have an available console, this parameter is ignored.
+ Logger::Logger(const string &id, bool logToConsole) :
+ m_logWriterThread(),
+ m_terminationEvent(),
+ m_eventsQueue(32),
+ m_txtLogFile(nullptr)
+ {
+ try
+ {
+ using namespace Windows::Storage;
+
+ // Open or create the file:
+ std::wstring_convert> transcoder;
+ auto loggerId = ref new Platform::String(transcoder.from_bytes(id).c_str());
+ m_txtLogFile = utils::WinRTExt::WaitForAsync(
+ ApplicationData::Current->LocalFolder->CreateFileAsync(loggerId + L".log.txt", CreationCollisionOption::OpenIfExists)
+ );
+
+ m_logWriterThread.swap(std::thread(&Logger::LogWriterThreadProc, this));
+ }
+ catch (...)
+ {/* DO NOTHING: SWALLOW EXCEPTION
+ Even when the set-up of the logger fails, the application must continue
+ to execute, because the logger is merely an auxiliary service. */
+ m_txtLogFile = nullptr;
+ }
+ }
+
+ ///
+ /// Finalizes an instance of the class.
+ ///
+ Logger::~Logger()
+ {
+ try
+ {
+ // Signalizes termination for the message loop
+ m_terminationEvent.Signalize();
+
+ if (m_logWriterThread.joinable())
+ m_logWriterThread.join();
+
+ _ASSERTE(m_eventsQueue.empty());
+
+ Event *ev;
+ while (m_eventsQueue.unsynchronized_pop(ev))
+ delete ev;
+ }
+ catch (...)
+ {
+ // DO NOTHING: SWALLOW EXCEPTION
+ }
+ }
+
+ ///
+ /// Writes a message and its details to the log output.
+ ///
+ /// The reason for the message.
+ /// The message details.
+ /// The priority for the message.
+ /// When set to true, append the call stack trace.
+ void Logger::WriteImpl(string &&what, string &&details, Priority prio, bool cst)
+ {
+ if (m_txtLogFile == nullptr)
+ return;
+
+ try
+ {
+ using namespace std::chrono;
+ auto now = system_clock::to_time_t(system_clock::now());
+
+ std::unique_ptr logEvent(new Event(now, prio, std::move(what)));
+
+# ifdef ENABLE_3FD_ERR_IMPL_DETAILS
+ if (details.empty() == false)
+ logEvent->details = std::move(details);
+# endif
+# ifdef ENABLE_3FD_CST
+ if (cst && CallStackTracer::GetInstance().IsReady())
+ logEvent->cst = CallStackTracer::GetInstance().GetStackReport();
+# endif
+ m_eventsQueue.push(logEvent.release()); // enqueue the request to write this event to the log file
+ }
+ catch (std::exception &)
+ {
+ // DO NOTHING: SWALLOW EXCEPTION
+ }
+ }
+
+ }// end of namespace core
+}// end of namespace _3fd
diff --git a/3FD.WinRT/3FD.WinRT.Shared/utils_winrt.cpp b/3FD.WinRT/3FD.WinRT.Shared/utils_winrt.cpp
new file mode 100644
index 0000000..b02bb01
--- /dev/null
+++ b/3FD.WinRT/3FD.WinRT.Shared/utils_winrt.cpp
@@ -0,0 +1,147 @@
+#include "stdafx.h"
+#include "utils_winrt.h"
+
+#include
+
+namespace _3fd
+{
+ namespace utils
+ {
+ ////////////////////////////////////
+ // shared_mutex Class
+ ////////////////////////////////////
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ shared_mutex::shared_mutex()
+ : m_curLockType(None)
+ {
+ InitializeSRWLock(&m_srwLockHandle);
+ }
+
+ ///
+ /// Finalizes an instance of the class.
+ ///
+ shared_mutex::~shared_mutex()
+ {
+ switch (m_curLockType)
+ {
+ case _3fd::utils::shared_mutex::Shared:
+ unlock_shared();
+ break;
+
+ case _3fd::utils::shared_mutex::Exclusive:
+ unlock();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ ///
+ /// Acquires a shared lock.
+ ///
+ void shared_mutex::lock_shared()
+ {
+ AcquireSRWLockShared(&m_srwLockHandle);
+ m_curLockType = Shared;
+ }
+
+ ///
+ /// Releases a shared lock.
+ ///
+ void shared_mutex::unlock_shared()
+ {
+ _ASSERTE(m_curLockType == Shared); // cannot release a lock that was not previously acquired
+ ReleaseSRWLockShared(&m_srwLockHandle);
+ m_curLockType = None;
+ }
+
+ ///
+ /// Acquires an exclusive lock
+ ///
+ void shared_mutex::lock()
+ {
+ AcquireSRWLockExclusive(&m_srwLockHandle);
+ m_curLockType = Exclusive;
+ }
+
+ ///
+ /// Releases the exclusive lock.
+ ///
+ void shared_mutex::unlock()
+ {
+ _ASSERTE(m_curLockType == Exclusive); // cannot release a lock that was not previously acquired
+ ReleaseSRWLockExclusive(&m_srwLockHandle);
+ m_curLockType = None;
+ }
+
+
+ ////////////////////////////////////
+ // WinRTExt Struct
+ ////////////////////////////////////
+
+ ///
+ /// Waits for an asynchronous WinRT actions.
+ ///
+ /// The asynchronous WinRT action to wait for.
+ void WinRTExt::WaitForAsync(Windows::Foundation::IAsyncAction ^asyncAction)
+ {
+ try
+ {
+ std::promise resultPromise;
+ auto resultFuture = resultPromise.get_future();
+
+ // Set delegate for completion event:
+ asyncAction->Completed = ref new Windows::Foundation::AsyncActionCompletedHandler(
+ // Handler for completion:
+ [&resultPromise](decltype(asyncAction) action, Windows::Foundation::AsyncStatus status)
+ {
+ try
+ {
+ // Get result and fulfill the promise:
+ action->GetResults();
+ action->Close();
+ resultPromise.set_value();
+ }
+ catch (Platform::Exception ^ex) // transport exception:
+ {
+ action->Close();
+ std::ostringstream oss;
+ oss << "A Windows Runtime asynchronous action has failed: " << core::WWAPI::GetDetailsFromWinRTEx(ex);
+ auto appEx = std::make_exception_ptr(core::AppException(oss.str()));
+ resultPromise.set_exception(appEx);
+ }
+ }
+ );
+
+ resultFuture.get(); // waits for completion and throws any transported exception
+ }
+ catch (core::IAppException &)
+ {
+ throw; // just forward exceptions for errors that have already been handled
+ }
+ catch (std::future_error &ex)
+ {
+ std::ostringstream oss;
+ oss << "Failed to wait for WinRT asynchronous action: " << core::StdLibExt::GetDetailsFromFutureError(ex);
+ throw core::AppException(oss.str());
+ }
+ catch (std::exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic error when waiting for WinRT asynchronous action: " << ex.what();
+ throw core::AppException(oss.str());
+ }
+ catch (Platform::Exception ^ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic failure when preparing to wait for Windows Runtime asynchronous action: " << core::WWAPI::GetDetailsFromWinRTEx(ex);
+ throw core::AppException(oss.str());
+ }
+ }
+
+ } // end of namespace utils
+} // end of namespace _3fd
diff --git a/3FD.WinRT/3FD.WinRT.Shared/utils_winrt.h b/3FD.WinRT/3FD.WinRT.Shared/utils_winrt.h
new file mode 100644
index 0000000..26a58f5
--- /dev/null
+++ b/3FD.WinRT/3FD.WinRT.Shared/utils_winrt.h
@@ -0,0 +1,172 @@
+#ifndef UTILS_WINRT_H // header guard
+#define UTILS_WINRT_H
+
+#include "base.h"
+#include "exceptions.h"
+
+#include
+#include
+
+namespace _3fd
+{
+ namespace utils
+ {
+ ///
+ /// Alternative implementation for std::shared_mutex from C++14 Std library.
+ ///
+ class shared_mutex : notcopiable
+ {
+ private:
+
+ enum LockType : short { None, Shared, Exclusive };
+
+ SRWLOCK m_srwLockHandle;
+ LockType m_curLockType;
+
+ public:
+
+ shared_mutex();
+ ~shared_mutex();
+
+ void lock_shared();
+ void unlock_shared();
+
+ void lock();
+ void unlock();
+ };
+
+ ///
+ /// Gathers WinRT API extensions that use C++/CX features.
+ ///
+ private ref struct WinRTExt
+ {
+ internal:
+
+ ///
+ /// Waits for an asynchronous WinRT operation that supports progress information.
+ ///
+ /// The asynchronous WinRT operation to wait for.
+ /// The result of the call.
+ template
+ static ResultType WaitForAsync(Windows::Foundation::IAsyncOperationWithProgress ^asyncOp)
+ {
+ try
+ {
+ std::promise resultPromise;
+ auto resultFuture = resultPromise.get_future();
+
+ // Set delegate for completion event:
+ asyncOp->Completed = ref new Windows::Foundation::AsyncOperationWithProgressCompletedHandler(
+ // Handler for completion:
+ [&resultPromise](decltype(asyncOp) op, Windows::Foundation::AsyncStatus status)
+ {
+ try
+ {
+ resultPromise.set_value(op->GetResults()); // get result and fulfill the promise
+ op->Close();
+ }
+ catch (Platform::Exception ^ex) // transport exception:
+ {
+ op->Close();
+ std::ostringstream oss;
+ oss << "A Windows Runtime asynchronous call has failed: " << core::WWAPI::GetDetailsFromWinRTEx(ex);
+ auto appEx = std::make_exception_ptr(core::AppException(oss.str()));
+ resultPromise.set_exception(appEx);
+ }
+ }
+ );
+
+ return resultFuture.get(); // returns the result, or throws a transported exception
+ }
+ catch (core::IAppException &)
+ {
+ throw; // just forward exceptions for errors that have already been handled
+ }
+ catch (std::future_error &ex)
+ {
+ std::ostringstream oss;
+ oss << "Failed to wait for WinRT asynchronous operation: " << core::StdLibExt::GetDetailsFromFutureError(ex);
+ throw core::AppException(oss.str());
+ }
+ catch (std::exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic error when waiting for WinRT asynchronous operation: " << ex.what();
+ throw core::AppException(oss.str());
+ }
+ catch (Platform::Exception ^ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic failure when preparing to wait for Windows Runtime asynchronous operation: " << core::WWAPI::GetDetailsFromWinRTEx(ex);
+ throw core::AppException(oss.str());
+ }
+ }
+
+ ///
+ /// Waits for an asynchronous WinRT operation.
+ ///
+ /// The asynchronous WinRT operation to wait for.
+ /// The result of the call.
+ template
+ static ResultType WaitForAsync(Windows::Foundation::IAsyncOperation ^asyncOp)
+ {
+ try
+ {
+ std::promise resultPromise;
+ auto resultFuture = resultPromise.get_future();
+
+ // Set delegate for completion event:
+ asyncOp->Completed = ref new Windows::Foundation::AsyncOperationCompletedHandler(
+ // Handler for completion:
+ [&resultPromise](decltype(asyncOp) op, Windows::Foundation::AsyncStatus status)
+ {
+ try
+ {
+ resultPromise.set_value(op->GetResults()); // get result and fulfill the promise
+ op->Close();
+ }
+ catch (Platform::Exception ^ex) // transport exception:
+ {
+ op->Close();
+ std::ostringstream oss;
+ oss << "A Windows Runtime asynchronous call has failed: " << core::WWAPI::GetDetailsFromWinRTEx(ex);
+ auto appEx = std::make_exception_ptr(core::AppException(oss.str()));
+ resultPromise.set_exception(appEx);
+ }
+ }
+ );
+
+ return resultFuture.get(); // returns the result, or throws a transported exception
+ }
+ catch (core::IAppException &)
+ {
+ throw; // just forward exceptions for errors that have already been handled
+ }
+ catch (std::future_error &ex)
+ {
+ std::ostringstream oss;
+ oss << "Failed to wait for WinRT asynchronous operation: " << core::StdLibExt::GetDetailsFromFutureError(ex);
+ throw core::AppException(oss.str());
+ }
+ catch (std::exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic error when waiting for WinRT asynchronous operation: " << ex.what();
+ throw core::AppException(oss.str());
+ }
+ catch (Platform::Exception ^ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic failure when preparing to wait for Windows Runtime asynchronous operation: " << core::WWAPI::GetDetailsFromWinRTEx(ex);
+ throw core::AppException(oss.str());
+ }
+ }
+
+ static void WaitForAsync(Windows::Foundation::IAsyncAction ^asyncAction);
+
+ };// end of WinRTExt class
+
+ }// end of namespace utils
+}// end of namespace _3fd
+
+#endif // end of header guard
diff --git a/3FD.WinRT/3FD.WinRT.Windows/3FD.WinRT.Windows.vcxproj b/3FD.WinRT/3FD.WinRT.Windows/3FD.WinRT.Windows.vcxproj
new file mode 100644
index 0000000..1d19970
--- /dev/null
+++ b/3FD.WinRT/3FD.WinRT.Windows/3FD.WinRT.Windows.vcxproj
@@ -0,0 +1,245 @@
+
+
+
+
+ Debug
+ ARM
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ ARM
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {ed6b839d-3ee6-46de-80dc-de2090a059c3}
+ _3FD_WinRT
+ en-US
+ 12.0
+ true
+ Windows Store
+ 8.1
+ CodeSharingStaticLibrary
+
+
+
+ StaticLibrary
+ true
+ v120
+
+
+ StaticLibrary
+ true
+ v120
+
+
+ StaticLibrary
+ true
+ v120
+
+
+ StaticLibrary
+ false
+ true
+ v120
+
+
+ StaticLibrary
+ false
+ true
+ v120
+
+
+ StaticLibrary
+ false
+ true
+ v120
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ $(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\
+ $(Platform)\$(Configuration)\
+ $(LibraryPath)
+ $(BOOST_HOME);$(IncludePath)
+
+
+ false
+ $(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\
+ $(Platform)\$(Configuration)\
+ $(LibraryPath)
+ $(BOOST_HOME);$(IncludePath)
+
+
+ false
+ $(LibraryPath)
+ $(BOOST_HOME);$(IncludePath)
+
+
+ false
+ $(LibraryPath)
+ $(BOOST_HOME);$(IncludePath)
+
+
+ false
+ $(LibraryPath)
+ $(BOOST_HOME);$(IncludePath)
+
+
+ false
+ $(LibraryPath)
+ $(BOOST_HOME);$(IncludePath)
+
+
+
+ Use
+ true
+ true
+ ENABLE_3FD_CST;ENABLE_3FD_ERR_IMPL_DETAILS;SQLITE_OS_WINRT=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ stdafx.h
+
+
+ $(SolutionDir)3FD;$(SolutionDir)btree;%(AdditionalIncludeDirectories)
+
+
+
+
+ Console
+ false
+ false
+
+
+
+
+ Use
+ true
+ true
+ ENABLE_3FD_CST;ENABLE_3FD_ERR_IMPL_DETAILS;SQLITE_OS_WINRT=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ stdafx.h
+
+
+ $(SolutionDir)3FD;$(SolutionDir)btree;%(AdditionalIncludeDirectories)
+
+
+
+
+ Console
+ false
+ false
+
+
+
+
+ Use
+ true
+ true
+ ENABLE_3FD_CST;ENABLE_3FD_ERR_IMPL_DETAILS;SQLITE_OS_WINRT=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ stdafx.h
+
+
+ $(SolutionDir)3FD;$(SolutionDir)btree;%(AdditionalIncludeDirectories)
+
+
+
+
+ Console
+ false
+ false
+
+
+
+
+ Use
+ true
+ true
+ ENABLE_3FD_CST;ENABLE_3FD_ERR_IMPL_DETAILS;SQLITE_OS_WINRT=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ stdafx.h
+
+
+ $(SolutionDir)3FD;$(SolutionDir)btree;%(AdditionalIncludeDirectories)
+
+
+
+
+ Console
+ false
+ false
+
+
+
+
+ Use
+ true
+ true
+ ENABLE_3FD_CST;ENABLE_3FD_ERR_IMPL_DETAILS;SQLITE_OS_WINRT=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ stdafx.h
+
+
+ $(SolutionDir)3FD;$(SolutionDir)btree;%(AdditionalIncludeDirectories)
+
+
+
+
+ Console
+ false
+ false
+
+
+
+
+ Use
+ true
+ true
+ ENABLE_3FD_CST;ENABLE_3FD_ERR_IMPL_DETAILS;SQLITE_OS_WINRT=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ stdafx.h
+
+
+ $(SolutionDir)3FD;$(SolutionDir)btree;%(AdditionalIncludeDirectories)
+
+
+
+
+ Console
+ false
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/3FD.WinRT/3FD.WinRT.Windows/3FD.WinRT.Windows.vcxproj.filters b/3FD.WinRT/3FD.WinRT.Windows/3FD.WinRT.Windows.vcxproj.filters
new file mode 100644
index 0000000..a7761ab
--- /dev/null
+++ b/3FD.WinRT/3FD.WinRT.Windows/3FD.WinRT.Windows.vcxproj.filters
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/3FD.WinRT/3FD.WinRT.WindowsPhone/3FD.WinRT.WindowsPhone.vcxproj b/3FD.WinRT/3FD.WinRT.WindowsPhone/3FD.WinRT.WindowsPhone.vcxproj
new file mode 100644
index 0000000..2661900
--- /dev/null
+++ b/3FD.WinRT/3FD.WinRT.WindowsPhone/3FD.WinRT.WindowsPhone.vcxproj
@@ -0,0 +1,160 @@
+
+
+
+
+ Debug
+ ARM
+
+
+ Debug
+ Win32
+
+
+ Release
+ ARM
+
+
+ Release
+ Win32
+
+
+
+ {d4d1d2d5-7594-49bb-9427-ff7d770f5ae8}
+ _3FD_WinRT
+ en-US
+ 12.0
+ true
+ Windows Phone
+ 8.1
+ CodeSharingStaticLibrary
+
+
+
+ StaticLibrary
+ true
+ v120_wp81
+
+
+ StaticLibrary
+ true
+ v120_wp81
+
+
+ StaticLibrary
+ false
+ true
+ v120_wp81
+
+
+ StaticLibrary
+ false
+ true
+ v120_wp81
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ $(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\
+ $(BOOST_HOME);$(IncludePath)
+
+
+ false
+ $(Platform)\$(Configuration)\
+ $(SolutionDir)$(Platform)\$(Configuration)\$(MSBuildProjectName)\
+ $(BOOST_HOME);$(IncludePath)
+
+
+ false
+ $(BOOST_HOME);$(IncludePath)
+
+
+ false
+ $(BOOST_HOME);$(IncludePath)
+
+
+
+ Use
+ true
+ true
+ ENABLE_3FD_CST;ENABLE_3FD_ERR_IMPL_DETAILS;SQLITE_OS_WINRT=1;SQLITE_WIN32_FILEMAPPING_API=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ stdafx.h
+
+
+ $(SolutionDir)3FD;$(SolutionDir)btree;%(AdditionalIncludeDirectories)
+
+
+ Console
+ false
+ false
+
+
+
+
+ Use
+ true
+ true
+ ENABLE_3FD_CST;ENABLE_3FD_ERR_IMPL_DETAILS;SQLITE_OS_WINRT=1;SQLITE_WIN32_FILEMAPPING_API=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ stdafx.h
+
+
+ $(SolutionDir)3FD;$(SolutionDir)btree;%(AdditionalIncludeDirectories)
+
+
+ Console
+ false
+ false
+
+
+
+
+ Use
+ true
+ true
+ ENABLE_3FD_CST;ENABLE_3FD_ERR_IMPL_DETAILS;SQLITE_OS_WINRT=1;SQLITE_WIN32_FILEMAPPING_API=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ stdafx.h
+
+
+ $(SolutionDir)3FD;$(SolutionDir)btree;%(AdditionalIncludeDirectories)
+
+
+ Console
+ false
+ false
+
+
+
+
+ Use
+ true
+ true
+ ENABLE_3FD_CST;ENABLE_3FD_ERR_IMPL_DETAILS;SQLITE_OS_WINRT=1;SQLITE_WIN32_FILEMAPPING_API=1;_CRT_SECURE_NO_WARNINGS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ stdafx.h
+
+
+ $(SolutionDir)3FD;$(SolutionDir)btree;%(AdditionalIncludeDirectories)
+
+
+ Console
+ false
+ false
+
+
+
+
+
+
\ No newline at end of file
diff --git a/3FD.WinRT/3FD.WinRT.WindowsPhone/3FD.WinRT.WindowsPhone.vcxproj.filters b/3FD.WinRT/3FD.WinRT.WindowsPhone/3FD.WinRT.WindowsPhone.vcxproj.filters
new file mode 100644
index 0000000..a7761ab
--- /dev/null
+++ b/3FD.WinRT/3FD.WinRT.WindowsPhone/3FD.WinRT.WindowsPhone.vcxproj.filters
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/App.xaml b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/App.xaml
new file mode 100644
index 0000000..9258b38
--- /dev/null
+++ b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/App.xaml
@@ -0,0 +1,7 @@
+
+
+
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/App.xaml.cpp b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/App.xaml.cpp
new file mode 100644
index 0000000..a3d7082
--- /dev/null
+++ b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/App.xaml.cpp
@@ -0,0 +1,125 @@
+//
+// App.xaml.cpp
+// Implementation of the App class.
+//
+
+#include "pch.h"
+#include "MainPage.xaml.h"
+
+using namespace IntegrationTestsApp_WinRT_Windows;
+
+using namespace Platform;
+using namespace Windows::ApplicationModel;
+using namespace Windows::ApplicationModel::Activation;
+using namespace Windows::Foundation;
+using namespace Windows::Foundation::Collections;
+using namespace Windows::UI::Xaml;
+using namespace Windows::UI::Xaml::Controls;
+using namespace Windows::UI::Xaml::Controls::Primitives;
+using namespace Windows::UI::Xaml::Data;
+using namespace Windows::UI::Xaml::Input;
+using namespace Windows::UI::Xaml::Interop;
+using namespace Windows::UI::Xaml::Media;
+using namespace Windows::UI::Xaml::Navigation;
+
+// The Blank Application template is documented at http://go.microsoft.com/fwlink/?LinkId=234227
+
+///
+/// Initializes the singleton application object. This is the first line of authored code
+/// executed, and as such is the logical equivalent of main() or WinMain().
+///
+App::App()
+{
+ InitializeComponent();
+ Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending);
+}
+
+///
+/// Invoked when the application is launched normally by the end user. Other entry points
+/// will be used such as when the application is launched to open a specific file.
+///
+/// Details about the launch request and process.
+void App::OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ e)
+{
+
+#if _DEBUG
+ // Show graphics profiling information while debugging.
+ if (IsDebuggerPresent())
+ {
+ // Display the current frame rate counters
+ DebugSettings->EnableFrameRateCounter = true;
+ }
+#endif
+
+ auto rootFrame = dynamic_cast(Window::Current->Content);
+
+ // Do not repeat app initialization when the Window already has content,
+ // just ensure that the window is active
+ if (rootFrame == nullptr)
+ {
+ // Create a Frame to act as the navigation context and associate it with
+ // a SuspensionManager key
+ rootFrame = ref new Frame();
+
+ // Set the default language
+ rootFrame->Language = Windows::Globalization::ApplicationLanguages::Languages->GetAt(0);
+
+ rootFrame->NavigationFailed += ref new Windows::UI::Xaml::Navigation::NavigationFailedEventHandler(this, &App::OnNavigationFailed);
+
+ if (e->PreviousExecutionState == ApplicationExecutionState::Terminated)
+ {
+ // TODO: Restore the saved session state only when appropriate, scheduling the
+ // final launch steps after the restore is complete
+
+ }
+
+ if (rootFrame->Content == nullptr)
+ {
+ // When the navigation stack isn't restored navigate to the first page,
+ // configuring the new page by passing required information as a navigation
+ // parameter
+ rootFrame->Navigate(TypeName(MainPage::typeid), e->Arguments);
+ }
+ // Place the frame in the current Window
+ Window::Current->Content = rootFrame;
+ // Ensure the current window is active
+ Window::Current->Activate();
+ }
+ else
+ {
+ if (rootFrame->Content == nullptr)
+ {
+ // When the navigation stack isn't restored navigate to the first page,
+ // configuring the new page by passing required information as a navigation
+ // parameter
+ rootFrame->Navigate(TypeName(MainPage::typeid), e->Arguments);
+ }
+ // Ensure the current window is active
+ Window::Current->Activate();
+ }
+}
+
+///
+/// Invoked when application execution is being suspended. Application state is saved
+/// without knowing whether the application will be terminated or resumed with the contents
+/// of memory still intact.
+///
+/// The source of the suspend request.
+/// Details about the suspend request.
+void App::OnSuspending(Object^ sender, SuspendingEventArgs^ e)
+{
+ (void) sender; // Unused parameter
+ (void) e; // Unused parameter
+
+ //TODO: Save application state and stop any background activity
+}
+
+///
+/// Invoked when Navigation to a certain page fails
+///
+/// The Frame which failed navigation
+/// Details about the navigation failure
+void App::OnNavigationFailed(Platform::Object ^sender, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs ^e)
+{
+ throw ref new FailureException("Failed to load Page " + e->SourcePageType.Name);
+}
\ No newline at end of file
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/App.xaml.h b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/App.xaml.h
new file mode 100644
index 0000000..0728bae
--- /dev/null
+++ b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/App.xaml.h
@@ -0,0 +1,27 @@
+//
+// App.xaml.h
+// Declaration of the App class.
+//
+
+#pragma once
+
+#include "App.g.h"
+
+namespace IntegrationTestsApp_WinRT_Windows
+{
+ ///
+ /// Provides application-specific behavior to supplement the default Application class.
+ ///
+ ref class App sealed
+ {
+ protected:
+ virtual void OnLaunched(Windows::ApplicationModel::Activation::LaunchActivatedEventArgs^ e) override;
+
+ internal:
+ App();
+
+ private:
+ void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ e);
+ void OnNavigationFailed(Platform::Object ^sender, Windows::UI::Xaml::Navigation::NavigationFailedEventArgs ^e);
+ };
+}
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Assets/Logo.scale-100.png b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Assets/Logo.scale-100.png
new file mode 100644
index 0000000..e26771c
Binary files /dev/null and b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Assets/Logo.scale-100.png differ
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Assets/SmallLogo.scale-100.png b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Assets/SmallLogo.scale-100.png
new file mode 100644
index 0000000..1eb0d9d
Binary files /dev/null and b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Assets/SmallLogo.scale-100.png differ
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Assets/SplashScreen.scale-100.png b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Assets/SplashScreen.scale-100.png
new file mode 100644
index 0000000..c951e03
Binary files /dev/null and b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Assets/SplashScreen.scale-100.png differ
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Assets/StoreLogo.scale-100.png b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Assets/StoreLogo.scale-100.png
new file mode 100644
index 0000000..dcb6727
Binary files /dev/null and b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Assets/StoreLogo.scale-100.png differ
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Generated Files/App.g.h b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Generated Files/App.g.h
new file mode 100644
index 0000000..342ec8a
--- /dev/null
+++ b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Generated Files/App.g.h
@@ -0,0 +1,33 @@
+
+
+#pragma once
+//------------------------------------------------------------------------------
+// This code was generated by a tool.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//------------------------------------------------------------------------------
+
+#include "XamlTypeInfo.g.h"
+
+namespace IntegrationTestsApp_WinRT_Windows
+{
+ partial ref class App : public ::Windows::UI::Xaml::Application,
+ public ::Windows::UI::Xaml::Markup::IXamlMetadataProvider,
+ public ::Windows::UI::Xaml::Markup::IComponentConnector
+ {
+ public:
+ void InitializeComponent();
+ virtual void Connect(int connectionId, ::Platform::Object^ target);
+
+ [Windows::Foundation::Metadata::DefaultOverload]
+ virtual ::Windows::UI::Xaml::Markup::IXamlType^ GetXamlType(::Windows::UI::Xaml::Interop::TypeName type);
+ virtual ::Windows::UI::Xaml::Markup::IXamlType^ GetXamlType(::Platform::String^ fullName);
+ virtual ::Platform::Array<::Windows::UI::Xaml::Markup::XmlnsDefinition>^ GetXmlnsDefinitions();
+ private:
+ ::XamlTypeInfo::InfoProvider::XamlTypeInfoProvider^ _provider;
+ bool _contentLoaded;
+
+ };
+}
+
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Generated Files/App.g.hpp b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Generated Files/App.g.hpp
new file mode 100644
index 0000000..e69de29
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Generated Files/MainPage.g.h b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Generated Files/MainPage.g.h
new file mode 100644
index 0000000..fe45638
--- /dev/null
+++ b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Generated Files/MainPage.g.h
@@ -0,0 +1,26 @@
+
+
+#pragma once
+//------------------------------------------------------------------------------
+// This code was generated by a tool.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//------------------------------------------------------------------------------
+
+
+namespace IntegrationTestsApp_WinRT_Windows
+{
+ partial ref class MainPage : public ::Windows::UI::Xaml::Controls::Page,
+ public ::Windows::UI::Xaml::Markup::IComponentConnector
+ {
+ public:
+ void InitializeComponent();
+ virtual void Connect(int connectionId, ::Platform::Object^ target);
+
+ private:
+ bool _contentLoaded;
+
+ };
+}
+
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Generated Files/MainPage.g.hpp b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Generated Files/MainPage.g.hpp
new file mode 100644
index 0000000..e69de29
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Generated Files/XamlLibMetadataProvider.g.cpp b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Generated Files/XamlLibMetadataProvider.g.cpp
new file mode 100644
index 0000000..c65238f
--- /dev/null
+++ b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Generated Files/XamlLibMetadataProvider.g.cpp
@@ -0,0 +1,2 @@
+
+
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Generated Files/XamlTypeInfo.Impl.g.cpp b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Generated Files/XamlTypeInfo.Impl.g.cpp
new file mode 100644
index 0000000..b39f146
--- /dev/null
+++ b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Generated Files/XamlTypeInfo.Impl.g.cpp
@@ -0,0 +1,542 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+#include "pch.h"
+#include
+#include "XamlTypeInfo.g.h"
+
+
+
+// XamlTypeInfoProvider
+::Windows::UI::Xaml::Markup::IXamlType^ ::XamlTypeInfo::InfoProvider::XamlTypeInfoProvider::GetXamlTypeByType(::Windows::UI::Xaml::Interop::TypeName type)
+{
+ auto xamlType = GetXamlTypeByName(type.Name);
+ ::XamlTypeInfo::InfoProvider::XamlUserType^ userXamlType = dynamic_cast<::XamlTypeInfo::InfoProvider::XamlUserType^>(xamlType);
+ if (xamlType == nullptr || (userXamlType != nullptr && userXamlType->IsReturnTypeStub && !userXamlType->IsLocalType))
+ {
+ ::Windows::UI::Xaml::Markup::IXamlType^ libXamlType = CheckOtherMetadataProvidersForType(type);
+ if (libXamlType != nullptr)
+ {
+ if(libXamlType->IsConstructible || xamlType == nullptr)
+ {
+ xamlType = libXamlType;
+ }
+ }
+ }
+ return xamlType;
+}
+
+::Windows::UI::Xaml::Markup::IXamlType^ ::XamlTypeInfo::InfoProvider::XamlTypeInfoProvider::GetXamlTypeByName(::Platform::String^ typeName)
+{
+ if (typeName == nullptr || typeName->IsEmpty())
+ {
+ return nullptr;
+ }
+
+ auto val = _xamlTypes.find(typeName);
+ ::Windows::UI::Xaml::Markup::IXamlType^ xamlType = nullptr;
+ if (val != _xamlTypes.end())
+ {
+ xamlType = (val->second).Resolve<::Windows::UI::Xaml::Markup::IXamlType>();
+ if(xamlType != nullptr)
+ {
+ return xamlType;
+ }
+ }
+
+ xamlType = CreateXamlType(typeName);
+ ::XamlTypeInfo::InfoProvider::XamlUserType^ userXamlType = dynamic_cast<::XamlTypeInfo::InfoProvider::XamlUserType^>(xamlType);
+ if (xamlType == nullptr || (userXamlType != nullptr && userXamlType->IsReturnTypeStub && !userXamlType->IsLocalType))
+ {
+ ::Windows::UI::Xaml::Markup::IXamlType^ libXamlType = CheckOtherMetadataProvidersForName(typeName);
+ if (libXamlType != nullptr)
+ {
+ if(libXamlType->IsConstructible || xamlType == nullptr)
+ {
+ xamlType = libXamlType;
+ }
+ }
+ }
+
+
+ if (xamlType != nullptr)
+ {
+ Platform::WeakReference wr(xamlType);
+ _xamlTypes[xamlType->FullName] = wr;
+ }
+ return xamlType;
+}
+
+::Windows::UI::Xaml::Markup::IXamlMember^ ::XamlTypeInfo::InfoProvider::XamlTypeInfoProvider::GetMemberByLongName(::Platform::String^ longMemberName)
+{
+ if (longMemberName == nullptr || longMemberName->IsEmpty())
+ {
+ return nullptr;
+ }
+
+ auto val = _xamlMembers.find(longMemberName);
+ if (val != _xamlMembers.end())
+ {
+ return val->second;
+ }
+
+ auto xamlMember = CreateXamlMember(longMemberName);
+
+ if (xamlMember != nullptr)
+ {
+ _xamlMembers[longMemberName] = xamlMember;
+ }
+ return xamlMember;
+}
+
+// XamlSystemBaseType
+::XamlTypeInfo::InfoProvider::XamlSystemBaseType::XamlSystemBaseType(::Platform::String^ name) :
+ _fullName(name)
+{
+}
+
+::Windows::UI::Xaml::Markup::IXamlType^ ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::BaseType::get()
+{
+ throw ref new ::Platform::NotImplementedException;
+}
+
+::Windows::UI::Xaml::Markup::IXamlMember^ ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::ContentProperty::get()
+{
+ throw ref new ::Platform::NotImplementedException;
+}
+
+::Platform::String^ ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::FullName::get()
+{
+ return _fullName;
+}
+
+::Platform::String^ ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::Name::get()
+{
+ const wchar_t* seperator = wcsrchr(_fullName->Data(), '.');
+ if (seperator == nullptr)
+ {
+ return _fullName;
+ }
+ return ref new ::Platform::String(seperator);
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::IsArray::get()
+{
+ throw ref new ::Platform::NotImplementedException;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::IsCollection::get()
+{
+ throw ref new ::Platform::NotImplementedException;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::IsConstructible::get()
+{
+ throw ref new ::Platform::NotImplementedException;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::IsDictionary::get()
+{
+ throw ref new ::Platform::NotImplementedException;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::IsMarkupExtension::get()
+{
+ throw ref new ::Platform::NotImplementedException;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::IsEnum::get()
+{
+ throw ref new ::Platform::NotImplementedException;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::IsSystemType::get()
+{
+ throw ref new ::Platform::NotImplementedException;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::IsBindable::get()
+{
+ throw ref new ::Platform::NotImplementedException;
+}
+
+::Windows::UI::Xaml::Markup::IXamlType^ ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::ItemType::get()
+{
+ throw ref new ::Platform::NotImplementedException;
+}
+
+::Windows::UI::Xaml::Markup::IXamlType^ ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::KeyType::get()
+{
+ throw ref new ::Platform::NotImplementedException;
+}
+
+::Windows::UI::Xaml::Interop::TypeName (::XamlTypeInfo::InfoProvider::XamlSystemBaseType::UnderlyingType::get)()
+{
+ ::Windows::UI::Xaml::Interop::TypeName typeName;
+
+ typeName.Name = _fullName;
+ typeName.Kind = ::Windows::UI::Xaml::Interop::TypeKind::Primitive;
+
+ return typeName;
+}
+
+::Platform::Object^ ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::ActivateInstance()
+{
+ throw ref new ::Platform::NotImplementedException;
+}
+
+::Windows::UI::Xaml::Markup::IXamlMember^ ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::GetMember(::Platform::String^)
+{
+ throw ref new ::Platform::NotImplementedException;
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::AddToVector(::Platform::Object^, ::Platform::Object^)
+{
+ throw ref new ::Platform::NotImplementedException;
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::AddToMap(::Platform::Object^, ::Platform::Object^, ::Platform::Object^)
+{
+ throw ref new ::Platform::NotImplementedException;
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::RunInitializer()
+{
+ throw ref new ::Platform::NotImplementedException;
+}
+
+::Platform::Object^ ::XamlTypeInfo::InfoProvider::XamlSystemBaseType::CreateFromString(::Platform::String^)
+{
+ throw ref new ::Platform::NotImplementedException;
+}
+
+//XamlUserType
+::XamlTypeInfo::InfoProvider::XamlUserType::XamlUserType(::XamlTypeInfo::InfoProvider::XamlTypeInfoProvider^ provider, ::Platform::String^ fullName, ::Windows::UI::Xaml::Markup::IXamlType^ baseType) :
+ _isArray(false),
+ _isMarkupExtension(false),
+ _isEnum(false),
+ _isBindable(false),
+ _isReturnTypeStub(false),
+ _isLocalType(false),
+ _fullName(fullName),
+ _provider(provider),
+ _baseType(baseType)
+{
+}
+
+::Platform::String^ ::XamlTypeInfo::InfoProvider::XamlUserType::FullName::get()
+{
+ return _fullName;
+}
+
+::Platform::String^ ::XamlTypeInfo::InfoProvider::XamlUserType::Name::get()
+{
+ const wchar_t *seperator = wcsrchr(_fullName->Data(), '.');
+ if (seperator == nullptr)
+ {
+ return _fullName;
+ }
+ return ref new ::Platform::String(seperator);
+}
+
+::Windows::UI::Xaml::Interop::TypeName (::XamlTypeInfo::InfoProvider::XamlUserType::UnderlyingType::get)()
+{
+ ::Windows::UI::Xaml::Interop::TypeName typeName;
+
+ typeName.Name = _fullName;
+ typeName.Kind = KindOfType;
+
+ return typeName;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlUserType::IsSystemType::get()
+{
+ return true;
+}
+
+::Windows::UI::Xaml::Markup::IXamlType^ ::XamlTypeInfo::InfoProvider::XamlUserType::BaseType::get()
+{
+ return _baseType;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlUserType::IsArray::get()
+{
+ return _isArray;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlUserType::IsCollection::get()
+{
+ return CollectionAdd != nullptr;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlUserType::IsConstructible::get()
+{
+ return Activator != nullptr;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlUserType::IsDictionary::get()
+{
+ return DictionaryAdd != nullptr;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlUserType::IsMarkupExtension::get()
+{
+ return _isMarkupExtension;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlUserType::IsEnum::get()
+{
+ return _isEnum;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlUserType::IsBindable::get()
+{
+ return _isBindable;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlUserType::IsReturnTypeStub::get()
+{
+ return _isReturnTypeStub;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlUserType::IsLocalType::get()
+{
+ return _isLocalType;
+}
+
+::Windows::UI::Xaml::Markup::IXamlMember^ ::XamlTypeInfo::InfoProvider::XamlUserType::ContentProperty::get()
+{
+ return _provider->GetMemberByLongName(_contentPropertyName);
+}
+
+::Windows::UI::Xaml::Markup::IXamlType^ ::XamlTypeInfo::InfoProvider::XamlUserType::ItemType::get()
+{
+ return _provider->GetXamlTypeByName(_itemTypeName);
+}
+
+::Windows::UI::Xaml::Markup::IXamlType^ ::XamlTypeInfo::InfoProvider::XamlUserType::KeyType::get()
+{
+ return _provider->GetXamlTypeByName(_keyTypeName);
+}
+
+::Windows::UI::Xaml::Markup::IXamlMember^ ::XamlTypeInfo::InfoProvider::XamlUserType::GetMember(::Platform::String^ name)
+{
+ auto val = _memberNames.find(name);
+ if (val != _memberNames.end())
+ {
+ return _provider->GetMemberByLongName(val->second);
+ }
+ return nullptr;
+}
+
+::Platform::Object^ ::XamlTypeInfo::InfoProvider::XamlUserType::ActivateInstance()
+{
+ return Activator();
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlUserType::AddToMap(::Platform::Object^ instance, ::Platform::Object^ key, ::Platform::Object^ item)
+{
+ DictionaryAdd(instance, key, item);
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlUserType::AddToVector(::Platform::Object^ instance, ::Platform::Object^ item)
+{
+ CollectionAdd(instance, item);
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlUserType::RunInitializer()
+{
+ // The C++ runtime will have already run all the Static Initializers at start up.
+}
+
+::Platform::Object^ ::XamlTypeInfo::InfoProvider::XamlUserType::CreateFromString(::Platform::String^ input)
+{
+ return FromStringConverter(this, input);
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlUserType::SetContentPropertyName(::Platform::String^ contentPropertyName)
+{
+ _contentPropertyName = contentPropertyName;
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlUserType::SetIsArray()
+{
+ _isArray = true;
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlUserType::SetIsMarkupExtension()
+{
+ _isMarkupExtension = true;
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlUserType::SetIsEnum()
+{
+ _isEnum = true;
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlUserType::SetIsBindable()
+{
+ _isBindable = true;
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlUserType::SetIsReturnTypeStub()
+{
+ _isReturnTypeStub = true;
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlUserType::SetIsLocalType()
+{
+ _isLocalType = true;
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlUserType::SetItemTypeName(::Platform::String^ itemTypeName)
+{
+ _itemTypeName = itemTypeName;
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlUserType::SetKeyTypeName(::Platform::String^ keyTypeName)
+{
+ _keyTypeName = keyTypeName;
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlUserType::AddMemberName(::Platform::String^ shortName)
+{
+ _memberNames[shortName] = FullName + "." + shortName;
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlUserType::AddEnumValue(::Platform::String^ name, ::Platform::Object^ value)
+{
+ _enumValues[name->Data()] = value;
+}
+
+::default::uint32 (::XamlTypeInfo::InfoProvider::XamlUserType::CreateEnumUIntFromString)(::Platform::String^ input)
+{
+ bool found = false;
+
+ const std::wregex regularExpression(L"^\\s+|\\s*,\\s*|\\s+$");
+ uint32 val = 0;
+
+ for (std::wcregex_token_iterator it(input->Begin(), input->End(), regularExpression, -1), end; it != end; ++it)
+ {
+ const std::wcsub_match& subMatch = *it;
+
+ if (subMatch.length() == 0 )
+ {
+ continue;
+ }
+
+ std::wstring lookup(subMatch.first, (unsigned int)subMatch.length());
+
+ try
+ {
+ auto entry = _enumValues.find(lookup);
+ if (entry != _enumValues.end())
+ {
+ const auto f = entry->second;
+ val |= safe_cast(f);
+ }
+ else
+ {
+ val |= std::stoi(subMatch);
+ }
+ found=true;
+ }
+ catch (const std::invalid_argument& )
+ {
+ found = false;
+ break;
+ }
+ }
+
+ if(found)
+ {
+ return val;
+ }
+ throw ref new ::Platform::InvalidArgumentException();
+}
+
+// XamlMember
+::XamlTypeInfo::InfoProvider::XamlMember::XamlMember(::XamlTypeInfo::InfoProvider::XamlTypeInfoProvider^ provider, ::Platform::String^ name, ::Platform::String^ typeName) :
+ _isAttachable(false),
+ _isDependencyProperty(false),
+ _isReadOnly(false),
+ _name(name),
+ _typeName(typeName),
+ _provider(provider)
+{
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlMember::SetIsAttachable()
+{
+ _isAttachable = true;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlMember::IsAttachable::get()
+{
+ return _isAttachable;
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlMember::SetIsDependencyProperty()
+{
+ _isDependencyProperty = true;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlMember::IsDependencyProperty::get()
+{
+ return _isDependencyProperty;
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlMember::SetIsReadOnly()
+{
+ _isReadOnly = true;
+}
+
+bool ::XamlTypeInfo::InfoProvider::XamlMember::IsReadOnly::get()
+{
+ return _isReadOnly;
+}
+
+::Platform::String^ ::XamlTypeInfo::InfoProvider::XamlMember::Name::get()
+{
+ return _name;
+}
+
+::Windows::UI::Xaml::Markup::IXamlType^ ::XamlTypeInfo::InfoProvider::XamlMember::Type::get()
+{
+ return _provider->GetXamlTypeByName(_typeName);
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlMember::SetTargetTypeName(::Platform::String^ targetTypeName)
+{
+ _targetTypeName = targetTypeName;
+}
+
+::Windows::UI::Xaml::Markup::IXamlType^ ::XamlTypeInfo::InfoProvider::XamlMember::TargetType::get()
+{
+ return _provider->GetXamlTypeByName(_targetTypeName);
+}
+
+::Platform::Object^ ::XamlTypeInfo::InfoProvider::XamlMember::GetValue(::Platform::Object^ instance)
+{
+ if (Getter != nullptr)
+ {
+ return Getter(instance);
+ }
+ throw ref new ::Platform::NullReferenceException();
+}
+
+void ::XamlTypeInfo::InfoProvider::XamlMember::SetValue(::Platform::Object^ instance, ::Platform::Object^ value)
+{
+ if (Setter != nullptr)
+ {
+ Setter(instance, value);
+ return;
+ }
+ throw ref new ::Platform::NullReferenceException();
+}
+
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Generated Files/XamlTypeInfo.g.h b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Generated Files/XamlTypeInfo.g.h
new file mode 100644
index 0000000..40088fc
--- /dev/null
+++ b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Generated Files/XamlTypeInfo.g.h
@@ -0,0 +1,339 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+#pragma once
+#include
+
+namespace XamlTypeInfo
+{
+ namespace InfoProvider
+ {
+ ref class XamlTypeInfoProvider sealed
+ {
+ internal:
+ ::Windows::UI::Xaml::Markup::IXamlType^ CreateXamlType(::Platform::String^ typeName);
+ ::Windows::UI::Xaml::Markup::IXamlMember^ CreateXamlMember(::Platform::String^ longMemberName);
+
+ ::Windows::UI::Xaml::Markup::IXamlType^ GetXamlTypeByName(::Platform::String^ typeName);
+ ::Windows::UI::Xaml::Markup::IXamlType^ GetXamlTypeByType(::Windows::UI::Xaml::Interop::TypeName t);
+ ::Windows::UI::Xaml::Markup::IXamlMember^ GetMemberByLongName(::Platform::String^ longMemberName);
+
+ private:
+ std::map<::Platform::String^, ::Platform::WeakReference> _xamlTypes;
+ std::map<::Platform::String^, ::Windows::UI::Xaml::Markup::IXamlMember^> _xamlMembers;
+
+ private:
+ ::Platform::Collections::Vector<::Windows::UI::Xaml::Markup::IXamlMetadataProvider^>^ _otherProviders;
+ property ::Platform::Collections::Vector<::Windows::UI::Xaml::Markup::IXamlMetadataProvider^>^ OtherProviders
+ {
+ ::Platform::Collections::Vector<::Windows::UI::Xaml::Markup::IXamlMetadataProvider^>^ get();
+ }
+
+ ::Windows::UI::Xaml::Markup::IXamlType^ CheckOtherMetadataProvidersForName(::Platform::String^ typeName);
+ ::Windows::UI::Xaml::Markup::IXamlType^ CheckOtherMetadataProvidersForType(::Windows::UI::Xaml::Interop::TypeName t);
+ };
+
+ ref class XamlSystemBaseType sealed : public ::Windows::UI::Xaml::Markup::IXamlType
+ {
+ internal:
+ XamlSystemBaseType(::Platform::String^ name);
+
+ public:
+ virtual property ::Windows::UI::Xaml::Markup::IXamlType^ BaseType
+ {
+ ::Windows::UI::Xaml::Markup::IXamlType^ get();
+ }
+
+ virtual property Windows::UI::Xaml::Markup::IXamlMember^ ContentProperty
+ {
+ ::Windows::UI::Xaml::Markup::IXamlMember^ get();
+ }
+
+ virtual property ::Platform::String^ FullName
+ {
+ ::Platform::String^ get();
+ }
+
+ virtual property ::Platform::String^ Name
+ {
+ ::Platform::String^ get();
+ }
+
+ virtual property bool IsArray
+ {
+ bool get();
+ }
+
+ virtual property bool IsCollection
+ {
+ bool get();
+ }
+
+ virtual property bool IsConstructible
+ {
+ bool get();
+ }
+
+ virtual property bool IsDictionary
+ {
+ bool get();
+ }
+
+ virtual property bool IsMarkupExtension
+ {
+ bool get();
+ }
+
+ virtual property bool IsEnum
+ {
+ bool get();
+ }
+
+ virtual property bool IsSystemType
+ {
+ bool get();
+ }
+
+ virtual property bool IsBindable
+ {
+ bool get();
+ }
+
+ virtual property ::Windows::UI::Xaml::Markup::IXamlType^ ItemType
+ {
+ ::Windows::UI::Xaml::Markup::IXamlType^ get();
+ }
+
+ virtual property ::Windows::UI::Xaml::Markup::IXamlType^ KeyType
+ {
+ ::Windows::UI::Xaml::Markup::IXamlType^ get();
+ }
+
+ virtual property Windows::UI::Xaml::Interop::TypeName UnderlyingType
+ {
+ ::Windows::UI::Xaml::Interop::TypeName get();
+ }
+
+ virtual ::Platform::Object^ ActivateInstance();
+ virtual ::Windows::UI::Xaml::Markup::IXamlMember^ GetMember(::Platform::String^ name);
+ virtual void AddToVector(::Platform::Object^ instance, ::Platform::Object^ value);
+ virtual void AddToMap(::Platform::Object^ instance, ::Platform::Object^ key, ::Platform::Object^ value);
+ virtual void RunInitializer();
+ virtual ::Platform::Object^ CreateFromString(::Platform::String^ value);
+
+ private:
+ ::Platform::String^ _fullName;
+ };
+
+ ref class XamlUserType sealed : public [::Platform::Metadata::RuntimeClassName] ::Windows::UI::Xaml::Markup::IXamlType
+ {
+ internal:
+ XamlUserType(::XamlTypeInfo::InfoProvider::XamlTypeInfoProvider^ provider, ::Platform::String^ fullName, ::Windows::UI::Xaml::Markup::IXamlType^ baseType);
+
+ public:
+ // --- Interface methods ----
+ virtual property ::Platform::String^ FullName
+ {
+ ::Platform::String^ get();
+ }
+
+ virtual property ::Platform::String^ Name
+ {
+ ::Platform::String^ get();
+ }
+
+ virtual property Windows::UI::Xaml::Interop::TypeName UnderlyingType
+ {
+ Windows::UI::Xaml::Interop::TypeName get();
+ }
+
+ virtual property bool IsSystemType
+ {
+ bool get();
+ }
+
+ virtual property ::Windows::UI::Xaml::Markup::IXamlType^ BaseType
+ {
+ ::Windows::UI::Xaml::Markup::IXamlType^ get();
+ }
+
+ virtual property bool IsArray
+ {
+ bool get();
+ }
+
+ virtual property bool IsCollection
+ {
+ bool get();
+ }
+
+ virtual property bool IsConstructible
+ {
+ bool get();
+ }
+
+ virtual property bool IsDictionary
+ {
+ bool get();
+ }
+
+ virtual property bool IsMarkupExtension
+ {
+ bool get();
+ }
+
+ virtual property bool IsEnum
+ {
+ bool get();
+ }
+
+ virtual property bool IsBindable
+ {
+ bool get();
+ }
+
+ virtual property ::Windows::UI::Xaml::Markup::IXamlMember^ ContentProperty
+ {
+ ::Windows::UI::Xaml::Markup::IXamlMember^ get();
+ }
+
+ virtual property ::Windows::UI::Xaml::Markup::IXamlType^ ItemType
+ {
+ ::Windows::UI::Xaml::Markup::IXamlType^ get();
+ }
+
+ virtual property ::Windows::UI::Xaml::Markup::IXamlType^ KeyType
+ {
+ ::Windows::UI::Xaml::Markup::IXamlType^ get();
+ }
+
+ virtual ::Windows::UI::Xaml::Markup::IXamlMember^ GetMember(::Platform::String^ name);
+ virtual ::Platform::Object^ ActivateInstance();
+ virtual void AddToMap(::Platform::Object^ instance, ::Platform::Object^ key, ::Platform::Object^ value);
+ virtual void AddToVector(::Platform::Object^ instance, ::Platform::Object^ value);
+ virtual void RunInitializer();
+ virtual ::Platform::Object^ CreateFromString(::Platform::String^ value);
+ // --- End of Interface methods
+
+ property bool IsReturnTypeStub
+ {
+ bool get();
+ }
+
+ property bool IsLocalType
+ {
+ bool get();
+ }
+
+ internal:
+ typedef ::Platform::Object^ (*ActivatorFn)();
+ typedef void (*AddToCollectionFn)(::Platform::Object^ instance, ::Platform::Object^ item);
+ typedef void (*AddToDictionaryFn)(::Platform::Object^ instance, ::Platform::Object^ key, ::Platform::Object^ item);
+ typedef ::Platform::Object^ (*StringConverterFn)(::XamlTypeInfo::InfoProvider::XamlUserType^ userType, ::Platform::String^ input);
+
+ property ActivatorFn Activator;
+ property AddToCollectionFn CollectionAdd;
+ property AddToDictionaryFn DictionaryAdd;
+ property ::Windows::UI::Xaml::Interop::TypeKind KindOfType;
+ property StringConverterFn FromStringConverter;
+
+ void SetContentPropertyName(::Platform::String^ contentPropertyName);
+ void SetIsArray();
+ void SetIsMarkupExtension();
+ void SetIsEnum();
+ void SetIsBindable();
+ void SetIsReturnTypeStub();
+ void SetIsLocalType();
+ void SetItemTypeName(::Platform::String^ itemTypeName);
+ void SetKeyTypeName(::Platform::String^ keyTypeName);
+ void AddMemberName(::Platform::String^ shortName);
+ void AddEnumValue(::Platform::String^ name, ::Platform::Object^ value);
+ uint32 CreateEnumUIntFromString(::Platform::String^ input);
+
+ private:
+ ::XamlTypeInfo::InfoProvider::XamlTypeInfoProvider^ _provider;
+ ::Windows::UI::Xaml::Markup::IXamlType^ _baseType;
+ bool _isArray;
+ bool _isConstructible;
+ bool _isDictionary;
+ bool _isMarkupExtension;
+ bool _isEnum;
+ bool _isBindable;
+ bool _isReturnTypeStub;
+ bool _isLocalType;
+
+ ::Platform::String^ _contentPropertyName;
+ ::Platform::String^ _itemTypeName;
+ ::Platform::String^ _keyTypeName;
+ ::Platform::String^ _fullName;
+ std::map<::Platform::String^, ::Platform::String^> _memberNames;
+ std::map _enumValues;
+ };
+
+ ref class XamlMember sealed : public ::Windows::UI::Xaml::Markup::IXamlMember
+ {
+ internal:
+ XamlMember(::XamlTypeInfo::InfoProvider::XamlTypeInfoProvider^ provider, ::Platform::String^ name, ::Platform::String^ typeName);
+
+ void SetIsAttachable();
+ void SetIsDependencyProperty();
+ void SetIsReadOnly();
+ void SetTargetTypeName(::Platform::String^ targetTypeName);
+
+ typedef ::Platform::Object^ (*PropertyGetterFn)(::Platform::Object^ instance);
+ typedef void (*PropertySetterFn)(::Platform::Object^ instance, ::Platform::Object^ value);
+
+ property PropertyGetterFn Getter;
+ property PropertySetterFn Setter;
+
+ public:
+ virtual property bool IsAttachable
+ {
+ bool get();
+ }
+
+ virtual property bool IsDependencyProperty
+ {
+ bool get();
+ }
+
+ virtual property bool IsReadOnly
+ {
+ bool get();
+ }
+
+ virtual property ::Platform::String^ Name
+ {
+ ::Platform::String^ get();
+ }
+
+ virtual property ::Windows::UI::Xaml::Markup::IXamlType^ Type
+ {
+ ::Windows::UI::Xaml::Markup::IXamlType^ get();
+ }
+
+ virtual property ::Windows::UI::Xaml::Markup::IXamlType^ TargetType
+ {
+ ::Windows::UI::Xaml::Markup::IXamlType^ get();
+ }
+
+ virtual ::Platform::Object^ GetValue(::Platform::Object^ instance);
+ virtual void SetValue(::Platform::Object^ instance, ::Platform::Object^ value);
+
+ private:
+ bool _isAttachable;
+ bool _isDependencyProperty;
+ bool _isReadOnly;
+ ::Platform::String^ _name;
+ ::Platform::String^ _targetTypeName;
+ ::Platform::String^ _typeName;
+ ::XamlTypeInfo::InfoProvider::XamlTypeInfoProvider^ _provider;
+ };
+ }
+}
+
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/IntegrationTestsApp.WinRT.Windows.vcxproj b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/IntegrationTestsApp.WinRT.Windows.vcxproj
new file mode 100644
index 0000000..dc39341
--- /dev/null
+++ b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/IntegrationTestsApp.WinRT.Windows.vcxproj
@@ -0,0 +1,209 @@
+
+
+
+
+
+ Debug
+ ARM
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ ARM
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+
+ {55b15fe0-d788-4101-80d1-2fadb87ca16b}
+ IntegrationTestsApp_WinRT_Windows
+ en-US
+ 12.0
+ true
+ Windows Store
+ 8.1
+
+
+
+
+
+ Application
+ true
+ v120
+
+
+ Application
+ true
+ v120
+
+
+ Application
+ true
+ v120
+
+
+ Application
+ false
+ true
+ v120
+
+
+ Application
+ false
+ true
+ v120
+
+
+ Application
+ false
+ true
+ v120
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ IntegrationTestsApp.WinRT.Windows_TemporaryKey.pfx
+
+
+
+
+
+ /bigobj %(AdditionalOptions)
+ 4453;28204
+
+
+
+
+ /bigobj %(AdditionalOptions)
+ 4453;28204
+
+
+
+
+ /bigobj %(AdditionalOptions)
+ 4453;28204
+
+
+
+
+ /bigobj %(AdditionalOptions)
+ 4453;28204
+
+
+
+
+ /bigobj %(AdditionalOptions)
+ 4453;28204
+
+
+
+
+ /bigobj %(AdditionalOptions)
+ 4453;28204
+
+
+
+
+
+
+ App.xaml
+
+
+ MainPage.xaml
+
+
+
+
+
+ Designer
+
+
+ Designer
+
+
+
+
+
+ Designer
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ App.xaml
+
+
+ MainPage.xaml
+
+
+
+ Create
+ Create
+ Create
+ Create
+ Create
+ Create
+
+
+
+
+
+
+
+
+
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/IntegrationTestsApp.WinRT.Windows.vcxproj.filters b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/IntegrationTestsApp.WinRT.Windows.vcxproj.filters
new file mode 100644
index 0000000..630bed9
--- /dev/null
+++ b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/IntegrationTestsApp.WinRT.Windows.vcxproj.filters
@@ -0,0 +1,24 @@
+
+
+
+
+ 55b15fe0-d788-4101-80d1-2fadb87ca16b
+
+
+ d72b5fa8-c6db-4dc1-9f7d-1f3e7c26ff92
+ bmp;fbx;gif;jpg;jpeg;tga;tiff;tif;png
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+ Assets
+
+
+
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/MainPage.xaml b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/MainPage.xaml
new file mode 100644
index 0000000..d4e2ea1
--- /dev/null
+++ b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/MainPage.xaml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/MainPage.xaml.cpp b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/MainPage.xaml.cpp
new file mode 100644
index 0000000..a593e0d
--- /dev/null
+++ b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/MainPage.xaml.cpp
@@ -0,0 +1,27 @@
+//
+// MainPage.xaml.cpp
+// Implementation of the MainPage class.
+//
+
+#include "pch.h"
+#include "MainPage.xaml.h"
+
+using namespace IntegrationTestsApp_WinRT_Windows;
+
+using namespace Platform;
+using namespace Windows::Foundation;
+using namespace Windows::Foundation::Collections;
+using namespace Windows::UI::Xaml;
+using namespace Windows::UI::Xaml::Controls;
+using namespace Windows::UI::Xaml::Controls::Primitives;
+using namespace Windows::UI::Xaml::Data;
+using namespace Windows::UI::Xaml::Input;
+using namespace Windows::UI::Xaml::Media;
+using namespace Windows::UI::Xaml::Navigation;
+
+// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
+
+MainPage::MainPage()
+{
+ InitializeComponent();
+}
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/MainPage.xaml.h b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/MainPage.xaml.h
new file mode 100644
index 0000000..99ce4db
--- /dev/null
+++ b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/MainPage.xaml.h
@@ -0,0 +1,21 @@
+//
+// MainPage.xaml.h
+// Declaration of the MainPage class.
+//
+
+#pragma once
+
+#include "MainPage.g.h"
+
+namespace IntegrationTestsApp_WinRT_Windows
+{
+ ///
+ /// An empty page that can be used on its own or navigated to within a Frame.
+ ///
+ public ref class MainPage sealed
+ {
+ public:
+ MainPage();
+
+ };
+}
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Package.appxmanifest b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Package.appxmanifest
new file mode 100644
index 0000000..8586631
--- /dev/null
+++ b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/Package.appxmanifest
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+ IntegrationTestsApp.WinRT.Windows
+ Felipe
+ Assets\StoreLogo.png
+
+
+
+ 6.3.0
+ 6.3.0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/pch.cpp b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/pch.cpp
new file mode 100644
index 0000000..01484ff
--- /dev/null
+++ b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/pch.cpp
@@ -0,0 +1,6 @@
+//
+// pch.cpp
+// Include the standard header and generate the precompiled header.
+//
+
+#include "pch.h"
diff --git a/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/pch.h b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/pch.h
new file mode 100644
index 0000000..2c4354d
--- /dev/null
+++ b/3FD.WinRT/IntegrationTestsApp.WinRT.Windows/pch.h
@@ -0,0 +1,11 @@
+//
+// pch.h
+// Header for standard system include files.
+//
+
+#pragma once
+
+#include
+#include
+
+#include "App.xaml.h"
diff --git a/3FD.sln b/3FD.sln
new file mode 100644
index 0000000..b4c23be
--- /dev/null
+++ b/3FD.sln
@@ -0,0 +1,177 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.31101.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "3FD", "3FD\3FD.vcxproj", "{CCC4A0A2-15FD-4A6E-AC6C-094AAAAEC80B}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnitTests", "UnitTests\UnitTests.vcxproj", "{A657480D-D083-4C31-B499-42FF50481AC1}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IntegrationTests", "IntegrationTests\IntegrationTests.vcxproj", "{B288E7DC-4F10-4432-8CB9-2061400F4E0C}"
+ ProjectSection(ProjectDependencies) = postProject
+ {CCC4A0A2-15FD-4A6E-AC6C-094AAAAEC80B} = {CCC4A0A2-15FD-4A6E-AC6C-094AAAAEC80B}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gtest-md", "gtest\msvc\gtest-md.vcxproj", "{C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Testing", "Testing", "{8E00B911-43B2-49D5-9B4A-AB6E1ED097A1}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3FD.WinRT", "3FD.WinRT", "{C6537317-4B66-427D-BFC6-2FC4FC6937E7}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "3FD.WinRT.Shared", "3FD.WinRT\3FD.WinRT.Shared\3FD.WinRT.Shared.vcxitems", "{857DC1C8-D5D4-471C-BCBE-C29E5F7DD49C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "3FD.WinRT.Windows", "3FD.WinRT\3FD.WinRT.Windows\3FD.WinRT.Windows.vcxproj", "{ED6B839D-3EE6-46DE-80DC-DE2090A059C3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "3FD.WinRT.WindowsPhone", "3FD.WinRT\3FD.WinRT.WindowsPhone\3FD.WinRT.WindowsPhone.vcxproj", "{D4D1D2D5-7594-49BB-9427-FF7D770F5AE8}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IntegrationTestsApp.WinRT.Windows", "3FD.WinRT\IntegrationTestsApp.WinRT.Windows\IntegrationTestsApp.WinRT.Windows.vcxproj", "{55B15FE0-D788-4101-80D1-2FADB87CA16B}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{6FE4019E-19FF-4D78-80F1-F44C0BF271BB}"
+ ProjectSection(SolutionItems) = preProject
+ Performance1.psess = Performance1.psess
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SharedMSBuildProjectFiles) = preSolution
+ 3FD.WinRT\3FD.WinRT.Shared\3FD.WinRT.Shared.vcxitems*{857dc1c8-d5d4-471c-bcbe-c29e5f7dd49c}*SharedItemsImports = 9
+ 3FD.WinRT\3FD.WinRT.Shared\3FD.WinRT.Shared.vcxitems*{ed6b839d-3ee6-46de-80dc-de2090a059c3}*SharedItemsImports = 4
+ 3FD.WinRT\3FD.WinRT.Shared\3FD.WinRT.Shared.vcxitems*{d4d1d2d5-7594-49bb-9427-ff7d770f5ae8}*SharedItemsImports = 4
+ EndGlobalSection
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|Mixed Platforms = Debug|Mixed Platforms
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|ARM = Release|ARM
+ Release|Mixed Platforms = Release|Mixed Platforms
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {CCC4A0A2-15FD-4A6E-AC6C-094AAAAEC80B}.Debug|ARM.ActiveCfg = Debug|Win32
+ {CCC4A0A2-15FD-4A6E-AC6C-094AAAAEC80B}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+ {CCC4A0A2-15FD-4A6E-AC6C-094AAAAEC80B}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+ {CCC4A0A2-15FD-4A6E-AC6C-094AAAAEC80B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CCC4A0A2-15FD-4A6E-AC6C-094AAAAEC80B}.Debug|Win32.Build.0 = Debug|Win32
+ {CCC4A0A2-15FD-4A6E-AC6C-094AAAAEC80B}.Debug|x64.ActiveCfg = Debug|x64
+ {CCC4A0A2-15FD-4A6E-AC6C-094AAAAEC80B}.Debug|x64.Build.0 = Debug|x64
+ {CCC4A0A2-15FD-4A6E-AC6C-094AAAAEC80B}.Release|ARM.ActiveCfg = Release|Win32
+ {CCC4A0A2-15FD-4A6E-AC6C-094AAAAEC80B}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+ {CCC4A0A2-15FD-4A6E-AC6C-094AAAAEC80B}.Release|Mixed Platforms.Build.0 = Release|Win32
+ {CCC4A0A2-15FD-4A6E-AC6C-094AAAAEC80B}.Release|Win32.ActiveCfg = Release|Win32
+ {CCC4A0A2-15FD-4A6E-AC6C-094AAAAEC80B}.Release|Win32.Build.0 = Release|Win32
+ {CCC4A0A2-15FD-4A6E-AC6C-094AAAAEC80B}.Release|x64.ActiveCfg = Release|x64
+ {CCC4A0A2-15FD-4A6E-AC6C-094AAAAEC80B}.Release|x64.Build.0 = Release|x64
+ {A657480D-D083-4C31-B499-42FF50481AC1}.Debug|ARM.ActiveCfg = Debug|Win32
+ {A657480D-D083-4C31-B499-42FF50481AC1}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+ {A657480D-D083-4C31-B499-42FF50481AC1}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+ {A657480D-D083-4C31-B499-42FF50481AC1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {A657480D-D083-4C31-B499-42FF50481AC1}.Debug|Win32.Build.0 = Debug|Win32
+ {A657480D-D083-4C31-B499-42FF50481AC1}.Debug|x64.ActiveCfg = Debug|x64
+ {A657480D-D083-4C31-B499-42FF50481AC1}.Debug|x64.Build.0 = Debug|x64
+ {A657480D-D083-4C31-B499-42FF50481AC1}.Release|ARM.ActiveCfg = Release|Win32
+ {A657480D-D083-4C31-B499-42FF50481AC1}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+ {A657480D-D083-4C31-B499-42FF50481AC1}.Release|Mixed Platforms.Build.0 = Release|Win32
+ {A657480D-D083-4C31-B499-42FF50481AC1}.Release|Win32.ActiveCfg = Release|Win32
+ {A657480D-D083-4C31-B499-42FF50481AC1}.Release|Win32.Build.0 = Release|Win32
+ {A657480D-D083-4C31-B499-42FF50481AC1}.Release|x64.ActiveCfg = Release|x64
+ {A657480D-D083-4C31-B499-42FF50481AC1}.Release|x64.Build.0 = Release|x64
+ {B288E7DC-4F10-4432-8CB9-2061400F4E0C}.Debug|ARM.ActiveCfg = Debug|Win32
+ {B288E7DC-4F10-4432-8CB9-2061400F4E0C}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+ {B288E7DC-4F10-4432-8CB9-2061400F4E0C}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+ {B288E7DC-4F10-4432-8CB9-2061400F4E0C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B288E7DC-4F10-4432-8CB9-2061400F4E0C}.Debug|Win32.Build.0 = Debug|Win32
+ {B288E7DC-4F10-4432-8CB9-2061400F4E0C}.Debug|x64.ActiveCfg = Debug|x64
+ {B288E7DC-4F10-4432-8CB9-2061400F4E0C}.Debug|x64.Build.0 = Debug|x64
+ {B288E7DC-4F10-4432-8CB9-2061400F4E0C}.Release|ARM.ActiveCfg = Release|Win32
+ {B288E7DC-4F10-4432-8CB9-2061400F4E0C}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+ {B288E7DC-4F10-4432-8CB9-2061400F4E0C}.Release|Mixed Platforms.Build.0 = Release|Win32
+ {B288E7DC-4F10-4432-8CB9-2061400F4E0C}.Release|Win32.ActiveCfg = Release|Win32
+ {B288E7DC-4F10-4432-8CB9-2061400F4E0C}.Release|Win32.Build.0 = Release|Win32
+ {B288E7DC-4F10-4432-8CB9-2061400F4E0C}.Release|x64.ActiveCfg = Release|x64
+ {B288E7DC-4F10-4432-8CB9-2061400F4E0C}.Release|x64.Build.0 = Release|x64
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug|ARM.ActiveCfg = Debug|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug|Win32.Build.0 = Debug|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug|x64.ActiveCfg = Debug|x64
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Debug|x64.Build.0 = Debug|x64
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release|ARM.ActiveCfg = Release|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release|Mixed Platforms.Build.0 = Release|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release|Win32.ActiveCfg = Release|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release|Win32.Build.0 = Release|Win32
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release|x64.ActiveCfg = Release|x64
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8}.Release|x64.Build.0 = Release|x64
+ {ED6B839D-3EE6-46DE-80DC-DE2090A059C3}.Debug|ARM.ActiveCfg = Debug|ARM
+ {ED6B839D-3EE6-46DE-80DC-DE2090A059C3}.Debug|ARM.Build.0 = Debug|ARM
+ {ED6B839D-3EE6-46DE-80DC-DE2090A059C3}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+ {ED6B839D-3EE6-46DE-80DC-DE2090A059C3}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+ {ED6B839D-3EE6-46DE-80DC-DE2090A059C3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {ED6B839D-3EE6-46DE-80DC-DE2090A059C3}.Debug|Win32.Build.0 = Debug|Win32
+ {ED6B839D-3EE6-46DE-80DC-DE2090A059C3}.Debug|x64.ActiveCfg = Debug|x64
+ {ED6B839D-3EE6-46DE-80DC-DE2090A059C3}.Debug|x64.Build.0 = Debug|x64
+ {ED6B839D-3EE6-46DE-80DC-DE2090A059C3}.Release|ARM.ActiveCfg = Release|ARM
+ {ED6B839D-3EE6-46DE-80DC-DE2090A059C3}.Release|ARM.Build.0 = Release|ARM
+ {ED6B839D-3EE6-46DE-80DC-DE2090A059C3}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+ {ED6B839D-3EE6-46DE-80DC-DE2090A059C3}.Release|Mixed Platforms.Build.0 = Release|Win32
+ {ED6B839D-3EE6-46DE-80DC-DE2090A059C3}.Release|Win32.ActiveCfg = Release|Win32
+ {ED6B839D-3EE6-46DE-80DC-DE2090A059C3}.Release|Win32.Build.0 = Release|Win32
+ {ED6B839D-3EE6-46DE-80DC-DE2090A059C3}.Release|x64.ActiveCfg = Release|x64
+ {ED6B839D-3EE6-46DE-80DC-DE2090A059C3}.Release|x64.Build.0 = Release|x64
+ {D4D1D2D5-7594-49BB-9427-FF7D770F5AE8}.Debug|ARM.ActiveCfg = Debug|ARM
+ {D4D1D2D5-7594-49BB-9427-FF7D770F5AE8}.Debug|ARM.Build.0 = Debug|ARM
+ {D4D1D2D5-7594-49BB-9427-FF7D770F5AE8}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+ {D4D1D2D5-7594-49BB-9427-FF7D770F5AE8}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+ {D4D1D2D5-7594-49BB-9427-FF7D770F5AE8}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D4D1D2D5-7594-49BB-9427-FF7D770F5AE8}.Debug|Win32.Build.0 = Debug|Win32
+ {D4D1D2D5-7594-49BB-9427-FF7D770F5AE8}.Debug|x64.ActiveCfg = Debug|Win32
+ {D4D1D2D5-7594-49BB-9427-FF7D770F5AE8}.Release|ARM.ActiveCfg = Release|ARM
+ {D4D1D2D5-7594-49BB-9427-FF7D770F5AE8}.Release|ARM.Build.0 = Release|ARM
+ {D4D1D2D5-7594-49BB-9427-FF7D770F5AE8}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+ {D4D1D2D5-7594-49BB-9427-FF7D770F5AE8}.Release|Mixed Platforms.Build.0 = Release|Win32
+ {D4D1D2D5-7594-49BB-9427-FF7D770F5AE8}.Release|Win32.ActiveCfg = Release|Win32
+ {D4D1D2D5-7594-49BB-9427-FF7D770F5AE8}.Release|Win32.Build.0 = Release|Win32
+ {D4D1D2D5-7594-49BB-9427-FF7D770F5AE8}.Release|x64.ActiveCfg = Release|Win32
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Debug|ARM.ActiveCfg = Debug|ARM
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Debug|ARM.Build.0 = Debug|ARM
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Debug|ARM.Deploy.0 = Debug|ARM
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Debug|Mixed Platforms.ActiveCfg = Debug|Win32
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Debug|Mixed Platforms.Build.0 = Debug|Win32
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Debug|Mixed Platforms.Deploy.0 = Debug|Win32
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Debug|Win32.Build.0 = Debug|Win32
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Debug|Win32.Deploy.0 = Debug|Win32
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Debug|x64.ActiveCfg = Debug|x64
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Debug|x64.Build.0 = Debug|x64
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Debug|x64.Deploy.0 = Debug|x64
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Release|ARM.ActiveCfg = Release|ARM
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Release|ARM.Build.0 = Release|ARM
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Release|ARM.Deploy.0 = Release|ARM
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Release|Mixed Platforms.ActiveCfg = Release|Win32
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Release|Mixed Platforms.Build.0 = Release|Win32
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Release|Mixed Platforms.Deploy.0 = Release|Win32
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Release|Win32.ActiveCfg = Release|Win32
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Release|Win32.Build.0 = Release|Win32
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Release|Win32.Deploy.0 = Release|Win32
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Release|x64.ActiveCfg = Release|x64
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Release|x64.Build.0 = Release|x64
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B}.Release|x64.Deploy.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {A657480D-D083-4C31-B499-42FF50481AC1} = {8E00B911-43B2-49D5-9B4A-AB6E1ED097A1}
+ {B288E7DC-4F10-4432-8CB9-2061400F4E0C} = {8E00B911-43B2-49D5-9B4A-AB6E1ED097A1}
+ {C8F6C172-56F2-4E76-B5FA-C3B423B31BE8} = {8E00B911-43B2-49D5-9B4A-AB6E1ED097A1}
+ {857DC1C8-D5D4-471C-BCBE-C29E5F7DD49C} = {C6537317-4B66-427D-BFC6-2FC4FC6937E7}
+ {ED6B839D-3EE6-46DE-80DC-DE2090A059C3} = {C6537317-4B66-427D-BFC6-2FC4FC6937E7}
+ {D4D1D2D5-7594-49BB-9427-FF7D770F5AE8} = {C6537317-4B66-427D-BFC6-2FC4FC6937E7}
+ {55B15FE0-D788-4101-80D1-2FADB87CA16B} = {C6537317-4B66-427D-BFC6-2FC4FC6937E7}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ VisualSVNWorkingCopyRoot = .
+ EndGlobalSection
+EndGlobal
diff --git a/3FD/3FD.pro b/3FD/3FD.pro
new file mode 100644
index 0000000..b0aa3ff
--- /dev/null
+++ b/3FD/3FD.pro
@@ -0,0 +1,76 @@
+TARGET = 3FD
+TEMPLATE = lib
+CONFIG += staticlib
+CONFIG -= qt
+CONFIG += c++11
+
+win32:CONFIG(release, debug|release): DEFINES += NDEBUG
+else:unix:!macx:CONFIG(release, debug|release): DEFINES += NDEBUG
+
+DEFINES += \
+ ENABLE_3FD_CST \
+ ENABLE_3FD_ERR_IMPL_DETAILS
+
+SOURCES += \
+ callstacktracer.cpp \
+ configuration.cpp \
+ dependencies.cpp \
+ exceptions.cpp \
+ gc_addresseshashtable.cpp \
+ gc_garbagecollector.cpp \
+ gc_mastertable.cpp \
+ gc_memblock.cpp \
+ gc_messages.cpp \
+ logger.cpp \
+ logger_poco.cpp \
+ opencl_impl.cpp \
+ opencl_impl_commandtracker.cpp \
+ opencl_impl_context.cpp \
+ opencl_impl_device.cpp \
+ opencl_impl_platform.cpp \
+ opencl_impl_program.cpp \
+ opencl_impl_programmanifest.cpp \
+ runtime.cpp \
+ sqlite_databaseconn.cpp \
+ sqlite_dbconnpool.cpp \
+ sqlite_prepstatement.cpp \
+ sqlite_transaction.cpp \
+ utils.cpp \
+ sqlite3.c
+
+HEADERS += \
+ base.h \
+ callstacktracer.h \
+ configuration.h \
+ dependencies.h \
+ exceptions.h \
+ gc.h \
+ gc_memblock.h \
+ gc_messages.h \
+ logger.h \
+ multilayerctnr.h \
+ opencl.h \
+ opencl_impl.h \
+ preprocessing.h \
+ runtime.h \
+ sptr.h \
+ sqlite.h \
+ sqlite3.h \
+ utils.h
+
+unix {
+ target.path = /usr/local/lib
+ INSTALLS += target
+ CONFIG(release, debug|release): DEFINES += NDEBUG
+}
+
+OTHER_FILES += \
+ ReadMe.txt \
+ config3fd-template.xml
+
+INCLUDEPATH += \
+ ../OpenCL \
+ /opt/Poco-1.4.7/include \
+ /opt/boost-1.55/include
+
+DEPENDPATH += /opt/Poco-1.4.7/include
diff --git a/3FD/3FD.vcxproj b/3FD/3FD.vcxproj
new file mode 100644
index 0000000..247b0b7
--- /dev/null
+++ b/3FD/3FD.vcxproj
@@ -0,0 +1,280 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {CCC4A0A2-15FD-4A6E-AC6C-094AAAAEC80B}
+ Win32Proj
+ My3FD
+
+
+
+ StaticLibrary
+ true
+ v120
+ Unicode
+
+
+ StaticLibrary
+ true
+ v120
+ Unicode
+
+
+ StaticLibrary
+ false
+ v120
+ true
+ Unicode
+
+
+ StaticLibrary
+ false
+ v120
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 433ab66f
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ $(BOOST_HOME);$(POCO_ROOT)\Foundation\include;$(POCO_ROOT)\XML\include;$(POCO_ROOT)\Util\include;C:\Program Files (x86)\Visual Leak Detector\include;$(IncludePath)
+ $(BOOST_HOME)\stage\lib\Win32;$(LibraryPath)
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ $(Platform)\$(Configuration)\
+ $(BOOST_HOME);$(POCO_ROOT)\Foundation\include;$(POCO_ROOT)\XML\include;$(POCO_ROOT)\Util\include;C:\Program Files (x86)\Visual Leak Detector\include;$(IncludePath)
+ $(BOOST_HOME)\stage\lib\Win32;$(LibraryPath)
+
+
+ $(BOOST_HOME);$(POCO_ROOT)\Foundation\include;$(POCO_ROOT)\XML\include;$(POCO_ROOT)\Util\include;C:\Program Files (x86)\Visual Leak Detector\include;$(IncludePath)
+ $(BOOST_HOME)\stage\lib\x64;$(LibraryPath)
+
+
+ $(BOOST_HOME);$(POCO_ROOT)\Foundation\include;$(POCO_ROOT)\XML\include;$(POCO_ROOT)\Util\include;C:\Program Files (x86)\Visual Leak Detector\include;$(IncludePath)
+ $(BOOST_HOME)\stage\lib\x64;$(LibraryPath)
+
+
+
+ Use
+ Level3
+ Disabled
+ _SCL_SECURE_NO_WARNINGS;ENABLE_3FD_CST;ENABLE_3FD_ERR_IMPL_DETAILS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ $(SolutionDir)btree;$(SolutionDir)OpenCL;%(AdditionalIncludeDirectories)
+ /D POCO_STATIC %(AdditionalOptions)
+
+
+ Windows
+ true
+
+
+ esent.lib;%(AdditionalDependencies)
+
+
+
+
+ Use
+ Level3
+ Disabled
+ _SCL_SECURE_NO_WARNINGS;ENABLE_3FD_CST;ENABLE_3FD_ERR_IMPL_DETAILS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ $(SolutionDir)btree;$(SolutionDir)OpenCL;%(AdditionalIncludeDirectories)
+ /D POCO_STATIC %(AdditionalOptions)
+
+
+ Windows
+ true
+
+
+ esent.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ Use
+ MaxSpeed
+ true
+ true
+ _SCL_SECURE_NO_WARNINGS;ENABLE_3FD_CST;ENABLE_3FD_ERR_IMPL_DETAILS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ $(SolutionDir)btree;$(SolutionDir)OpenCL;%(AdditionalIncludeDirectories)
+ /D POCO_STATIC %(AdditionalOptions)
+
+
+ Windows
+ true
+ true
+ true
+
+
+ esent.lib;%(AdditionalDependencies)
+
+
+
+
+ Level3
+ Use
+ MaxSpeed
+ true
+ true
+ _SCL_SECURE_NO_WARNINGS;ENABLE_3FD_CST;ENABLE_3FD_ERR_IMPL_DETAILS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ $(SolutionDir)btree;$(SolutionDir)OpenCL;%(AdditionalIncludeDirectories)
+ /D POCO_STATIC %(AdditionalOptions)
+
+
+ Windows
+ true
+ true
+ true
+
+
+ esent.lib;%(AdditionalDependencies)
+
+
+
+
+
+
+
+
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NotUsing
+ NotUsing
+ NotUsing
+ NotUsing
+
+
+ Create
+ Create
+ Create
+ Create
+
+
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+ Designer
+
+
+
+
+
\ No newline at end of file
diff --git a/3FD/3FD.vcxproj.filters b/3FD/3FD.vcxproj.filters
new file mode 100644
index 0000000..9ed6890
--- /dev/null
+++ b/3FD/3FD.vcxproj.filters
@@ -0,0 +1,298 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hpp;hxx;hm;inl;inc;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {ac16d35f-aa39-45c3-9b2c-5543cec419b9}
+
+
+ {30173bc6-2c99-4711-bdf2-4969e618fce7}
+
+
+ {8b1ea7ec-6a50-4d55-bdbf-b092c26fc292}
+
+
+ {4de76b28-d59d-46c2-b554-24836ed641ae}
+
+
+ {0cee6fc2-4873-453d-ae55-232836f8b89c}
+
+
+ {8d8dc2c4-8a72-4150-8c2d-28696b3e904a}
+
+
+ {395999a4-24a7-4dfe-9a52-6bf9eb87e510}
+
+
+ {9dd1a655-8f07-4b3d-807f-d5f7640be150}
+
+
+ {ccc3c52c-aff6-436c-8adf-78d07d1a852a}
+
+
+ {edc38cba-bae7-491a-8bd9-6a4f526bac49}
+
+
+ {29555dd9-0109-4efe-bdab-39050ae8185b}
+
+
+ {ca2b298e-0fc2-484d-9742-7e1cbb00a56e}
+
+
+ {adaad3a7-931d-4ff9-a154-1acf0e0f2eae}
+
+
+ {1e15f524-b36e-41e4-a678-89ad500e083d}
+
+
+ {0275ac77-e49a-48fb-83b7-7bd7c155c1f1}
+
+
+
+
+ MORE
+
+
+ MORE
+
+
+
+
+ Header Files
+
+
+ MORE\SQLite3
+
+
+ MORE\OpenCL
+
+
+ MORE\OpenCL
+
+
+ MORE\OpenCL
+
+
+ Header Files\core
+
+
+ Header Files\core
+
+
+ Header Files\core
+
+
+ Header Files\core
+
+
+ Header Files\core
+
+
+ Header Files\core
+
+
+ Header Files\ISAM
+
+
+ Header Files\ISAM
+
+
+ Header Files\core
+
+
+ MORE\Visual C++
+
+
+ MORE\Visual C++
+
+
+ Header Files\core
+
+
+ Header Files\OpenCL
+
+
+ Header Files\OpenCL
+
+
+ Header Files\GC
+
+
+ Header Files\GC
+
+
+ Header Files\GC
+
+
+ Header Files\GC
+
+
+ Header Files\GC
+
+
+ Header Files\GC
+
+
+ Header Files\GC
+
+
+ Header Files\GC
+
+
+ Header Files\GC
+
+
+ Header Files\utilities
+
+
+ Header Files\utilities
+
+
+
+
+ MORE\SQLite3
+
+
+ Source Files\core
+
+
+ Source Files\core
+
+
+ Source Files\core
+
+
+ Source Files\core
+
+
+ Source Files\core
+
+
+ Source Files\core
+
+
+ Source Files\ISAM
+
+
+ Source Files\ISAM
+
+
+ MORE\Visual C++
+
+
+ Source Files\ISAM
+
+
+ Source Files\core
+
+
+ Source Files\OpenCL
+
+
+ Source Files\OpenCL
+
+
+ Source Files\OpenCL
+
+
+ Source Files\OpenCL
+
+
+ Source Files\OpenCL
+
+
+ Source Files\OpenCL
+
+
+ Source Files\OpenCL
+
+
+ Source Files\SQLite
+
+
+ Source Files\SQLite
+
+
+ Source Files\SQLite
+
+
+ Source Files\SQLite
+
+
+ Source Files\GC
+
+
+ Source Files\GC
+
+
+ Source Files\GC
+
+
+ Source Files\GC
+
+
+ Source Files\GC
+
+
+ Source Files\ISAM
+
+
+ Source Files\ISAM
+
+
+ Source Files\ISAM
+
+
+ Source Files\ISAM
+
+
+ Source Files\ISAM
+
+
+ Source Files\ISAM
+
+
+ Source Files\ISAM
+
+
+ Source Files\ISAM
+
+
+ Source Files\GC
+
+
+ Source Files\utilities
+
+
+ Source Files\utilities
+
+
+ Source Files\utilities
+
+
+ Source Files\utilities
+
+
+ Source Files\GC
+
+
+ Source Files\utilities
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/3FD/ReadMe.txt b/3FD/ReadMe.txt
new file mode 100644
index 0000000..1179c56
--- /dev/null
+++ b/3FD/ReadMe.txt
@@ -0,0 +1,37 @@
+========================================================================
+ STATIC LIBRARY : 3FD Project Overview
+========================================================================
+
+AppWizard has created this 3FD library project for you.
+
+This file contains a summary of what you will find in each of the files that
+make up your 3FD application.
+
+
+3FD.vcxproj
+ This is the main project file for VC++ projects generated using an Application Wizard.
+ It contains information about the version of Visual C++ that generated the file, and
+ information about the platforms, configurations, and project features selected with the
+ Application Wizard.
+
+3FD.vcxproj.filters
+ This is the filters file for VC++ projects generated using an Application Wizard.
+ It contains information about the association between the files in your project
+ and the filters. This association is used in the IDE to show grouping of files with
+ similar extensions under a specific node (for e.g. ".cpp" files are associated with the
+ "Source Files" filter).
+
+
+/////////////////////////////////////////////////////////////////////////////
+
+StdAfx.h, StdAfx.cpp
+ These files are used to build a precompiled header (PCH) file
+ named 3FD.pch and a precompiled types file named StdAfx.obj.
+
+/////////////////////////////////////////////////////////////////////////////
+Other notes:
+
+AppWizard uses "TODO:" comments to indicate parts of the source code you
+should add to or customize.
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/3FD/WWS_API/web_impl.cpp b/3FD/WWS_API/web_impl.cpp
new file mode 100644
index 0000000..e279463
--- /dev/null
+++ b/3FD/WWS_API/web_impl.cpp
@@ -0,0 +1,1002 @@
+#include "stdafx.h"
+#include "web_impl.h"
+
+#include "callstacktracer.h"
+#include "logger.h"
+#include "Poco\AutoPtr.h"
+#include "Poco\DOM\DOMParser.h"
+#include "Poco\DOM\Document.h"
+#include "Poco\DOM\NodeList.h"
+#include "Poco\DOM\NamedNodeMap.h"
+#include "Poco\DOM\Attr.h"
+#include "Poco\SAX\XMLReader.h"
+#include "Poco\SAX\NamespaceSupport.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace _3fd
+{
+ namespace web
+ {
+ using std::string;
+ using namespace _3fd::core;
+
+ /////////////////////////////
+ // WSError Class
+ /////////////////////////////
+
+ ///
+ /// Initializes a new instance of the class.
+ /// In order to save resources, this class uses delayed initialization.
+ ///
+ WSError::WSError()
+ : m_wsErrorHandle(nullptr) {}
+
+ ///
+ /// Initializes the class resources.
+ ///
+ void WSError::Initialize()
+ {
+ if (m_wsErrorHandle == nullptr)
+ {
+ auto hr = WsCreateError(nullptr, 0, &m_wsErrorHandle);
+ if (hr != S_OK)
+ throw AppException("Failed to delayed-initialize object for rich error information", WWAPI::GetHResultLabel(hr));
+ }
+ }
+
+ ///
+ /// Gets the error handle.
+ /// Because the
+ ///
+ /// The handle for the opaque error object.
+ WS_ERROR * WSError::GetHandle()
+ {
+ if (m_wsErrorHandle != nullptr)
+ return m_wsErrorHandle;
+ else
+ {
+ Initialize();
+ return m_wsErrorHandle;
+ }
+ }
+
+ ///
+ /// Finalizes an instance of the class.
+ ///
+ WSError::~WSError()
+ {
+ if (m_wsErrorHandle != nullptr)
+ WsFreeError(m_wsErrorHandle);
+ }
+
+ ///
+ /// Resets the error object so as to be reused.
+ ///
+ void WSError::Reset()
+ {
+ if (m_wsErrorHandle != nullptr)
+ {
+ auto hr = WsResetError(m_wsErrorHandle);
+ if (hr != S_OK)
+ throw AppException("Failed to reset rich error object for reuse", WWAPI::GetHResultLabel(hr));
+ }
+ }
+
+ ///
+ /// Raises an exception when the error state has been set.
+ ///
+ /// The returned HRESULT code.
+ /// Name of the function.
+ /// The error message.
+ /// The service name if applicable, otherwise, 'nullptr'.
+ void WSError::RaiseExceptionWhenError(
+ HRESULT hres,
+ const char *funcName,
+ const char *message,
+ const char *svcName)
+ {
+ if (hres == S_OK)
+ return;
+ else
+ {
+ // Incorrect use of WWS API must trigger an assertion instead of exception:
+ //_ASSERTE(hres != E_INVALIDARG && hres != WS_E_INVALID_OPERATION);
+
+ try
+ {
+ std::wstring_convert> transcoder;
+ std::ostringstream oss;
+ oss << funcName << " returned " << WWAPI::GetHResultLabel(hres);
+
+ if (svcName != nullptr)
+ oss << " (Web service \'" << svcName << "\')";
+
+ Initialize();
+ unsigned long strCount;
+ auto hr = WsGetErrorProperty(m_wsErrorHandle, WS_ERROR_PROPERTY_STRING_COUNT, &strCount, sizeof strCount);
+ if (hr != S_OK)
+ {
+ oss << "Parallel failure prevented retrieving count of strings from rich error information. WsGetErrorProperty returned " << WWAPI::GetHResultLabel(hr);
+ throw AppException(message, oss.str());
+ }
+
+ if (strCount > 0)
+ oss << " Rich error info: ";
+
+ for (unsigned long idx = 0; idx < strCount; ++idx)
+ {
+ WS_STRING str;
+ hr = WsGetErrorString(m_wsErrorHandle, idx, &str);
+
+ if (hr == S_OK)
+ oss << transcoder.to_bytes(str.chars, str.chars + str.length);
+ else
+ oss << "Failed to get this error string. WsGetErrorString returned " << WWAPI::GetHResultLabel(hr);
+
+ if (idx + 1 < strCount)
+ oss << " / ";
+ }
+
+ Reset();
+ throw AppException(message, oss.str());
+ }
+ catch (IAppException &ex)
+ {
+ throw; // just forward exceptions known to have been already handled
+ }
+ catch (std::exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "Parallel generic failure prevented retrieving the error details. Reason: " << ex.what();
+ throw AppException(message, oss.str());
+ }
+ }
+ }
+
+ /////////////////////////////
+ // WSHeap Class
+ /////////////////////////////
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The heap opaque object handle.
+ WSHeap::WSHeap(WS_HEAP *wsHeapHandle)
+ : m_wsHeapHandle(wsHeapHandle), m_allowRelease(false) {}
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ WSHeap::WSHeap() :
+ m_wsHeapHandle(nullptr),
+ m_allowRelease(true)
+ {
+ CALL_STACK_TRACE;
+ WSError err;
+ auto hr = WsCreateHeap(1024, 0, nullptr, 0, &m_wsHeapHandle, err.GetHandle());
+ err.RaiseExceptionWhenError(hr, "WsCreateHeap", "Failed to create heap");
+ }
+
+ ///
+ /// Finalizes an instance of the class.
+ ///
+ WSHeap::~WSHeap()
+ {
+ if (m_allowRelease)
+ WsFreeHeap(m_wsHeapHandle);
+ }
+
+ ///
+ /// Resets this instance.
+ ///
+ void WSHeap::Reset()
+ {
+ CALL_STACK_TRACE;
+ WSError err;
+ auto hr = WsResetHeap(m_wsHeapHandle, err.GetHandle());
+ err.RaiseExceptionWhenError(hr, "WsResetHeap", "Failed to release heap allocations");
+ }
+
+ ///
+ /// Allocates some memory.
+ ///
+ /// The amount of bytes to allocate.
+ /// A pointer to the allocated amount of memory.
+ void * WSHeap::Alloc(size_t qtBytes)
+ {
+ CALL_STACK_TRACE;
+ WSError err;
+ void *ptr;
+ auto hr = WsAlloc(m_wsHeapHandle, qtBytes, &ptr, err.GetHandle());
+ err.RaiseExceptionWhenError(hr, "WsAlloc", "Failed to allocate heap memory");
+ return ptr;
+ }
+
+ /////////////////////////////
+ // WebServiceHost Class
+ /////////////////////////////
+
+ ///
+ /// Reads a file to a buffer.
+ ///
+ /// The file path.
+ /// The buffer.
+ static void ReadFile(const string &path, std::vector &buffer)
+ {
+ CALL_STACK_TRACE;
+
+ try
+ {
+ buffer.clear(); // if something goes wrong, do not keep any previous content in the buffer
+
+ std::ifstream inputStream(path, std::ios::in | std::ios::binary); // open file
+
+ if (inputStream.is_open() == false)
+ {
+ std::ostringstream oss;
+ oss << "Failed to open file \'" << path << "\' in read mode";
+ throw AppException(oss.str());
+ }
+
+ const auto fileSizeBytes = inputStream.seekg(0, std::ios::end).tellg().seekpos(); // move cursor to the end to get the zize
+
+ // File is not trunked:
+ if (fileSizeBytes > 0)
+ {
+ inputStream.seekg(0, std::ios::beg); // rewind
+
+ // Read the file contents to the buffer:
+ buffer.resize(fileSizeBytes);
+ inputStream.read(buffer.data(), buffer.size());
+ _ASSERTE(inputStream.gcount() == buffer.size());
+
+ if (inputStream.bad())
+ {
+ std::ostringstream oss;
+ oss << "Failed to read from file \'" << path << '\'';
+ throw AppException(oss.str());
+ }
+
+ inputStream.close(); // release the file
+ }
+ }
+ catch (IAppException &ex)
+ {
+ throw; // just forward exceptions regarding errors known to have been previously handled
+ }
+ catch (std::exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic failure when reading file \'" << path << "\'. Reason: " << ex.what();
+ throw AppException(oss.str());
+ }
+ }
+
+ ///
+ /// Parses information about endpoints from a WSDL document.
+ ///
+ /// Web service definition content previously loaded from a file.
+ /// Where to save the target namespace.
+ /// Where to save the service name.
+ /// Where to save the parsed information regarding the endpoints.
+ static void ParseEndpointsFromWSD(
+ const std::vector &wsdContent,
+ string &targetNamespace,
+ string &serviceName,
+ std::vector &endpoints)
+ {
+ using namespace Poco;
+
+ CALL_STACK_TRACE;
+ /* Assumes the usage of HTTP & SOAP, but does not check if the document is thoroughly
+ well formed. Because this library is meant to integrate with wsutil.exe generated code,
+ the WSDL document is expected to follow the specification in http://www.w3.org/TR/wsdl.
+ Also, the bindings MUST BE declared in the target namespace using the prefix tns. */
+ try
+ {
+ // If anything goes wrong, do not keep any previous content in the output:
+ targetNamespace.clear();
+ serviceName.clear();
+ endpoints.clear();
+
+ // Fundamental namespaces URI's:
+ static const string wsdlNs("http://schemas.xmlsoap.org/wsdl/"),
+ soapNs("http://schemas.xmlsoap.org/wsdl/soap/");
+
+ XML::NamespaceSupport nsmap;
+ nsmap.declarePrefix("wsdl", wsdlNs);
+ nsmap.declarePrefix("soap", soapNs);
+
+ // Parse XML from memory:
+ XML::DOMParser parser;
+ parser.setFeature(XML::SAXParser::FEATURE_NAMESPACE_PREFIXES, true);
+ parser.setFeature(XML::SAXParser::FEATURE_NAMESPACES, true);
+ AutoPtr document = parser.parseMemory(wsdContent.data(), wsdContent.size());
+
+ // Get /wsdl:definitions
+ auto definitions = static_cast (document->getNodeByPathNS("/wsdl:definitions", nsmap));
+ if (definitions == nullptr)
+ throw AppException("Web service definition is not compliant", "The WSDL definitions element is missing");
+
+ // Get /wsdl:definitions[@targetNamespace]
+ auto attr = definitions->getAttributeNode("targetNamespace");
+ if (attr != nullptr)
+ {
+ targetNamespace = attr->nodeValue();
+ nsmap.declarePrefix("tns", targetNamespace);
+ }
+ else
+ throw AppException("Web service definition is not compliant", "The target namespace is missing from WSDL document");
+
+ // Get /wsdl:definitions/wsdl:service
+ auto svcElement = definitions->getChildElementNS(wsdlNs, "service");
+ if (svcElement == nullptr)
+ throw AppException("Web service definition is not compliant", "The WSDL service element is missing from document");
+
+ // Get /wsdl:definitions/wsdl:service[@name]
+ attr = svcElement->getAttributeNode("name");
+ if (attr != nullptr)
+ serviceName = attr->nodeValue();
+ else
+ throw AppException("Web service definition is not compliant", "The attribute \'name\' was missing from the WSDL service element");
+
+ // Iterate over each 'wsdl:port' element:
+ AutoPtr portNodes = svcElement->getElementsByTagNameNS(wsdlNs, "port");
+ for (unsigned long idx = 0; idx < portNodes->length(); ++idx)
+ {
+ auto portElement = static_cast (portNodes->item(idx));
+
+ // Add a new endpoint to the service
+ endpoints.emplace_back();
+ auto &endpoint = endpoints.back();
+
+ // Get /wsdl:definitions/wsdl:service/wsdl:port[@name]
+ attr = portElement->getAttributeNode("name");
+ if (attr != nullptr)
+ endpoint.portName = attr->nodeValue();
+ else
+ {
+ std::ostringstream oss;
+ oss << "Attribute \'name\' is missing from WSDL port element in service \'" << serviceName << '\'';
+ throw AppException("Web service definition is not compliant", oss.str());
+ }
+
+ // Get /wsdl:definitions/wsdl:service/wsdl:port[@binding]
+ attr = portElement->getAttributeNode("binding");
+ if (attr == nullptr)
+ {
+ std::ostringstream oss;
+ oss << "Attribute \'binding\' is missing from WSDL port \'" << endpoint.portName
+ << "\' in service \'" << serviceName << '\'';
+ throw AppException("Web service definition is not compliant", oss.str());
+ }
+
+ if (nsmap.processName(attr->nodeValue(), endpoint.bindingNs, endpoint.bindingName, false) == false)
+ {
+ std::ostringstream oss;
+ oss << "Could not resolve WSDL binding \'" << attr->nodeValue()
+ << "\' of port \'" << endpoint.portName
+ << "\' in service \'" << serviceName << '\'';
+ throw AppException("Web service definition is not compliant", oss.str());
+ }
+
+ // Get /wsdl:definitions/wsdl:service/wsdl:port/soap:address[@location]
+ attr = static_cast (portElement->getNodeByPath("/soap:address[@location]"));
+ if (attr != nullptr)
+ endpoint.address = attr->nodeValue();
+ else
+ {
+ std::ostringstream oss;
+ oss << "Endpoint soap address not found for WSDL port \'" << endpoint.portName
+ << "\' in service \'" << serviceName << '\'';
+ throw AppException("Web service definition is not compliant", oss.str());
+ }
+ }// for loop end
+
+ if (endpoints.empty())
+ throw AppException("Web service definition is not compliant", "No valid specification for endpoint has been found");
+ }
+ catch (IAppException &ex)
+ {
+ throw; // just forward exceptions regarding errors known to have been previously handled
+ }
+ catch (Poco::Exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "POCO C++ library reported: " << ex.message();
+ throw AppException("Failed to parse web service definition", oss.str());
+ }
+ catch (std::exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic failure when parsing web service definition: " << ex.what();
+ throw AppException(oss.str());
+ }
+ }
+
+ ///
+ /// Creates the endpoints for a web service.
+ ///
+ /// The configurations common to all endpoints in the web service.
+ /// Contains the information about each endpoint to create.
+ /// The function table.
+ /// The callback which invokes code generated by wsutil.exe to create a service endpoint.
+ /// Where to save the endpoints to be created.
+ /// The heap that provides memory allocation.
+ static void CreateWebSvcEndpoints(
+ const SvcEndpointsConfig &config,
+ const std::vector &fromEndpointsInfo,
+ void *functionTable,
+ CallbackWrapperCreateWSEndpoint createWebSvcEndpointCallback,
+ std::vector &toSvcEndpoints,
+ WSHeap &heap)
+ {
+ CALL_STACK_TRACE;
+
+ try
+ {
+ toSvcEndpoints.clear(); // if anything goes wrong, do not keep any previous content in the output
+ toSvcEndpoints.reserve(fromEndpointsInfo.size());
+
+ for (auto &endpointInfo : fromEndpointsInfo)
+ {
+ // The endpoint port to show in the WSDL document (available through MEX):
+ auto port = heap.Alloc();
+ port->portName = new (heap.Alloc(sizeof(WS_XML_STRING))) WS_XML_STRING{ endpointInfo.portName.length(), (unsigned char *)endpointInfo.portName.data(), nullptr, 0 };
+ port->bindingName = new (heap.Alloc(sizeof(WS_XML_STRING))) WS_XML_STRING{ endpointInfo.bindingName.length(), (unsigned char *)endpointInfo.bindingName.data(), nullptr, 0 };
+ port->bindingNs = new (heap.Alloc(sizeof(WS_XML_STRING))) WS_XML_STRING{ endpointInfo.bindingNs.length(), (unsigned char *)endpointInfo.bindingNs.data(), nullptr, 0 };
+
+ auto mexUrlSuffix = heap.Alloc();
+ *mexUrlSuffix = WS_STRING_VALUE(L"mex"); // URL suffix to get MEX
+
+ auto metadataExchangeType = heap.Alloc();
+ *metadataExchangeType = WS_METADATA_EXCHANGE_TYPE_MEX; // use MEX
+
+ // Set the endpoint properties from the settings in the parameters:
+ auto endpointProps = heap.Alloc(5);
+ endpointProps[0] = WS_SERVICE_ENDPOINT_PROPERTY{ WS_SERVICE_ENDPOINT_PROPERTY_MAX_ACCEPTING_CHANNELS, const_cast (&config.maxAcceptingChannels), sizeof config.maxAcceptingChannels };
+ endpointProps[1] = WS_SERVICE_ENDPOINT_PROPERTY{ WS_SERVICE_ENDPOINT_PROPERTY_MAX_CONCURRENCY, const_cast (&config.maxConcurrency), sizeof config.maxConcurrency };
+ endpointProps[2] = WS_SERVICE_ENDPOINT_PROPERTY{ WS_SERVICE_ENDPOINT_PROPERTY_METADATA_EXCHANGE_TYPE, metadataExchangeType, sizeof *metadataExchangeType };
+ endpointProps[3] = WS_SERVICE_ENDPOINT_PROPERTY{ WS_SERVICE_ENDPOINT_PROPERTY_METADATA_EXCHANGE_URL_SUFFIX, mexUrlSuffix, sizeof *mexUrlSuffix };
+ endpointProps[4] = WS_SERVICE_ENDPOINT_PROPERTY{ WS_SERVICE_ENDPOINT_PROPERTY_METADATA, port, sizeof *port };
+
+ // Invoke the callback, which takes care of the remaining settings:
+ WSError err;
+ WS_SERVICE_ENDPOINT *endpoint;
+ auto hr = createWebSvcEndpointCallback(
+ endpointInfo.address,
+ functionTable,
+ nullptr,
+ endpointProps,
+ 5,
+ heap,
+ &endpoint
+ );
+
+ if (hr != S_OK)
+ {
+ std::ostringstream oss;
+ oss << "Failed to create web service endpoint at " << endpointInfo.address;
+ err.RaiseExceptionWhenError(hr, "WsCreateServiceEndpointFromTemplate", oss.str().c_str());
+ }
+
+ // Add the newly created endpoint to the output vector
+ toSvcEndpoints.push_back(endpoint);
+ }
+ }
+ catch (IAppException &ex)
+ {
+ throw; // just forward exceptions known to have been already handled
+ }
+ catch (std::exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic failure when creating service endpoint: " << ex.what();
+ throw AppException(oss.str());
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ WebServiceHostImpl::WebServiceHostImpl()
+ try :
+ m_webSvcHostHandle(nullptr),
+ m_svcThread(),
+ m_svcStateMutex(),
+ m_svcHeap()
+ {
+ }
+ catch (IAppException &ex)
+ {
+ throw; // just forward exceptions known to have been already handled
+ }
+ catch (std::system_error &ex)
+ {
+ CALL_STACK_TRACE;
+ std::ostringstream oss;
+ oss << "Failed to create web service host: " << StdLibExt::GetDetailsFromSystemError(ex);
+ throw AppException(oss.str());
+ }
+ catch (std::exception &ex)
+ {
+ CALL_STACK_TRACE;
+ std::ostringstream oss;
+ oss << "Generic failure when creating web service host: " << ex.what();
+ throw AppException(oss.str());
+ }
+
+ ///
+ /// Finalizes an instance of the class.
+ ///
+ WebServiceHostImpl::~WebServiceHostImpl()
+ {
+ if (m_webSvcHostHandle == nullptr)
+ return;
+
+ CALL_STACK_TRACE;
+
+ try
+ {
+ // If the service thread is running:
+ if (m_svcThread.get_id() != std::thread::id())
+ {
+ // Ask for the service current state:
+ WSError err;
+ WS_SERVICE_HOST_STATE state;
+ auto hr = WsGetServiceHostProperty(
+ m_webSvcHostHandle,
+ WS_SERVICE_PROPERTY_HOST_STATE,
+ &state,
+ sizeof state,
+ err.GetHandle()
+ );
+ err.RaiseExceptionWhenError(hr, "WsGetServiceHostProperty", "Failed to get state of web service host", m_serviceName);
+
+ if (state == WS_SERVICE_HOST_STATE_OPENING
+ || state == WS_SERVICE_HOST_STATE_OPEN)
+ {
+ std::ostringstream oss;
+ oss << "Stopping web service \'" << m_serviceName << "\'...";
+ Logger::GetInstance().Write(oss.str(), Poco::Message::Priority::PRIO_INFORMATION);
+
+ // Abort web service asynchronous execution
+ hr = WsAbortServiceHost(m_webSvcHostHandle, err.GetHandle());
+ err.RaiseExceptionWhenError(hr, "WsAbortServiceHost", "Failed to abort web service asynchronous execution", m_serviceName);
+
+ // Close web service:
+ hr = WsCloseServiceHost(m_webSvcHostHandle, nullptr, err.GetHandle());
+ err.RaiseExceptionWhenError(hr, "WsCloseServiceHost", "Failed to close web service host", m_serviceName);
+
+ oss.str("");
+ oss << "Web service \'" << m_serviceName << "\' successfully stopped";
+ Logger::GetInstance().Write(oss.str(), Poco::Message::Priority::PRIO_INFORMATION);
+ }
+
+ // Ensure thread termination:
+ if (m_svcThread.joinable())
+ m_svcThread.join();
+ }
+
+ // Finalize and release resources
+ WsFreeServiceHost(m_webSvcHostHandle);
+ }
+ catch (IAppException &ex)
+ {
+ Logger::GetInstance().Write(ex, Poco::Message::Priority::PRIO_CRITICAL);
+ }
+ catch (std::system_error &ex)
+ {
+ std::ostringstream oss;
+ oss << "Failed to terminate web service host asynchronous execution: " << StdLibExt::GetDetailsFromSystemError(ex);
+ Logger::GetInstance().Write(oss.str(), Poco::Message::Priority::PRIO_CRITICAL);
+ }
+ catch (std::exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic failure when terminating web service host: " << ex.what();
+ Logger::GetInstance().Write(oss.str(), Poco::Message::Priority::PRIO_CRITICAL);
+ }
+ }
+
+ ///
+ /// Setups the specified WSD file path.
+ ///
+ /// The web service definition file path.
+ /// The configuration common for all service endpoints.
+ /// The callback implementation for endpoint creation (generated by wsutil.exe).
+ /// The function table, which contains the pointers for the functions implementing the service operations.
+ void WebServiceHostImpl::Setup(
+ const string &wsdFilePath,
+ const SvcEndpointsConfig &config,
+ CallbackWrapperCreateWSEndpoint createWebSvcEndpointCallback,
+ void *functionTable)
+ {
+ CALL_STACK_TRACE;
+
+ try
+ {
+ _ASSERTE(m_webSvcHostHandle == nullptr); // cannot setup a service that has been already set
+
+ // First acquire lock to manage service host
+ std::lock_guard lock(m_svcStateMutex);
+
+ // Read web service definition from file
+ ReadFile(wsdFilePath, m_wsdContentBuffer);
+
+ // Parse information from the WSDL:
+ ParseEndpointsFromWSD(m_wsdContentBuffer, m_wsdTargetNs, m_serviceName, m_endpointsInfo);
+
+ // Create the web service endpoints:
+ std::vector endpoints;
+ CreateWebSvcEndpoints(config, m_endpointsInfo, functionTable, createWebSvcEndpointCallback, endpoints, m_svcHeap);
+
+ // Define a document to be provided by MEX:
+ auto document = m_svcHeap.Alloc();
+ document->name = nullptr;
+ document->content = new (m_svcHeap.Alloc(sizeof(WS_XML_STRING))) WS_XML_STRING{ 0 };
+ document->content->length = m_wsdContentBuffer.size();
+ document->content->bytes = reinterpret_cast (m_wsdContentBuffer.data());
+
+ // Set service host metadata:
+ WS_SERVICE_METADATA metadata;
+ metadata.documentCount = 1;
+ metadata.documents = &document;
+ metadata.serviceName = new (m_svcHeap.Alloc(sizeof(WS_XML_STRING))) WS_XML_STRING{ m_serviceName.length(), (unsigned char *)m_serviceName.data(), nullptr, 0 };
+ metadata.serviceNs = new (m_svcHeap.Alloc(sizeof(WS_XML_STRING))) WS_XML_STRING{ m_wsdTargetNs.length(), (unsigned char *)m_wsdTargetNs.data(), nullptr, 0 };
+
+# ifdef _DEBUG
+ WS_FAULT_DISCLOSURE faultDisclosure(WS_FULL_FAULT_DISCLOSURE);
+# else
+ WS_FAULT_DISCLOSURE faultDisclosure(WS_MINIMAL_FAULT_DISCLOSURE);
+# endif
+ // Service host properties:
+ std::array serviceProps =
+ {
+ WS_SERVICE_PROPERTY{ WS_SERVICE_PROPERTY_METADATA, &metadata, sizeof metadata },
+ WS_SERVICE_PROPERTY{ WS_SERVICE_PROPERTY_FAULT_DISCLOSURE, &faultDisclosure, sizeof faultDisclosure }
+ };
+
+ // Finally create the web service host:
+ WSError err;
+ auto hr = WsCreateServiceHost(
+ endpoints.data(),
+ endpoints.size(),
+ serviceProps.data(),
+ serviceProps.size(),
+ &m_webSvcHostHandle,
+ err.GetHandle()
+ );
+ err.RaiseExceptionWhenError(hr, "WsCreateServiceHost", "Failed to create web service host", m_serviceName);
+ }
+ catch (IAppException &ex)
+ {
+ throw; // just forward exceptions known to have been already handled
+ }
+ catch (std::exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic failure when setting up web service host: " << ex.what();
+ throw AppException(oss.str(), wsdFilePath);
+ }
+ }
+
+ ///
+ /// Opens the web service host to start receiving requests.
+ ///
+ void WebServiceHostImpl::OpenAsync()
+ {
+ CALL_STACK_TRACE;
+
+ try
+ {
+ _ASSERTE(m_webSvcHostHandle != nullptr); // service host must be set up before use
+
+ // First acquire lock to manage service host
+ std::lock_guard lock(m_svcStateMutex);
+
+ if (m_svcThread.get_id() != std::thread::id())
+ {
+ std::ostringstream oss;
+ oss << "Tried to open web service \'" << m_serviceName << "\' when it was already running asynchronously";
+ throw AppException(oss.str());
+ }
+
+ std::ostringstream oss;
+ oss << "Starting web service \'" << m_serviceName << '\'';
+ Logger::GetInstance().Write(oss.str(), Poco::Message::Priority::PRIO_INFORMATION);
+
+ // Open the web service host for client requests in a parallel thread:
+ m_svcThread.swap(
+ std::thread([this]()
+ {
+ CALL_STACK_TRACE;
+
+ try
+ {
+ WSError err;
+ auto hr = WsOpenServiceHost(m_webSvcHostHandle, nullptr, err.GetHandle());
+ err.RaiseExceptionWhenError(hr, "WsOpenServiceHost", "Failed to open web service host", m_serviceName);
+ }
+ catch (IAppException &ex)
+ {
+ Logger::GetInstance().Write(ex, Poco::Message::Priority::PRIO_CRITICAL);
+ }
+ })
+ );
+ }
+ catch (IAppException &ex)
+ {
+ throw; // just forward exceptions known to have been already handled
+ }
+ catch (std::system_error &ex)
+ {
+ std::ostringstream oss;
+ oss << "Failed to open web service host asynchronously: " << StdLibExt::GetDetailsFromSystemError(ex);
+ throw AppException(oss.str());
+ }
+ catch (std::exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic failure when opening web service host: " << ex.what();
+ throw AppException(oss.str());
+ }
+ }
+
+ ///
+ /// Closes down communication with the service host (but wait sessions to disconnect) and make it ready for possible restart.
+ ///
+ /// Whether the call managed to close the service host when it was actively running.
+ bool WebServiceHostImpl::CloseAsync()
+ {
+ CALL_STACK_TRACE;
+
+ try
+ {
+ _ASSERTE(m_webSvcHostHandle != nullptr); // service host must be set up before use
+
+ std::lock_guard lock(m_svcStateMutex);
+
+ bool wasRunning(false);
+ WSError err;
+ HRESULT hr;
+
+ // The web service thread is still running:
+ if (m_svcThread.get_id() != std::thread::id())
+ {
+ // Ask for the service current state:
+ WS_SERVICE_HOST_STATE state;
+ auto hr = WsGetServiceHostProperty(
+ m_webSvcHostHandle,
+ WS_SERVICE_PROPERTY_HOST_STATE,
+ &state,
+ sizeof state,
+ err.GetHandle()
+ );
+ err.RaiseExceptionWhenError(hr, "WsGetServiceHostProperty", "Failed to get state of web service host", m_serviceName);
+
+ if (state == WS_SERVICE_HOST_STATE_OPENING
+ || state == WS_SERVICE_HOST_STATE_OPEN)
+ {
+ std::ostringstream oss;
+ oss << "Stopping web service \'" << m_serviceName << "\'...";
+ Logger::GetInstance().Write(oss.str(), Poco::Message::Priority::PRIO_INFORMATION);
+
+ // Close service host:
+ hr = WsCloseServiceHost(m_webSvcHostHandle, nullptr, err.GetHandle());
+ err.RaiseExceptionWhenError(hr, "WsCloseServiceHost", "Failed to close web service host", m_serviceName);
+ wasRunning = true;
+
+ oss.str("");
+ oss << "Web service \'" << m_serviceName << "\' successfully stopped";
+ Logger::GetInstance().Write(oss.str(), Poco::Message::Priority::PRIO_INFORMATION);
+ }
+
+ // Wait for thread termination:
+ if (m_svcThread.joinable())
+ m_svcThread.join();
+ }
+
+ // Reset the service host:
+ hr = WsResetServiceHost(m_webSvcHostHandle, err.GetHandle());
+ err.RaiseExceptionWhenError(hr, "WsResetServiceHost", "Failed to reset web service host", m_serviceName);
+
+ return wasRunning;
+ }
+ catch (IAppException &ex)
+ {
+ throw; // just forward exceptions known to have been already handled
+ }
+ catch (std::system_error &ex)
+ {
+ std::ostringstream oss;
+ oss << "Failed to close web service host: " << StdLibExt::GetDetailsFromSystemError(ex);
+ throw AppException(oss.str());
+ }
+ catch (std::exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic failure when closing web service host: " << ex.what();
+ throw AppException(oss.str());
+ }
+ }
+
+ ///
+ /// Closes down communication with the service host (immediately, drops clients) and make it ready for possible restart.
+ ///
+ /// Whether the call managed to abort the service host when it was actively running.
+ bool WebServiceHostImpl::AbortAsync()
+ {
+ CALL_STACK_TRACE;
+
+ try
+ {
+ _ASSERTE(m_webSvcHostHandle != nullptr); // service host must be set up before use
+
+ // First acquire lock to manage service host
+ std::lock_guard lock(m_svcStateMutex);
+
+ bool wasRunning(false);
+ WSError err;
+ HRESULT hr;
+
+ // The web service thread is sill running:
+ if (m_svcThread.get_id() != std::thread::id())
+ {
+ // Ask for the service current state:
+ WS_SERVICE_HOST_STATE state;
+ auto hr = WsGetServiceHostProperty(
+ m_webSvcHostHandle,
+ WS_SERVICE_PROPERTY_HOST_STATE,
+ &state,
+ sizeof state,
+ err.GetHandle()
+ );
+ err.RaiseExceptionWhenError(hr, "WsGetServiceHostProperty", "Failed to get state of web service host", m_serviceName);
+
+ if (state == WS_SERVICE_HOST_STATE_OPENING
+ || state == WS_SERVICE_HOST_STATE_OPEN)
+ {
+ std::ostringstream oss;
+ oss << "Stopping web service \'" << m_serviceName << "\'...";
+ Logger::GetInstance().Write(oss.str(), Poco::Message::Priority::PRIO_INFORMATION);
+
+ // Abort service host:
+ hr = WsAbortServiceHost(m_webSvcHostHandle, err.GetHandle());
+ err.RaiseExceptionWhenError(hr, "WsAbortServiceHost", "Failed to abort web service host", m_serviceName);
+
+ // Close service host:
+ hr = WsCloseServiceHost(m_webSvcHostHandle, nullptr, err.GetHandle());
+ err.RaiseExceptionWhenError(hr, "WsCloseServiceHost", "Failed to close web service host", m_serviceName);
+ wasRunning = true;
+
+ oss.str("");
+ oss << "Web service \'" << m_serviceName << "\' successfully stopped";
+ Logger::GetInstance().Write(oss.str(), Poco::Message::Priority::PRIO_INFORMATION);
+ }
+
+ // Ensure thread termination:
+ if (m_svcThread.joinable())
+ m_svcThread.join();
+ }
+
+ // Reset the service host:
+ hr = WsResetServiceHost(m_webSvcHostHandle, err.GetHandle());
+ err.RaiseExceptionWhenError(hr, "WsResetServiceHost", "Failed to reset web service host", m_serviceName);
+
+ return wasRunning;
+ }
+ catch (IAppException &ex)
+ {
+ throw; // just forward exceptions known to have been already handled
+ }
+ catch (std::system_error &ex)
+ {
+ std::ostringstream oss;
+ oss << "Failed to abort web service host: " << StdLibExt::GetDetailsFromSystemError(ex);
+ throw AppException(oss.str());
+ }
+ catch (std::exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic failure when aborting web service host: " << ex.what();
+ throw AppException(oss.str());
+ }
+ }
+
+ /////////////////////
+ // Utilities
+ /////////////////////
+
+ ///
+ /// Creates a SOAP fault from an exception (server error) and record it into rich error information.
+ ///
+ /// The exception thrown by the web service operation implementation.
+ /// Handle for the the current web service operation context.
+ /// Handle for the rich error info utility.
+ void CreateSoapFault(core::IAppException &operEx, WS_OPERATION_CONTEXT *wsOperContextHandle, WS_ERROR *wsErrorHandle)
+ {
+ CALL_STACK_TRACE;
+
+ try
+ {
+ // Get the heap from the current operation context:
+ WSError err;
+ WS_HEAP *wsHeapHandle;
+ auto hr = WsGetOperationContextProperty(
+ wsOperContextHandle,
+ WS_OPERATION_CONTEXT_PROPERTY_HEAP,
+ &wsHeapHandle,
+ sizeof wsHeapHandle,
+ err.GetHandle()
+ );
+ err.RaiseExceptionWhenError(hr, "WsGetOperationContextProperty", "Failed to retrieve heap object from web service operation context");
+
+ WSHeap heap(wsHeapHandle); // wraps the heap handle into an object
+
+ // Create an empty SOAP fault structure
+ auto fault = heap.Alloc();
+ *fault = {};
+
+ // The fault code:
+ fault->code = heap.Alloc();
+ fault->code->subCode = nullptr;
+ fault->code->value.ns = WS_XML_STRING_VALUE("http://www.w3.org/2003/05/soap-envelope");
+ fault->code->value.localName = WS_XML_STRING_VALUE("Receiver");
+
+ // Go through the nested chain of exceptions and translate their messages to unicode:
+ std::wstring_convert> transcoder;
+ std::list messages;
+ auto exPtr = &operEx;
+ while (exPtr != nullptr)
+ {
+ messages.push_back(
+ transcoder.from_bytes(exPtr->GetErrorMessage())
+ );
+ exPtr = exPtr->GetInnerException();
+ }
+
+ // The fault reasons:
+ fault->reasonCount = messages.size();
+ fault->reasons = heap.Alloc(fault->reasonCount);
+
+ // Copy the exceptions messages into the fault reasons:
+ int idx(0);
+ while (messages.empty() == false)
+ {
+ auto &msg = messages.front();
+ auto &reason = fault->reasons[idx];
+ reason.lang = WS_STRING_VALUE(L"en");
+ reason.text.length = msg.length();
+ reason.text.chars = heap.Alloc(msg.length());
+ memcpy(reason.text.chars, msg.data(), msg.length() * sizeof msg[0]);
+ messages.pop_front();
+ ++idx;
+ }
+
+ // Record the assembled SOAP fault into the error object:
+ hr = WsSetFaultErrorProperty(wsErrorHandle, WS_FAULT_ERROR_PROPERTY_FAULT, fault, sizeof *fault);
+ err.RaiseExceptionWhenError(hr, "", "Failed to record SOAP fault response into rich error information");
+ }
+ catch (IAppException &ex)
+ {
+ Logger::GetInstance().Write(operEx, Poco::Message::Priority::PRIO_ERROR);
+ Logger::GetInstance().Write(ex, Poco::Message::Priority::PRIO_CRITICAL);
+ }
+ catch (std::exception &ex)
+ {
+ Logger::GetInstance().Write(operEx, Poco::Message::Priority::PRIO_ERROR);
+ std::ostringstream oss;
+ oss << "Generic failure when assembling SOAP fault response: " << ex.what();
+ Logger::GetInstance().Write(oss.str(), Poco::Message::Priority::PRIO_CRITICAL);
+ }
+ }
+
+ }// end of namespace web
+
+}// end of namespace _3fd
\ No newline at end of file
diff --git a/3FD/WWS_API/web_impl.h b/3FD/WWS_API/web_impl.h
new file mode 100644
index 0000000..66ac765
--- /dev/null
+++ b/3FD/WWS_API/web_impl.h
@@ -0,0 +1,230 @@
+#ifndef WEB_IMPL_H // header guard
+#define WEB_IMPL_H
+
+#include
+#include "base.h"
+#include "exceptions.h"
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace _3fd
+{
+ using std::string;
+
+ namespace web
+ {
+ ///
+ /// A reusable object model capable to hold rich error information regarding a web service utilization.
+ ///
+ class WSError : notcopiable
+ {
+ private:
+
+ WS_ERROR *m_wsErrorHandle;
+
+ void Initialize();
+ void Reset();
+
+ public:
+
+ WSError();
+ ~WSError();
+
+ void RaiseExceptionWhenError(
+ HRESULT hres,
+ const char *funcName,
+ const char *message,
+ const char *svcName = nullptr);
+
+ void RaiseExceptionWhenError(
+ HRESULT hres,
+ const char *funcName,
+ const char *message,
+ const string &svcName)
+ {
+ RaiseExceptionWhenError(hres, funcName, message, svcName.c_str());
+ }
+
+ WS_ERROR *GetHandle();
+ };
+
+ ///
+ /// A heap provides precise control over memory allocation when producing or
+ /// consuming messages and when needing to allocate various other API structures.
+ ///
+ class WSHeap : notcopiable
+ {
+ private:
+
+ WS_HEAP *m_wsHeapHandle;
+ bool m_allowRelease;
+
+ public:
+
+ WSHeap(WS_HEAP *wsHeapHandle);
+ WSHeap();
+ ~WSHeap();
+
+ void Reset();
+
+ void *Alloc(size_t qtBytes);
+
+ template Type *Alloc()
+ {
+ return static_cast (Alloc(sizeof(Type)));
+ }
+
+ template Type *Alloc(size_t qtObjects)
+ {
+ _ASSERTE(qtObjects > 0);
+ return static_cast (Alloc(sizeof(Type) * qtObjects));
+ }
+
+ ///
+ /// Gets the heap handle.
+ ///
+ /// The handle for the opaque handle object.
+ WS_HEAP *GetHandle() { return m_wsHeapHandle; }
+ };
+
+ ///
+ /// Holds key information
+ ///
+ struct SvcEndpointInfo
+ {
+ string
+ portName,
+ bindingName,
+ bindingNs,
+ address;
+ };
+
+ ///
+ /// Contains several settings for a service endpoint.
+ ///
+ struct SvcEndpointsConfig
+ {
+ unsigned int
+ maxAcceptingChannels, // specifies the maximum number of concurrent channels service host will have actively accepting new connections for a given endpoint
+ maxConcurrency; // specifies the maximum number of concurrent calls that would be serviced on a session based channel
+
+ unsigned long
+ timeoutDnsResolve, // limits the amount of time (in milliseconds) that will be spent resolving the DNS name
+ timeoutSend, // limits the amount of time (in milliseconds) that will be spent sending the HTTP headers and the bytes of the message
+ timeoutReceive; // limits the amount of time (in milliseconds) that will be spent receiving the the bytes of the message
+
+ SvcEndpointsConfig() :
+ maxAcceptingChannels(1),
+ maxConcurrency(1),
+ timeoutDnsResolve(5000),
+ timeoutSend(2500),
+ timeoutReceive(2500)
+ {}
+ };
+
+ // Callback type for code automatically generated by wsutil.exe
+ template
+ using CallbackCreateWSEndpointImpl = HRESULT(*)(
+ _In_opt_ WS_HTTP_BINDING_TEMPLATE* templateValue,
+ _In_opt_ CONST WS_STRING* address,
+ _In_opt_ FuncTableStructType* functionTable,
+ _In_opt_ WS_SERVICE_SECURITY_CALLBACK authorizationCallback,
+ _In_reads_opt_(endpointPropertyCount) WS_SERVICE_ENDPOINT_PROPERTY* endpointProperties,
+ _In_ const ULONG endpointPropertyCount,
+ _In_ WS_HEAP* heap,
+ _Outptr_ WS_SERVICE_ENDPOINT** serviceEndpoint,
+ _In_opt_ WS_ERROR* error);
+
+ // Callback type that invokes code automatically generated by wsutil.exe
+ typedef HRESULT(*CallbackWrapperCreateWSEndpoint)(
+ const string &, // address
+ void *, // function table
+ WS_SERVICE_SECURITY_CALLBACK,
+ WS_SERVICE_ENDPOINT_PROPERTY *, // endpoint properties
+ size_t, // endpoint properties count
+ WSHeap &,
+ WS_SERVICE_ENDPOINT **);
+
+ ///
+ /// A template that performs some parameter translations need to call automatically generated code.
+ ///
+ template callback>
+ HRESULT CreateWSEndpoint(
+ const string &address,
+ void *functionTable,
+ WS_SERVICE_SECURITY_CALLBACK callbackSecurity,
+ WS_SERVICE_ENDPOINT_PROPERTY *endpointProps,
+ size_t endpointPropsCount,
+ web::WSHeap &heap,
+ WS_SERVICE_ENDPOINT **endpoint)
+ {
+ std::wstring_convert> transcoder;
+ auto ucs2address = transcoder.from_bytes(address);
+
+ auto wsaddr = heap.Alloc();
+ wsaddr->length = ucs2address.length();
+ wsaddr->chars = heap.Alloc(ucs2address.length());
+ memcpy(wsaddr->chars, ucs2address.data(), ucs2address.length() * sizeof ucs2address[0]);
+
+ WSError err;
+ auto hr = callback(
+ &WS_HTTP_BINDING_TEMPLATE{},
+ wsaddr,
+ static_cast (functionTable),
+ nullptr,
+ endpointProps,
+ endpointPropsCount,
+ heap.GetHandle(),
+ endpoint,
+ err.GetHandle()
+ );
+ return hr;
+ }
+
+ ///
+ /// Implements the web service host instance.
+ ///
+ class WebServiceHostImpl : notcopiable
+ {
+ private:
+
+ WS_SERVICE_HOST *m_webSvcHostHandle;
+ std::vector m_wsdContentBuffer;
+ string m_serviceName;
+ string m_wsdTargetNs;
+ std::vector m_endpointsInfo;
+ std::thread m_svcThread;
+ std::mutex m_svcStateMutex;
+ WSHeap m_svcHeap;
+
+ public:
+
+ WebServiceHostImpl();
+ ~WebServiceHostImpl();
+
+ void Setup(
+ const string &wsdFilePath,
+ const SvcEndpointsConfig &config,
+ CallbackWrapperCreateWSEndpoint createWebSvcEndpointCallback,
+ void *functionTable);
+
+ void OpenAsync();
+ bool CloseAsync();
+ bool AbortAsync();
+ };
+
+ /////////////////////
+ // Utilities
+ /////////////////////
+
+ void CreateSoapFault(core::IAppException &ex, WS_OPERATION_CONTEXT *wsOperContextHandle, WS_ERROR *wsErrorHandle);
+
+ }// end of namespace web
+
+}// end of namespace _3fd
+
+#endif // end of header guard
\ No newline at end of file
diff --git a/3FD/WWS_API/wsdl-example.wsdl b/3FD/WWS_API/wsdl-example.wsdl
new file mode 100644
index 0000000..db89a3d
--- /dev/null
+++ b/3FD/WWS_API/wsdl-example.wsdl
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/3FD/arrayofbits.h b/3FD/arrayofbits.h
new file mode 100644
index 0000000..6b87899
--- /dev/null
+++ b/3FD/arrayofbits.h
@@ -0,0 +1,73 @@
+#ifndef UTILS_ARRAYOFBITS_H // header guard
+#define UTILS_ARRAYOFBITS_H
+
+#include "base.h"
+#include "exceptions.h"
+
+#include
+
+namespace _3fd
+{
+ namespace utils
+ {
+ ///
+ /// A fixed size array of booleans stored as a single bit.
+ ///
+ class ArrayOfBits : notcopiable
+ {
+ private:
+
+ const size_t m_nBits;
+
+ uintptr_t *m_data;
+ size_t m_activatedBitsCount;
+
+ uintptr_t *GetWord(size_t bitIdx, uint32_t &bitInPos) const;
+
+ public:
+
+ ArrayOfBits(size_t nBits, bool val);
+
+ ArrayOfBits(ArrayOfBits &&ob);
+
+ ~ArrayOfBits();
+
+ ///
+ /// Gets the amount of bits the array was set to store.
+ ///
+ /// How many bits the array was set to store upon construction.
+ size_t Size() const { return m_nBits; }
+
+ ///
+ /// Gets how many bits in the array are currently activated.
+ ///
+ /// The amount of activated bits in the array.
+ size_t GetActivatedCount() const { return m_activatedBitsCount; }
+
+ ///
+ /// Determines whether there is any activated bit in the array.
+ ///
+ ///
+ /// true if there is at least one activated bit in the array, otherwise, false.
+ ///
+ bool IsAnyActivated() const { return m_activatedBitsCount > 0; }
+
+ bool operator[](size_t bitIdx) const;
+
+ size_t FindFirstActivated() const;
+
+ size_t FindFirstDeactivated() const;
+
+ size_t FindLastActivated() const;
+
+ size_t FindLastDeactivated() const;
+
+ void Activate(size_t bitIdx);
+
+ void Deactivate(size_t bitIdx);
+ };
+
+ }// end of namespace utils
+}// end of namespace _3fd
+
+#endif // end of header guard
diff --git a/3FD/base.h b/3FD/base.h
new file mode 100644
index 0000000..511fdd3
--- /dev/null
+++ b/3FD/base.h
@@ -0,0 +1,28 @@
+#ifndef BASE_H
+#define BASE_H
+
+namespace _3fd
+{
+ ////////////////////////////////
+ // Utility Base Classes
+ ////////////////////////////////
+
+ ///
+ /// If a class derives NotCopiable, it cannot be copied.
+ /// If you try to do that, an error is reported during the compilation.
+ ///
+ class NotCopiable
+ {
+ private:
+
+ NotCopiable(const NotCopiable &) {}
+
+ public:
+
+ NotCopiable() {}
+ };
+
+# define notcopiable public ::_3fd::NotCopiable
+}
+
+#endif // end of header guard
diff --git a/3FD/callstacktracer.cpp b/3FD/callstacktracer.cpp
new file mode 100644
index 0000000..f4d9a99
--- /dev/null
+++ b/3FD/callstacktracer.cpp
@@ -0,0 +1,215 @@
+#include "stdafx.h"
+#include "callstacktracer.h"
+#include "configuration.h"
+#include "exceptions.h"
+#include
+
+namespace _3fd
+{
+ namespace core
+ {
+ ///////////////////////////////////////
+ // CallStack Class
+ ///////////////////////////////////////
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The log initial capacity.
+ CallStack::CallStack(size_t logInitialCap)
+ {
+ m_stackFrames.reserve(logInitialCap);
+ }
+
+ ///
+ /// Registers the frame.
+ ///
+ /// The file name.
+ /// The line number.
+ /// The function of the frame.
+ void CallStack::RegisterFrame(const char *file,
+ unsigned long line,
+ const char *function) throw()
+ {
+ m_stackFrames.push_back(
+ Frame(file, function, line)
+ );
+ }
+
+ ///
+ /// Pops the last added stack frame.
+ ///
+ /// Whether the stack log is empty after popping an entry from it.
+ bool CallStack::PopStackFrameEntry() throw()
+ {
+ m_stackFrames.pop_back();
+ return m_stackFrames.empty();
+ }
+
+ ///
+ /// Gets the call stack trace report.
+ ///
+ /// A string which shows the current stack trace.
+ string CallStack::GetReport()
+ {
+ std::ostringstream oss;
+
+ for(int index = 0 ; index < m_stackFrames.size() ; ++index)
+ {
+ auto &frame = m_stackFrames[index];
+ oss << frame.file << " (" << frame.line << ") @ " << frame.function;
+
+ if(index + 1 != m_stackFrames.size())
+ oss << "; ";
+ else
+ oss << ';';
+ }
+
+ return oss.str();
+ }
+
+
+ //////////////////////////////////
+ // CallStackTracer Class
+ //////////////////////////////////
+
+ thread_local_def CallStack * CallStackTracer::callStack(nullptr);
+
+ CallStackTracer * CallStackTracer::uniqueObject(nullptr);
+
+ std::mutex CallStackTracer::singleInstanceCreationMutex;
+
+ ///
+ /// Creates the singleton instance.
+ ///
+ /// A pointer to the newly created singleton of
+ CallStackTracer * CallStackTracer::CreateInstance()
+ {
+ try
+ {
+ std::lock_guard lock(singleInstanceCreationMutex);
+
+ if(uniqueObject == nullptr)
+ uniqueObject = new CallStackTracer ();
+
+ return uniqueObject;
+ }
+ catch(IAppException &)
+ {
+ throw; // just forward exceptions known to have been previously handled
+ }
+ catch(std::system_error &ex)
+ {
+ std::ostringstream oss;
+ oss << "Failed to acquire lock when creating the call stack tracer: " << core::StdLibExt::GetDetailsFromSystemError(ex);
+ throw AppException(oss.str());
+ }
+ catch(std::bad_alloc &)
+ {
+ throw AppException("Failed to allocate memory to create the call stack tracer");
+ }
+ }
+
+ ///
+ /// Gets the singleton instance.
+ ///
+ ///
+ CallStackTracer & CallStackTracer::GetInstance()
+ {
+ // If there is no object, create one and returns a reference to it. If there is an object, return its reference.
+ if(uniqueObject != nullptr)
+ return *uniqueObject;
+ else
+ return *CreateInstance();
+ }
+
+ ///
+ /// Shutdowns the call stack tracer instance releasing all associated resources.
+ ///
+ void CallStackTracer::Shutdown()
+ {
+ delete uniqueObject; // Call the destructor
+ uniqueObject = nullptr;
+ }
+
+ ///
+ /// Registers the current thread to have its stack traced.
+ ///
+ ///
+ void CallStackTracer::RegisterThread()
+ {
+ if(callStack == nullptr)
+ {
+ try
+ {
+ callStack = new CallStack (
+ AppConfig::GetSettings().framework.stackTracing.stackLogInitialCap
+ );
+ }
+ catch(IAppException &)
+ {
+ throw; // just forward exceptions known to have been previously handled
+ }
+ catch(std::exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic failure when registering thread for call stack tracing: " << ex.what();
+ throw AppException(oss.str());
+ }
+ }
+ }
+
+ ///
+ /// Unregisters the current thread for stack tracing.
+ ///
+ void CallStackTracer::UnregisterThread()
+ {
+ if(callStack != nullptr)
+ {
+ delete callStack;
+ callStack = nullptr;
+ }
+ }
+
+ ///
+ /// Tracks the call.
+ ///
+ /// The file name.
+ /// The line number.
+ /// The function name.
+ void CallStackTracer::TrackCall(const char *file,
+ unsigned long line,
+ const char *function)
+ {
+ if(callStack != nullptr)
+ callStack->RegisterFrame(file, line, function);
+ else
+ {
+ RegisterThread();
+ callStack->RegisterFrame(file, line, function);
+ }
+ }
+
+ ///
+ /// Pops the last added stack frame.
+ /// If the stack become empty, this object will be destroyed.
+ ///
+ void CallStackTracer::PopStackFrameEntry() throw()
+ {
+ if(callStack->PopStackFrameEntry() == false)
+ return;
+ else
+ UnregisterThread();
+ }
+
+ ///
+ /// Gets the stack frame report.
+ ///
+ /// A text encoded report of the stack frame.
+ string CallStackTracer::GetStackReport() const
+ {
+ return callStack->GetReport();
+ }
+
+ }// end of namespace core
+}// end of namespace _3fd
diff --git a/3FD/callstacktracer.h b/3FD/callstacktracer.h
new file mode 100644
index 0000000..920ea33
--- /dev/null
+++ b/3FD/callstacktracer.h
@@ -0,0 +1,135 @@
+#ifndef CALLSTACKTRACER_H
+#define CALLSTACKTRACER_H
+
+#include "base.h"
+#include "preprocessing.h"
+#include
+#include
+#include
+
+namespace _3fd
+{
+ using std::string;
+
+ namespace core
+ {
+ /////////////////////////////////////////
+ // Early class declarations
+ /////////////////////////////////////////
+
+ class StackTracer;
+ class StackDeactivationTrigger;
+
+
+ ///
+ /// Stores an history of procedure call events
+ ///
+ class CallStack : notcopiable
+ {
+ private:
+
+ ///
+ /// Represents a stack frame traced event
+ ///
+ struct Frame
+ {
+ const char *file;
+ const char *function;
+ unsigned long line;
+
+ Frame(const char *p_file,
+ const char *p_function,
+ unsigned long p_line)
+ : file(p_file), function(p_function), line(p_line)
+ {}
+ };
+
+ std::vector m_stackFrames;
+
+ public:
+
+ CallStack(size_t logInitialCap);
+
+ void RegisterFrame(const char *file,
+ unsigned long line,
+ const char *function) throw();
+
+ bool PopStackFrameEntry() throw();
+
+ string GetReport();
+ };
+
+
+ ///
+ /// A class for the call stack tracer, which is operated through macros defined on 'preprocessing.h'
+ ///
+ class CallStackTracer : notcopiable
+ {
+ private:
+
+ thread_local_decl static CallStack *callStack;
+
+ static std::mutex singleInstanceCreationMutex;
+ static CallStackTracer *uniqueObject;
+ static CallStackTracer *CreateInstance();
+
+ ///
+ /// Prevents a default instance of the class from being created.
+ ///
+ CallStackTracer() {}
+
+ void RegisterThread();
+ void UnregisterThread();
+
+ public:
+
+ static CallStackTracer &GetInstance();
+
+ static void Shutdown();
+
+ ///
+ /// Determines whether call stack tracing is ready for the calling thread.
+ ///
+ /// 'true' if available, otherwise, 'false'.
+ static bool IsReady()
+ {
+ /* This method is necessary to prevent things such as an exception attempting to access CST when it is not started yet,
+ or any other piece of code trying to access the framework configurations before they were loaded. These situations might
+ take place if the initialization of the frameowrk core features runs into an error, when neither CST is ready or/nor the
+ configurations are available. In these cases, an exception still has to be used in order to signalize the failure, but it
+ cannot make use of such 'services'.
+
+ Obs.: If the exception tries to invoke the RTM to get trace information, the framework initialization is requested again recursively,
+ leading to a stack overflow. */
+ return callStack != nullptr;
+ }
+
+ void TrackCall(const char *file,
+ unsigned long line,
+ const char *function);
+
+ void PopStackFrameEntry() throw();
+
+ string GetStackReport() const;
+ };
+
+ ///
+ /// This class is a trick to automatize the call stack tracing using scope finalizations.
+ ///
+ class StackDeactivationTrigger
+ {
+ public:
+
+ ///
+ /// Finalizes an instance of the class.
+ ///
+ ~StackDeactivationTrigger()
+ {
+ CallStackTracer::GetInstance().PopStackFrameEntry();
+ }
+ };
+
+ }// end of namespace core
+}// end of namespace _3fd
+
+#endif // header guard
diff --git a/3FD/config3fd-template.xml b/3FD/config3fd-template.xml
new file mode 100644
index 0000000..fd89277
--- /dev/null
+++ b/3FD/config3fd-template.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+ true
+ 10
+
+ 365
+
+ 2048
+
+
+
+
+
+ false
+
+
+
+ 64
+
+
+ 64
+ 100
+
+ 128
+ 1.0
+
+
+ 8
+
+ 0.7
+
+
+
+
+ 128
+ 5120
+
+
+
+ true
+
+
+
+
+
+
\ No newline at end of file
diff --git a/3FD/configuration.cpp b/3FD/configuration.cpp
new file mode 100644
index 0000000..4b07219
--- /dev/null
+++ b/3FD/configuration.cpp
@@ -0,0 +1,376 @@
+#include "stdafx.h"
+#include "configuration.h"
+#include "exceptions.h"
+
+#ifdef _3FD_PLATFORM_WINRT
+# include "utils_winrt.h"
+#endif
+
+#ifdef _3FD_POCO_SUPPORT
+# include "Poco/AutoPtr.h"
+# include "Poco/Util/XMLConfiguration.h"
+#endif
+
+#include
+#include
+#include
+#include
+
+#if defined __linux__ || defined __unix__ // POSIX:
+# include
+#endif
+
+namespace _3fd
+{
+ using std::ostringstream;
+
+ namespace core
+ {
+ std::unique_ptr AppConfig::uniqueObject;
+
+ std::mutex AppConfig::initializationMutex;
+
+ ///
+ /// Gets the instance already initialized.
+ ///
+ /// The unique instance of already initialized.
+ AppConfig & AppConfig::GetInstanceInitialized()
+ {
+ static bool initialized(false);
+
+ if(initialized)
+ return *uniqueObject;
+ else
+ {
+ try
+ {
+ std::lock_guard lock(initializationMutex);
+
+ if(initialized == false)
+ {
+ if (!uniqueObject)
+ uniqueObject.reset(new AppConfig());
+
+ uniqueObject->Initialize();
+ initialized = true;
+ }
+
+ return *uniqueObject;
+ }
+ catch(core::IAppException &)
+ {
+ throw; // just forward the exceptions regarding error that are known to have been previously handled
+ }
+ catch(std::system_error &ex)
+ {
+ std::ostringstream oss;
+ oss << "Failed to acquire lock before loading framework configurations: " << core::StdLibExt::GetDetailsFromSystemError(ex);
+ throw AppException(oss.str());
+ }
+ catch (std::exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic failure when initializing framework configurations: " << ex.what();
+ throw AppException(oss.str());
+ }
+ }
+ }
+
+ ///
+ /// Gets the application identifier.
+ ///
+ /// The application ID, which is the name of the current executable.
+ const string & AppConfig::GetApplicationId()
+ {
+ return GetInstanceInitialized().m_applicationId;
+ }
+
+ ///
+ /// Gets the settings.
+ ///
+ /// A reference to the hierarchy of settings loaded from the XML configuration file.
+ const AppConfig::Tree & AppConfig::GetSettings()
+ {
+ return GetInstanceInitialized().settings;
+ }
+
+#if _WIN32 // Microsoft Windows:
+
+# ifdef _3FD_PLATFORM_WIN32API // Windows Desktop Apps only:
+
+ ///
+ /// Gets an ID for the running application, invoking a system call.
+ ///
+ /// Where to store the retrieved file path for the running application.
+ /// A text ID (UTF-8 encoded) for the running application.
+ static string CallSysForApplicationId(string &appFilePath)
+ {
+ std::array chBuffer;
+
+ if (GetModuleFileNameW(nullptr, chBuffer.data(), chBuffer.size()) == 0)
+ throw AppException("It was not possible to get the full file name of the executable.", "Windows API: GetModuleFileName");
+
+ try
+ {
+ std::wstring_convert> converter;
+ appFilePath = converter.to_bytes(chBuffer.data());
+ }
+ catch (std::exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic failures when getting the file name of the framework configuration file: " << ex.what();
+ throw AppException(oss.str());
+ }
+
+ // The application ID is the name of the executable without the extension:
+ return string(appFilePath.begin() + appFilePath.rfind('\\') + 1,
+ appFilePath.begin() + appFilePath.rfind('.'));
+ }
+
+# elif defined _3FD_PLATFORM_WINRT // Store Apps only:
+
+ ///
+ /// Gets an ID for the running application, invoking a system call.
+ ///
+ /// Where to store the retrieved file path for the running application.
+ /// A text ID (UTF-8 encoded) for the running application.
+ static string CallSysForApplicationId(Platform::String ^&appFilePath)
+ {
+ auto curPackageIdName = Windows::ApplicationModel::Package::Current->Id->Name;
+
+ try
+ {
+ appFilePath = curPackageIdName + L".3fd.config";
+ std::wstring_convert> converter;
+ return converter.to_bytes(curPackageIdName->Data());
+ }
+ catch (std::exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic failure when getting the file name of the framework configuration file: " << ex.what();
+ throw AppException(oss.str());
+ }
+ }
+
+# endif
+
+#elif defined __linux__ || defined __unix__ // POSIX only:
+
+ ///
+ /// Gets an ID for the running application, invoking a system call.
+ ///
+ /// Where to store the retrieved file path for the running application.
+ /// A text ID (UTF-8 encoded) for the running application.
+ static string CallSysForApplicationId(string &appFilePath)
+ {
+ std::array chBuffer;
+ auto rval = readlink("/proc/self/exe", chBuffer.data(), chBuffer.size());
+
+ if (rval != -1)
+ {
+ // The application ID is the name of the executable:
+ chBuffer[rval] = 0;
+ appFilePath = string(chBuffer.begin(), chBuffer.begin() + rval);
+ return string(appFilePath.begin() + appFilePath.rfind('/') + 1, appFilePath.end());
+ }
+ else
+ throw std::system_error(std::make_error_code(static_cast(errno)), "POSIX API: readlink");
+ }
+
+#endif
+
+#ifdef _3FD_POCO_SUPPORT
+
+ ///
+ /// Initializes this instance with data from the XML configuration file.
+ ///
+ void AppConfig::Initialize()
+ {
+ try
+ {
+ string appFilePath;
+ m_applicationId = CallSysForApplicationId(appFilePath);
+
+ using Poco::AutoPtr;
+ using Poco::Util::XMLConfiguration;
+
+ // Load the configurations in the file
+ AutoPtr config(new XMLConfiguration(appFilePath + ".3fd.config"));
+
+ settings.common.log.purgeAge = config->getInt("common.log.purgeAge", 30);
+ settings.common.log.purgeCount = config->getInt("common.log.purgeCount", 16);
+ settings.common.log.writeToConsole = config->getBool("common.log.writeToConsole", false);
+
+ settings.framework.dependencies.opencl = config->getBool("framework.dependencies.opencl", false);
+
+ settings.framework.stackTracing.stackLogInitialCap = config->getInt("framework.stackTracing.stackLogInitialCap", 32);
+
+ settings.framework.gc.msgQueueInitCap = config->getInt("framework.gc.msgQueueInitCap", 64);
+ settings.framework.gc.msgLoopSleepTimeoutMilisecs = config->getInt("framework.gc.msgLoopSleepTimeoutMilisecs", 100);
+ settings.framework.gc.memBlocksMemPool.initialSize = config->getInt("framework.gc.memBlocksMemPool.initialSize", 128);
+ settings.framework.gc.memBlocksMemPool.growingFactor = static_cast (config->getDouble("framework.gc.memBlocksMemPool.growingFactor", 1.0));
+ settings.framework.gc.sptrObjectsHashTable.initialSizeLog2 = config->getInt("framework.gc.sptrObjectsHashTable.initialSizeLog2", 8);
+ settings.framework.gc.sptrObjectsHashTable.loadFactorThreshold = static_cast (config->getDouble("framework.gc.sptrObjectsHashTable.loadFactorThreshold", 0.7));
+
+# ifdef _3FD_OPENCL_SUPPORT
+ settings.framework.opencl.maxSourceCodeLineLength = config->getInt("framework.opencl.maxSourceCodeLineLength", 128);
+ settings.framework.opencl.maxBuildLogSize = config->getInt("framework.opencl.maxBuildLogSize", 5120);
+# endif
+
+# ifdef _3FD_ESENT_SUPPORT
+ settings.framework.isam.useWindowsFileCache = config->getBool("framework.isam.useWindowsFileCache", true);
+# endif
+
+ }
+ catch (std::system_error &ex)
+ {
+ std::ostringstream oss;
+ oss << "Failed to initialize the application settings: " << ex.what();
+ throw AppException(oss.str());
+ }
+ catch (Poco::Exception &ex)
+ {
+ ostringstream oss;
+ oss << "POCO C++ library reported: " << ex.message();
+ throw AppException("Failed to initialize the application settings", oss.str());
+ }
+ }
+
+#elif defined _3FD_PLATFORM_WINRT // Store Apps only:
+
+ ///
+ /// Helper function to get a text value of configuration inside a DOM node.
+ ///
+ /// The node of the section where to look for the configuration.
+ /// The xpath for the configuration, starting from the right section.
+ /// The default value.
+ /// The configuration value.
+ static string GetString(
+ Windows::Data::Xml::Dom::IXmlNode ^nodeSection,
+ Platform::String ^xpathNodeConfig,
+ const string &defaultValue)
+ {
+ if (nodeSection == nullptr)
+ return defaultValue;
+
+ auto nodeConfig = nodeSection->SelectSingleNode(xpathNodeConfig);
+ if (nodeConfig == nullptr)
+ return defaultValue;
+
+ auto innerText = nodeConfig->InnerText;
+ if (innerText->IsEmpty() == false)
+ {
+ std::wstring_convert> converter;
+ return converter.to_bytes(innerText->Data());
+ }
+ else
+ return defaultValue;
+ }
+
+ ///
+ /// Helper function to get an integer value of configuration inside a DOM node.
+ ///
+ /// The node of the section where to look for the configuration.
+ /// The xpath for the configuration, starting from the right section.
+ /// The default value.
+ /// The configuration value.
+ static int GetInteger(
+ Windows::Data::Xml::Dom::IXmlNode ^nodeSection,
+ Platform::String ^xpathNodeConfig,
+ int defaultValue)
+ {
+ if (nodeSection == nullptr)
+ return defaultValue;
+
+ auto nodeConfig = nodeSection->SelectSingleNode(xpathNodeConfig);
+ if (nodeConfig == nullptr)
+ return defaultValue;
+
+ auto innerText = nodeConfig->InnerText->Data();
+ long parsedVal = wcstol(innerText, nullptr, 10);
+ return static_cast (parsedVal > 0 ? parsedVal : defaultValue);
+ }
+
+ ///
+ /// Helper function to get a floating point value of configuration inside a DOM node.
+ ///
+ /// The node of the section where to look for the configuration.
+ /// The xpath for the configuration, starting from the right section.
+ /// The default value.
+ /// The configuration value.
+ static float GetFloat(
+ Windows::Data::Xml::Dom::IXmlNode ^nodeSection,
+ Platform::String ^xpathNodeConfig,
+ float defaultValue)
+ {
+ if (nodeSection == nullptr)
+ return defaultValue;
+
+ auto nodeConfig = nodeSection->SelectSingleNode(xpathNodeConfig);
+ if (nodeConfig == nullptr)
+ return defaultValue;
+
+ auto innerText = nodeConfig->InnerText->Data();
+ long parsedVal = wcstod(innerText, nullptr);
+ return parsedVal > 0.0 ? parsedVal : defaultValue;
+ }
+
+ ///
+ /// Initializes this instance with data from the XML configuration file.
+ ///
+ void AppConfig::Initialize()
+ {
+ try
+ {
+ Platform::String ^appFilePath;
+ m_applicationId = CallSysForApplicationId(appFilePath);
+
+ auto file = utils::WinRTExt::WaitForAsync(
+ Windows::ApplicationModel::Package::Current->InstalledLocation->GetFileAsync(appFilePath)
+ );
+
+ auto config = utils::WinRTExt::WaitForAsync(
+ Windows::Data::Xml::Dom::XmlDocument::LoadFromFileAsync(file)
+ );
+
+ // Logging options:
+ auto root = config->SelectSingleNode(L"/root");
+ auto node = root->SelectSingleNode(L"./common/log");
+ settings.common.log.sizeLimit = GetInteger(node, L"./sizeLimit", 2048);
+
+ // Stack tracing options:
+ auto framework = root->SelectSingleNode(L"./framework");
+ node = framework->SelectSingleNode(L"./stackTracing");
+ settings.framework.stackTracing.stackLogInitialCap = GetInteger(node, L"./stackLogInitialCap", 32);
+
+ // Garbage collector options:
+ auto nodeGC = framework->SelectSingleNode(L"./gc");
+ settings.framework.gc.msgQueueInitCap = GetInteger(nodeGC, L"./msgQueueInitCap", 64);
+ settings.framework.gc.msgLoopSleepTimeoutMilisecs = GetInteger(nodeGC, L"./msgLoopSleepTimeoutMilisecs", 100);
+
+ node = nodeGC->SelectSingleNode(L"./memBlocksMemPool");
+ settings.framework.gc.memBlocksMemPool.initialSize = GetInteger(node, L"./initialSize", 128);
+ settings.framework.gc.memBlocksMemPool.growingFactor = GetFloat(node, L"./growingFactor", 1.0F);
+
+ node = nodeGC->SelectSingleNode(L"./sptrObjectsHashTable");
+ settings.framework.gc.sptrObjectsHashTable.initialSizeLog2 = GetInteger(node, L"./initialSizeLog2", 8);
+ settings.framework.gc.sptrObjectsHashTable.loadFactorThreshold = GetFloat(node, L"./loadFactorThreshold", 0.7F);
+ }
+ catch (Platform::Exception ^ex)
+ {
+ ostringstream oss;
+ oss << "Windows Runtime library reported: " << WWAPI::GetDetailsFromWinRTEx(ex);
+ throw AppException("Failed to initialize the application settings", oss.str());
+ }
+ catch (std::exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic failure when initializing the application settings: " << ex.what();
+ throw AppException(oss.str());
+ }
+ }
+
+#endif
+
+ }// end of namespace core
+}// end of namespace _3fd
diff --git a/3FD/configuration.h b/3FD/configuration.h
new file mode 100644
index 0000000..19e883b
--- /dev/null
+++ b/3FD/configuration.h
@@ -0,0 +1,114 @@
+#ifndef CONFIGURATION_H
+#define CONFIGURATION_H
+
+#include "preprocessing.h"
+#include
+#include
+#include
+#include
+
+namespace _3fd
+{
+ using std::string;
+
+ namespace core
+ {
+ ///
+ /// A singleton that holds the application settings.
+ ///
+ class AppConfig
+ {
+ private:
+
+ struct Tree
+ {
+ // Used by both application and framework:
+ struct
+ {
+ struct
+ {
+#ifdef _3FD_POCO_SUPPORT // For POCO C++ logging facilities:
+ int purgeAge;
+ int purgeCount;
+ bool writeToConsole;
+#elif defined _3FD_PLATFORM_WINRT
+ int sizeLimit;
+#endif
+ } log;
+ } common;
+
+ // Required by the framework and for its exclusive use:
+ struct
+ {
+ struct
+ {
+#ifdef _3FD_OPENCL_SUPPORT
+ bool opencl;
+#endif
+ } dependencies;
+
+ struct
+ {
+ int stackLogInitialCap;
+ } stackTracing;
+
+ struct
+ {
+ int msgQueueInitCap;
+ int msgLoopSleepTimeoutMilisecs;
+
+ struct
+ {
+ int initialSize;
+ float growingFactor;
+ } memBlocksMemPool;
+
+ struct
+ {
+ int initialSizeLog2;
+ float loadFactorThreshold;
+ } sptrObjectsHashTable;
+ } gc;
+
+#ifdef _3FD_OPENCL_SUPPORT
+ struct
+ {
+ int maxSourceCodeLineLength;
+ int maxBuildLogSize;
+ } opencl;
+#endif
+
+#ifdef _3FD_ESENT_SUPPORT
+ struct
+ {
+ bool useWindowsFileCache;
+ } isam;
+#endif
+ } framework;
+
+ struct
+ {
+ /* HERE YOU CAN INSERT YOUR OWN STRUCTURES FOR NEW KEYS IN THE XML CONFIGURATION FILE */
+ } application;
+ } settings;
+
+ string m_applicationId;
+
+ static std::unique_ptr uniqueObject;
+ static std::mutex initializationMutex;
+
+ static AppConfig &GetInstanceInitialized();
+
+ void Initialize();
+
+ AppConfig() {} // empty private constructor
+
+ public:
+
+ static const string &GetApplicationId();
+ static const Tree &GetSettings();
+ };
+ }
+}
+
+#endif // end of header guard
diff --git a/3FD/dependencies.cpp b/3FD/dependencies.cpp
new file mode 100644
index 0000000..ef9863a
--- /dev/null
+++ b/3FD/dependencies.cpp
@@ -0,0 +1,132 @@
+#include "stdafx.h"
+#include "configuration.h"
+#include "dependencies.h"
+#include "exceptions.h"
+
+#if defined __linux__ || defined __unix__ // POSIX only:
+# include
+#endif
+
+namespace _3fd
+{
+ namespace core
+ {
+ std::unique_ptr Dependencies::singleInstancePtr;
+ std::mutex Dependencies::singleInstanceCreationMutex;
+
+#ifdef _3FD_PLATFORM_WIN32API
+
+ ///
+ /// Prevents a default instance of the class from being created.
+ ///
+ Dependencies::Dependencies() :
+ m_openclDllHandle(nullptr),
+ OpenCLDllHandle(m_openclDllHandle)
+ {
+ if (AppConfig::GetSettings().framework.dependencies.opencl)
+ {
+ m_openclDllHandle = ::LoadLibraryW(L"OpenCL.dll");
+
+ if (m_openclDllHandle == nullptr)
+ throw AppException("Could not load OpenCL.dll", "Windows API: LoadLibrary");
+ }
+ }
+
+ ///
+ /// Finalizes an instance of the class.
+ ///
+ Dependencies::~Dependencies()
+ {
+ if (m_openclDllHandle != nullptr)
+ FreeLibrary(m_openclDllHandle);
+ }
+
+#elif defined __linux__
+
+ ///
+ /// Prevents a default instance of the class from being created.
+ ///
+ Dependencies::Dependencies() :
+ m_openclDllHandle(nullptr),
+ OpenCLDllHandle(m_openclDllHandle)
+ {
+ if (AppConfig::GetSettings().framework.dependencies.opencl)
+ {
+ m_openclDllHandle = dlopen("libOpenCL.so", RTLD_LAZY);
+
+ if (m_openclDllHandle == nullptr)
+ {
+ std::ostringstream oss;
+
+ auto errdesc = dlerror();
+ if (errdesc != nullptr)
+ oss << errdesc << " - POSIX API: dlopen";
+ else
+ oss << "POSIX API: dlopen";
+
+ throw AppException("Could not load OpenCL library", oss.str());
+ }
+ }
+ }
+
+ ///
+ /// Finalizes an instance of the class.
+ ///
+ Dependencies::~Dependencies()
+ {
+ if (m_openclDllHandle != nullptr)
+ dlclose(m_openclDllHandle);
+ }
+
+#else
+
+ ///
+ /// Prevents a default instance of the class from being created.
+ ///
+ Dependencies::Dependencies()
+ {
+ }
+
+ ///
+ /// Finalizes an instance of the class.
+ ///
+ Dependencies::~Dependencies()
+ {
+ }
+
+#endif
+
+ ///
+ /// Gets the singleton .
+ ///
+ /// The unique instance
+ Dependencies & Dependencies::Get()
+ {
+ if(singleInstancePtr)
+ return *singleInstancePtr;
+ else
+ {
+ try
+ {
+ std::lock_guard lock(singleInstanceCreationMutex);
+
+ if(singleInstancePtr.get() == nullptr)
+ singleInstancePtr.reset(new Dependencies ());
+
+ return *singleInstancePtr;
+ }
+ catch(std::system_error &ex)
+ {
+ std::ostringstream oss;
+ oss << "Failed to acquire lock when instantiating the dependencies manager: " << core::StdLibExt::GetDetailsFromSystemError(ex);
+ throw core::AppException(oss.str());
+ }
+ catch(std::bad_alloc &)
+ {
+ throw core::AppException("Failed to allocate memory for the dependencies manager.");
+ }
+ }
+ }
+
+ }// end of namespace core
+}// end of namespace _3fd
diff --git a/3FD/dependencies.h b/3FD/dependencies.h
new file mode 100644
index 0000000..981c2df
--- /dev/null
+++ b/3FD/dependencies.h
@@ -0,0 +1,43 @@
+#include "base.h"
+#include
+#include
+
+#ifdef _WIN32 // Microsoft Windows:
+# include
+#else // POSIX:
+# define HINSTANCE void *
+#endif
+
+namespace _3fd
+{
+ namespace core
+ {
+ ///
+ /// Takes care of the framework's DLL dependencies.
+ ///
+ class Dependencies : notcopiable
+ {
+ private:
+
+ static std::unique_ptr singleInstancePtr;
+ static std::mutex singleInstanceCreationMutex;
+
+ Dependencies();
+
+ public:
+
+ ~Dependencies(); // must be public so the 'unique_ptr<>' holding the single object can destroy it
+
+ // Get the singleton instance.
+ static Dependencies &Get();
+
+#ifdef _3FD_OPENCL_SUPPORT
+ private:
+ HINSTANCE m_openclDllHandle;
+
+ public:
+ HINSTANCE &OpenCLDllHandle;
+#endif
+ };
+ }
+}
diff --git a/3FD/exceptions.cpp b/3FD/exceptions.cpp
new file mode 100644
index 0000000..c2ef585
--- /dev/null
+++ b/3FD/exceptions.cpp
@@ -0,0 +1,73 @@
+#include "stdafx.h"
+#include "exceptions.h"
+#include
+#include
+
+namespace _3fd
+{
+ namespace core
+ {
+ ///////////////////////////////////////
+ // StdLibExt Class
+ ///////////////////////////////////////
+
+ ///
+ /// Gets the details from a system error.
+ ///
+ /// The system error.
+ /// A string with a detailed description of the given system error.
+ string StdLibExt::GetDetailsFromSystemError(std::system_error &ex)
+ {
+ std::ostringstream oss;
+ oss << ex.code().category().name() << " / " << ex.code().message();
+ return oss.str();
+ }
+
+ ///
+ /// Gets the details from a future error.
+ ///
+ /// The future error.
+ /// A string with a detailed description of the given future error.
+ string StdLibExt::GetDetailsFromFutureError(std::future_error &ex)
+ {
+ std::ostringstream oss;
+ oss << ex.code().category().name() << " / " << ex.code().message();
+ return oss.str();
+ }
+
+#ifdef _WIN32
+
+ ///////////////////////////////////////
+ // WWAPI Class
+ ///////////////////////////////////////
+
+ ///
+ /// Get a description label for an HRESULT code.
+ ///
+ /// The HRESULT code.
+ /// A label with a brief description of the code.
+ string WWAPI::GetHResultLabel(HRESULT errCode)
+ {
+ std::ostringstream oss;
+ oss << "HRESULT error code = 0x" << std::hex << errCode << std::flush;
+ return oss.str();
+ }
+
+# ifdef _3FD_PLATFORM_WINRT // Store Apps only:
+ ///
+ /// Gets the details from a WinRT exception.
+ ///
+ /// The exception handle.
+ /// The details about the exception.
+ string WWAPI::GetDetailsFromWinRTEx(Platform::Exception ^ex)
+ {
+ std::wstring_convert> transcoder;
+ std::ostringstream oss;
+ oss << "HRESULT error code = 0x" << std::hex << ex->HResult << ", " << transcoder.to_bytes(ex->Message->Data()) << std::flush;
+ return oss.str();
+ }
+# endif
+
+#endif
+ }// end of namespace core
+}// end of namespace _3fd
diff --git a/3FD/exceptions.h b/3FD/exceptions.h
new file mode 100644
index 0000000..4c0adf4
--- /dev/null
+++ b/3FD/exceptions.h
@@ -0,0 +1,173 @@
+#ifndef EXCEPTIONS_H
+#define EXCEPTIONS_H
+
+#include "callstacktracer.h"
+#include
+#include
+#include
+#include
+
+namespace _3fd
+{
+ using std::string;
+
+ namespace core
+ {
+ ///
+ /// Aggregates extension functions that work on objects of the C++ Standard Library.
+ ///
+ class StdLibExt
+ {
+ public:
+
+ static string GetDetailsFromSystemError(std::system_error &ex);
+
+ static string GetDetailsFromFutureError(std::future_error &ex);
+ };
+
+#ifdef _WIN32
+ ///
+ /// Aggregates extension functions that work on types/objects of the Windows API
+ ///
+ class WWAPI
+ {
+ public:
+
+ static string GetHResultLabel(HRESULT errCode);
+
+# ifdef _3FD_PLATFORM_WINRT
+ static string GetDetailsFromWinRTEx(Platform::Exception ^ex);
+# endif
+ };
+#endif
+
+ ///
+ /// An interface that encompasses all type of exceptions dealt by this application.
+ ///
+ class IAppException
+ {
+ public:
+
+ virtual ~IAppException() {}
+ virtual IAppException *Move() = 0;
+ virtual IAppException *GetInnerException() const = 0;
+ virtual string GetErrorMessage() const = 0;
+ };
+
+ ///
+ /// A template used to wrap different types of exceptions under the same interface.
+ ///
+ template
+ class AppException : public IAppException, public StdExType
+ {
+ private:
+
+ string m_details;
+ string m_cst;
+ IAppException *m_innerEx;
+
+ ///
+ /// Moves this instance exporting the resources to a new object dynamically allocated.
+ ///
+ /// A new exception object built from the resources of this object.
+ virtual AppException *Move() override { return new AppException(std::move(*this)); }
+
+ ///
+ /// Gets the inner exception.
+ ///
+ virtual IAppException *GetInnerException() const override { return m_innerEx; }
+
+ public:
+
+ template
+ AppException(StrType &&what) :
+ StdExType(std::forward(what)),
+ m_innerEx(nullptr)
+ {
+# ifdef ENABLE_3FD_CST
+ if(CallStackTracer::IsReady())
+ m_cst = CallStackTracer::GetInstance().GetStackReport();
+# endif
+ }
+
+ template
+ AppException(StrType &&what, IAppException &innerEx) :
+ StdExType(std::forward(what)),
+ m_innerEx(innerEx.Move())
+ {
+# ifdef ENABLE_3FD_CST
+ if(CallStackTracer::IsReady())
+ m_cst = CallStackTracer::GetInstance().GetStackReport();
+# endif
+ }
+
+ template
+ AppException(StrType1 &&what, StrType2 &&details) :
+ StdExType(std::forward(what)),
+ m_details(std::forward(details)),
+ m_innerEx(nullptr)
+ {
+# ifdef ENABLE_3FD_CST
+ if(CallStackTracer::IsReady())
+ m_cst = CallStackTracer::GetInstance().GetStackReport();
+# endif
+ }
+
+ template
+ AppException(StrType1 &&what, StrType2 &&details, IAppException &innerEx) :
+ StdExType(std::forward(what)),
+ m_details(std::forward(details)),
+ m_innerEx(innerEx.Move())
+ {
+# ifdef ENABLE_3FD_CST
+ if(CallStackTracer::IsReady())
+ m_cst = CallStackTracer::GetInstance().GetStackReport();
+# endif
+ }
+
+ ///
+ /// Initializes a new instance of the class using move semantics.
+ ///
+ /// The object whose resources will be stolen.
+ AppException(AppException &&ob) :
+ StdExType(std::move(ob.what())),
+ m_details(std::move(ob.m_details)),
+ m_cst(std::move(ob.m_cst)),
+ m_innerEx(ob.m_innerEx)
+ {
+ ob.m_innerEx = nullptr;
+ }
+
+ ///
+ /// Finalizes an instance of the class.
+ ///
+ virtual ~AppException()
+ {
+ delete m_innerEx;
+ }
+
+ ///
+ /// Gets the error message (including the details if in debug mode).
+ ///
+ virtual string GetErrorMessage() const override
+ {
+ std::ostringstream oss;
+ oss << StdExType::what();
+
+# ifdef ENABLE_3FD_ERR_IMPL_DETAILS
+ if(m_details.empty() == false)
+ oss << " - " << m_details;
+# endif
+# ifdef ENABLE_3FD_CST
+ if(m_cst.empty() == false)
+ oss << " - Call Stack: { " << m_cst << " }";
+# endif
+
+ return oss.str();
+ }
+ };
+
+ }// end namespace core
+}// end namespace _3fd
+
+#endif // header guard
diff --git a/3FD/gc.h b/3FD/gc.h
new file mode 100644
index 0000000..a8993df
--- /dev/null
+++ b/3FD/gc.h
@@ -0,0 +1,80 @@
+#ifndef GC_H
+#define GC_H
+
+#include "base.h"
+#include "utils.h"
+#include "gc_mastertable.h"
+
+#include
+#include
+#include
+#include
+
+/* Convention:
+
+ Access point - a sptr object which does not belong to a region of memory managed
+ by the garbage collector. In other words, it is a sptr object that is not inside
+ any MemBlock region.
+*/
+namespace _3fd
+{
+ namespace memory
+ {
+ ///
+ /// The interface that all GC messages must implement.
+ ///
+ class INTFOPT IMessage
+ {
+ public:
+
+ virtual ~IMessage() {}
+
+ virtual void Execute(MasterTable &masterTable) = 0;
+ };
+
+ ///
+ /// Implements the garbage collector engine.
+ ///
+ class GarbageCollector : notcopiable
+ {
+ private:
+
+ std::thread m_thread;
+ std::exception_ptr m_error;
+ MasterTable m_masterTable;
+ boost::lockfree::queue m_messagesQueue;
+ utils::Event m_terminationEvent;
+
+ GarbageCollector();
+
+ void GCThreadProc();
+
+ // Singleton needs:
+
+ static std::mutex singleInstanceCreationMutex;
+ static GarbageCollector *uniqueObjectPtr;
+ static GarbageCollector *CreateInstance();
+
+ public:
+
+ static GarbageCollector &GetInstance();
+
+ static void Shutdown();
+
+ ~GarbageCollector();
+
+ void UpdateReference(void *sptrObjAddr, void *pointedAddr);
+
+ void RegisterNewObject(void *sptrObjAddr, void *pointedAddr, size_t blockSize, FreeMemProc freeMemCallback);
+
+ void UnregisterAbortedObject(void *sptrObjAddr);
+
+ void RegisterSptr(void *sptrObjAddr, void *pointedAddr);
+
+ void UnregisterSptr(void *sptrObjAddr);
+ };
+
+ }// end of namespace memory
+}// end of namespace _3fd
+
+#endif // end of header guard
diff --git a/3FD/gc_addresseshashtable.cpp b/3FD/gc_addresseshashtable.cpp
new file mode 100644
index 0000000..8b7f6e2
--- /dev/null
+++ b/3FD/gc_addresseshashtable.cpp
@@ -0,0 +1,234 @@
+#include "stdafx.h"
+#include "gc_addresseshashtable.h"
+#include "configuration.h"
+
+namespace _3fd
+{
+ namespace memory
+ {
+ using core::AppConfig;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ AddressesHashTable::AddressesHashTable() :
+ m_elementsCount(0),
+ m_outHashSizeInBits(0)
+ {}
+
+ ///
+ /// Hashes a key using the FNV1a algorithm modified for outputs smaller than 16 bits.
+ ///
+ /// The key.
+ /// The hashed key.
+ size_t AddressesHashTable::Hash(void *key)
+ {
+ uint32_t hash = 2166136261; // use the FNV offset basis for 32 bits hashes
+
+ for (int bitsToShift = ((sizeof key) - 1) * 8;
+ bitsToShift >= 0;
+ bitsToShift -= 8)
+ {
+ auto octet = (reinterpret_cast (key) >> bitsToShift) & 255;
+ hash ^= octet;
+ hash *= 16777619; // use the FNV prime for 32 bits hashes
+ }
+
+ return hash;
+ }
+
+ ///
+ /// XOR-fold's a hash to adapt to the bucket array size.
+ ///
+ /// The hash.
+ /// The size of the returned hash in bits.
+ /// The xor-folded hash.
+ size_t AddressesHashTable::XorFold(size_t hash, uint32_t outHashSizeInBits)
+ {
+ const uint32_t maskForLowerBits = (1UL << outHashSizeInBits) - 1;
+ return ((hash >> outHashSizeInBits) ^ hash) & maskForLowerBits;
+ }
+
+ ///
+ /// Expands the hash table to twice its size.
+ ///
+ void AddressesHashTable::ExpandTable()
+ {
+ if (m_bucketArray.empty() == false)
+ {
+ ++m_outHashSizeInBits;
+ std::vector newArray(1 << m_outHashSizeInBits);
+
+ // Rehash the table to the new array:
+ for (auto &element : m_bucketArray)
+ {
+ if (element.GetSptrObjectAddr() != nullptr)
+ {
+ auto hashedKey = Hash(element.GetSptrObjectAddr());
+ auto idx = XorFold(hashedKey, m_outHashSizeInBits);
+
+ if (newArray[idx].GetSptrObjectAddr() == nullptr)
+ newArray[idx] = element;
+ else
+ {// Linear probe:
+ do
+ {
+ if (++idx < newArray.size())
+ continue;
+ else
+ idx = 0;
+ } while (newArray[idx].GetSptrObjectAddr() != nullptr);
+
+ newArray[idx] = element;
+ }
+ }
+ }
+
+ m_bucketArray.swap(newArray);
+ }
+ else
+ {// Allocate the bucket array for the first time:
+ m_outHashSizeInBits = AppConfig::GetSettings().framework.gc.sptrObjectsHashTable.initialSizeLog2;
+ m_bucketArray.resize(1 << m_outHashSizeInBits);
+ }
+ }
+
+ ///
+ /// Shrinks the hash table to half its size.
+ ///
+ void AddressesHashTable::ShrinkTable()
+ {
+ --m_outHashSizeInBits;
+ const auto newSize = 1 << m_outHashSizeInBits;
+ _ASSERTE(newSize >= m_elementsCount); // Can only shrink the table if the new table can fit all currently stored elements
+
+ std::vector newArray(newSize);
+
+ // Rehash the table to the new array:
+ for (auto &element : m_bucketArray)
+ {
+ if (element.GetSptrObjectAddr() == nullptr)
+ continue;
+ else
+ {
+ auto hashedKey = Hash(element.GetSptrObjectAddr());
+ auto idx = XorFold(hashedKey, m_outHashSizeInBits);
+
+ if (newArray[idx].GetSptrObjectAddr() == nullptr)
+ newArray[idx] = element;
+ else
+ {// Linear probe:
+ do
+ {
+ if (++idx < newArray.size())
+ continue;
+ else
+ idx = 0;
+ } while (newArray[idx].GetSptrObjectAddr() != nullptr);
+
+ newArray[idx] = element;
+ }
+ }
+ }
+
+ m_bucketArray.swap(newArray);
+ }
+
+ ///
+ /// Inserts a new entry in the hash table, placed according the memory address of the object.
+ ///
+ /// The object address.
+ /// The address pointed by the object.
+ /// The container memory block.
+ /// A view to the inserted element.
+ AddressesHashTable::Element &
+ AddressesHashTable::Insert(void *sptrObjectAddr, void *pointedAddr, MemAddrContainer *container)
+ {
+ if (CalculateLoadFactor() > AppConfig::GetSettings().framework.gc.sptrObjectsHashTable.loadFactorThreshold
+ || m_bucketArray.empty())
+ {
+ ExpandTable();
+ }
+
+ auto hashedKey = Hash(sptrObjectAddr);
+ auto idx = XorFold(hashedKey, m_outHashSizeInBits);
+
+ /* The code below could be simplified, but it will be kept this way so as to prevent
+ misprediction of instructions. However, that should not be a concern if the compiler
+ in use will apply PGO.*/
+
+ if (m_bucketArray[idx].GetSptrObjectAddr() == nullptr)
+ {
+ ++m_elementsCount;
+ return m_bucketArray[idx] = Element(sptrObjectAddr, pointedAddr, container);
+ }
+ else // Linear probe:
+ {
+ auto &element = m_bucketArray[idx];
+ auto displacedElement = element;
+
+ // Place the new element in the first hashed index
+ element = Element(sptrObjectAddr, pointedAddr, container);
+ ++m_elementsCount;
+
+ // And move the displaced element to the first vacant position:
+ do
+ {
+ if (++idx < m_bucketArray.size())
+ continue;
+ else
+ idx = 0;
+ } while (m_bucketArray[idx].GetSptrObjectAddr() != nullptr);
+
+ m_bucketArray[idx] = displacedElement;
+
+ // Return a reference inserted element:
+ return element;
+ }
+ }
+
+ ///
+ /// Looks up for the specified object address.
+ ///
+ /// The object address.
+ /// The object corresponding to the object address.
+ AddressesHashTable::Element &
+ AddressesHashTable::Lookup(void *sptrObjectAddr)
+ {
+ auto hashedKey = Hash(sptrObjectAddr);
+ auto idx = XorFold(hashedKey, m_outHashSizeInBits);
+
+ if (m_bucketArray[idx].GetSptrObjectAddr() == sptrObjectAddr)
+ return m_bucketArray[idx];
+ else
+ {// Linear probe:
+ do
+ {
+ if (++idx < m_bucketArray.size())
+ continue;
+ else
+ idx = 0;
+ } while (m_bucketArray[idx].GetSptrObjectAddr() != sptrObjectAddr);
+
+ return m_bucketArray[idx];
+ }
+ }
+
+ ///
+ /// Removes the element corresponding to a object address.
+ ///
+ /// The specified object address.
+ void AddressesHashTable::Remove(void *sptrObjectAddr)
+ {
+ Lookup(sptrObjectAddr) = Element();
+ --m_elementsCount;
+
+ if (m_outHashSizeInBits > AppConfig::GetSettings().framework.gc.sptrObjectsHashTable.initialSizeLog2
+ && CalculateLoadFactor() < AppConfig::GetSettings().framework.gc.sptrObjectsHashTable.loadFactorThreshold / 3)
+ {
+ ShrinkTable();
+ }
+ }
+
+ }// end of namespace memory
+}// end of namespace _3fd
\ No newline at end of file
diff --git a/3FD/gc_addresseshashtable.h b/3FD/gc_addresseshashtable.h
new file mode 100644
index 0000000..c3814c8
--- /dev/null
+++ b/3FD/gc_addresseshashtable.h
@@ -0,0 +1,107 @@
+#ifndef GC_ADDRESSESHASHTABLE_H // header guard
+#define GC_ADDRESSESHASHTABLE_H
+
+#include "base.h"
+#include "gc_memaddress.h"
+#include
+#include
+
+namespace _3fd
+{
+ namespace memory
+ {
+ ///
+ /// This class uses hash table data structure (with open addressing and linear probing) to store information about
+ /// the objects managed by the GC. It was not converted to a template because it was designed
+ /// very specifically (optimized) for its job. The implementation could be more "OOP/C++ like", but the concern here
+ /// is to save memory. If you find yourself wishing to change its model to make it more OOP compliant, remember it was
+ /// designed that way so as to save something around 8 or 16 bytes per element added to the table.
+ ///
+ class AddressesHashTable : notcopiable
+ {
+ public:
+
+ ///
+ /// This structure is the actual bucket element
+ ///
+ class Element
+ {
+ private:
+
+ void *m_sptrObjectAddr; // This is the unique key (the memory address of the sptr object)
+ void *m_pointedAddr; // This is a value (where the sptr points to)
+ MemAddrContainer *m_container; // This is a value (what contains sptr)
+
+ public:
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ Element()
+ : m_sptrObjectAddr(nullptr), m_pointedAddr(nullptr), m_container(nullptr) {}
+
+ ///
+ /// Constructor for the objects allocated on the stack.
+ ///
+ /// The object address.
+ /// The address pointed by the object.
+ /// The container memory block.
+ Element(void *sptrObjectAddr, void *pointedAddr, MemAddrContainer *container) :
+ m_sptrObjectAddr(sptrObjectAddr),
+ m_pointedAddr(pointedAddr),
+ m_container(container)
+ {}
+
+ void *GetSptrObjectAddr() const { return m_sptrObjectAddr; }
+
+ void *GetPointedAddr() const { return m_pointedAddr; }
+
+ MemAddrContainer *GetContainerMemBlock() const { return m_container; }
+
+ void SetAddrPointed(void *pointedAddr) { m_pointedAddr = pointedAddr; }
+ };
+
+ private:
+
+ std::vector m_bucketArray;
+ size_t m_elementsCount;
+ uint32_t m_outHashSizeInBits;
+
+ ///
+ /// Calculates the load factor.
+ ///
+ /// The current load factor of the table.
+ float CalculateLoadFactor() const
+ {
+ if (m_bucketArray.empty() == false)
+ return ((float)m_elementsCount) / m_bucketArray.size();
+ else
+ return 0.0;
+ }
+
+ static size_t Hash(void *key);
+ static size_t XorFold(size_t hash, uint32_t outHashSizeInBits);
+
+ void ExpandTable();
+ void ShrinkTable();
+
+ public:
+
+ AddressesHashTable();
+
+ Element &Insert(
+ void *sptrObjectAddr,
+ void *pointedAddr,
+ MemAddrContainer *container);
+
+ // Lookup for an sptr object
+ Element &Lookup(void *sptrObjectAddr);
+
+ // Removes an entry from the hash table
+ void Remove(void *sptrObjectAddr);
+ };
+
+ }// end of namespace memory
+}// end of namespace _3fd
+
+#endif // end of header guard
diff --git a/3FD/gc_common.h b/3FD/gc_common.h
new file mode 100644
index 0000000..2b867d8
--- /dev/null
+++ b/3FD/gc_common.h
@@ -0,0 +1,20 @@
+#ifndef GC_COMMON_H
+#define GC_COMMON_H
+
+#include
+
+namespace _3fd
+{
+ namespace memory
+ {
+ typedef void (*FreeMemProc)(void *addr, bool destroy);
+
+ void *AllocMemoryAndRegisterWithGC(
+ size_t size,
+ void *sptrObjAddr,
+ FreeMemProc freeMemCallback);
+
+ }// end of namespace memory
+}// end of namespace _3fd
+
+#endif // end of header guard
diff --git a/3FD/gc_garbagecollector.cpp b/3FD/gc_garbagecollector.cpp
new file mode 100644
index 0000000..53543a4
--- /dev/null
+++ b/3FD/gc_garbagecollector.cpp
@@ -0,0 +1,275 @@
+#include "stdafx.h"
+#include "gc.h"
+#include "gc_common.h"
+#include "gc_messages.h"
+
+#include "utils.h"
+#include "logger.h"
+#include "exceptions.h"
+#include "callstacktracer.h"
+#include "configuration.h"
+
+#include
+#include
+#include
+#include
+#include
+
+namespace _3fd
+{
+ using std::string;
+ using std::for_each;
+
+ namespace memory
+ {
+ using core::AppConfig;
+ using core::AppException;
+
+ ///
+ /// Allocates memory and register it with the garbage collector.
+ ///
+ /// The size of the memory block to allocated.
+ /// The address of the smart pointer that will refer to the same memory.
+ /// The callback that must be used to free the allocated memory.
+ /// The address of the allocated memory.
+ void *AllocMemoryAndRegisterWithGC(size_t size,
+ void *sptrObjAddr,
+ FreeMemProc freeMemCallback)
+ {
+ void *ptr = malloc(size);
+
+ if(ptr != nullptr)
+ GarbageCollector::GetInstance()
+ .RegisterNewObject(sptrObjAddr, ptr, size, freeMemCallback);
+ else
+ throw AppException("Memory allocation failed.", "std::malloc");
+
+ return ptr;
+ }
+
+ GarbageCollector * GarbageCollector::uniqueObjectPtr(nullptr);
+
+ std::mutex GarbageCollector::singleInstanceCreationMutex;
+
+ ///
+ /// Creates the unique instance of the class.
+ ///
+ ///
+ GarbageCollector * GarbageCollector::CreateInstance()
+ {
+ CALL_STACK_TRACE;
+
+ try
+ {
+ std::lock_guard lock(singleInstanceCreationMutex);
+
+ if(uniqueObjectPtr == nullptr)
+ uniqueObjectPtr = new GarbageCollector();
+
+ return uniqueObjectPtr;
+ }
+ catch(core::IAppException &)
+ {
+ throw; // just forward exceptions known to have been previously handled
+ }
+ catch(std::system_error &ex)
+ {
+ std::ostringstream oss;
+ oss << "Failed to instantiate the garbage collector engine: " << core::StdLibExt::GetDetailsFromSystemError(ex);
+ throw AppException(oss.str());
+ }
+ catch(std::exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic failure when instantiating the garbage collector engine: " << ex.what();
+ throw AppException(oss.str());
+ }
+ }
+
+ ///
+ /// Gets the unique instance of the class.
+ ///
+ ///
+ GarbageCollector & GarbageCollector::GetInstance()
+ {
+ if(uniqueObjectPtr != nullptr)
+ return *uniqueObjectPtr;
+ else
+ return *CreateInstance();
+ }
+
+ ///
+ /// Shuts down the garbage collector releasing all associated resources.
+ ///
+ void GarbageCollector::Shutdown()
+ {
+ if(uniqueObjectPtr != nullptr)
+ {
+ try
+ {
+ std::lock_guard lock(singleInstanceCreationMutex);
+ delete uniqueObjectPtr;
+ uniqueObjectPtr = nullptr;
+ }
+ catch (std::system_error &)
+ {/* DO NOTHING: SWALLOW EXCEPTION
+ This method cannot throw an exception because it can be invoked by a destructor.
+ If an exception is thrown, memory leaks are expected. */
+ }
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ GarbageCollector::GarbageCollector()
+ try :
+ m_error(nullptr),
+ m_masterTable(),
+ m_messagesQueue(AppConfig::GetSettings().framework.gc.msgQueueInitCap),
+ m_terminationEvent()
+ {
+ CALL_STACK_TRACE;
+
+ _ASSERTE(m_messagesQueue.is_lock_free()); // Queue must be implemented lock-free
+
+ // Create the GC dedicated thread
+ std::thread temp(&GarbageCollector::GCThreadProc, this);
+ m_thread.swap(temp);
+ }
+ catch(core::IAppException &)
+ {
+ throw; // just forward exceptions known to have been previously handled
+ }
+ catch(std::system_error &ex)
+ {
+ CALL_STACK_TRACE;
+ std::ostringstream oss;
+ oss << "Failed to create garbage collection thread: " << core::StdLibExt::GetDetailsFromSystemError(ex);
+ throw AppException(oss.str());
+ }
+ catch(std::exception &ex)
+ {
+ CALL_STACK_TRACE;
+ std::ostringstream oss;
+ oss << "Generic failure when creating garbage collector instance: " << ex.what();
+ throw AppException(oss.str());
+ }
+
+ ///
+ /// Finalizes an instance of the class.
+ ///
+ GarbageCollector::~GarbageCollector()
+ {
+ CALL_STACK_TRACE;
+
+ try
+ {
+ // Signalizes termination for the message loop
+ m_terminationEvent.Signalize();
+
+ if( m_thread.joinable() )
+ m_thread.join();
+
+ if(m_error != nullptr)
+ std::rethrow_exception(m_error);
+ }
+ catch(core::IAppException &ex)
+ {
+ core::Logger::Write(ex, core::Logger::PRIO_CRITICAL);
+ }
+ catch(std::system_error &ex)
+ {
+ std::ostringstream oss;
+ oss << "Failed when attempted to stop garbage collection thread: " << core::StdLibExt::GetDetailsFromSystemError(ex);
+ core::Logger::Write(oss.str(), core::Logger::PRIO_CRITICAL, true);
+ }
+ catch(std::exception &ex)
+ {
+ core::Logger::Write(ex.what(), core::Logger::PRIO_CRITICAL, true);
+ }
+ }
+
+ ///
+ /// Executed by the GC dedicated thread.
+ ///
+ void GarbageCollector::GCThreadProc()
+ {
+ CALL_STACK_TRACE;
+
+ try
+ {
+ bool terminate(false);
+
+ // The message loop:
+ do
+ {
+ // Wait for either the termination event or a timeout
+ terminate = m_terminationEvent.WaitFor(
+ AppConfig::GetSettings().framework.gc.msgLoopSleepTimeoutMilisecs
+ );
+
+ IMessage *message;
+
+ // Consume the messages in the queue:
+ while(m_messagesQueue.pop(message))
+ {
+ message->Execute(m_masterTable);
+ delete message;
+ }
+
+ // If there is still work to do, optimize the master table
+ if(terminate == false)
+ m_masterTable.Shrink();
+ }
+ while(terminate == false);
+ }
+ catch(core::IAppException &ex)
+ {
+ core::Logger::Write(ex, core::Logger::PRIO_CRITICAL);
+ m_error = std::current_exception();
+ }
+ catch(std::system_error &ex)
+ {
+ std::ostringstream oss;
+ oss << "There was an error in garbage collector thread: " << core::StdLibExt::GetDetailsFromSystemError(ex);
+ core::Logger::Write(oss.str(), core::Logger::PRIO_CRITICAL);
+ m_error = std::current_exception();
+ }
+ catch(std::exception &ex)
+ {
+ std::ostringstream oss;
+ oss << "Generic failure in garbage collector thread: " << ex.what();
+ core::Logger::Write(oss.str(), core::Logger::PRIO_CRITICAL);
+ m_error = std::current_exception();
+ }
+ }
+
+ void GarbageCollector::UpdateReference(void *sptrObjAddr, void *pointedAddr)
+ {
+ m_messagesQueue.push(new ReferenceUpdateMsg (sptrObjAddr, pointedAddr));
+ }
+
+ void GarbageCollector::RegisterNewObject(void *sptrObjAddr, void *pointedAddr, size_t blockSize, FreeMemProc freeMemCallback)
+ {
+ m_messagesQueue.push(new NewObjectMsg (sptrObjAddr, pointedAddr, blockSize, freeMemCallback));
+ }
+
+ void GarbageCollector::UnregisterAbortedObject(void *sptrObjAddr)
+ {
+ m_messagesQueue.push(new AbortedObjectMsg(sptrObjAddr));
+ }
+
+ void GarbageCollector::RegisterSptr(void *sptrObjAddr, void *pointedAddr)
+ {
+ m_messagesQueue.push(new SptrRegistrationMsg (sptrObjAddr, pointedAddr));
+ }
+
+ void GarbageCollector::UnregisterSptr(void *sptrObjAddr)
+ {
+ m_messagesQueue.push(new SptrUnregistrationMsg (sptrObjAddr));
+ }
+
+ }// end of namespace memory
+}// end of namespace _3fd
+
diff --git a/3FD/gc_mastertable.cpp b/3FD/gc_mastertable.cpp
new file mode 100644
index 0000000..85fad2f
--- /dev/null
+++ b/3FD/gc_mastertable.cpp
@@ -0,0 +1,119 @@
+#include "stdafx.h"
+#include "gc_memaddress.h"
+#include "gc_mastertable.h"
+
+namespace _3fd
+{
+ namespace memory
+ {
+ ///
+ /// Shrinks the amount of memory allocated by the resources used by this master table.
+ ///
+ void MasterTable::Shrink()
+ {
+ m_memDigraph.ShrinkObjectPool();
+ }
+
+ ///
+ /// Sets in master table the connection between a safe pointer and its referred memory address.
+ ///
+ /// A hashtable element which represents the safe pointer.
+ /// The referred memory address.
+ void MasterTable::MakeReference(AddressesHashTable::Element *sptrObjHashTableElem, void *pointedAddr)
+ {
+ // If the reference is not null, look for the corresponding MemBlock object and sets a connection
+ if (pointedAddr != 0)
+ {
+ MemAddrContainer *receiver = m_memDigraph.GetVertex(pointedAddr),
+ *originator = sptrObjHashTableElem->GetContainerMemBlock();
+
+ if (originator == nullptr)
+ // Sets the connection with the safe pointer ('root vertex' or 'access point')
+ m_memDigraph.AddEdge(sptrObjHashTableElem->GetSptrObjectAddr(), receiver);
+ else
+ /* It is not a safe pointer ('root vertex' or 'access point'), so set up a connection
+ between the container memory address and the pointed memory address: */
+ m_memDigraph.AddEdge(originator, receiver);
+ }
+
+ sptrObjHashTableElem->SetAddrPointed(pointedAddr);
+ }
+
+ ///
+ /// Unsets in master table the connection between a safe pointer and its referred memory address.
+ ///
+ /// A hashtable element which represents the safe pointer.
+ /// Whether the pointed object should have its destructor invoked just in case it is to be collected.
+ /// The destruction must not be allowed when the object construction has failed due to a thrown exception.
+ void MasterTable::UnmakeReference(AddressesHashTable::Element *sptrObjHashTableElem, bool allowDestruction)
+ {
+ void *pointedAddr = sptrObjHashTableElem->GetPointedAddr();
+
+ // If the sptr object currently references an address, unmake the reference:
+ if (pointedAddr != 0)
+ {
+ MemAddrContainer *receiver = m_memDigraph.GetVertex(pointedAddr);
+
+ if (receiver != nullptr)
+ {
+ MemAddrContainer *originator = sptrObjHashTableElem->GetContainerMemBlock();
+
+ // Undo the reference of the sptr object:
+ if (originator == nullptr)
+ m_memDigraph.RemoveEdge(sptrObjHashTableElem->GetSptrObjectAddr(), receiver, allowDestruction);
+ else
+ m_memDigraph.RemoveEdge(originator, receiver, allowDestruction);
+ }
+ }
+ }
+
+ ///
+ /// Performs registering a new memory address to be managed by the GC.
+ ///
+ /// The memory address.
+ /// Size of the block.
+ /// The callback used to free the memory and destroy the object.
+ void MasterTable::DoRegisterMemAddr(void *addr, size_t blockSize, FreeMemProc freeMemCallback) throw()
+ {
+ m_memDigraph.AddVertex(addr, blockSize, freeMemCallback);
+ }
+
+ ///
+ /// Performs registering a new object to be tracked by the GC.
+ ///
+ /// The safe pointer object address.
+ /// The memory address referred by the safe pointer.
+ void MasterTable::DoRegisterSptr(void *sptrObjAddr, void *pointedAddr) throw()
+ {
+ auto container = m_memDigraph.GetContainerVertex(sptrObjAddr);
+ auto &sptrObjHashTableElem = m_sptrObjects.Insert(sptrObjAddr, nullptr, container);
+ MakeReference(&sptrObjHashTableElem, pointedAddr);
+ }
+
+ ///
+ /// Performs unregistering a object which no longer will be tracked by the GC.
+ ///
+ /// The safe pointer object address.
+ void MasterTable::DoUnregisterSptr(void *sptrObjAddr) throw()
+ {
+ auto &sptrObjHashTableElem = m_sptrObjects.Lookup(sptrObjAddr);
+ UnmakeReference(&sptrObjHashTableElem, true);
+ m_sptrObjects.Remove(sptrObjAddr);
+ }
+
+ ///
+ /// Performs updating the register of a object which was changed to refer to another memory address.
+ ///
+ /// The safe pointer object address.
+ /// The new memory address referred by the safe pointer.
+ /// Whether the referred object should have its destructor invoked just in case it is to be collected.
+ /// The destruction must not be allowed when the object construction has failed due to a thrown exception.
+ void MasterTable::DoUpdateReference(void *sptrObjAddr, void *pointedAddr, bool allowRefObjDtion) throw()
+ {
+ auto &sptrObjHashTableElem = m_sptrObjects.Lookup(sptrObjAddr);
+ UnmakeReference(&sptrObjHashTableElem, allowRefObjDtion);
+ MakeReference(&sptrObjHashTableElem, pointedAddr);
+ }
+
+ }// end of namespace _3fd
+}// end of namespace memory
diff --git a/3FD/gc_mastertable.h b/3FD/gc_mastertable.h
new file mode 100644
index 0000000..87680c1
--- /dev/null
+++ b/3FD/gc_mastertable.h
@@ -0,0 +1,44 @@
+#ifndef GC_MASTERTABLE_H // header guard
+#define GC_MASTERTABLE_H
+
+#include "gc_common.h"
+#include "gc_memorydigraph.h"
+#include "gc_addresseshashtable.h"
+
+namespace _3fd
+{
+ namespace memory
+ {
+ ///
+ /// Master table of memory addresses and sptr objects
+ ///
+ class MasterTable : notcopiable
+ {
+ private:
+
+ MemoryDigraph m_memDigraph;
+ AddressesHashTable m_sptrObjects; // A hash table here might improve performance and can be used because it does not have to be sorted
+
+ void MakeReference(AddressesHashTable::Element *sptrObjHashTableElem, void *pointedAddr);
+
+ void UnmakeReference(AddressesHashTable::Element *sptrObjHashTableElem, bool allowDestruction);
+
+ public:
+
+ void Shrink();
+
+ void DoRegisterMemAddr(void *addr, size_t blockSize, FreeMemProc freeMemCallback) throw();
+
+ void DoRegisterSptr(void *sptrObjAddr, void *pointedAddr) throw();
+
+ void DoUnregisterSptr(void *sptrObjAddr) throw();
+
+ void DoUnregisterMemAddr(void *pointedAddr) throw();
+
+ void DoUpdateReference(void *sptrObjAddr, void *pointedAddr, bool allowRefObjDtion = true) throw();
+ };
+
+ }// end of namespace memory
+}// end of namespace _3fd
+
+#endif // end of header guard
diff --git a/3FD/gc_memaddress.h b/3FD/gc_memaddress.h
new file mode 100644
index 0000000..c8220aa
--- /dev/null
+++ b/3FD/gc_memaddress.h
@@ -0,0 +1,115 @@
+#ifndef GC_MEMADDRESS_H // header guard
+#define GC_MEMADDRESS_H
+
+#include
+
+namespace _3fd
+{
+ namespace memory
+ {
+ ///
+ /// Holds a single memory address which can be flagged using less significant bits available.
+ ///
+ class MemAddress
+ {
+ private:
+
+ mutable void *m_address;
+
+#if defined(_M_X64) || defined(__amd64__)
+ static const uintptr_t mask = 0xfffffffffffffffe;
+#else
+ static const uintptr_t mask = 0xfffffffe;
+#endif
+ public:
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The memory address.
+ explicit MemAddress(void *address)
+ : m_address(address) {}
+
+ ///
+ /// Gets the stored memory address.
+ ///
+ /// The memory address, without the encoded flag.
+ void *Get() const
+ {
+ return reinterpret_cast (reinterpret_cast (m_address) & mask);
+ }
+
+ ///
+ /// Sets a bit flag to mark the memory address.
+ ///
+ /// if set to true, activates the less significant bit in the address.
+ void Mark(bool on) const
+ {
+ if (on)
+ m_address = reinterpret_cast (reinterpret_cast (m_address) | 1);
+ else
+ m_address = reinterpret_cast (reinterpret_cast (m_address) & mask);
+ }
+
+ ///
+ /// Determines whether the memory address is marked.
+ ///
+ /// Whether a bit flag was activated to mark the memory address.
+ bool isMarked() const
+ {
+ return static_cast (reinterpret_cast (m_address)& 1);
+ }
+
+ ///
+ /// Equality operator.
+ ///
+ /// The object to compare with.
+ /// true if both object are equivalent, which means they have same address and mark, otherwise, false.
+ bool operator ==(const MemAddress &ob)
+ {
+ return m_address == ob.m_address;
+ }
+ };
+
+ ///
+ /// Base class for .
+ /// Its only purpose is to ease searching a std::set{MemBlock *}.
+ ///
+ class MemAddrContainer
+ {
+ private:
+
+ MemAddress m_memAddr;
+
+ public:
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The memory address to store.
+ MemAddrContainer(void *memAddress)
+ : m_memAddr(memAddress) {}
+
+ MemAddress &memoryAddress() { return m_memAddr; }
+
+ const MemAddress &memoryAddress() const { return m_memAddr; }
+ };
+
+ ///
+ /// Implementation of functor for std::set{MemAddrContainer} that takes into consideration
+ /// the address of the represented memory pieces, rather than the addresses of the actual
+ /// objects.
+ ///
+ struct LessOperOnMemBlockRepAddr
+ {
+ bool operator()(MemAddrContainer *left, MemAddrContainer *right) const
+ {
+ return left->memoryAddress().Get()
+ < right->memoryAddress().Get();
+ }
+ };
+
+ }// end of namespace memory
+}// end of namespace _3fd
+
+#endif // end of header guard
diff --git a/3FD/gc_memblock.cpp b/3FD/gc_memblock.cpp
new file mode 100644
index 0000000..bd72886
--- /dev/null
+++ b/3FD/gc_memblock.cpp
@@ -0,0 +1,111 @@
+#include "stdafx.h"
+#include "gc_memblock.h"
+
+namespace _3fd
+{
+ namespace memory
+ {
+ utils::DynamicMemPool * MemBlock::dynMemPool(nullptr);
+
+ ///
+ /// Sets the object pool that provides all the instances.
+ ///
+ /// The object pool to use.
+ void MemBlock::SetMemoryPool(utils::DynamicMemPool &ob)
+ {
+ dynMemPool = &ob;
+ }
+
+ ///
+ /// Implements the operator new, to construct a new instance from resources in the object pool.
+ ///
+ /// Currently not used.
+ ///
+ /// A new instance retrieved from the object pool.
+ ///
+ void * MemBlock::operator new(size_t)
+ {
+ return dynMemPool->GetFreeBlock();
+ }
+
+ ///
+ /// Implements the operator delete, to destroy a instance returning itself to the object pool.
+ ///
+ /// The address of the object to delete.
+ void MemBlock::operator delete(void *ptr)
+ {
+ dynMemPool->ReturnBlock(ptr);
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The address of the memory block.
+ /// Size of the block.
+ /// The callback that frees the memory block.
+ MemBlock::MemBlock(void *memAddr, size_t blockSize, FreeMemProc freeMemCallback) :
+ MemAddrContainer(memAddr),
+ m_blockSize(blockSize),
+ m_freeMemCallback(freeMemCallback)
+ {}
+
+ ///
+ /// Finalizes an instance of the class.
+ ///
+ MemBlock::~MemBlock()
+ {
+ RemoveAllEdges();
+ }
+
+ ///
+ /// Determines whether this memory block contains the specified memory address.
+ ///
+ /// The memory address to test.
+ /// Whether this memory block contains the specified memory address
+ bool MemBlock::Contains(void *someAddr) const
+ {
+ return someAddr >= memoryAddress().Get()
+ && someAddr < (void *)((uintptr_t)memoryAddress().Get() + m_blockSize);
+ }
+
+ ///
+ /// Determines whether this instance is reachable.
+ ///
+ ///
+ bool MemBlock::IsReachable() const
+ {
+ if (HasRootEdge())
+ return true;
+
+ // Avoid cyclic paths by marking vertices
+ memoryAddress().Mark(true);
+
+ // Check if any receiving edge is a path coming from a reaching root vertex:
+ bool isUnreachableViaReceivingEdges =
+ ForEachRegularEdgeWhile([this](const Vertex &vtx)
+ {
+ auto &memBlock = static_cast (vtx);
+
+ if (!memBlock.memoryAddress().isMarked())
+ return !memBlock.IsReachable();
+ else
+ return true;
+ });
+
+ // unmark this vertex so as to leave the graph inaltered at the end of the algorithm
+ memoryAddress().Mark(false);
+
+ return !isUnreachableViaReceivingEdges;
+ }
+
+ ///
+ /// Frees the specified destroy.
+ ///
+ /// if set to true [destroy].
+ void MemBlock::Free(bool destroy)
+ {
+ (*m_freeMemCallback)(memoryAddress().Get(), destroy);
+ }
+
+ }// end of namespace memory
+}// end of namespace _3fd
diff --git a/3FD/gc_memblock.h b/3FD/gc_memblock.h
new file mode 100644
index 0000000..50253eb
--- /dev/null
+++ b/3FD/gc_memblock.h
@@ -0,0 +1,106 @@
+#ifndef GC_MEMORYBLOCK_H // header guard
+#define GC_MEMORYBLOCK_H
+
+#include "utils.h"
+#include "gc_common.h"
+#include "gc_memaddress.h"
+
+#include
+#include
+#include
+
+namespace _3fd
+{
+ namespace memory
+ {
+ /*
+ The convention here will be:
+ + Regular vertices are passed as 'Vertex *'
+ + Root vertices are passed as 'void *'
+ + Memory addresses in general are handled as 'void *'
+ */
+
+ ///
+ /// Represents a vertex in a directed graph of pieces of memory.
+ ///
+ class Vertex : notcopiable
+ {
+ private:
+
+ ///
+ /// Holds pointers to all vertices which have an edge directed to this node.
+ /// Root vertices are marked.
+ ///
+ MemAddress *m_arrayEdges;
+
+ uint32_t m_arraySize;
+
+ uint32_t m_arrayCapacity;
+
+ ///
+ /// Counting of how many root vertices are in the array.
+ ///
+ uint32_t m_rootCount;
+
+ void EvaluateShrinkCapacity();
+
+ void ReceiveEdgeImpl(MemAddress vtx);
+
+ void RemoveEdgeImpl(MemAddress vtx);
+
+ public:
+
+ Vertex();
+
+ ~Vertex();
+
+ void ReceiveEdge(Vertex *vtxRegular);
+
+ void ReceiveEdge(void *vtxRoot);
+
+ void RemoveEdge(Vertex *vtxRegular);
+
+ void RemoveEdge(void *vtxRoot);
+
+ void RemoveAllEdges();
+
+ bool HasRootEdge() const;
+
+ bool ForEachRegularEdgeWhile(const std::function &callback) const;
+ };
+
+ ///
+ /// Represents a memory block region managed by the GC.
+ ///
+ class MemBlock : notcopiable, public Vertex, public MemAddrContainer
+ {
+ private:
+
+ FreeMemProc m_freeMemCallback;
+ uint32_t m_blockSize;
+
+ static utils::DynamicMemPool *dynMemPool;
+
+ public:
+
+ static void SetMemoryPool(utils::DynamicMemPool &ob);
+
+ void *operator new(size_t);
+
+ void operator delete(void *ptr);
+
+ MemBlock(void *memAddr, size_t blockSize, FreeMemProc freeMemCallback);
+
+ ~MemBlock();
+
+ bool Contains(void *someAddr) const;
+
+ bool IsReachable() const;
+
+ void Free(bool destroy);
+ };
+
+ }// end of namespace memory
+}// end of namespace _3fd
+
+#endif // end of header guard
diff --git a/3FD/gc_memorydigraph.cpp b/3FD/gc_memorydigraph.cpp
new file mode 100644
index 0000000..f72b745
--- /dev/null
+++ b/3FD/gc_memorydigraph.cpp
@@ -0,0 +1,183 @@
+#include "stdafx.h"
+#include "gc_memorydigraph.h"
+#include "gc_memblock.h"
+#include "configuration.h"
+
+#include
+
+namespace _3fd
+{
+ namespace memory
+ {
+ using core::AppConfig;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ MemoryDigraph::MemoryDigraph() :
+ m_memBlocksPool(AppConfig::GetSettings().framework.gc.memBlocksMemPool.initialSize,
+ sizeof(MemBlock),
+ AppConfig::GetSettings().framework.gc.memBlocksMemPool.growingFactor)
+ {
+ MemBlock::SetMemoryPool(m_memBlocksPool);
+ }
+
+ ///
+ /// Shrinks the pool of objects.
+ ///
+ void MemoryDigraph::ShrinkObjectPool()
+ {
+ m_memBlocksPool.Shrink();
+ }
+
+ ///
+ /// Adds a new vertex to the graph.
+ ///
+ /// The memory address represented by the new vertex.
+ /// Size of the represented memory block.
+ /// The callback that frees the memory block.
+ MemAddrContainer *MemoryDigraph::AddVertex(void *memAddr, size_t blockSize, FreeMemProc freeMemCallback)
+ {
+ auto vtx = new MemBlock(memAddr, blockSize, freeMemCallback);
+ m_vertices.insert(vtx);
+ return vtx;
+ }
+
+ ///
+ /// Removes a given vertex.
+ ///
+ /// The vertex to remove.
+ /// Whether the pointed object should have its destructor invoked.
+ /// The destruction must not be allowed when the object construction has failed due to a thrown exception.
+ ///
+ /// The resources allocated to the vertex and its represented memory block will be released.
+ ///
+ void MemoryDigraph::RemoveVertex(MemAddrContainer *vtx, bool allowDestruction)
+ {
+ auto iter = m_vertices.find(vtx);
+ _ASSERTE(m_vertices.end() != iter); // cannot handle removal of unexistent vertex
+ m_vertices.erase(iter);
+
+ auto memBlock = static_cast (vtx);
+ memBlock->Free(allowDestruction);
+ delete memBlock; // ATTENTION: destructor is not virtual, so the type must be right!
+ }
+
+ ///
+ /// Gets the vertex representing a given memory address.
+ ///
+ /// The given memory address.
+ /// The vertex representing the given memory address.
+ MemAddrContainer * MemoryDigraph::GetVertex(void *blockMemAddr) const
+ {
+ MemAddrContainer key(blockMemAddr);
+ auto iter = m_vertices.find(&key);
+ if (m_vertices.end() != iter)
+ return *iter;
+ else
+ return nullptr;
+ }
+
+ ///
+ /// Gets the regular vertex which represents a memory block containing a given address.
+ ///
+ /// The address for which a container will looked.
+ /// The vertex representing the memory block which contains the given address, if existent. Otherwise, a nullptr.
+ MemAddrContainer * MemoryDigraph::GetContainerVertex(void *addr) const
+ {
+ if (!m_vertices.empty())
+ {
+ MemAddrContainer key(addr);
+ auto iter = m_vertices.lower_bound(&key);
+
+ if (m_vertices.end() != iter)
+ {
+ auto vtx = static_cast (*iter);
+ if (vtx->Contains(addr))
+ return vtx;
+
+ if (m_vertices.begin() != iter)
+ --iter;
+ }
+ else
+ --iter;
+
+ auto vtx = static_cast (*iter);
+ if (vtx->Contains(addr))
+ return vtx;
+ }
+
+ return nullptr;
+ }
+
+
+ ///
+ /// Adds an edge that goes from a root vertex to a regular vertex.
+ ///
+ /// The address of the root vertex.
+ /// The address of the memory block represented by the regular vertex.
+ void MemoryDigraph::AddEdge(void *vtxRootFrom, MemAddrContainer *vtxRegularTo)
+ {
+ _ASSERTE(vtxRegularTo != nullptr);
+ auto receivingVtx = static_cast (vtxRegularTo);
+ receivingVtx->ReceiveEdge(vtxRootFrom);
+ }
+
+ ///
+ /// Adds an edge that goes from one regular vertex to another.
+ ///
+ /// The vertex from which the edge comes.
+ /// The vertex to which the edge goes.
+ void MemoryDigraph::AddEdge(MemAddrContainer *originatorVtx, MemAddrContainer *receivingVtx)
+ {
+ _ASSERTE(receivingVtx != nullptr);
+ static_cast (receivingVtx)->ReceiveEdge(
+ static_cast (originatorVtx)
+ );
+ }
+
+ ///
+ /// Removes an edge that goes from a root vertex to a regular vertex.
+ ///
+ /// The address of the root vertex.
+ /// The regular vertex.
+ /// Whether the pointed object should have its destructor invoked just in case it is to be collected.
+ /// The destruction must not be allowed when the object construction has failed due to a thrown exception.
+ ///
+ /// If the receiving vertex becomes unreachable as a result of this operation, the resources allocated to
+ /// this vertex and its represented memory block will be released.
+ ///
+ void MemoryDigraph::RemoveEdge(void *vtxRootFrom, MemAddrContainer *vtxRegularTo, bool allowDestruction)
+ {
+ _ASSERTE(vtxRegularTo != nullptr);
+ auto receivingVtx = static_cast (vtxRegularTo);
+ receivingVtx->RemoveEdge(vtxRootFrom);
+
+ // If the memory block became unreachable, free its resources and return the MemBlock object to the pool:
+ if (!receivingVtx->IsReachable())
+ RemoveVertex(receivingVtx, allowDestruction);
+ }
+
+ ///
+ /// Removes an edge that goes from one regular vertex to another.
+ ///
+ /// The vertex from which the edge comes.
+ /// The vertex to which the edge goes.
+ /// Whether the pointed object should have its destructor invoked just in case it is to be collected.
+ /// The destruction must not be allowed when the object construction has failed due to a thrown exception.
+ ///
+ /// If the receiving vertex becomes unreachable as a result of this operation, the resources allocated to
+ /// this vertex and its represented memory block will be released.
+ ///
+ void MemoryDigraph::RemoveEdge(MemAddrContainer *originatorVtx, MemAddrContainer *receivingVtx, bool allowDestruction)
+ {
+ auto memBlock = static_cast (receivingVtx);
+ memBlock->RemoveEdge(static_cast (originatorVtx));
+
+ // If the memory block became unreachable, free its resources and return the MemBlock object to the pool:
+ if (!memBlock->IsReachable())
+ RemoveVertex(memBlock, allowDestruction);
+ }
+
+ }// end of namespace memory
+}// end of namespace _3fd
diff --git a/3FD/gc_memorydigraph.h b/3FD/gc_memorydigraph.h
new file mode 100644
index 0000000..5919cbc
--- /dev/null
+++ b/3FD/gc_memorydigraph.h
@@ -0,0 +1,70 @@
+#ifndef DIGRAPH_H // header guard
+#define DIGRAPH_H
+
+/*
+ Here is implemented a directed graph tuned for reachability analysis used by the garbage collector.
+ In this graph, each vertex is either a safe pointer or a piece of garbage collected memmory (which
+ might contain a safe pointer inside it). The vertices are distinguished as regular or root. A root
+ vertex is a safe pointer allocated in memory not managed by the garbage collector. That means client
+ code uses such pointers to access the remaining of the graph (garbage collected memory pieces), that
+ are the regular vertices.
+
+ This distinction is central for the GC to perform reachability analysis. When a given piece of memory
+ is not connected to any root vertex, that means it became out of reach and has to be collected. This
+ approach is not vulnerable to cyclic references, unlike reference counting.
+*/
+
+#include "utils.h"
+#include "gc_common.h"
+#include "gc_memaddress.h"
+
+#include "stx/btree_set.h"
+
+namespace _3fd
+{
+ namespace memory
+ {
+ ///
+ /// Directed graph representing the connections made by safe pointers between pieces of memory managed by the GC.
+ ///
+ class MemoryDigraph : notcopiable
+ {
+ private:
+
+ utils::DynamicMemPool m_memBlocksPool;
+
+ typedef stx::btree_set SetOfMemBlocks;
+
+ ///
+ /// A binary tree of garbage collected pieces of memory, ordered by the memory addresses of those pieces.
+ ///
+ /// Although a hash table could be faster, it is not sorted, hence cannot be used.
+ SetOfMemBlocks m_vertices;
+
+ void RemoveVertex(MemAddrContainer *vtx, bool allowDestruction);
+
+ public:
+
+ MemoryDigraph();
+
+ void ShrinkObjectPool();
+
+ MemAddrContainer *AddVertex(void *memAddr, size_t blockSize, FreeMemProc freeMemCallback);
+
+ MemAddrContainer *GetVertex(void *blockMemAddr) const;
+
+ MemAddrContainer *GetContainerVertex(void *addr) const;
+
+ void AddEdge(void *vtxRootFrom, MemAddrContainer *vtxRegularTo);
+
+ void AddEdge(MemAddrContainer *originatorVtx, MemAddrContainer *receivingVtx);
+
+ void RemoveEdge(void *vtxRootFrom, MemAddrContainer *vtxRegularTo, bool allowDestruction);
+
+ void RemoveEdge(MemAddrContainer *originatorVtx, MemAddrContainer *receivingVtx, bool allowDestruction);
+ };
+
+ }// end of namespace ctl
+}// end of namespace _3fd
+
+#endif // end of header guard
diff --git a/3FD/gc_messages.cpp b/3FD/gc_messages.cpp
new file mode 100644
index 0000000..abba28d
--- /dev/null
+++ b/3FD/gc_messages.cpp
@@ -0,0 +1,35 @@
+#include "stdafx.h"
+#include "gc_messages.h"
+
+namespace _3fd
+{
+ namespace memory
+ {
+ void ReferenceUpdateMsg::Execute(MasterTable &masterTable)
+ {
+ masterTable.DoUpdateReference(m_sptrObjAddr, m_pointedAddr);
+ }
+
+ void NewObjectMsg::Execute(MasterTable &masterTable)
+ {
+ masterTable.DoRegisterMemAddr(m_pointedAddr, m_blockSize, m_freeMemCallback);
+ masterTable.DoUpdateReference(m_sptrObjectAddr, m_pointedAddr);
+ }
+
+ void AbortedObjectMsg::Execute(MasterTable &masterTable)
+ {
+ masterTable.DoUpdateReference(m_sptrObjAddr, nullptr, false);
+ }
+
+ void SptrRegistrationMsg::Execute(MasterTable &masterTable)
+ {
+ masterTable.DoRegisterSptr(m_sptrObjAddr, m_pointedAddr);
+ }
+
+ void SptrUnregistrationMsg::Execute(MasterTable &masterTable)
+ {
+ masterTable.DoUnregisterSptr(m_sptrObjAddr);
+ }
+
+ }// end of namespace memory
+}// end of namespace _3fd
diff --git a/3FD/gc_messages.h b/3FD/gc_messages.h
new file mode 100644
index 0000000..1a8fb91
--- /dev/null
+++ b/3FD/gc_messages.h
@@ -0,0 +1,121 @@
+#ifndef GC_MESSAGES_H // header guard
+#define GC_MESSAGES_H
+
+#include "gc.h"
+
+namespace _3fd
+{
+ namespace memory
+ {
+ ///
+ /// Message used to inform that a object is now referencing a different/new object.
+ ///
+ class ReferenceUpdateMsg : public IMessage
+ {
+ private:
+
+ void *m_sptrObjAddr,
+ *m_pointedAddr;
+
+ public:
+
+ ReferenceUpdateMsg(void *sptrObjAddr, void *pointedAddr) throw() :
+ m_sptrObjAddr(sptrObjAddr),
+ m_pointedAddr(pointedAddr)
+ {}
+
+ virtual void Execute(MasterTable &masterTable) override;
+ };
+
+ ///
+ /// Message used to inform that the memory address of a new object is to be managed by the GC,
+ /// which means it will handle both the release of memory and object destruction.
+ ///
+ class NewObjectMsg : public IMessage
+ {
+ private:
+
+ void *m_sptrObjectAddr,
+ *m_pointedAddr;
+ size_t m_blockSize;
+ FreeMemProc m_freeMemCallback;
+
+ public:
+
+ NewObjectMsg(void *sptrObjaddr, void *pointedAddr, size_t blockSize, FreeMemProc freeMemCallback) throw() :
+ m_sptrObjectAddr(sptrObjaddr),
+ m_pointedAddr(pointedAddr),
+ m_blockSize(blockSize),
+ m_freeMemCallback(freeMemCallback)
+ {}
+
+ virtual void Execute(MasterTable &masterTable) override;
+ };
+
+ ///
+ /// Message used to inform that the construction of an object has failed, and so its memory must be unregistered
+ /// as well as the referer object must be updated.
+ ///
+ class AbortedObjectMsg : public IMessage
+ {
+ private:
+
+ void *m_sptrObjAddr;
+
+ public:
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The memory address of the object
+ /// whose referred object experienced failure during construction.
+ AbortedObjectMsg(void *sptrObjAddr) throw() :
+ m_sptrObjAddr(sptrObjAddr)
+ {}
+
+ virtual void Execute(MasterTable &masterTable) override;
+ };
+
+ ///
+ /// Message used to inform that a new object was created, and so must registered by the GC.
+ ///
+ class SptrRegistrationMsg : public IMessage
+ {
+ private:
+
+ void *m_sptrObjAddr,
+ *m_pointedAddr;
+
+ public:
+
+ SptrRegistrationMsg(void *sptrObjAddr, void *pointedAddr) throw() :
+ m_sptrObjAddr(sptrObjAddr),
+ m_pointedAddr(pointedAddr)
+ {}
+
+ virtual void Execute(MasterTable &masterTable) override;
+ };
+
+ ///
+ /// Message used to inform that a object was destroyed, and so must be unregistered by the GC.
+ ///
+ class SptrUnregistrationMsg : public IMessage
+ {
+ private:
+
+ void *m_sptrObjAddr;
+
+ public:
+
+ SptrUnregistrationMsg(void *sptrObjAddr) throw() :
+ m_sptrObjAddr(sptrObjAddr)
+ {}
+
+ virtual void Execute(MasterTable &masterTable) override;
+ };
+
+
+ }// end of memory
+}// end of namespace _3fd
+
+#endif // end of header guard
\ No newline at end of file
diff --git a/3FD/gc_vertex.cpp b/3FD/gc_vertex.cpp
new file mode 100644
index 0000000..0e26536
--- /dev/null
+++ b/3FD/gc_vertex.cpp
@@ -0,0 +1,249 @@
+#include "stdafx.h"
+#include "gc_memblock.h"
+
+#include
+#include
+
+/*
+ Regular vertices are kept in the second partition whereas root vertices stay in the first. That is
+ because the handling of regular vertices is expected to happen more often, hence their insertion must
+ be simple (faster). They happen more often when the graph has long and complex paths, which is the
+ scenario where garbage collection makes sense.
+*/
+namespace _3fd
+{
+ namespace memory
+ {
+ ///
+ /// Does insertion sort.
+ /// It expects a array interval that was sorted until the last insertion to the right.
+ /// The algorithm is fast (linear complexity) for such cases.
+ ///
+ /// An iterator to the first position in the array interval to sort.
+ /// An iterator to one past the last position in the array interval to sort.
+ static void InsertionSort(MemAddress *begin, MemAddress *end)
+ {
+ auto &right = end;
+ while (begin < --right)
+ {
+ auto left = right - 1;
+ if (left->Get() > right->Get())
+ {
+ auto temp = *right;
+ *right = *left;
+ *left = temp;
+ }
+ else
+ return;
+ }
+ }
+
+ ///
+ /// Searches for a value in a sorted array interval.
+ ///
+ /// An iterator to the first position in the array interval to search.
+ /// An iterator to one past the last position in the array interval to search.
+ /// The address value to look for.
+ /// An iterator to the position where it was found, otherwise, nullptr.
+ static MemAddress *Search(MemAddress *left, MemAddress *right, MemAddress what)
+ {
+ // Use scan if the vector is small enough:
+ auto size = right - left;
+ if (size <= 7)
+ return std::find(left, right, what);
+
+ // Otherwise, do binary search:
+ do
+ {
+ auto middle = left + size / 2;
+
+ if (what.Get() < middle->Get())
+ right = middle;
+ else if (what.Get() > middle->Get())
+ left = middle + 1;
+ else
+ return middle;
+
+ size = right - left;
+ }
+ while (size > 0);
+
+ return nullptr;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ Vertex::Vertex() :
+ m_arrayEdges(nullptr),
+ m_arraySize(0),
+ m_arrayCapacity(0),
+ m_rootCount(0)
+ {}
+
+ ///
+ /// Finalizes an instance of the class.
+ ///
+ Vertex::~Vertex()
+ {
+ if (m_arrayEdges != nullptr)
+ free(m_arrayEdges);
+ }
+
+ ///
+ /// Implementation for receiving a new edge.
+ ///
+ /// The address of the vertex object. Root vertices must be marked.
+ void Vertex::ReceiveEdgeImpl(MemAddress vtx)
+ {
+ if (m_arrayCapacity > m_arraySize) // there is room in the array
+ {
+ m_arrayEdges[m_arraySize++] = vtx;
+ }
+ else if (m_arrayCapacity > 0) // it must expand the array so as to make room
+ {
+ m_arrayCapacity *= 2;
+ auto temp = (MemAddress *)realloc(m_arrayEdges, m_arrayCapacity * sizeof(MemAddress));
+
+ if (temp != nullptr)
+ m_arrayEdges = temp;
+ else
+ throw std::bad_alloc();
+
+ m_arrayEdges[m_arraySize++] = vtx;
+ }
+ else // the array is not yet allocated
+ {
+ m_arrayEdges = (MemAddress *)malloc(sizeof(MemAddress));
+
+ if (m_arrayEdges != nullptr)
+ m_arrayEdges[0] = vtx;
+ else
+ throw std::bad_alloc();
+
+ m_arrayCapacity = m_arraySize = 1;
+ return;
+ }
+
+ // keep the array sorted
+ InsertionSort(m_arrayEdges, m_arrayEdges + m_arraySize);
+ }
+
+ ///
+ /// Adds a receiving an edge from a regultar vertex.
+ ///
+ /// The regular vertex.
+ void Vertex::ReceiveEdge(Vertex *vtxRegular)
+ {
+ ReceiveEdgeImpl(MemAddress(vtxRegular));
+ }
+
+ ///
+ /// Adds a receiving edge from a root vertex.
+ ///
+ /// The root vertex.
+ void Vertex::ReceiveEdge(void *vtxRoot)
+ {
+ MemAddress vtx(vtxRoot);
+ vtx.Mark(true);
+ ReceiveEdgeImpl(vtx);
+ ++m_rootCount;
+ }
+
+ ///
+ /// Evaluates whether capacity should shrink, then execute it.
+ ///
+ void Vertex::EvaluateShrinkCapacity()
+ {
+ if (m_arraySize < m_arrayCapacity / 4)
+ {
+ m_arrayCapacity /= 2;
+ auto temp = (MemAddress *)realloc(m_arrayEdges, m_arrayCapacity * sizeof(MemAddress));
+
+ if (temp != nullptr)
+ m_arrayEdges = temp;
+ else
+ throw std::bad_alloc();
+ }
+ }
+
+ ///
+ /// Implementation for removing an edge.
+ ///
+ /// The vertex to remove. Root vertices must be marked.
+ void Vertex::RemoveEdgeImpl(MemAddress vtx)
+ {
+ auto where = Search(m_arrayEdges, m_arrayEdges + m_arraySize--, vtx);
+ _ASSERTE(where != nullptr); // cannot handle removal of unexistent edge
+
+ for (auto idx = where - m_arrayEdges; idx < m_arraySize; ++idx)
+ m_arrayEdges[idx] = m_arrayEdges[idx + 1];
+
+ EvaluateShrinkCapacity();
+ }
+
+ ///
+ /// Removes an edge coming from a regular vertex.
+ ///
+ /// The regular vertex.
+ void Vertex::RemoveEdge(Vertex *vtxRegular)
+ {
+ RemoveEdgeImpl(MemAddress(vtxRegular));
+ }
+
+ ///
+ /// Removes an edge coming from a root vertex.
+ ///
+ /// The root vertex.
+ void Vertex::RemoveEdge(void *vtxRoot)
+ {
+ MemAddress vtx(vtxRoot);
+ vtx.Mark(true);
+ RemoveEdgeImpl(vtx);
+ --m_rootCount;
+ }
+
+ ///
+ /// Removes all receiving edges from this vertex.
+ ///
+ void Vertex::RemoveAllEdges()
+ {
+ m_arraySize = m_rootCount = 0;
+ EvaluateShrinkCapacity();
+ }
+
+ ///
+ /// Determines whether this vertex has any receiving edge from a root vertex.
+ ///
+ /// Whether it has a receiving edge from a root vertex.
+ bool Vertex::HasRootEdge() const
+ {
+ return m_rootCount > 0;
+ }
+
+ ///
+ /// Iterates over regular edges while the callback keeps asking for continuation.
+ ///
+ /// The callback that receives the vertices as parameter. Iteration continues while it returns 'true'.
+ /// false if the callback has returned false for any edge from regular vertex.
+ bool Vertex::ForEachRegularEdgeWhile(const std::function &callback) const
+ {
+ if (m_arraySize > 0)
+ {
+ uint32_t idx(0);
+ bool goAhead(true);
+ while (idx < m_arraySize && goAhead)
+ {
+ auto edge = m_arrayEdges[idx++];
+ if (!edge.isMarked())
+ goAhead = callback(*static_cast (edge.Get()));
+ }
+
+ return idx == m_arraySize && goAhead;
+ }
+ else
+ return true;
+ }
+
+ }// end of namespace memory
+}// end of namespace _3fd
diff --git a/3FD/isam.h b/3FD/isam.h
new file mode 100644
index 0000000..0fdfccc
--- /dev/null
+++ b/3FD/isam.h
@@ -0,0 +1,816 @@
+#ifndef ISAM_H
+#define ISAM_H
+
+#include "base.h"
+#include "exceptions.h"
+#include "callstacktracer.h"
+#include
+#include