<commit_before>#include "MacauPrior.h"

#include <SmurffCpp/IO/MatrixIO.h>
#include <SmurffCpp/IO/GenericIO.h>

#include <SmurffCpp/Utils/Distribution.h>
#include <SmurffCpp/Utils/Error.h>
#include <SmurffCpp/Utils/counters.h>

#include <SmurffCpp/Utils/linop.h>

#include <ios>

using namespace smurff;

MacauPrior::MacauPrior()
    : NormalPrior()
{
}

MacauPrior::MacauPrior(std::shared_ptr<Session> session, uint32_t mode)
    : NormalPrior(session, mode, "MacauPrior")
{
    beta_precision = SideInfoConfig::BETA_PRECISION_DEFAULT_VALUE;
    tol = SideInfoConfig::TOL_DEFAULT_VALUE;

    enable_beta_precision_sampling = Config::ENABLE_BETA_PRECISION_SAMPLING_DEFAULT_VALUE;
}

MacauPrior::~MacauPrior()
{
}

void MacauPrior::init()
{
   NormalPrior::init();

   THROWERROR_ASSERT_MSG(Features->rows() == num_item(), "Number of rows in train must be equal to number of rows in features");

   if (use_FtF)
   {
      std::uint64_t dim = num_feat();
      FtF_plus_precision.resize(dim, dim);
      Features->At_mul_A(FtF_plus_precision);
      FtF_plus_precision.diagonal().array() += beta_precision;
   }

   Uhat.resize(num_latent(), Features->rows());
   Uhat.setZero();

   m_beta = std::make_shared<Eigen::MatrixXd>(num_latent(), num_feat());
   beta().setZero();

   BBt = beta() * beta().transpose();

   m_session->model().setLinkMatrix(m_mode, m_beta);
}

void MacauPrior::update_prior()
{
    /*
>> compute_uhat:                     0.5012     (12%) in        110
>> main:                             4.1396     (100%) in       1
>> rest of update_prior:             0.1684     (4%) in 110
>> sample hyper mu/Lambda:           0.3804     (9%) in 110
>> sample_beta:                      1.4927     (36%) in        110
>> sample_latents:                   3.8824     (94%) in        220
>> step:                             3.9824     (96%) in        111
>> update_prior:                     2.5436     (61%) in        110
*/
    COUNTER("update_prior");
    {
        COUNTER("rest of update_prior");

    }

    // sampling Gaussian
    {
        COUNTER("sample hyper mu/Lambda");
        //uses: U, Uhat
        // writes: Udelta
        // complexity: num_latent x num_items
        Udelta = U() - Uhat;
        // uses: Udelta
        // complexity: num_latent x num_items
        std::tie(mu, Lambda) = CondNormalWishart(Udelta, mu0, b0, WI + beta_precision * BBt, df + num_feat());
    }

    // uses: U, F
    // writes: Ft_y
    // uses: U, F
    // writes: Ft_y
    // complexity: num_latent x num_feat x num_item
    compute_Ft_y(Ft_y);

    sample_beta();

    {
        COUNTER("compute_uhat");
        // Uhat = beta * F
        // uses: beta, F
        // output: Uhat
        // complexity: num_feat x num_latent x num_item
        Features->compute_uhat(Uhat, beta());
    }

    if (enable_beta_precision_sampling)
    {
        // uses: beta
        // writes: FtF
        COUNTER("sample_beta_precision");
        double old_beta = beta_precision;
        beta_precision = sample_beta_precision(BBt, Lambda, beta_precision_nu0, beta_precision_mu0, beta().cols());
        FtF_plus_precision.diagonal().array() += beta_precision - old_beta;
   }
}

void MacauPrior::sample_beta()
{
    COUNTER("sample_beta");
    if (use_FtF)
    {
        // uses: FtF, Ft_y,
        // writes: m_beta
        // complexity: num_feat^3
        beta() = FtF_plus_precision.llt().solve(Ft_y.transpose()).transpose();
    }
    else
    {
        // uses: Features, beta_precision, Ft_y,
        // writes: beta
        // complexity: num_feat x num_feat x num_iter
        blockcg_iter = Features->solve_blockcg(beta(), beta_precision, Ft_y, tol, 32, 8, throw_on_cholesky_error);
    }
    // complexity: num_feat x num_feat x num_latent
    BBt = beta() * beta().transpose();
    std::cout << "beta: " << beta().rows() << " x " << beta().cols() << std::endl;
    std::cout << "BBt: " << BBt.rows() << " x " << BBt.cols() << std::endl;
}

const Eigen::VectorXd MacauPrior::getMu(int n) const
{
   return mu + Uhat.col(n);
}

void MacauPrior::compute_Ft_y(Eigen::MatrixXd& Ft_y)
{
    COUNTER("compute Ft_y");
   // Ft_y = (U .- mu + Normal(0, Lambda^-1)) * F + std::sqrt(beta_precision) * Normal(0, Lambda^-1)
   // Ft_y is [ num_latent x num_feat ] matrix

   //HyperU: num_latent x num_item
   HyperU = (U() + MvNormal_prec(Lambda, num_item())).colwise() - mu;
   Ft_y = Features->A_mul_B(HyperU); // num_latent x num_feat

   //--  add beta_precision
   HyperU2 = MvNormal_prec(Lambda, num_feat()); // num_latent x num_feat
   Ft_y += std::sqrt(beta_precision) * HyperU2;
}

void MacauPrior::addSideInfo(const std::shared_ptr<ISideInfo>& side_info_a, double beta_precision_a, double tolerance_a, bool direct_a, bool enable_beta_precision_sampling_a, bool throw_on_cholesky_error_a)
{
    //FIXME: remove old code

    // old code

    // side information
    Features = side_info_a;
    beta_precision = beta_precision_a;
    tol = tolerance_a;
    use_FtF = direct_a;
    enable_beta_precision_sampling = enable_beta_precision_sampling_a;
    throw_on_cholesky_error = throw_on_cholesky_error_a;

    // new code

    // side information
    side_info_values.push_back(side_info_a);
    beta_precision_values.push_back(beta_precision_a);
    tol_values.push_back(tolerance_a);
    direct_values.push_back(direct_a);
    enable_beta_precision_sampling_values.push_back(enable_beta_precision_sampling_a);
    throw_on_cholesky_error_values.push_back(throw_on_cholesky_error_a);

    // other code

    // Hyper-prior for beta_precision (mean 1.0, var of 1e+3):
    beta_precision_mu0 = 1.0;
    beta_precision_nu0 = 1e-3;
}

bool MacauPrior::save(std::shared_ptr<const StepFile> sf) const
{
    NormalPrior::save(sf);

   std::string path = sf->makeLinkMatrixFileName(m_mode);
   smurff::matrix_io::eigen::write_matrix(path, beta());

    return true;
}

void MacauPrior::restore(std::shared_ptr<const StepFile> sf)
{
    NormalPrior::restore(sf);

    std::string path = sf->getLinkMatrixFileName(m_mode);

   smurff::matrix_io::eigen::read_matrix(path, beta());
}

std::ostream& MacauPrior::info(std::ostream &os, std::string indent)
{
   NormalPrior::info(os, indent);
   os << indent << " SideInfo: ";
   Features->print(os);
   os << indent << " Method: ";
   if (use_FtF)
   {
      os << "Cholesky Decomposition";
      double needs_gb = (double)num_feat() / 1024. * (double)num_feat() / 1024. / 1024.;
      if (needs_gb > 1.0) os << " (needing " << needs_gb << " GB of memory)";
      os << std::endl;
   } else {
      os << "CG Solver with tolerance: " << std::scientific << tol << std::fixed << std::endl;
   }
   os << indent << " BetaPrecision: ";
   if (enable_beta_precision_sampling)
   {
       os << "sampled around ";
   }
   else
   {
       os << "fixed at ";
   }
   os << beta_precision << std::endl;
   return os;
}

std::ostream &MacauPrior::status(std::ostream &os, std::string indent) const
{
   os << indent << m_name << ": " << std::endl;
   indent += "  ";
   os << indent << "blockcg iter = " << blockcg_iter << std::endl;
   os << indent << "FtF_plus_precision= " << FtF_plus_precision.norm() << std::endl;
   os << indent << "HyperU       = " << HyperU.norm() << std::endl;
   os << indent << "HyperU2      = " << HyperU2.norm() << std::endl;
   os << indent << "Beta         = " << beta().norm() << std::endl;
   os << indent << "beta_precision  = " << beta_precision << std::endl;
   os << indent << "Ft_y         = " << Ft_y.norm() << std::endl;
   return os;
}

std::pair<double, double> MacauPrior::posterior_beta_precision(const Eigen::MatrixXd & BBt, Eigen::MatrixXd & Lambda_u, double nu, double mu, int N)
{
   double nux = nu + N * BBt.cols();
   double mux = mu * nux / (nu + mu * (BBt.selfadjointView<Eigen::Lower>() * Lambda_u).trace());
   double b = nux / 2;
   double c = 2 * mux / nux;
   return std::make_pair(b, c);
}

double MacauPrior::sample_beta_precision(const Eigen::MatrixXd & BBt, Eigen::MatrixXd & Lambda_u, double nu, double mu, int N)
{
   auto gamma_post = posterior_beta_precision(BBt, Lambda_u, nu, mu, N);
   return rgamma(gamma_post.first, gamma_post.second);
}
<commit_msg>FIX: renmove debug printing<commit_after>#include "MacauPrior.h"

#include <SmurffCpp/IO/MatrixIO.h>
#include <SmurffCpp/IO/GenericIO.h>

#include <SmurffCpp/Utils/Distribution.h>
#include <SmurffCpp/Utils/Error.h>
#include <SmurffCpp/Utils/counters.h>

#include <SmurffCpp/Utils/linop.h>

#include <ios>

using namespace smurff;

MacauPrior::MacauPrior()
    : NormalPrior()
{
}

MacauPrior::MacauPrior(std::shared_ptr<Session> session, uint32_t mode)
    : NormalPrior(session, mode, "MacauPrior")
{
    beta_precision = SideInfoConfig::BETA_PRECISION_DEFAULT_VALUE;
    tol = SideInfoConfig::TOL_DEFAULT_VALUE;

    enable_beta_precision_sampling = Config::ENABLE_BETA_PRECISION_SAMPLING_DEFAULT_VALUE;
}

MacauPrior::~MacauPrior()
{
}

void MacauPrior::init()
{
   NormalPrior::init();

   THROWERROR_ASSERT_MSG(Features->rows() == num_item(), "Number of rows in train must be equal to number of rows in features");

   if (use_FtF)
   {
      std::uint64_t dim = num_feat();
      FtF_plus_precision.resize(dim, dim);
      Features->At_mul_A(FtF_plus_precision);
      FtF_plus_precision.diagonal().array() += beta_precision;
   }

   Uhat.resize(num_latent(), Features->rows());
   Uhat.setZero();

   m_beta = std::make_shared<Eigen::MatrixXd>(num_latent(), num_feat());
   beta().setZero();

   BBt = beta() * beta().transpose();

   m_session->model().setLinkMatrix(m_mode, m_beta);
}

void MacauPrior::update_prior()
{
    /*
>> compute_uhat:                     0.5012     (12%) in        110
>> main:                             4.1396     (100%) in       1
>> rest of update_prior:             0.1684     (4%) in 110
>> sample hyper mu/Lambda:           0.3804     (9%) in 110
>> sample_beta:                      1.4927     (36%) in        110
>> sample_latents:                   3.8824     (94%) in        220
>> step:                             3.9824     (96%) in        111
>> update_prior:                     2.5436     (61%) in        110
*/
    COUNTER("update_prior");
    {
        COUNTER("rest of update_prior");

    }

    // sampling Gaussian
    {
        COUNTER("sample hyper mu/Lambda");
        //uses: U, Uhat
        // writes: Udelta
        // complexity: num_latent x num_items
        Udelta = U() - Uhat;
        // uses: Udelta
        // complexity: num_latent x num_items
        std::tie(mu, Lambda) = CondNormalWishart(Udelta, mu0, b0, WI + beta_precision * BBt, df + num_feat());
    }

    // uses: U, F
    // writes: Ft_y
    // uses: U, F
    // writes: Ft_y
    // complexity: num_latent x num_feat x num_item
    compute_Ft_y(Ft_y);

    sample_beta();

    {
        COUNTER("compute_uhat");
        // Uhat = beta * F
        // uses: beta, F
        // output: Uhat
        // complexity: num_feat x num_latent x num_item
        Features->compute_uhat(Uhat, beta());
    }

    if (enable_beta_precision_sampling)
    {
        // uses: beta
        // writes: FtF
        COUNTER("sample_beta_precision");
        double old_beta = beta_precision;
        beta_precision = sample_beta_precision(BBt, Lambda, beta_precision_nu0, beta_precision_mu0, beta().cols());
        FtF_plus_precision.diagonal().array() += beta_precision - old_beta;
   }
}

void MacauPrior::sample_beta()
{
    COUNTER("sample_beta");
    if (use_FtF)
    {
        // uses: FtF, Ft_y,
        // writes: m_beta
        // complexity: num_feat^3
        beta() = FtF_plus_precision.llt().solve(Ft_y.transpose()).transpose();
    }
    else
    {
        // uses: Features, beta_precision, Ft_y,
        // writes: beta
        // complexity: num_feat x num_feat x num_iter
        blockcg_iter = Features->solve_blockcg(beta(), beta_precision, Ft_y, tol, 32, 8, throw_on_cholesky_error);
    }
    // complexity: num_feat x num_feat x num_latent
    BBt = beta() * beta().transpose();
}

const Eigen::VectorXd MacauPrior::getMu(int n) const
{
   return mu + Uhat.col(n);
}

void MacauPrior::compute_Ft_y(Eigen::MatrixXd& Ft_y)
{
    COUNTER("compute Ft_y");
   // Ft_y = (U .- mu + Normal(0, Lambda^-1)) * F + std::sqrt(beta_precision) * Normal(0, Lambda^-1)
   // Ft_y is [ num_latent x num_feat ] matrix

   //HyperU: num_latent x num_item
   HyperU = (U() + MvNormal_prec(Lambda, num_item())).colwise() - mu;
   Ft_y = Features->A_mul_B(HyperU); // num_latent x num_feat

   //--  add beta_precision
   HyperU2 = MvNormal_prec(Lambda, num_feat()); // num_latent x num_feat
   Ft_y += std::sqrt(beta_precision) * HyperU2;
}

void MacauPrior::addSideInfo(const std::shared_ptr<ISideInfo>& side_info_a, double beta_precision_a, double tolerance_a, bool direct_a, bool enable_beta_precision_sampling_a, bool throw_on_cholesky_error_a)
{
    //FIXME: remove old code

    // old code

    // side information
    Features = side_info_a;
    beta_precision = beta_precision_a;
    tol = tolerance_a;
    use_FtF = direct_a;
    enable_beta_precision_sampling = enable_beta_precision_sampling_a;
    throw_on_cholesky_error = throw_on_cholesky_error_a;

    // new code

    // side information
    side_info_values.push_back(side_info_a);
    beta_precision_values.push_back(beta_precision_a);
    tol_values.push_back(tolerance_a);
    direct_values.push_back(direct_a);
    enable_beta_precision_sampling_values.push_back(enable_beta_precision_sampling_a);
    throw_on_cholesky_error_values.push_back(throw_on_cholesky_error_a);

    // other code

    // Hyper-prior for beta_precision (mean 1.0, var of 1e+3):
    beta_precision_mu0 = 1.0;
    beta_precision_nu0 = 1e-3;
}

bool MacauPrior::save(std::shared_ptr<const StepFile> sf) const
{
    NormalPrior::save(sf);

   std::string path = sf->makeLinkMatrixFileName(m_mode);
   smurff::matrix_io::eigen::write_matrix(path, beta());

    return true;
}

void MacauPrior::restore(std::shared_ptr<const StepFile> sf)
{
    NormalPrior::restore(sf);

    std::string path = sf->getLinkMatrixFileName(m_mode);

   smurff::matrix_io::eigen::read_matrix(path, beta());
}

std::ostream& MacauPrior::info(std::ostream &os, std::string indent)
{
   NormalPrior::info(os, indent);
   os << indent << " SideInfo: ";
   Features->print(os);
   os << indent << " Method: ";
   if (use_FtF)
   {
      os << "Cholesky Decomposition";
      double needs_gb = (double)num_feat() / 1024. * (double)num_feat() / 1024. / 1024.;
      if (needs_gb > 1.0) os << " (needing " << needs_gb << " GB of memory)";
      os << std::endl;
   } else {
      os << "CG Solver with tolerance: " << std::scientific << tol << std::fixed << std::endl;
   }
   os << indent << " BetaPrecision: ";
   if (enable_beta_precision_sampling)
   {
       os << "sampled around ";
   }
   else
   {
       os << "fixed at ";
   }
   os << beta_precision << std::endl;
   return os;
}

std::ostream &MacauPrior::status(std::ostream &os, std::string indent) const
{
   os << indent << m_name << ": " << std::endl;
   indent += "  ";
   os << indent << "blockcg iter = " << blockcg_iter << std::endl;
   os << indent << "FtF_plus_precision= " << FtF_plus_precision.norm() << std::endl;
   os << indent << "HyperU       = " << HyperU.norm() << std::endl;
   os << indent << "HyperU2      = " << HyperU2.norm() << std::endl;
   os << indent << "Beta         = " << beta().norm() << std::endl;
   os << indent << "beta_precision  = " << beta_precision << std::endl;
   os << indent << "Ft_y         = " << Ft_y.norm() << std::endl;
   return os;
}

std::pair<double, double> MacauPrior::posterior_beta_precision(const Eigen::MatrixXd & BBt, Eigen::MatrixXd & Lambda_u, double nu, double mu, int N)
{
   double nux = nu + N * BBt.cols();
   double mux = mu * nux / (nu + mu * (BBt.selfadjointView<Eigen::Lower>() * Lambda_u).trace());
   double b = nux / 2;
   double c = 2 * mux / nux;
   return std::make_pair(b, c);
}

double MacauPrior::sample_beta_precision(const Eigen::MatrixXd & BBt, Eigen::MatrixXd & Lambda_u, double nu, double mu, int N)
{
   auto gamma_post = posterior_beta_precision(BBt, Lambda_u, nu, mu, N);
   return rgamma(gamma_post.first, gamma_post.second);
}
<|endoftext|>


<commit_before>/*
* Assorted commonly used Vulkan helper functions
*
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/

#include "VulkanTools.h"

namespace vks
{
	namespace tools
	{
		std::string errorString(VkResult errorCode)
		{
			switch (errorCode)
			{
#define STR(r) case VK_ ##r: return #r
				STR(NOT_READY);
				STR(TIMEOUT);
				STR(EVENT_SET);
				STR(EVENT_RESET);
				STR(INCOMPLETE);
				STR(ERROR_OUT_OF_HOST_MEMORY);
				STR(ERROR_OUT_OF_DEVICE_MEMORY);
				STR(ERROR_INITIALIZATION_FAILED);
				STR(ERROR_DEVICE_LOST);
				STR(ERROR_MEMORY_MAP_FAILED);
				STR(ERROR_LAYER_NOT_PRESENT);
				STR(ERROR_EXTENSION_NOT_PRESENT);
				STR(ERROR_FEATURE_NOT_PRESENT);
				STR(ERROR_INCOMPATIBLE_DRIVER);
				STR(ERROR_TOO_MANY_OBJECTS);
				STR(ERROR_FORMAT_NOT_SUPPORTED);
				STR(ERROR_SURFACE_LOST_KHR);
				STR(ERROR_NATIVE_WINDOW_IN_USE_KHR);
				STR(SUBOPTIMAL_KHR);
				STR(ERROR_OUT_OF_DATE_KHR);
				STR(ERROR_INCOMPATIBLE_DISPLAY_KHR);
				STR(ERROR_VALIDATION_FAILED_EXT);
				STR(ERROR_INVALID_SHADER_NV);
#undef STR
			default:
				return "UNKNOWN_ERROR";
			}
		}

		std::string physicalDeviceTypeString(VkPhysicalDeviceType type)
		{
			switch (type)
			{
#define STR(r) case VK_PHYSICAL_DEVICE_TYPE_ ##r: return #r
				STR(OTHER);
				STR(INTEGRATED_GPU);
				STR(DISCRETE_GPU);
				STR(VIRTUAL_GPU);
#undef STR
			default: return "UNKNOWN_DEVICE_TYPE";
			}
		}

		VkBool32 getSupportedDepthFormat(VkPhysicalDevice physicalDevice, VkFormat *depthFormat)
		{
			// Since all depth formats may be optional, we need to find a suitable depth format to use
			// Start with the highest precision packed format
			std::vector<VkFormat> depthFormats = {
				VK_FORMAT_D32_SFLOAT_S8_UINT,
				VK_FORMAT_D32_SFLOAT,
				VK_FORMAT_D24_UNORM_S8_UINT,
				VK_FORMAT_D16_UNORM_S8_UINT,
				VK_FORMAT_D16_UNORM
			};

			for (auto& format : depthFormats)
			{
				VkFormatProperties formatProps;
				vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProps);
				// Format must support depth stencil attachment for optimal tiling
				if (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
				{
					*depthFormat = format;
					return true;
				}
			}

			return false;
		}

		// Create an image memory barrier for changing the layout of
		// an image and put it into an active command buffer
		// See chapter 11.4 "Image Layout" for details

		void setImageLayout(
			VkCommandBuffer cmdbuffer,
			VkImage image,
			VkImageAspectFlags aspectMask,
			VkImageLayout oldImageLayout,
			VkImageLayout newImageLayout,
			VkImageSubresourceRange subresourceRange,
			VkPipelineStageFlags srcStageMask,
			VkPipelineStageFlags dstStageMask)
		{
			// Create an image barrier object
			VkImageMemoryBarrier imageMemoryBarrier = vks::initializers::imageMemoryBarrier();
			imageMemoryBarrier.oldLayout = oldImageLayout;
			imageMemoryBarrier.newLayout = newImageLayout;
			imageMemoryBarrier.image = image;
			imageMemoryBarrier.subresourceRange = subresourceRange;

			// Source layouts (old)
			// Source access mask controls actions that have to be finished on the old layout
			// before it will be transitioned to the new layout
			switch (oldImageLayout)
			{
			case VK_IMAGE_LAYOUT_UNDEFINED:
				// Image layout is undefined (or does not matter)
				// Only valid as initial layout
				// No flags required, listed only for completeness
				imageMemoryBarrier.srcAccessMask = 0;
				break;

			case VK_IMAGE_LAYOUT_PREINITIALIZED:
				// Image is preinitialized
				// Only valid as initial layout for linear images, preserves memory contents
				// Make sure host writes have been finished
				imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
				break;

			case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
				// Image is a color attachment
				// Make sure any writes to the color buffer have been finished
				imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
				break;

			case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
				// Image is a depth/stencil attachment
				// Make sure any writes to the depth/stencil buffer have been finished
				imageMemoryBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
				break;

			case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
				// Image is a transfer source
				// Make sure any reads from the image have been finished
				imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
				break;

			case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
				// Image is a transfer destination
				// Make sure any writes to the image have been finished
				imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
				break;

			case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
				// Image is read by a shader
				// Make sure any shader reads from the image have been finished
				imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
				break;
			}

			// Target layouts (new)
			// Destination access mask controls the dependency for the new image layout
			switch (newImageLayout)
			{
			case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
				// Image will be used as a transfer destination
				// Make sure any writes to the image have been finished
				imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
				break;

			case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
				// Image will be used as a transfer source
				// Make sure any reads from the image have been finished
				imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
				break;

			case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
				// Image will be used as a color attachment
				// Make sure any writes to the color buffer have been finished
				imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
				break;

			case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
				// Image layout will be used as a depth/stencil attachment
				// Make sure any writes to depth/stencil buffer have been finished
				imageMemoryBarrier.dstAccessMask = imageMemoryBarrier.dstAccessMask | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
				break;

			case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
				// Image will be read in a shader (sampler, input attachment)
				// Make sure any writes to the image have been finished
				if (imageMemoryBarrier.srcAccessMask == 0)
				{
					imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
				}
				imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
				break;
			}

			// Put barrier inside setup command buffer
			vkCmdPipelineBarrier(
				cmdbuffer,
				srcStageMask,
				dstStageMask,
				0,
				0, nullptr,
				0, nullptr,
				1, &imageMemoryBarrier);
		}

		// Fixed sub resource on first mip level and layer
		void setImageLayout(
			VkCommandBuffer cmdbuffer,
			VkImage image,
			VkImageAspectFlags aspectMask,
			VkImageLayout oldImageLayout,
			VkImageLayout newImageLayout,
			VkPipelineStageFlags srcStageMask,
			VkPipelineStageFlags dstStageMask)
		{
			VkImageSubresourceRange subresourceRange = {};
			subresourceRange.aspectMask = aspectMask;
			subresourceRange.baseMipLevel = 0;
			subresourceRange.levelCount = 1;
			subresourceRange.layerCount = 1;
			setImageLayout(cmdbuffer, image, aspectMask, oldImageLayout, newImageLayout, subresourceRange);
		}

		void insertImageMemoryBarrier(
			VkCommandBuffer cmdbuffer,
			VkImage image,
			VkAccessFlags srcAccessMask,
			VkAccessFlags dstAccessMask,
			VkImageLayout oldImageLayout,
			VkImageLayout newImageLayout,
			VkPipelineStageFlags srcStageMask,
			VkPipelineStageFlags dstStageMask,
			VkImageSubresourceRange subresourceRange)
		{
			VkImageMemoryBarrier imageMemoryBarrier = vks::initializers::imageMemoryBarrier();
			imageMemoryBarrier.srcAccessMask = srcAccessMask;
			imageMemoryBarrier.dstAccessMask = dstAccessMask;
			imageMemoryBarrier.oldLayout = oldImageLayout;
			imageMemoryBarrier.newLayout = newImageLayout;
			imageMemoryBarrier.image = image;
			imageMemoryBarrier.subresourceRange = subresourceRange;

			vkCmdPipelineBarrier(
				cmdbuffer,
				srcStageMask,
				dstStageMask,
				0,
				0, nullptr,
				0, nullptr,
				1, &imageMemoryBarrier);
		}

		void exitFatal(std::string message, std::string caption)
		{
#if defined(_WIN32)
			MessageBox(NULL, message.c_str(), caption.c_str(), MB_OK | MB_ICONERROR);
#elif defined(__ANDROID__)
			LOGE("Fatal error: %s", message.c_str());
#else
			std::cerr << message << "\n";
#endif
			exit(1);
		}

		std::string readTextFile(const char *fileName)
		{
			std::string fileContent;
			std::ifstream fileStream(fileName, std::ios::in);
			if (!fileStream.is_open()) {
				printf("File %s not found\n", fileName);
				return "";
			}
			std::string line = "";
			while (!fileStream.eof()) {
				getline(fileStream, line);
				fileContent.append(line + "\n");
			}
			fileStream.close();
			return fileContent;
		}

#if defined(__ANDROID__)
		// Android shaders are stored as assets in the apk
		// So they need to be loaded via the asset manager
		VkShaderModule loadShader(AAssetManager* assetManager, const char *fileName, VkDevice device, VkShaderStageFlagBits stage)
		{
			// Load shader from compressed asset
			AAsset* asset = AAssetManager_open(assetManager, fileName, AASSET_MODE_STREAMING);
			assert(asset);
			size_t size = AAsset_getLength(asset);
			assert(size > 0);

			char *shaderCode = new char[size];
			AAsset_read(asset, shaderCode, size);
			AAsset_close(asset);

			VkShaderModule shaderModule;
			VkShaderModuleCreateInfo moduleCreateInfo;
			moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
			moduleCreateInfo.pNext = NULL;
			moduleCreateInfo.codeSize = size;
			moduleCreateInfo.pCode = (uint32_t*)shaderCode;
			moduleCreateInfo.flags = 0;

			VK_CHECK_RESULT(vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderModule));

			delete[] shaderCode;

			return shaderModule;
		}
#else
		VkShaderModule loadShader(const char *fileName, VkDevice device, VkShaderStageFlagBits stage)
		{
			std::ifstream is(fileName, std::ios::binary | std::ios::in | std::ios::ate);

			if (is.is_open())
			{
				size_t size = is.tellg();
				is.seekg(0, std::ios::beg);
				char* shaderCode = new char[size];
				is.read(shaderCode, size);
				is.close();

				assert(size > 0);

				VkShaderModule shaderModule;
				VkShaderModuleCreateInfo moduleCreateInfo{};
				moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
				moduleCreateInfo.codeSize = size;
				moduleCreateInfo.pCode = (uint32_t*)shaderCode;

				VK_CHECK_RESULT(vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderModule));

				delete[] shaderCode;

				return shaderModule;
			}
			else
			{
				std::cerr << "Error: Could not open shader file \"" << fileName << "\"" << std::endl;
				return VK_NULL_HANDLE;
			}
		}
#endif

		VkShaderModule loadShaderGLSL(const char *fileName, VkDevice device, VkShaderStageFlagBits stage)
		{
			std::string shaderSrc = readTextFile(fileName);
			const char *shaderCode = shaderSrc.c_str();
			size_t size = strlen(shaderCode);
			assert(size > 0);

			VkShaderModule shaderModule;
			VkShaderModuleCreateInfo moduleCreateInfo;
			moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
			moduleCreateInfo.pNext = NULL;
			moduleCreateInfo.codeSize = 3 * sizeof(uint32_t) + size + 1;
			moduleCreateInfo.pCode = (uint32_t*)malloc(moduleCreateInfo.codeSize);
			moduleCreateInfo.flags = 0;

			// Magic SPV number
			((uint32_t *)moduleCreateInfo.pCode)[0] = 0x07230203;
			((uint32_t *)moduleCreateInfo.pCode)[1] = 0;
			((uint32_t *)moduleCreateInfo.pCode)[2] = stage;
			memcpy(((uint32_t *)moduleCreateInfo.pCode + 3), shaderCode, size + 1);

			VK_CHECK_RESULT(vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderModule));

			return shaderModule;
		}

		bool fileExists(const std::string &filename)
		{
			std::ifstream f(filename.c_str());
			return !f.fail();
		}
	}
}<commit_msg>Default route for image layout switch statements (fixes gcc compiler warnings, refs #103)<commit_after>/*
* Assorted commonly used Vulkan helper functions
*
* Copyright (C) 2016 by Sascha Willems - www.saschawillems.de
*
* This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
*/

#include "VulkanTools.h"

namespace vks
{
	namespace tools
	{
		std::string errorString(VkResult errorCode)
		{
			switch (errorCode)
			{
#define STR(r) case VK_ ##r: return #r
				STR(NOT_READY);
				STR(TIMEOUT);
				STR(EVENT_SET);
				STR(EVENT_RESET);
				STR(INCOMPLETE);
				STR(ERROR_OUT_OF_HOST_MEMORY);
				STR(ERROR_OUT_OF_DEVICE_MEMORY);
				STR(ERROR_INITIALIZATION_FAILED);
				STR(ERROR_DEVICE_LOST);
				STR(ERROR_MEMORY_MAP_FAILED);
				STR(ERROR_LAYER_NOT_PRESENT);
				STR(ERROR_EXTENSION_NOT_PRESENT);
				STR(ERROR_FEATURE_NOT_PRESENT);
				STR(ERROR_INCOMPATIBLE_DRIVER);
				STR(ERROR_TOO_MANY_OBJECTS);
				STR(ERROR_FORMAT_NOT_SUPPORTED);
				STR(ERROR_SURFACE_LOST_KHR);
				STR(ERROR_NATIVE_WINDOW_IN_USE_KHR);
				STR(SUBOPTIMAL_KHR);
				STR(ERROR_OUT_OF_DATE_KHR);
				STR(ERROR_INCOMPATIBLE_DISPLAY_KHR);
				STR(ERROR_VALIDATION_FAILED_EXT);
				STR(ERROR_INVALID_SHADER_NV);
#undef STR
			default:
				return "UNKNOWN_ERROR";
			}
		}

		std::string physicalDeviceTypeString(VkPhysicalDeviceType type)
		{
			switch (type)
			{
#define STR(r) case VK_PHYSICAL_DEVICE_TYPE_ ##r: return #r
				STR(OTHER);
				STR(INTEGRATED_GPU);
				STR(DISCRETE_GPU);
				STR(VIRTUAL_GPU);
#undef STR
			default: return "UNKNOWN_DEVICE_TYPE";
			}
		}

		VkBool32 getSupportedDepthFormat(VkPhysicalDevice physicalDevice, VkFormat *depthFormat)
		{
			// Since all depth formats may be optional, we need to find a suitable depth format to use
			// Start with the highest precision packed format
			std::vector<VkFormat> depthFormats = {
				VK_FORMAT_D32_SFLOAT_S8_UINT,
				VK_FORMAT_D32_SFLOAT,
				VK_FORMAT_D24_UNORM_S8_UINT,
				VK_FORMAT_D16_UNORM_S8_UINT,
				VK_FORMAT_D16_UNORM
			};

			for (auto& format : depthFormats)
			{
				VkFormatProperties formatProps;
				vkGetPhysicalDeviceFormatProperties(physicalDevice, format, &formatProps);
				// Format must support depth stencil attachment for optimal tiling
				if (formatProps.optimalTilingFeatures & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)
				{
					*depthFormat = format;
					return true;
				}
			}

			return false;
		}

		// Create an image memory barrier for changing the layout of
		// an image and put it into an active command buffer
		// See chapter 11.4 "Image Layout" for details

		void setImageLayout(
			VkCommandBuffer cmdbuffer,
			VkImage image,
			VkImageAspectFlags aspectMask,
			VkImageLayout oldImageLayout,
			VkImageLayout newImageLayout,
			VkImageSubresourceRange subresourceRange,
			VkPipelineStageFlags srcStageMask,
			VkPipelineStageFlags dstStageMask)
		{
			// Create an image barrier object
			VkImageMemoryBarrier imageMemoryBarrier = vks::initializers::imageMemoryBarrier();
			imageMemoryBarrier.oldLayout = oldImageLayout;
			imageMemoryBarrier.newLayout = newImageLayout;
			imageMemoryBarrier.image = image;
			imageMemoryBarrier.subresourceRange = subresourceRange;

			// Source layouts (old)
			// Source access mask controls actions that have to be finished on the old layout
			// before it will be transitioned to the new layout
			switch (oldImageLayout)
			{
			case VK_IMAGE_LAYOUT_UNDEFINED:
				// Image layout is undefined (or does not matter)
				// Only valid as initial layout
				// No flags required, listed only for completeness
				imageMemoryBarrier.srcAccessMask = 0;
				break;

			case VK_IMAGE_LAYOUT_PREINITIALIZED:
				// Image is preinitialized
				// Only valid as initial layout for linear images, preserves memory contents
				// Make sure host writes have been finished
				imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
				break;

			case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
				// Image is a color attachment
				// Make sure any writes to the color buffer have been finished
				imageMemoryBarrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
				break;

			case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
				// Image is a depth/stencil attachment
				// Make sure any writes to the depth/stencil buffer have been finished
				imageMemoryBarrier.srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
				break;

			case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
				// Image is a transfer source
				// Make sure any reads from the image have been finished
				imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
				break;

			case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
				// Image is a transfer destination
				// Make sure any writes to the image have been finished
				imageMemoryBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
				break;

			case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
				// Image is read by a shader
				// Make sure any shader reads from the image have been finished
				imageMemoryBarrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT;
				break;
			default:
				// Other source layouts aren't handled (yet)
				break;
			}

			// Target layouts (new)
			// Destination access mask controls the dependency for the new image layout
			switch (newImageLayout)
			{
			case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
				// Image will be used as a transfer destination
				// Make sure any writes to the image have been finished
				imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
				break;

			case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
				// Image will be used as a transfer source
				// Make sure any reads from the image have been finished
				imageMemoryBarrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT;
				break;

			case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
				// Image will be used as a color attachment
				// Make sure any writes to the color buffer have been finished
				imageMemoryBarrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
				break;

			case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
				// Image layout will be used as a depth/stencil attachment
				// Make sure any writes to depth/stencil buffer have been finished
				imageMemoryBarrier.dstAccessMask = imageMemoryBarrier.dstAccessMask | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
				break;

			case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
				// Image will be read in a shader (sampler, input attachment)
				// Make sure any writes to the image have been finished
				if (imageMemoryBarrier.srcAccessMask == 0)
				{
					imageMemoryBarrier.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT;
				}
				imageMemoryBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
				break;
			default:
				// Other source layouts aren't handled (yet)
				break;
			}

			// Put barrier inside setup command buffer
			vkCmdPipelineBarrier(
				cmdbuffer,
				srcStageMask,
				dstStageMask,
				0,
				0, nullptr,
				0, nullptr,
				1, &imageMemoryBarrier);
		}

		// Fixed sub resource on first mip level and layer
		void setImageLayout(
			VkCommandBuffer cmdbuffer,
			VkImage image,
			VkImageAspectFlags aspectMask,
			VkImageLayout oldImageLayout,
			VkImageLayout newImageLayout,
			VkPipelineStageFlags srcStageMask,
			VkPipelineStageFlags dstStageMask)
		{
			VkImageSubresourceRange subresourceRange = {};
			subresourceRange.aspectMask = aspectMask;
			subresourceRange.baseMipLevel = 0;
			subresourceRange.levelCount = 1;
			subresourceRange.layerCount = 1;
			setImageLayout(cmdbuffer, image, aspectMask, oldImageLayout, newImageLayout, subresourceRange);
		}

		void insertImageMemoryBarrier(
			VkCommandBuffer cmdbuffer,
			VkImage image,
			VkAccessFlags srcAccessMask,
			VkAccessFlags dstAccessMask,
			VkImageLayout oldImageLayout,
			VkImageLayout newImageLayout,
			VkPipelineStageFlags srcStageMask,
			VkPipelineStageFlags dstStageMask,
			VkImageSubresourceRange subresourceRange)
		{
			VkImageMemoryBarrier imageMemoryBarrier = vks::initializers::imageMemoryBarrier();
			imageMemoryBarrier.srcAccessMask = srcAccessMask;
			imageMemoryBarrier.dstAccessMask = dstAccessMask;
			imageMemoryBarrier.oldLayout = oldImageLayout;
			imageMemoryBarrier.newLayout = newImageLayout;
			imageMemoryBarrier.image = image;
			imageMemoryBarrier.subresourceRange = subresourceRange;

			vkCmdPipelineBarrier(
				cmdbuffer,
				srcStageMask,
				dstStageMask,
				0,
				0, nullptr,
				0, nullptr,
				1, &imageMemoryBarrier);
		}

		void exitFatal(std::string message, std::string caption)
		{
#if defined(_WIN32)
			MessageBox(NULL, message.c_str(), caption.c_str(), MB_OK | MB_ICONERROR);
#elif defined(__ANDROID__)
			LOGE("Fatal error: %s", message.c_str());
#else
			std::cerr << message << "\n";
#endif
			exit(1);
		}

		std::string readTextFile(const char *fileName)
		{
			std::string fileContent;
			std::ifstream fileStream(fileName, std::ios::in);
			if (!fileStream.is_open()) {
				printf("File %s not found\n", fileName);
				return "";
			}
			std::string line = "";
			while (!fileStream.eof()) {
				getline(fileStream, line);
				fileContent.append(line + "\n");
			}
			fileStream.close();
			return fileContent;
		}

#if defined(__ANDROID__)
		// Android shaders are stored as assets in the apk
		// So they need to be loaded via the asset manager
		VkShaderModule loadShader(AAssetManager* assetManager, const char *fileName, VkDevice device, VkShaderStageFlagBits stage)
		{
			// Load shader from compressed asset
			AAsset* asset = AAssetManager_open(assetManager, fileName, AASSET_MODE_STREAMING);
			assert(asset);
			size_t size = AAsset_getLength(asset);
			assert(size > 0);

			char *shaderCode = new char[size];
			AAsset_read(asset, shaderCode, size);
			AAsset_close(asset);

			VkShaderModule shaderModule;
			VkShaderModuleCreateInfo moduleCreateInfo;
			moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
			moduleCreateInfo.pNext = NULL;
			moduleCreateInfo.codeSize = size;
			moduleCreateInfo.pCode = (uint32_t*)shaderCode;
			moduleCreateInfo.flags = 0;

			VK_CHECK_RESULT(vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderModule));

			delete[] shaderCode;

			return shaderModule;
		}
#else
		VkShaderModule loadShader(const char *fileName, VkDevice device, VkShaderStageFlagBits stage)
		{
			std::ifstream is(fileName, std::ios::binary | std::ios::in | std::ios::ate);

			if (is.is_open())
			{
				size_t size = is.tellg();
				is.seekg(0, std::ios::beg);
				char* shaderCode = new char[size];
				is.read(shaderCode, size);
				is.close();

				assert(size > 0);

				VkShaderModule shaderModule;
				VkShaderModuleCreateInfo moduleCreateInfo{};
				moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
				moduleCreateInfo.codeSize = size;
				moduleCreateInfo.pCode = (uint32_t*)shaderCode;

				VK_CHECK_RESULT(vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderModule));

				delete[] shaderCode;

				return shaderModule;
			}
			else
			{
				std::cerr << "Error: Could not open shader file \"" << fileName << "\"" << std::endl;
				return VK_NULL_HANDLE;
			}
		}
#endif

		VkShaderModule loadShaderGLSL(const char *fileName, VkDevice device, VkShaderStageFlagBits stage)
		{
			std::string shaderSrc = readTextFile(fileName);
			const char *shaderCode = shaderSrc.c_str();
			size_t size = strlen(shaderCode);
			assert(size > 0);

			VkShaderModule shaderModule;
			VkShaderModuleCreateInfo moduleCreateInfo;
			moduleCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
			moduleCreateInfo.pNext = NULL;
			moduleCreateInfo.codeSize = 3 * sizeof(uint32_t) + size + 1;
			moduleCreateInfo.pCode = (uint32_t*)malloc(moduleCreateInfo.codeSize);
			moduleCreateInfo.flags = 0;

			// Magic SPV number
			((uint32_t *)moduleCreateInfo.pCode)[0] = 0x07230203;
			((uint32_t *)moduleCreateInfo.pCode)[1] = 0;
			((uint32_t *)moduleCreateInfo.pCode)[2] = stage;
			memcpy(((uint32_t *)moduleCreateInfo.pCode + 3), shaderCode, size + 1);

			VK_CHECK_RESULT(vkCreateShaderModule(device, &moduleCreateInfo, NULL, &shaderModule));

			return shaderModule;
		}

		bool fileExists(const std::string &filename)
		{
			std::ifstream f(filename.c_str());
			return !f.fail();
		}
	}
}<|endoftext|>


<commit_before>
// g++-4.4 bench_gemm.cpp -I .. -O2 -DNDEBUG -lrt -fopenmp && OMP_NUM_THREADS=2  ./a.out
// icpc bench_gemm.cpp -I .. -O3 -DNDEBUG -lrt -openmp  && OMP_NUM_THREADS=2  ./a.out

#include <iostream>
#include <Eigen/Core>
#include <bench/BenchTimer.h>

using namespace std;
using namespace Eigen;

#ifndef SCALAR
// #define SCALAR std::complex<float>
#define SCALAR float
#endif

typedef SCALAR Scalar;
typedef NumTraits<Scalar>::Real RealScalar;
typedef Matrix<RealScalar,Dynamic,Dynamic> A;
typedef Matrix</*Real*/Scalar,Dynamic,Dynamic> B;
typedef Matrix<Scalar,Dynamic,Dynamic> C;
typedef Matrix<RealScalar,Dynamic,Dynamic> M;

#ifdef HAVE_BLAS

extern "C" {
  #include <bench/btl/libs/C_BLAS/blas.h>
}

static float fone = 1;
static float fzero = 0;
static double done = 1;
static double szero = 0;
static std::complex<float> cfone = 1;
static std::complex<float> cfzero = 0;
static std::complex<double> cdone = 1;
static std::complex<double> cdzero = 0;
static char notrans = 'N';
static char trans = 'T';
static char nonunit = 'N';
static char lower = 'L';
static char right = 'R';
static int intone = 1;

void blas_gemm(const MatrixXf& a, const MatrixXf& b, MatrixXf& c)
{
  int M = c.rows(); int N = c.cols(); int K = a.cols();
  int lda = a.rows(); int ldb = b.rows(); int ldc = c.rows();

  sgemm_(&notrans,&notrans,&M,&N,&K,&fone,
         const_cast<float*>(a.data()),&lda,
         const_cast<float*>(b.data()),&ldb,&fone,
         c.data(),&ldc);
}

EIGEN_DONT_INLINE void blas_gemm(const MatrixXd& a, const MatrixXd& b, MatrixXd& c)
{
  int M = c.rows(); int N = c.cols(); int K = a.cols();
  int lda = a.rows(); int ldb = b.rows(); int ldc = c.rows();

  dgemm_(&notrans,&notrans,&M,&N,&K,&done,
         const_cast<double*>(a.data()),&lda,
         const_cast<double*>(b.data()),&ldb,&done,
         c.data(),&ldc);
}

void blas_gemm(const MatrixXcf& a, const MatrixXcf& b, MatrixXcf& c)
{
  int M = c.rows(); int N = c.cols(); int K = a.cols();
  int lda = a.rows(); int ldb = b.rows(); int ldc = c.rows();

  cgemm_(&notrans,&notrans,&M,&N,&K,(float*)&cfone,
         const_cast<float*>((const float*)a.data()),&lda,
         const_cast<float*>((const float*)b.data()),&ldb,(float*)&cfone,
         (float*)c.data(),&ldc);
}

void blas_gemm(const MatrixXcd& a, const MatrixXcd& b, MatrixXcd& c)
{
  int M = c.rows(); int N = c.cols(); int K = a.cols();
  int lda = a.rows(); int ldb = b.rows(); int ldc = c.rows();

  zgemm_(&notrans,&notrans,&M,&N,&K,(double*)&cdone,
         const_cast<double*>((const double*)a.data()),&lda,
         const_cast<double*>((const double*)b.data()),&ldb,(double*)&cdone,
         (double*)c.data(),&ldc);
}

#endif

void matlab_cplx_cplx(const M& ar, const M& ai, const M& br, const M& bi, M& cr, M& ci)
{
  cr.noalias() += ar * br;
  cr.noalias() -= ai * bi;
  ci.noalias() += ar * bi;
  ci.noalias() += ai * br;
}

void matlab_real_cplx(const M& a, const M& br, const M& bi, M& cr, M& ci)
{
  cr.noalias() += a * br;
  ci.noalias() += a * bi;
}

void matlab_cplx_real(const M& ar, const M& ai, const M& b, M& cr, M& ci)
{
  cr.noalias() += ar * b;
  ci.noalias() += ai * b;
}

template<typename A, typename B, typename C>
EIGEN_DONT_INLINE void gemm(const A& a, const B& b, C& c)
{
 c.noalias() += a * b;
}

int main(int argc, char ** argv)
{
  std::ptrdiff_t l1 = internal::queryL1CacheSize();
  std::ptrdiff_t l2 = internal::queryTopLevelCacheSize();
  std::cout << "L1 cache size     = " << (l1>0 ? l1/1024 : -1) << " KB\n";
  std::cout << "L2/L3 cache size  = " << (l2>0 ? l2/1024 : -1) << " KB\n";
  typedef internal::gebp_traits<Scalar,Scalar> Traits;
  std::cout << "Register blocking = " << Traits::mr << " x " << Traits::nr << "\n";

  int rep = 1;    // number of repetitions per try
  int tries = 2;  // number of tries, we keep the best

  int s = 2048;
  int cache_size = -1;

  bool need_help = false;
  for (int i=1; i<argc; ++i)
  {
    if(argv[i][0]=='s')
      s = atoi(argv[i]+1);
    else if(argv[i][0]=='c')
      cache_size = atoi(argv[i]+1);
    else if(argv[i][0]=='t')
      tries = atoi(argv[i]+1);
    else if(argv[i][0]=='p')
      rep = atoi(argv[i]+1);
    else
      need_help = true;
  }

  if(need_help)
  {
    std::cout << argv[0] << " s<matrix size> c<cache size> t<nb tries> p<nb repeats>\n";
    return 1;
  }

  if(cache_size>0)
    setCpuCacheSizes(cache_size,96*cache_size);

  int m = s;
  int n = s;
  int p = s;
  A a(m,p); a.setRandom();
  B b(p,n); b.setRandom();
  C c(m,n); c.setOnes();

  std::cout << "Matrix sizes = " << m << "x" << p << " * " << p << "x" << n << "\n";
  std::ptrdiff_t mc(m), nc(n), kc(p);
  computeProductBlockingSizes<Scalar,Scalar>(kc, mc, nc);
  std::cout << "blocking size (mc x kc) = " << mc << " x " << kc << "\n";

  C r = c;

  // check the parallel product is correct
  #if defined EIGEN_HAS_OPENMP
  int procs = omp_get_max_threads();
  if(procs>1)
  {
    #ifdef HAVE_BLAS
    blas_gemm(a,b,r);
    #else
    omp_set_num_threads(1);
    r.noalias() += a * b;
    omp_set_num_threads(procs);
    #endif
    c.noalias() += a * b;
    if(!r.isApprox(c)) std::cerr << "Warning, your parallel product is crap!\n\n";
  }
  #elif defined HAVE_BLAS
    blas_gemm(a,b,r);
    c.noalias() += a * b;
    if(!r.isApprox(c)) std::cerr << "Warning, your product is crap!\n\n";
//     std::cerr << r << "\n\n" << c << "\n\n";
  #else
    gemm(a,b,c);
    r.noalias() += a.cast<Scalar>() * b.cast<Scalar>();
    if(!r.isApprox(c)) std::cerr << "Warning, your product is crap!\n\n";
//     std::cerr << c << "\n\n";
//     std::cerr << r << "\n\n";
  #endif

  #ifdef HAVE_BLAS
  BenchTimer tblas;
  BENCH(tblas, tries, rep, blas_gemm(a,b,c));
  std::cout << "blas  cpu         " << tblas.best(CPU_TIMER)/rep  << "s  \t" << (double(m)*n*p*rep*2/tblas.best(CPU_TIMER))*1e-9  <<  " GFLOPS \t(" << tblas.total(CPU_TIMER)  << "s)\n";
  std::cout << "blas  real        " << tblas.best(REAL_TIMER)/rep << "s  \t" << (double(m)*n*p*rep*2/tblas.best(REAL_TIMER))*1e-9 <<  " GFLOPS \t(" << tblas.total(REAL_TIMER) << "s)\n";
  #endif

  BenchTimer tmt;
  BENCH(tmt, tries, rep, gemm(a,b,c));
  std::cout << "eigen cpu         " << tmt.best(CPU_TIMER)/rep  << "s  \t" << (double(m)*n*p*rep*2/tmt.best(CPU_TIMER))*1e-9  <<  " GFLOPS \t(" << tmt.total(CPU_TIMER)  << "s)\n";
  std::cout << "eigen real        " << tmt.best(REAL_TIMER)/rep << "s  \t" << (double(m)*n*p*rep*2/tmt.best(REAL_TIMER))*1e-9 <<  " GFLOPS \t(" << tmt.total(REAL_TIMER) << "s)\n";

  #ifdef EIGEN_HAS_OPENMP
  if(procs>1)
  {
    BenchTimer tmono;
    //omp_set_num_threads(1);
    Eigen::setNbThreads(1);
    BENCH(tmono, tries, rep, gemm(a,b,c));
    std::cout << "eigen mono cpu    " << tmono.best(CPU_TIMER)/rep  << "s  \t" << (double(m)*n*p*rep*2/tmono.best(CPU_TIMER))*1e-9  <<  " GFLOPS \t(" << tmono.total(CPU_TIMER)  << "s)\n";
    std::cout << "eigen mono real   " << tmono.best(REAL_TIMER)/rep << "s  \t" << (double(m)*n*p*rep*2/tmono.best(REAL_TIMER))*1e-9 <<  " GFLOPS \t(" << tmono.total(REAL_TIMER) << "s)\n";
    std::cout << "mt speed up x" << tmono.best(CPU_TIMER) / tmt.best(REAL_TIMER)  << " => " << (100.0*tmono.best(CPU_TIMER) / tmt.best(REAL_TIMER))/procs << "%\n";
  }
  #endif

  #ifdef DECOUPLED
  if((NumTraits<A::Scalar>::IsComplex) && (NumTraits<B::Scalar>::IsComplex))
  {
    M ar(m,p); ar.setRandom();
    M ai(m,p); ai.setRandom();
    M br(p,n); br.setRandom();
    M bi(p,n); bi.setRandom();
    M cr(m,n); cr.setRandom();
    M ci(m,n); ci.setRandom();

    BenchTimer t;
    BENCH(t, tries, rep, matlab_cplx_cplx(ar,ai,br,bi,cr,ci));
    std::cout << "\"matlab\" cpu    " << t.best(CPU_TIMER)/rep  << "s  \t" << (double(m)*n*p*rep*2/t.best(CPU_TIMER))*1e-9  <<  " GFLOPS \t(" << t.total(CPU_TIMER)  << "s)\n";
    std::cout << "\"matlab\" real   " << t.best(REAL_TIMER)/rep << "s  \t" << (double(m)*n*p*rep*2/t.best(REAL_TIMER))*1e-9 <<  " GFLOPS \t(" << t.total(REAL_TIMER) << "s)\n";
  }
  if((!NumTraits<A::Scalar>::IsComplex) && (NumTraits<B::Scalar>::IsComplex))
  {
    M a(m,p);  a.setRandom();
    M br(p,n); br.setRandom();
    M bi(p,n); bi.setRandom();
    M cr(m,n); cr.setRandom();
    M ci(m,n); ci.setRandom();

    BenchTimer t;
    BENCH(t, tries, rep, matlab_real_cplx(a,br,bi,cr,ci));
    std::cout << "\"matlab\" cpu    " << t.best(CPU_TIMER)/rep  << "s  \t" << (double(m)*n*p*rep*2/t.best(CPU_TIMER))*1e-9  <<  " GFLOPS \t(" << t.total(CPU_TIMER)  << "s)\n";
    std::cout << "\"matlab\" real   " << t.best(REAL_TIMER)/rep << "s  \t" << (double(m)*n*p*rep*2/t.best(REAL_TIMER))*1e-9 <<  " GFLOPS \t(" << t.total(REAL_TIMER) << "s)\n";
  }
  if((NumTraits<A::Scalar>::IsComplex) && (!NumTraits<B::Scalar>::IsComplex))
  {
    M ar(m,p); ar.setRandom();
    M ai(m,p); ai.setRandom();
    M b(p,n);  b.setRandom();
    M cr(m,n); cr.setRandom();
    M ci(m,n); ci.setRandom();

    BenchTimer t;
    BENCH(t, tries, rep, matlab_cplx_real(ar,ai,b,cr,ci));
    std::cout << "\"matlab\" cpu    " << t.best(CPU_TIMER)/rep  << "s  \t" << (double(m)*n*p*rep*2/t.best(CPU_TIMER))*1e-9  <<  " GFLOPS \t(" << t.total(CPU_TIMER)  << "s)\n";
    std::cout << "\"matlab\" real   " << t.best(REAL_TIMER)/rep << "s  \t" << (double(m)*n*p*rep*2/t.best(REAL_TIMER))*1e-9 <<  " GFLOPS \t(" << t.total(REAL_TIMER) << "s)\n";
  }
  #endif

  return 0;
}

<commit_msg>fix bench_gemm<commit_after>
// g++-4.4 bench_gemm.cpp -I .. -O2 -DNDEBUG -lrt -fopenmp && OMP_NUM_THREADS=2  ./a.out
// icpc bench_gemm.cpp -I .. -O3 -DNDEBUG -lrt -openmp  && OMP_NUM_THREADS=2  ./a.out

#include <iostream>
#include <Eigen/Core>
#include <bench/BenchTimer.h>

using namespace std;
using namespace Eigen;

#ifndef SCALAR
// #define SCALAR std::complex<float>
#define SCALAR float
#endif

typedef SCALAR Scalar;
typedef NumTraits<Scalar>::Real RealScalar;
typedef Matrix<RealScalar,Dynamic,Dynamic> A;
typedef Matrix</*Real*/Scalar,Dynamic,Dynamic> B;
typedef Matrix<Scalar,Dynamic,Dynamic> C;
typedef Matrix<RealScalar,Dynamic,Dynamic> M;

#ifdef HAVE_BLAS

extern "C" {
  #include <bench/btl/libs/C_BLAS/blas.h>
}

static float fone = 1;
static float fzero = 0;
static double done = 1;
static double szero = 0;
static std::complex<float> cfone = 1;
static std::complex<float> cfzero = 0;
static std::complex<double> cdone = 1;
static std::complex<double> cdzero = 0;
static char notrans = 'N';
static char trans = 'T';
static char nonunit = 'N';
static char lower = 'L';
static char right = 'R';
static int intone = 1;

void blas_gemm(const MatrixXf& a, const MatrixXf& b, MatrixXf& c)
{
  int M = c.rows(); int N = c.cols(); int K = a.cols();
  int lda = a.rows(); int ldb = b.rows(); int ldc = c.rows();

  sgemm_(&notrans,&notrans,&M,&N,&K,&fone,
         const_cast<float*>(a.data()),&lda,
         const_cast<float*>(b.data()),&ldb,&fone,
         c.data(),&ldc);
}

EIGEN_DONT_INLINE void blas_gemm(const MatrixXd& a, const MatrixXd& b, MatrixXd& c)
{
  int M = c.rows(); int N = c.cols(); int K = a.cols();
  int lda = a.rows(); int ldb = b.rows(); int ldc = c.rows();

  dgemm_(&notrans,&notrans,&M,&N,&K,&done,
         const_cast<double*>(a.data()),&lda,
         const_cast<double*>(b.data()),&ldb,&done,
         c.data(),&ldc);
}

void blas_gemm(const MatrixXcf& a, const MatrixXcf& b, MatrixXcf& c)
{
  int M = c.rows(); int N = c.cols(); int K = a.cols();
  int lda = a.rows(); int ldb = b.rows(); int ldc = c.rows();

  cgemm_(&notrans,&notrans,&M,&N,&K,(float*)&cfone,
         const_cast<float*>((const float*)a.data()),&lda,
         const_cast<float*>((const float*)b.data()),&ldb,(float*)&cfone,
         (float*)c.data(),&ldc);
}

void blas_gemm(const MatrixXcd& a, const MatrixXcd& b, MatrixXcd& c)
{
  int M = c.rows(); int N = c.cols(); int K = a.cols();
  int lda = a.rows(); int ldb = b.rows(); int ldc = c.rows();

  zgemm_(&notrans,&notrans,&M,&N,&K,(double*)&cdone,
         const_cast<double*>((const double*)a.data()),&lda,
         const_cast<double*>((const double*)b.data()),&ldb,(double*)&cdone,
         (double*)c.data(),&ldc);
}

#endif

void matlab_cplx_cplx(const M& ar, const M& ai, const M& br, const M& bi, M& cr, M& ci)
{
  cr.noalias() += ar * br;
  cr.noalias() -= ai * bi;
  ci.noalias() += ar * bi;
  ci.noalias() += ai * br;
}

void matlab_real_cplx(const M& a, const M& br, const M& bi, M& cr, M& ci)
{
  cr.noalias() += a * br;
  ci.noalias() += a * bi;
}

void matlab_cplx_real(const M& ar, const M& ai, const M& b, M& cr, M& ci)
{
  cr.noalias() += ar * b;
  ci.noalias() += ai * b;
}

template<typename A, typename B, typename C>
EIGEN_DONT_INLINE void gemm(const A& a, const B& b, C& c)
{
 c.noalias() += a * b;
}

int main(int argc, char ** argv)
{
  std::ptrdiff_t l1 = internal::queryL1CacheSize();
  std::ptrdiff_t l2 = internal::queryTopLevelCacheSize();
  std::cout << "L1 cache size     = " << (l1>0 ? l1/1024 : -1) << " KB\n";
  std::cout << "L2/L3 cache size  = " << (l2>0 ? l2/1024 : -1) << " KB\n";
  typedef internal::gebp_traits<Scalar,Scalar> Traits;
  std::cout << "Register blocking = " << Traits::mr << " x " << Traits::nr << "\n";

  int rep = 1;    // number of repetitions per try
  int tries = 2;  // number of tries, we keep the best

  int s = 2048;
  int cache_size = -1;

  bool need_help = false;
  for (int i=1; i<argc; ++i)
  {
    if(argv[i][0]=='s')
      s = atoi(argv[i]+1);
    else if(argv[i][0]=='c')
      cache_size = atoi(argv[i]+1);
    else if(argv[i][0]=='t')
      tries = atoi(argv[i]+1);
    else if(argv[i][0]=='p')
      rep = atoi(argv[i]+1);
    else
      need_help = true;
  }

  if(need_help)
  {
    std::cout << argv[0] << " s<matrix size> c<cache size> t<nb tries> p<nb repeats>\n";
    return 1;
  }

  if(cache_size>0)
    setCpuCacheSizes(cache_size,96*cache_size);

  int m = s;
  int n = s;
  int p = s;
  A a(m,p); a.setRandom();
  B b(p,n); b.setRandom();
  C c(m,n); c.setOnes();
  C rc = c;

  std::cout << "Matrix sizes = " << m << "x" << p << " * " << p << "x" << n << "\n";
  std::ptrdiff_t mc(m), nc(n), kc(p);
  internal::computeProductBlockingSizes<Scalar,Scalar>(kc, mc, nc);
  std::cout << "blocking size (mc x kc) = " << mc << " x " << kc << "\n";

  C r = c;

  // check the parallel product is correct
  #if defined EIGEN_HAS_OPENMP
  int procs = omp_get_max_threads();
  if(procs>1)
  {
    #ifdef HAVE_BLAS
    blas_gemm(a,b,r);
    #else
    omp_set_num_threads(1);
    r.noalias() += a * b;
    omp_set_num_threads(procs);
    #endif
    c.noalias() += a * b;
    if(!r.isApprox(c)) std::cerr << "Warning, your parallel product is crap!\n\n";
  }
  #elif defined HAVE_BLAS
    blas_gemm(a,b,r);
    c.noalias() += a * b;
    if(!r.isApprox(c)) std::cerr << "Warning, your product is crap!\n\n";
  #else
    gemm(a,b,c);
    r.noalias() += a.cast<Scalar>() * b.cast<Scalar>();
    if(!r.isApprox(c)) std::cerr << "Warning, your product is crap!\n\n";
  #endif

  #ifdef HAVE_BLAS
  BenchTimer tblas;
  c = rc;
  BENCH(tblas, tries, rep, blas_gemm(a,b,c));
  std::cout << "blas  cpu         " << tblas.best(CPU_TIMER)/rep  << "s  \t" << (double(m)*n*p*rep*2/tblas.best(CPU_TIMER))*1e-9  <<  " GFLOPS \t(" << tblas.total(CPU_TIMER)  << "s)\n";
  std::cout << "blas  real        " << tblas.best(REAL_TIMER)/rep << "s  \t" << (double(m)*n*p*rep*2/tblas.best(REAL_TIMER))*1e-9 <<  " GFLOPS \t(" << tblas.total(REAL_TIMER) << "s)\n";
  #endif

  BenchTimer tmt;
  c = rc;
  BENCH(tmt, tries, rep, gemm(a,b,c));
  std::cout << "eigen cpu         " << tmt.best(CPU_TIMER)/rep  << "s  \t" << (double(m)*n*p*rep*2/tmt.best(CPU_TIMER))*1e-9  <<  " GFLOPS \t(" << tmt.total(CPU_TIMER)  << "s)\n";
  std::cout << "eigen real        " << tmt.best(REAL_TIMER)/rep << "s  \t" << (double(m)*n*p*rep*2/tmt.best(REAL_TIMER))*1e-9 <<  " GFLOPS \t(" << tmt.total(REAL_TIMER) << "s)\n";

  #ifdef EIGEN_HAS_OPENMP
  if(procs>1)
  {
    BenchTimer tmono;
    omp_set_num_threads(1);
    Eigen::internal::setNbThreads(1);
    c = rc;
    BENCH(tmono, tries, rep, gemm(a,b,c));
    std::cout << "eigen mono cpu    " << tmono.best(CPU_TIMER)/rep  << "s  \t" << (double(m)*n*p*rep*2/tmono.best(CPU_TIMER))*1e-9  <<  " GFLOPS \t(" << tmono.total(CPU_TIMER)  << "s)\n";
    std::cout << "eigen mono real   " << tmono.best(REAL_TIMER)/rep << "s  \t" << (double(m)*n*p*rep*2/tmono.best(REAL_TIMER))*1e-9 <<  " GFLOPS \t(" << tmono.total(REAL_TIMER) << "s)\n";
    std::cout << "mt speed up x" << tmono.best(CPU_TIMER) / tmt.best(REAL_TIMER)  << " => " << (100.0*tmono.best(CPU_TIMER) / tmt.best(REAL_TIMER))/procs << "%\n";
  }
  #endif

  #ifdef DECOUPLED
  if((NumTraits<A::Scalar>::IsComplex) && (NumTraits<B::Scalar>::IsComplex))
  {
    M ar(m,p); ar.setRandom();
    M ai(m,p); ai.setRandom();
    M br(p,n); br.setRandom();
    M bi(p,n); bi.setRandom();
    M cr(m,n); cr.setRandom();
    M ci(m,n); ci.setRandom();

    BenchTimer t;
    BENCH(t, tries, rep, matlab_cplx_cplx(ar,ai,br,bi,cr,ci));
    std::cout << "\"matlab\" cpu    " << t.best(CPU_TIMER)/rep  << "s  \t" << (double(m)*n*p*rep*2/t.best(CPU_TIMER))*1e-9  <<  " GFLOPS \t(" << t.total(CPU_TIMER)  << "s)\n";
    std::cout << "\"matlab\" real   " << t.best(REAL_TIMER)/rep << "s  \t" << (double(m)*n*p*rep*2/t.best(REAL_TIMER))*1e-9 <<  " GFLOPS \t(" << t.total(REAL_TIMER) << "s)\n";
  }
  if((!NumTraits<A::Scalar>::IsComplex) && (NumTraits<B::Scalar>::IsComplex))
  {
    M a(m,p);  a.setRandom();
    M br(p,n); br.setRandom();
    M bi(p,n); bi.setRandom();
    M cr(m,n); cr.setRandom();
    M ci(m,n); ci.setRandom();

    BenchTimer t;
    BENCH(t, tries, rep, matlab_real_cplx(a,br,bi,cr,ci));
    std::cout << "\"matlab\" cpu    " << t.best(CPU_TIMER)/rep  << "s  \t" << (double(m)*n*p*rep*2/t.best(CPU_TIMER))*1e-9  <<  " GFLOPS \t(" << t.total(CPU_TIMER)  << "s)\n";
    std::cout << "\"matlab\" real   " << t.best(REAL_TIMER)/rep << "s  \t" << (double(m)*n*p*rep*2/t.best(REAL_TIMER))*1e-9 <<  " GFLOPS \t(" << t.total(REAL_TIMER) << "s)\n";
  }
  if((NumTraits<A::Scalar>::IsComplex) && (!NumTraits<B::Scalar>::IsComplex))
  {
    M ar(m,p); ar.setRandom();
    M ai(m,p); ai.setRandom();
    M b(p,n);  b.setRandom();
    M cr(m,n); cr.setRandom();
    M ci(m,n); ci.setRandom();

    BenchTimer t;
    BENCH(t, tries, rep, matlab_cplx_real(ar,ai,b,cr,ci));
    std::cout << "\"matlab\" cpu    " << t.best(CPU_TIMER)/rep  << "s  \t" << (double(m)*n*p*rep*2/t.best(CPU_TIMER))*1e-9  <<  " GFLOPS \t(" << t.total(CPU_TIMER)  << "s)\n";
    std::cout << "\"matlab\" real   " << t.best(REAL_TIMER)/rep << "s  \t" << (double(m)*n*p*rep*2/t.best(REAL_TIMER))*1e-9 <<  " GFLOPS \t(" << t.total(REAL_TIMER) << "s)\n";
  }
  #endif

  return 0;
}

<|endoftext|>


<commit_before>#pragma once

#include <cstdio>  // declaration of ::fileno
#include <fstream>  // for basic_filebuf template
#include <cerrno>

#if defined(__GLIBCXX__) || (defined(__GLIBCPP__) && __GLIBCPP__>=20020514)  // GCC >= 3.1.0
# include <ext/stdio_filebuf.h>
#endif
#if defined(__GLIBCXX__) // GCC >= 3.4.0
# include <ext/stdio_sync_filebuf.h>
#endif

#if defined(_LIBCPP_VERSION)
// Generate a static data member of type Tag::type in which to store
// the address of a private member. It is crucial that Tag does not
// depend on the /value/ of the the stored address in any way so that
// we can access it from ordinary code without directly touching
// private data.
template < class Tag >
struct stowed
{
  static typename Tag::type value;
};

template < class Tag >
typename Tag::type stowed< Tag >::value;

// Generate a static data member whose constructor initializes
// stowed< Tag >::value. This type will only be named in an explicit
// instantiation, where it is legal to pass the address of a private
// member.
template < class Tag, typename Tag::type x >
struct stow_private
{
  stow_private() { stowed< Tag >::value = x; }
  static stow_private instance;
};
template < class Tag, typename Tag::type x >
stow_private< Tag, x > stow_private< Tag, x >::instance;

struct filebuf_file { typedef FILE*( std::filebuf::*type ); };
template struct stow_private< filebuf_file, &std::filebuf::__file_ >;
#endif

//! Similar to fileno(3), but taking a C++ stream as argument instead of a
//! FILE*.  Note that there is no way for the library to track what you do with
//! the descriptor, so be careful.
//! \return  The integer file descriptor associated with the stream, or -1 if
//!   that stream is invalid.  In the latter case, for the sake of keeping the
//!   code as similar to fileno(3), errno is set to EBADF.
//! \see  The upstream page at
//!   http://www.ginac.de/~kreckel/fileno/ of this code provides more
//!   detailed information.
template <typename charT, typename traits>
inline int
fileno_hack(const std::basic_ios<charT, traits>& stream)
{
    // Some C++ runtime libraries shipped with ancient GCC, Sun Pro,
    // Sun WS/Forte 5/6, Compaq C++ supported non-standard file descriptor
    // access basic_filebuf<>::fd().  Alas, starting from GCC 3.1, the GNU C++
    // runtime removes all non-standard std::filebuf methods and provides an
    // extension template class __gnu_cxx::stdio_filebuf on all systems where
    // that appears to make sense (i.e. at least all Unix systems).  Starting
    // from GCC 3.4, there is an __gnu_cxx::stdio_sync_filebuf, in addition.
    // Sorry, darling, I must get brutal to fetch the darn file descriptor!
    // Please complain to your compiler/libstdc++ vendor...
#if defined(__GLIBCXX__) || defined(__GLIBCPP__)
    // OK, stop reading here, because it's getting obscene.  Cross fingers!
# if defined(__GLIBCXX__)  // >= GCC 3.4.0
    // This applies to cin, cout and cerr when not synced with stdio:
    typedef __gnu_cxx::stdio_filebuf<charT, traits> unix_filebuf_t;
    unix_filebuf_t* fbuf = dynamic_cast<unix_filebuf_t*>(stream.rdbuf());
    if (fbuf != NULL) {
        return fbuf->fd();
    }

    // This applies to filestreams:
    typedef std::basic_filebuf<charT, traits> filebuf_t;
    filebuf_t* bbuf = dynamic_cast<filebuf_t*>(stream.rdbuf());
    if (bbuf != NULL) {
        // This subclass is only there for accessing the FILE*.  Ouuwww, sucks!
        struct my_filebuf : public std::basic_filebuf<charT, traits> {
            // Note: _M_file is of type __basic_file<char> which has a
            // FILE* as its first (but private) member variable.
            FILE* c_file() { return *(FILE**)(&this->_M_file); }
        };
        FILE* c_file = static_cast<my_filebuf*>(bbuf)->c_file();
        if (c_file != NULL) {  // Could be NULL for failed ifstreams.
            return ::fileno(c_file);
        }
    }

    // This applies to cin, cout and cerr when synced with stdio:
    typedef __gnu_cxx::stdio_sync_filebuf<charT, traits> sync_filebuf_t;
    sync_filebuf_t* sbuf = dynamic_cast<sync_filebuf_t*>(stream.rdbuf());
    if (sbuf != NULL) {
#  if (__GLIBCXX__<20040906) // GCC < 3.4.2
        // This subclass is only there for accessing the FILE*.
        // See GCC PR#14600 and PR#16411.
        struct my_filebuf : public sync_filebuf_t {
            my_filebuf();  // Dummy ctor keeps the compiler happy.
            // Note: stdio_sync_filebuf has a FILE* as its first (but private)
            // member variable.  However, it is derived from basic_streambuf<>
            // and the FILE* is the first non-inherited member variable.
            FILE* c_file() {
                return *(FILE**)((char*)this + sizeof(std::basic_streambuf<charT, traits>));
            }
        };
        return ::fileno(static_cast<my_filebuf*>(sbuf)->c_file());
#  else
        return ::fileno(sbuf->file());
#  endif
    }
# else  // GCC < 3.4.0 used __GLIBCPP__
#  if (__GLIBCPP__>=20020514)  // GCC >= 3.1.0
    // This applies to cin, cout and cerr:
    typedef __gnu_cxx::stdio_filebuf<charT, traits> unix_filebuf_t;
    unix_filebuf_t* buf = dynamic_cast<unix_filebuf_t*>(stream.rdbuf());
    if (buf != NULL) {
        return buf->fd();
    }

    // This applies to filestreams:
    typedef std::basic_filebuf<charT, traits> filebuf_t;
    filebuf_t* bbuf = dynamic_cast<filebuf_t*>(stream.rdbuf());
    if (bbuf != NULL) {
        // This subclass is only there for accessing the FILE*.  Ouuwww, sucks!
        struct my_filebuf : public std::basic_filebuf<charT, traits> {
            // Note: _M_file is of type __basic_file<char> which has a
            // FILE* as its first (but private) member variable.
            FILE* c_file() { return *(FILE**)(&this->_M_file); }
        };
        FILE* c_file = static_cast<my_filebuf*>(bbuf)->c_file();
        if (c_file != NULL) {  // Could be NULL for failed ifstreams.
            return ::fileno(c_file);
        }
    }
#  else  // GCC 3.0.x
    typedef std::basic_filebuf<charT, traits> filebuf_t;
    filebuf_t* fbuf = dynamic_cast<filebuf_t*>(stream.rdbuf());
    if (fbuf != NULL) {
        struct my_filebuf : public filebuf_t {
            // Note: basic_filebuf<charT, traits> has a __basic_file<charT>* as
            // its first (but private) member variable.  Since it is derived
            // from basic_streambuf<charT, traits> we can guess its offset.
            // __basic_file<charT> in turn has a FILE* as its first (but
            // private) member variable.  Get it by brute force.  Oh, geez!
            FILE* c_file() {
                std::__basic_file<charT>* ptr_M_file = *(std::__basic_file<charT>**)((char*)this + sizeof(std::basic_streambuf<charT, traits>));
#  if _GLIBCPP_BASIC_FILE_INHERITANCE
                // __basic_file<charT> inherits from __basic_file_base<charT>
                return *(FILE**)((char*)ptr_M_file + sizeof(std::__basic_file_base<charT>));
#  else
                // __basic_file<charT> is base class, but with vptr.
                return *(FILE**)((char*)ptr_M_file + sizeof(void*));
#  endif
            }
        };
        return ::fileno(static_cast<my_filebuf*>(fbuf)->c_file());
    }
#  endif
# endif
#elif defined(_LIBCPP_VERSION)
    return ::fileno(stream.rdbuf()->*stowed< filebuf_file >::value);
#else
#  error "Does anybody know how to fetch the bloody file descriptor?"
    return stream.rdbuf()->fd();  // Maybe a good start?
#endif
#if !defined(_LIBCPP_VERSION)
    errno = EBADF;
#endif
    return -1;
}

#if defined(_LIBCPP_VERSION)
//! 8-Bit character instantiation: fileno(ios).
template <>
int
fileno_hack<char>(const std::ios& stream)
{
    return fileno_hack(stream);
}

//! Wide character instantiation: fileno(wios).
template <>
int
fileno_hack<wchar_t>(const std::wios& stream)
{
    return fileno_hack(stream);
}
#endif
<commit_msg>Remove unused file fileno.hpp.<commit_after><|endoftext|>


<commit_before>#ifndef SOLAIRE_CONTAINER_HPP
#define SOLAIRE_CONTAINER_HPP

//Copyright 2015 Adam Smith
//
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.

// Contact :
// Email             : solairelibrary@mail.com
// GitHub repository : https://github.com/SolaireLibrary/SolaireCPP

/*!
	\file Container.hpp
	\brief
	\author
	Created			: Adam Smith
	Last modified	: Adam Smith
	\date
	Created			: 3rd December 2015
	Last Modified	: 10th January 2016
*/

#include "Solaire/Core/Iterator.hpp"
#include "Solaire/Core/Allocator.hpp"

namespace Solaire {

	template<class T>
	SOLAIRE_EXPORT_INTERFACE StaticContainer {
    public:
        typedef T Type;
        typedef T* Pointer;
        typedef T& Reference;
        typedef const T* ConstPointer;
        typedef const T& ConstReference;
    protected:
        virtual Pointer SOLAIRE_EXPORT_CALL getPtr(int32_t) throw() = 0;
        virtual SharedAllocation<Iterator<T>> SOLAIRE_EXPORT_CALL begin_() throw() = 0;
        virtual SharedAllocation<Iterator<T>> SOLAIRE_EXPORT_CALL end_() throw() = 0;
        virtual SharedAllocation<Iterator<T>> SOLAIRE_EXPORT_CALL rbegin_() throw() = 0;
        virtual SharedAllocation<Iterator<T>> SOLAIRE_EXPORT_CALL rend_() throw() = 0;
    public:
        virtual SOLAIRE_EXPORT_CALL ~StaticContainer() throw() {}

        virtual bool SOLAIRE_EXPORT_CALL isContiguous() const throw() = 0;
        virtual int32_t SOLAIRE_EXPORT_CALL size() const throw() = 0;
        virtual Allocator& SOLAIRE_EXPORT_CALL getAllocator() const throw() = 0;

        SOLAIRE_FORCE_INLINE Reference operator[](const int32_t aIndex) throw() {
            return *getPtr(aIndex);
        }

        SOLAIRE_FORCE_INLINE ConstReference operator[](const int32_t aIndex) const throw() {
            return *const_cast<StaticContainer<T>*>(this)->getPtr(aIndex);
        }

        SOLAIRE_FORCE_INLINE STLIterator<T> begin() throw() {
            return STLIterator<T>(begin_());
        }

        SOLAIRE_FORCE_INLINE STLIterator<T> end() throw() {
            return STLIterator<T>(end_());
        }

        SOLAIRE_FORCE_INLINE STLIterator<const T> begin() const throw() {
            return STLIterator<T>(const_cast<StaticContainer<T>*>(this)->begin_());
        }

        SOLAIRE_FORCE_INLINE STLIterator<const T> end() const throw() {
            return STLIterator<T>(const_cast<StaticContainer<T>*>(this)->end_());
        }

        SOLAIRE_FORCE_INLINE STLIterator<T> rbegin() throw() {
            return STLIterator<T>(rbegin_());
        }

        SOLAIRE_FORCE_INLINE STLIterator<T> rend() throw() {
            return STLIterator<T>(rend_());
        }

        SOLAIRE_FORCE_INLINE STLIterator<const T> rbegin() const throw() {
            return STLIterator<T>(const_cast<StaticContainer<T>*>(this)->rbegin_());
        }

        SOLAIRE_FORCE_INLINE STLIterator<const T> rend() const throw() {
            return STLIterator<T>(const_cast<StaticContainer<T>*>(this)->rend_());
        }

        SOLAIRE_FORCE_INLINE operator StaticContainer<const T>&() throw() {
            return *reinterpret_cast<StaticContainer<const T>*>(this);
        }

        SOLAIRE_FORCE_INLINE operator const StaticContainer<const T>&() const throw() {
            return *reinterpret_cast<StaticContainer<const T>*>(this);
        }

        inline bool operator==(const StaticContainer<const T>& aOther) const throw() {
            const int32_t length = size();
            if(length != aOther.size()) return false;
            if(std::is_fundamental<T>::value && isContiguous() && aOther.isContiguous()) {
                return std::memcmp(getPtr(0), aOther.getPtr(0), sizeof(T) * length) == 0;
            }else {
                for(int32_t i = 0; i < length; ++i) {
                    if(getPtr(i) != aOther.getPtr(i)) return false;
                }
                return true;
            }
        }

        inline bool operator!=(const StaticContainer<const T>& aOther) const throw() {
            const int32_t length = size();
            if(length != aOther.size()) return true;
            if(std::is_fundamental<T>::value && isContiguous() && aOther.isContiguous()) {
                return std::memcmp(getPtr(0), aOther.getPtr(0), sizeof(T) * length) != 0;
            }else {
                for(int32_t i = 0; i < length; ++i) {
                    if(getPtr(i) != aOther.getPtr(i)) return true;
                }
                return false;
            }
        }

        SOLAIRE_FORCE_INLINE int32_t FindFirstOf(const T& aValue) const throw() {
            return FindNextOf(0, aValue);
        }

        inline int32_t FindNextOf(const int32_t aIndex, const T& aValue) const throw() {
            const int32_t length = size();
            if(isContiguous()) {
                const T* const ptr = getPtr(0);
                for(int32_t i = aIndex; i < length; ++i) {
                    if(ptr[i] == aValue) return i;
                }
            }else {
                for(int32_t i = aIndex; i < length; ++i) {
                    if(*getPtr(i) == aValue) return i;
                }
            }

            return length;
        }

        inline int32_t FindLastOf(const T& aValue) const throw() {
            const int32_t end = size();
            int32_t i = FindFirstOf(aValue);
            int32_t j = i;

            while(i != end) {
                j = i;
                i = FindNextOf(i + 1, aValue);
            }

            return j;
        }
	};

	template<class T>
	SOLAIRE_EXPORT_INTERFACE Stack : public StaticContainer<T> {
	public:
		virtual  SOLAIRE_EXPORT_CALL ~Stack() throw() {}
		virtual T& SOLAIRE_EXPORT_CALL pushBack(const T&) throw() = 0;
		virtual T SOLAIRE_EXPORT_CALL popBack() throw() = 0;
		virtual void SOLAIRE_EXPORT_CALL clear() throw() = 0;

		SOLAIRE_FORCE_INLINE T& SOLAIRE_DEFAULT_CALL back() throw() {
			return StaticContainer<T>::operator[](StaticContainer<T>::size() - 1);
		}

		SOLAIRE_FORCE_INLINE const T& SOLAIRE_DEFAULT_CALL back() const throw() {
			return StaticContainer<T>::operator[](StaticContainer<T>::size() - 1);
		}

        SOLAIRE_FORCE_INLINE operator Stack<const T>&() throw() {
            return *reinterpret_cast<Stack<const T>*>(this);
        }

        SOLAIRE_FORCE_INLINE operator const Stack<const T>&() const throw() {
            return *reinterpret_cast<Stack<const T>*>(this);
        }
	};

	template<class T>
	SOLAIRE_EXPORT_INTERFACE Deque : public Stack<T> {
	public:
		virtual SOLAIRE_EXPORT_CALL ~Deque() throw() {}

		virtual T& SOLAIRE_EXPORT_CALL pushFront(const T&) throw() = 0;
		virtual T SOLAIRE_EXPORT_CALL popFront() throw() = 0;

		SOLAIRE_FORCE_INLINE T& SOLAIRE_DEFAULT_CALL front() throw() {
			return StaticContainer<T>::operator[](0);
		}

		SOLAIRE_FORCE_INLINE const T& SOLAIRE_DEFAULT_CALL front() const throw() {
			return StaticContainer<T>::operator[](0);
		}

        SOLAIRE_FORCE_INLINE operator Deque<const T>&() throw() {
            return *reinterpret_cast<Deque<const T>*>(this);
        }

        SOLAIRE_FORCE_INLINE operator const Deque<const T>&() const throw() {
            return *reinterpret_cast<Deque<const T>*>(this);
        }
	};

	template<class T>
	SOLAIRE_EXPORT_INTERFACE List : public Deque<T> {
	public:
		virtual SOLAIRE_EXPORT_CALL ~List() throw() {}

		virtual T& SOLAIRE_EXPORT_CALL insertBefore(const int32_t, const T&) throw() = 0;
		virtual T& SOLAIRE_EXPORT_CALL insertAfter(const int32_t, const T&) throw() = 0;
		virtual bool SOLAIRE_EXPORT_CALL erase(const int32_t) throw() = 0;

        SOLAIRE_FORCE_INLINE operator List<const T>&() throw() {
            return *reinterpret_cast<List<const T>*>(this);
        }

        SOLAIRE_FORCE_INLINE operator const List<const T>&() const throw() {
            return *reinterpret_cast<List<const T>*>(this);
        }
	};

	typedef StaticContainer<const char> StringConstant;
	typedef List<char> String;

}

#endif
<commit_msg>Fixed find function naming<commit_after>#ifndef SOLAIRE_CONTAINER_HPP
#define SOLAIRE_CONTAINER_HPP

//Copyright 2015 Adam Smith
//
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.

// Contact :
// Email             : solairelibrary@mail.com
// GitHub repository : https://github.com/SolaireLibrary/SolaireCPP

/*!
	\file Container.hpp
	\brief
	\author
	Created			: Adam Smith
	Last modified	: Adam Smith
	\date
	Created			: 3rd December 2015
	Last Modified	: 10th January 2016
*/

#include "Solaire/Core/Iterator.hpp"
#include "Solaire/Core/Allocator.hpp"

namespace Solaire {

	template<class T>
	SOLAIRE_EXPORT_INTERFACE StaticContainer {
    public:
        typedef T Type;
        typedef T* Pointer;
        typedef T& Reference;
        typedef const T* ConstPointer;
        typedef const T& ConstReference;
    protected:
        virtual Pointer SOLAIRE_EXPORT_CALL getPtr(int32_t) throw() = 0;
        virtual SharedAllocation<Iterator<T>> SOLAIRE_EXPORT_CALL begin_() throw() = 0;
        virtual SharedAllocation<Iterator<T>> SOLAIRE_EXPORT_CALL end_() throw() = 0;
        virtual SharedAllocation<Iterator<T>> SOLAIRE_EXPORT_CALL rbegin_() throw() = 0;
        virtual SharedAllocation<Iterator<T>> SOLAIRE_EXPORT_CALL rend_() throw() = 0;
    public:
        virtual SOLAIRE_EXPORT_CALL ~StaticContainer() throw() {}

        virtual bool SOLAIRE_EXPORT_CALL isContiguous() const throw() = 0;
        virtual int32_t SOLAIRE_EXPORT_CALL size() const throw() = 0;
        virtual Allocator& SOLAIRE_EXPORT_CALL getAllocator() const throw() = 0;

        SOLAIRE_FORCE_INLINE Reference operator[](const int32_t aIndex) throw() {
            return *getPtr(aIndex);
        }

        SOLAIRE_FORCE_INLINE ConstReference operator[](const int32_t aIndex) const throw() {
            return *const_cast<StaticContainer<T>*>(this)->getPtr(aIndex);
        }

        SOLAIRE_FORCE_INLINE STLIterator<T> begin() throw() {
            return STLIterator<T>(begin_());
        }

        SOLAIRE_FORCE_INLINE STLIterator<T> end() throw() {
            return STLIterator<T>(end_());
        }

        SOLAIRE_FORCE_INLINE STLIterator<const T> begin() const throw() {
            return STLIterator<T>(const_cast<StaticContainer<T>*>(this)->begin_());
        }

        SOLAIRE_FORCE_INLINE STLIterator<const T> end() const throw() {
            return STLIterator<T>(const_cast<StaticContainer<T>*>(this)->end_());
        }

        SOLAIRE_FORCE_INLINE STLIterator<T> rbegin() throw() {
            return STLIterator<T>(rbegin_());
        }

        SOLAIRE_FORCE_INLINE STLIterator<T> rend() throw() {
            return STLIterator<T>(rend_());
        }

        SOLAIRE_FORCE_INLINE STLIterator<const T> rbegin() const throw() {
            return STLIterator<T>(const_cast<StaticContainer<T>*>(this)->rbegin_());
        }

        SOLAIRE_FORCE_INLINE STLIterator<const T> rend() const throw() {
            return STLIterator<T>(const_cast<StaticContainer<T>*>(this)->rend_());
        }

        SOLAIRE_FORCE_INLINE operator StaticContainer<const T>&() throw() {
            return *reinterpret_cast<StaticContainer<const T>*>(this);
        }

        SOLAIRE_FORCE_INLINE operator const StaticContainer<const T>&() const throw() {
            return *reinterpret_cast<StaticContainer<const T>*>(this);
        }

        inline bool operator==(const StaticContainer<const T>& aOther) const throw() {
            const int32_t length = size();
            if(length != aOther.size()) return false;
            if(std::is_fundamental<T>::value && isContiguous() && aOther.isContiguous()) {
                return std::memcmp(getPtr(0), aOther.getPtr(0), sizeof(T) * length) == 0;
            }else {
                for(int32_t i = 0; i < length; ++i) {
                    if(getPtr(i) != aOther.getPtr(i)) return false;
                }
                return true;
            }
        }

        inline bool operator!=(const StaticContainer<const T>& aOther) const throw() {
            const int32_t length = size();
            if(length != aOther.size()) return true;
            if(std::is_fundamental<T>::value && isContiguous() && aOther.isContiguous()) {
                return std::memcmp(getPtr(0), aOther.getPtr(0), sizeof(T) * length) != 0;
            }else {
                for(int32_t i = 0; i < length; ++i) {
                    if(getPtr(i) != aOther.getPtr(i)) return true;
                }
                return false;
            }
        }

        SOLAIRE_FORCE_INLINE int32_t findFirstOf(const T& aValue) const throw() {
            return findNextOf(0, aValue);
        }

        inline int32_t findNextOf(const int32_t aIndex, const T& aValue) const throw() {
            const int32_t length = size();
            if(isContiguous()) {
                const T* const ptr = getPtr(0);
                for(int32_t i = aIndex; i < length; ++i) {
                    if(ptr[i] == aValue) return i;
                }
            }else {
                for(int32_t i = aIndex; i < length; ++i) {
                    if(*getPtr(i) == aValue) return i;
                }
            }

            return length;
        }

        inline int32_t findLastOf(const T& aValue) const throw() {
            const int32_t end = size();
            int32_t i = findFirstOf(aValue);
            int32_t j = i;

            while(i != end) {
                j = i;
                i = findNextOf(i + 1, aValue);
            }

            return j;
        }
	};

	template<class T>
	SOLAIRE_EXPORT_INTERFACE Stack : public StaticContainer<T> {
	public:
		virtual  SOLAIRE_EXPORT_CALL ~Stack() throw() {}
		virtual T& SOLAIRE_EXPORT_CALL pushBack(const T&) throw() = 0;
		virtual T SOLAIRE_EXPORT_CALL popBack() throw() = 0;
		virtual void SOLAIRE_EXPORT_CALL clear() throw() = 0;

		SOLAIRE_FORCE_INLINE T& SOLAIRE_DEFAULT_CALL back() throw() {
			return StaticContainer<T>::operator[](StaticContainer<T>::size() - 1);
		}

		SOLAIRE_FORCE_INLINE const T& SOLAIRE_DEFAULT_CALL back() const throw() {
			return StaticContainer<T>::operator[](StaticContainer<T>::size() - 1);
		}

        SOLAIRE_FORCE_INLINE operator Stack<const T>&() throw() {
            return *reinterpret_cast<Stack<const T>*>(this);
        }

        SOLAIRE_FORCE_INLINE operator const Stack<const T>&() const throw() {
            return *reinterpret_cast<Stack<const T>*>(this);
        }
	};

	template<class T>
	SOLAIRE_EXPORT_INTERFACE Deque : public Stack<T> {
	public:
		virtual SOLAIRE_EXPORT_CALL ~Deque() throw() {}

		virtual T& SOLAIRE_EXPORT_CALL pushFront(const T&) throw() = 0;
		virtual T SOLAIRE_EXPORT_CALL popFront() throw() = 0;

		SOLAIRE_FORCE_INLINE T& SOLAIRE_DEFAULT_CALL front() throw() {
			return StaticContainer<T>::operator[](0);
		}

		SOLAIRE_FORCE_INLINE const T& SOLAIRE_DEFAULT_CALL front() const throw() {
			return StaticContainer<T>::operator[](0);
		}

        SOLAIRE_FORCE_INLINE operator Deque<const T>&() throw() {
            return *reinterpret_cast<Deque<const T>*>(this);
        }

        SOLAIRE_FORCE_INLINE operator const Deque<const T>&() const throw() {
            return *reinterpret_cast<Deque<const T>*>(this);
        }
	};

	template<class T>
	SOLAIRE_EXPORT_INTERFACE List : public Deque<T> {
	public:
		virtual SOLAIRE_EXPORT_CALL ~List() throw() {}

		virtual T& SOLAIRE_EXPORT_CALL insertBefore(const int32_t, const T&) throw() = 0;
		virtual T& SOLAIRE_EXPORT_CALL insertAfter(const int32_t, const T&) throw() = 0;
		virtual bool SOLAIRE_EXPORT_CALL erase(const int32_t) throw() = 0;

        SOLAIRE_FORCE_INLINE operator List<const T>&() throw() {
            return *reinterpret_cast<List<const T>*>(this);
        }

        SOLAIRE_FORCE_INLINE operator const List<const T>&() const throw() {
            return *reinterpret_cast<List<const T>*>(this);
        }
	};

	typedef StaticContainer<const char> StringConstant;
	typedef List<char> String;

}

#endif
<|endoftext|>